gpt4 book ai didi

windows - 我必须做什么才能使我的 WH_SHELL 或 WH_CBT Hook 过程从其他进程接收事件?

转载 作者:可可西里 更新时间:2023-11-01 12:35:18 27 4
gpt4 key购买 nike

我正在尝试使用 SetWindowsHookEx 设置一个 WH_SHELL Hook ,以获取系统范围内 HSHELL_WINDOWCREATEDHSHELL_WINDOWDESTROYED 的通知 事件。我为最后的 dwThreadId 参数传递了 0,根据 the docs ,应该“将 Hook 过程与所有现有线程关联起来,这些线程与调用线程在同一桌面上运行”。我还为 hMod 参数将句柄传递到我的 DLL(Delphi 中的 HInstance),就像我查看的所有示例一样。

然而,我只收到由我自己的应用程序创建的窗口的通知,而且 - 通常情况下 - 我的测试结果是一旦我关闭我的应用程序,桌面进程就会崩溃。在您询问之前,我会调用 UnhookWindowsHookEx。我也总是从我的处理程序中调用 CallNextHookEx

我正在从一个有限的用户帐户运行我的测试应用程序,但到目前为止我还没有发现任何提示表明这会发挥作用......(尽管这实际上让我感到惊讶)

AFAICT,我按照书做了所有事情(显然我没有,但到目前为止我看不出在哪里)。

我使用的是 Delphi (2007),但我认为这并不重要。

编辑:也许我之前应该提到这一点:我确实下载并尝试了几个示例(尽管不幸的是没有那么多可用于 Delphi - 尤其是 WH_SHELLWH_CBT)。虽然它们不会像我的测试应用程序那样使系统崩溃,但它们仍然不会从其他进程捕获事件(即使我可以使用 ProcessExplorer 验证它们是否正确加载到它们中)。因此,我的系统配置似乎有问题,或者示例有误,或者根本不可能从其他进程捕获事件。谁能赐教一下?

EDIT2:好的,这是我的测试项目的源代码。

包含钩子(Hook)程序的DLL:

library HookHelper;

uses
Windows;

{$R *.res}

type
THookCallback = procedure(ACode, AWParam, ALParam: Integer); stdcall;

var
WndHookCallback: THookCallback;
Hook: HHook;

function HookProc(ACode, AWParam, ALParam: Integer): Integer; stdcall;
begin
Result := CallNextHookEx(Hook, ACode, AWParam, 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, AWParam, ALParam);
except
// plop!
end;
end;

procedure InitHook(ACallback: THookCallback); register;
begin
// Hook := SetWindowsHookEx(WH_SHELL, @HookProc, HInstance, 0);
Hook := SetWindowsHookEx(WH_CBT, @HookProc, HInstance, 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.

以及使用钩子(Hook)的应用程序的主要形式:

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, AWParam, ALParam: Integer); stdcall;

procedure InitHook(const ACallback: THookCallback); register; external 'HookHelper.dll';
procedure UninitHook; register; external 'HookHelper.dll';

procedure HookCallback(ACode, AWParam, 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, AWParam, 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.

最佳答案

问题是你的钩子(Hook) DLL 实际上被加载到几个不同的地址空间。任何时候 Windows 在某些外部进程中检测到必须由您的 Hook 处理的事件时,它都会将 Hook DLL 加载到该进程中(当然,如果它尚未加载的话)。

但是,每个进程都有自己的地址空间。这意味着您在 InitHook() 中传递的回调函数指针仅在您的 EXE 上下文中有意义(这就是它适用于您应用程序中的事件的原因)。在任何其他进程中,指针都是垃圾;它可能指向无效的内存位置或(更糟)指向某个随机代码部分。结果可能是访问冲突或静默内存损坏。

通常,解决方案是使用某种 interprocess communication (IPC) 以正确通知您的 EXE。对于您的情况,最轻松的方法是发布一条消息并将所需的信息(事件和 HWND)塞入其 WPARAM/LPARAM 中。您可以使用 WM_APP+n 或使用 RegisterWindowMessage() 创建一个。确保消息已发布但未发送,以避免任何死锁。

关于windows - 我必须做什么才能使我的 WH_SHELL 或 WH_CBT Hook 过程从其他进程接收事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/299370/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com