【问题标题】:Observe opened windows with SetWindowsHookEx使用 SetWindowsHookEx 观察打开的窗口
【发布时间】:2016-06-17 13:50:36
【问题描述】:

我正在尝试使用全局 Windows 挂钩观察打开和关闭窗口。因此,我试图将回调函数传递给包含我的钩子过程的 DLL。但是,挂钩过程本身永远不会被调用。

/** Handle to this DLL */
HINSTANCE dllModule = 0;
/** Hook procedure */
HHOOK windowHook = 0;
/** Callbacks are called when a new window is opened, or closed. */
HWND_CALLBACK windowOpenCallback = 0;
HWND_CALLBACK windowCloseCallback = 0;

WINDOWHOOK_API int WINAPI DllMain(HINSTANCE hInstance, DWORD reason, LPVOID reserved)
{
    if(reason == DLL_PROCESS_ATTACH)
    {
        dllModule = hInstance;
        std::cout << "Process attached." << std::endl;
    }
    else if (reason == DLL_PROCESS_DETACH)
    {
        std::cout << "Process detached." << std::endl;
    }
    else if (reason == DLL_THREAD_ATTACH)
    {
    }
    else if (reason == DLL_THREAD_DETACH)
    {
    }
    return 1;
}

WINDOWHOOK_API bool setWindowHook(HWND_CALLBACK openCallback, HWND_CALLBACK closeCallback)
{
    if(windowHook != 0 || windowOpenCallback != 0 || windowCloseCallback != 0)
    {
        return false;
    }
    windowOpenCallback = openCallback;
    windowCloseCallback = closeCallback;
    windowHook = SetWindowsHookEx(WH_SHELL, (HOOKPROC)hookCallback, dllModule, 0);

    return windowHook != 0;
}

WINDOWHOOK_API bool releaseWindowHook()
{
    bool result = windowHook != 0 && UnhookWindowsHookEx(windowHook) != 0;

    windowHook = 0;
    windowOpenCallback = 0;
    windowCloseCallback = 0;

    return result;
}

LRESULT CALLBACK hookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    std::cout << "Hook callback" << std::endl;

    return CallNextHookEx(windowHook, nCode, wParam, lParam);
}

从我的主程序中,我加载库并调用 setWindowHook 过程。然后我简单地启动一个无限循环并等待调用钩子,但是虽然 setWindowHook 没有失败,但钩子过程永远不会被调用。我不明白为什么。

我尝试设置一个 WH_KEYBOARD 挂钩。这样,钩子程序就会在按键上被调用,但前提是它们位于我程序的控制台窗口内。

我在 64 位机器上将其编译为 32 位。但是,它至少不应该适用于我所有的 32 位应用程序吗?

提前致谢。

【问题讨论】:

  • 你的钩子可能会被调用,但是它将在属于它被注入的进程的线程上调用。它将尝试在另一个进程的上下文中输出到std::cout,对于大多数 Windows 进程,这将失败,因为它们没有附加的控制台。使用不涉及写入控制台的另一种方法来监控您的钩子。
  • 谢谢,这确实是问题所在。然而,现在我面临着另一个。每当窗口打开时传递要调用的回调的想法实际上并不奏效。虽然我可以使函数 ptr 在加载了 DLL 的所有进程之间共享,但这些进程无法调用它,因为它们位于不同的地址空间中。我怎样才能让他们与我的程序进行通信?我可以发送窗口消息,但不能保证会处理这些消息,是吗?
  • 将消息发布回您的主窗口可以正常工作(阅读有关 WM_COPYDATA 的信息)。共享内存将起作用(使用适当的锁定)。套接字可以工作,但您必须小心处理。
  • WM_COPYDATA 专门设计用于跨越进程边界。话虽如此,请注意窗口消息受 User Interface Privilege Isolation (UIPI) 的约束,因此您应该调用 ChangeWindowMessageFilterEx() 以允许您接收 HWND 接收 WM_COPYDATA(或任何您选择的窗口消息)来自任何完整性级别的任何进程。
  • 全局挂钩是错误的工具。要监视窗口的创建和销毁,请使用WinEvents。额外的好处:这种方法不需要任何 IPC,您不再需要等待 PostThreadMessage 失败(请参阅 Why do messages posted by PostThreadMessage disappear?)。

标签: c++ winapi dll hook


【解决方案1】:

谢谢,我让它与 DLL 和 SetWindowsHookEx 一起工作,但是 SetWinEventHook 解决方案效果更好,您不需要为此使用 DLL。 唯一的问题是,WINEVENTHOOK 没有我们可以传递类实例的 LPVOID 指针属性。因此,如果您正在寻找一种 OO 方法并且正在为此苦苦挣扎,this codeproject link 可能会有所帮助。

还要确保,无论您从哪个线程设置挂钩,都具有消息循环,否则您将不会收到任何事件。

while (!stopped)
{
    if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
    {
        // you don't have to do anything here
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    相关资源
    最近更新 更多