请教线程注入DLL窗体的问题.(100)

  • 主题发起人 主题发起人 wyd19790823
  • 开始时间 开始时间
W

wyd19790823

Unregistered / Unconfirmed
GUEST, unregistred user!
问题一: 如果DLL中的窗体是非模态窗体只是闪烁一下又消失了,否则模态窗体一直显示,但是主程序无法结束该线程.如果没有结束线程,主程序退出时可能报非法引用内存错误;问题二: 线程插入后的DLL,我的EXE程序能否传递参数给DLL?如果能,如何传递?针对这两问题,各位主手有没有什么好的方法?
 
怎么都没人回复啊?各位高手都忙啥去了?
 
ShowModal内有消息循环,所以会一直显示。在其他进程创建的线程,是需要消息循环的。不然线程直接就结束了,当然闪烁一下就消失了。给DLL传参数可以发消息给DLL创建的窗体,自定义消息或者WM_COPYDATA,或者内存映射,等等方法。
 
不好意思,我对这些不太了解,有没有demo给我学习一下啊?或者提供一些代码出来.先谢谢了
 
to 刘兄! 能不能帮帮我啊.我想做到的是,传递参数进去,并有返回值,怎么做,能否把代码贴出来学习一下啊?麻烦你了!
 
进程之间发送字符串 procedure PostStrToOther(H: HWND; OtherStr: string); var DS: TCopyDataStruct; begin ShowMessage('发送:' + OtherStr); Ds.cbData := Length(OtherStr) + 1; GetMem(Ds.lpData, Ds.cbData); StrCopy(ds.lpData, PChar(OtherStr)); SendMessage(H, WM_COPYDATA, Application.Handle, Cardinal(@ds)); FreeMem(Ds.lpData); end; procedure TFrmOther.MyMessage(var t: TWMCopyData); //Message WM_COPYDATA; var tmpStr:String; begin //接受消息并显示。 tmpStr:=StrPas(t.CopyDataStruct^.lpData); Memo1.Lines.Add(tmpStr); end;================当然,也可以发送自定义的结构体,目标窗体接收到该消息后,通过类似方法将结果发送回去。(结构体中应该需要包括源窗体句柄)
 
可以传递参数啊,例如用内存映射,你的现成里面作一个循环读标志的,标志成立,那么取新参数,现成里面复位标志
 
to znxia我也正是想传自定义结构体进去,返回的也是结构体.我的传入的结构体是: TMyFileInfo=record FileName :String[255]; ExeSize :Integer; end;传出的结构体是: TReadResult=record FileName :String[255]; MS :TmemoryStream; end;能否帮我修改一下代码?不好意思,我这对个不懂.
 
另外一个问题,假如我的DLL没有Form,并且DLL是注入到A.exe程序,这时B.exe 程序向DLL发消息的话,PostStrToOther(H: HWND; OtherStr: string)中,H值应该怎么取?
 
参考一下Timer控件,里面创建了一个没有窗口的句柄。为此,新建一个单元Unit2:DLL中主动将句柄发送给B.EXE.unit Unit2;interfaceuses Classes, Windows, Messages, Forms, Consts,Dialogs,Sysutils;type TReadResult = record FileName: string[255]; MS: TmemoryStream; end; PReadResult = ^TReadResult; TTimerEx = class(TComponent) private FInterval: Cardinal; FWindowHandle: HWND; FOnTimer: TNotifyEvent; FEnabled: Boolean; procedure UpdateTimer; procedure SetEnabled(Value: Boolean); procedure SetInterval(Value: Cardinal); procedure SetOnTimer(Value: TNotifyEvent); procedure WndProc(var Msg: TMessage); protected procedure Timer; dynamic; procedure DoCopyMsg(Var Msg:TWMCopyData); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property Enabled: Boolean read FEnabled write SetEnabled default True; property Interval: Cardinal read FInterval write SetInterval default 1000; property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer; property WinHandle: HWND read FWindowHandle; //新增加的,用于接收消息的句柄 end;implementation{ TTimerEx }constructor TTimerEx.Create(AOwner: TComponent);begin inherited Create(AOwner); FEnabled := True; FInterval := 1000;{$IFDEF MSWINDOWS} FWindowHandle := Classes.AllocateHWnd(WndProc);{$ENDIF}{$IFDEF LINUX} FWindowHandle := WinUtils.AllocateHWnd(WndProc);{$ENDIF}end;destructor TTimerEx.Destroy;begin FEnabled := False; UpdateTimer;{$IFDEF MSWINDOWS} Classes.DeallocateHWnd(FWindowHandle);{$ENDIF}{$IFDEF LINUX} WinUtils.DeallocateHWnd(FWindowHandle);{$ENDIF} inherited Destroy;end;procedure TTimerEx.WndProc(var Msg: TMessage);begin case Msg.Msg of WM_TIMER: try Timer; except Application.HandleException(Self); end; WM_COPYDATA: DoCopyMsg( TWMCopyData(Msg)); else Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam); end;end;procedure TTimerEx.UpdateTimer;begin KillTimer(FWindowHandle, 1); if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then if SeTTimer(FWindowHandle, 1, FInterval, nil) = 0 then raise EOutOfResources.Create(SNoTimers);end;procedure TTimerEx.SetEnabled(Value: Boolean);begin if Value <> FEnabled then begin FEnabled := Value; UpdateTimer; end;end;procedure TTimerEx.SetInterval(Value: Cardinal);begin if Value <> FInterval then begin FInterval := Value; UpdateTimer; end;end;procedure TTimerEx.SetOnTimer(Value: TNotifyEvent);begin FOnTimer := Value; UpdateTimer;end;procedure TTimerEx.Timer;var H: THandle;begin if Assigned(FOnTimer) then FOnTimer(Self); H := Windows.FindWindow(nil, 'B.exe的Caption'); if H<>nil then 发送消息给B程序,告知DLL中的Handle(Self.FWindowHandle)是多少。建议用 TCopyDataStruct.dwData参数表示类别(如1表示发送的是Handle,2表示发送的是TMyFileInfo)end;procedure TTimerEx.DoCopyMsg(var Msg: TWMCopyData);var t:TmemoryStream;begin if Msg.CopyDataStruct.dwData=2 then begin t:=PReadResult(Msg.CopyDataStruct.lpData).MS;// showmessage(inttostr(t.Size)); t.SaveToFile('D:/a.txt'); end;end;end.=========================主程序调用:unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, ExtCtrls, StdCtrls;type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end;var Form1: TForm1;implementationuses Unit2;{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);var Timer1: TTimerEx; t: PReadResult; DS: TCopyDataStruct;begin Timer1 := TTimerEx.Create(Self); new(t); t.MS := TmemoryStream.Create; t.MS.WriteComponent(Self); Ds.dwData := 2; Ds.cbData := Sizeof(t) + 1; Ds.lpData := t; SendMessage(Timer1.WinHandle, WM_COPYDATA, Application.Handle, Cardinal(@ds)); FreeMem(Ds.lpData);end;end.不过,接收到流后,对流进行的操作,不会反应到原始流上去。
 
忘了说,为了方便测试,我直接把这个单元加入到工程文件了。Unit2应该是加入到DLL中,然后通过其它程序A.exe调用DLL,再写一个B程序,B程序获得DLL中发送过来的消息后,才可以得到DLL中的句柄,然后才可以给DLL发送消息。
 
to znxia呵呵,真有办法!不过,能不能再缩减点啊?会不会还有很多无用的代码啊?
 
绝大多数代码拷贝于Timer的代码。修改部分为: 1>将原来没开放的句柄开放了。 2>增加处理WM_COPYDATA消息。
 
谢谢各位,特别感谢znxia,我采用的是内存映射的方法来解决.
 
帮顶,接分
 
后退
顶部