微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我需要做些什么来使我的WH_SHELL或WH_CBT挂钩程序从其他进程接收事件?

我试图使用SetwindowsHookEx来build立一个WH_SHELL挂钩来获得系统范围的HSHELL_WINDOWCREATED和HSHELL_WINDOWDESTROYED事件的通知。 我把0传递给最后一个dwThreadId参数,根据文档 , 这个参数应该“将钩子过程与调用线程在同一桌面上运行的所有现有线程相关联”。 我也传递了我的DLL( HInstance在Delphi中)的句柄hMod参数,我所看到的所有例子。

然而,我只能得到我自己的应用程序创build的窗口的通知,而且往往会导致桌面进程一旦closures我的应用程序就会熄灭。 在你问之前,我打电话给UnhookWindowsHookEx 。 我也总是从我的处理程序中调用CallNextHookEx 。

我从一个有限的用户帐户运行我的testing应用程序,但到目前为止,我还没有发现任何暗示,这将发挥作用…(虽然这实际上令我惊讶)

AFAICT,我做了所有的书(显然我没有,但到目前为止,我不知道在哪里)。

Win32,如何在编译的程序中使用C ++挂钩函数

如果鼠标和触摸板都启用,如何检测input设备

64位DLL入口点覆盖

在64位Windows中挂钩32位进程

在挂接WH_CALLWNDPROC之后没有得到Window Procedure消息

我正在使用delphi(2007年),但这应该不是真的,我想。

编辑:也许我应该提到这之前:我下载并尝试了几个例子(虽然不幸的是没有那么多的delphi – 特别是没有WH_SHELL或WH_CBT )。 虽然他们不会像我的testing应用程序那样崩溃系统,但是他们仍然不会捕获来自其他进程的事件(尽pipe我可以使用ProcessExplorervalidation它们是否可以加载到其中)。 所以看起来我的系统configuration有问题,或者这个例子错了,或者根本无法从其他进程捕获事件。 任何人都可以启发我吗?

编辑2:好的,这是我的testing项目的来源。

包含挂钩过程的DLL:

library HookHelper; uses Windows; {$R *.res} type THookCallback = procedure(ACode,AWParam,ALParam: Integer); stdcall; var WndHookCallback: THookCallback; Hook: HHook; function HookProc(ACode,ALParam: Integer): Integer; stdcall; begin Result := CallNextHookEx(Hook,ACode,ALParam); if ACode < 0 then Exit; try if Assigned(WndHookCallback) // and (ACode in [HSHELL_WINDOWCREATED,HSHELL_WINDOWDESTROYED]) then and (ACode in [HCBT_CREATEWND,HCBT_DESTROYWND]) then WndHookCallback(ACode,ALParam); except // plop! end; end; procedure InitHook(ACallback: THookCallback); register; begin // Hook := SetwindowsHookEx(WH_SHELL,@HookProc,HInstance,0); Hook := SetwindowsHookEx(WH_CBT,0); if Hook = 0 then begin // ShowMessage(SysErrorMessage(GetLastError)); end else begin WndHookCallback := ACallback; end; end; procedure UninitHook; register; begin if Hook <> 0 then UnhookWindowsHookEx(Hook); WndHookCallback := nil; end; exports InitHook,UninitHook; begin end.

而使用钩子的应用程序的主要forms:

unit MainFo; interface uses Windows,SysUtils,Forms,Dialogs,Classes,Controls,Buttons,StdCtrls; type THookTest_Fo = class(TForm) Hook_Btn: TSpeedButton; Output_Lbx: TListBox; Test_Btn: TButton; procedure Hook_BtnClick(Sender: TObject); procedure Test_BtnClick(Sender: TObject); public destructor Destroy; override; end; var HookTest_Fo: THookTest_Fo; implementation {$R *.dfm} type THookCallback = procedure(ACode,ALParam: Integer); stdcall; procedure InitHook(const ACallback: THookCallback); register; external 'HookHelper.dll'; procedure UninitHook; register; external 'HookHelper.dll'; procedure HookCallback(ACode,ALParam: Integer); stdcall; begin if Assigned(HookTest_Fo) then case ACode of // HSHELL_WINDOWCREATED: HCBT_CREATEWND: HookTest_Fo.Output_Lbx.Items.Add('created handle #' + IntToStr(AWParam)); // HSHELL_WINDOWDESTROYED: HCBT_DESTROYWND: HookTest_Fo.Output_Lbx.Items.Add('destroyed handle #' + IntToStr(AWParam)); else HookTest_Fo.Output_Lbx.Items.Add(Format('code: %d,WParam: $%x,LParam: $%x',[ACode,ALParam])); end; end; procedure THookTest_Fo.Test_BtnClick(Sender: TObject); begin ShowMessage('Boo!'); end; destructor THookTest_Fo.Destroy; begin UninitHook; // just to make sure inherited; end; procedure THookTest_Fo.Hook_BtnClick(Sender: TObject); begin if Hook_Btn.Down then InitHook(HookCallback) else UninitHook; end; end.

Windows将总是允许钩子和/或日志logging?

如何捕获任何正在运行的控制台进程的特定键盘序列?

如何在没有任何DLL注入的情况下返回一个窗口的句柄?

C ++跳转钩子

如何挂钩我自己的进程的所有操作系统调用

问题是你的钩子DLL实际上被加载到几个不同的地址空间。 任何时候,Windows在一些必须由你的钩子处理的外部进程中检测到一个事件的时候,它会把钩子DLL加载到这个进程中(如果它还没有被加载的话)。

但是,每个进程都有自己的地址空间。 这意味着您在InitHook()中传递的回调函数指针只在您的EXE环境中有意义(这就是为什么它适用于您的应用程序中的事件)。 在其他任何指针是垃圾过程中; 它可能指向一个无效的内存位置,或者(更糟糕的)进入一些随机代码段。 结果可能是访问冲突或无记忆内容损坏。

通常,解决方案是使用某种进程间通信 (IPC)来正确地通知您的EXE。 对于您的情况最无痛的方式是发布消息,并将所需的信息(事件和HWND)塞入到其WParaM / LParaM中。 您可以使用WM_APP + n或使用RegisterWindowMessage()创建一个。 确保邮件已发布,而不是发送,以避免任何死锁。

这可能是你的问题的第三大问题,但是正如你所看到的,钩子很难得到正确的结果 – 如果你可以避免使用这种方法,那就去做吧。 你会遇到各种各样的问题,特别是在Vista上,你将不得不面对UIPI。

只是为了澄清“efotinis”中提到的有关将消息发布回您的进程的内容 – 您发布到主进程的wParam和lParam不能是指针,它们只能是“数字”。

例如,让我们说你挂钩了WM_WINDOWPOSCHANGING消息,windows向你传递一个指向lparam中的WINDOWPOS的指针。 你不能把这个lparam放回你的主进程,因为lparam所指向的内存只在收到该消息的进程中有效。

当他说“将所需的信息(事件和HWND)塞入其WParaM / LParaM”时,这就是“efotinis”的意思。 如果你想传递更复杂的消息,你需要使用一些其他的IPC(如命名管道,TCP或内存映射文件)。

大声笑,它看起来像错误是在测试代码

如果你创建两个单独的按钮,一个用于Init,一个用于UnInit(我更喜欢Exit)。

procedure THooktest_FO.UnInitClick(Sender: TObject); begin UninitHook; end; procedure THooktest_FO.InitClick(Sender: TObject); begin InitHook(HookCallback) end;

启动应用程序。 点击初始化,然后点击测试按钮,显示如下输出

created handle #1902442 destroyed handle #1902442 created handle #1967978 created handle #7276488

然后显示消息框。

如果你点击确定你会得到:

destroyed handle #1967978

HTH

我找到了SetwindowsHookEx的Delphi基础文档。 但文字有点模糊。

function SetwindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HInst; dwThreadId: DWORD): HHOOK;

hmod:包含由lpfn参数指向的钩子函数的模块(DLL)的句柄。 如果dwThreadId标识由当前进程创建的线程,则该参数必须设置为零。dlpfn指向位于与当前进程关联的代码中的钩子函数

dwThreadId:安装的钩子函数将被关联到的线程的标识符。 如果此参数设置为零,则挂钩将是与所有现有线程关联的全系统挂钩。

顺便说一句,对于hmod参数,你应该使用模块句柄。 (HINSTANCE指向应用程序句柄)。

hand := GetmoduleeHandle('hookhelper.dll'); Hook := SetwindowsHookEx(WH_SHELL,hand,0);

但是,虽然手与HINSTANCE不同,但仍显示相同的结果。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐