delphi – 如何使用WH_CBT挂钩和WndProc捕获发送到窗口的所有消
发布时间:2020-12-15 09:15:07 所属栏目:大数据 来源:网络整理
导读:我正在构建一个dll内部的日志系统,其主要任务是捕获目标应用程序的一些特定 Windows消息并执行一些任务.但遗憾的是,WndProc方法(WM_GETMINMAXINFO)只捕获了一条消息.我错过了什么?为什么不将所有Windows消息写入日志? 这是解决问题的最小示例代码 DLL libr
我正在构建一个dll内部的日志系统,其主要任务是捕获目标应用程序的一些特定
Windows消息并执行一些任务.但遗憾的是,WndProc方法(WM_GETMINMAXINFO)只捕获了一条消息.我错过了什么?为什么不将所有Windows消息写入日志?
这是解决问题的最小示例代码 DLL library LogDll; uses Winapi.Windows,Winapi.Messages,System.IOUtils,System.SysUtils,System.Classes; {$R *.res} type TLogInspector = class private WndHandle: THandle; ProcAddrInst: Pointer; OrgWndProc: Pointer; protected function CallOrgWndProc(Message: TMessage): LRESULT; procedure WndProc(var Message: TMessage); virtual; public constructor Create(AHandle: THandle); virtual; end; var MainHook: HHook; Log : TLogInspector; function TLogInspector.CallOrgWndProc(Message: TMessage): LRESULT; begin Result := CallWindowProc(OrgWndProc,WndHandle,Message.Msg,Message.wParam,Message.lParam); end; constructor TLogInspector.Create(AHandle: THandle); begin OrgWndProc := Pointer(GetWindowLongPtr(AHandle,GWL_WNDPROC)); ProcAddrInst := MakeObjectInstance(WndProc); WndHandle := AHandle; SetWindowLongPtr(WndHandle,GWL_WNDPROC,LONG_PTR(ProcAddrInst)); end; procedure TLogInspector.WndProc(var Message: TMessage); begin //log the current message TFile.AppendAllText('C:Delphilog.txt','WndProc '+IntToStr(Message.Msg)+sLineBreak); //call the org WndProc Message.Result := CallOrgWndProc(Message); end; function HookCallBack(nCode: Integer; _WPARAM: WPARAM; _LPARAM: LPARAM): LRESULT; stdcall; var lpClassName : array [0 .. 256] of Char; begin if nCode = HCBT_CREATEWND then begin GetClassName(_WPARAM,lpClassName,256); if lpClassName = 'TForm1' then Log:= TLogInspector.Create(_WPARAM); end; Result := CallNextHookEx(MainHook,nCode,_WPARAM,_LPARAM); end; procedure InitLog; stdcall; begin MainHook := SetWindowsHookEx(WH_CBT,@HookCallBack,GetCurrentThreadId); end; procedure DoneLog; stdcall; begin UnhookWindowsHookEx(MainHook); end; exports InitLog,DoneLog; begin end. 应用 type TForm1 = class(TForm) Button1: TButton; private { Private declarations } public { Public declarations } end; var Form1: TForm1; procedure InitLog; stdcall; external 'LogDll.dll' name 'InitLog'; procedure DoneLog; stdcall; external 'LogDll.dll' name 'DoneLog'; implementation {$R *.dfm} initialization InitLog; finalization DoneLog; end. 解决方法
您的测试用例过早地替换了窗口过程.操作系统’在将第一个消息传递到实际窗口的窗口过程之前通过窗口创建通知挂钩导致在VCL最终设置窗体的窗口过程之前替换窗口过程.以下是关于如何用VCL替换窗口过程的关键事件的摘要:
>在项目中,VCL将表单的初始窗口过程设置为’controls’中的InitWndProc. 在SetWindowLongPtr上的dll中设置一个断点,在’controls.pas’的InitWndProc中的SetWindowLong上设置一个断点,以查看它的运行情况. ?使用WH_CALLWNDPROC挂钩,您可能不需要对窗口进行子类化以便能够记录发送给它的消息.例如.: function HookCallBack(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var lpClassName : array [0 .. 256] of Char; begin Result := CallNextHookEx(MainHook,wParam,lParam); if nCode >= 0 then begin GetClassName(PCWPStruct(lParam).hwnd,256); if lpClassName = 'TForm1' then TFile.AppendAllText('C:Delphilog.txt','WndProc ' + IntToStr(PCWPStruct(lParam).message) + sLineBreak); end; end; procedure InitLog; stdcall; begin MainHook := SetWindowsHookEx(WH_CALLWNDPROC,GetCurrentThreadId); end; 但是,如果你必须,你可以做到f.i.在WM_NCCREATE中. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |