C++ 64位Windows上的全局Keyhook

C++ 64位Windows上的全局Keyhook,c++,winapi,hook,keyhook,C++,Winapi,Hook,Keyhook,目前,我在Windows 7 64位操作系统上使用全局keyhook时遇到了一些麻烦。现在我知道Stackoverflow上已经有很多关于这个主题的线程,但是没有一个能给我一个可以使用的答案,或者我不太明白如何在这些线程中解决这个问题 因此,我将努力解释我正在努力解决的问题,并希望任何人都能帮助我走出困境,或为我指明正确的方向 基本上,我的目标是截取CTRL+C和CTRL+V键盘输入,作为一种剪贴板管理器。出于这个原因,我目前的尝试是注册一个系统范围的WH_键盘hook,它根据我的需要处理截获的

目前,我在Windows 7 64位操作系统上使用全局keyhook时遇到了一些麻烦。现在我知道Stackoverflow上已经有很多关于这个主题的线程,但是没有一个能给我一个可以使用的答案,或者我不太明白如何在这些线程中解决这个问题

因此,我将努力解释我正在努力解决的问题,并希望任何人都能帮助我走出困境,或为我指明正确的方向

基本上,我的目标是截取CTRL+C和CTRL+V键盘输入,作为一种剪贴板管理器。出于这个原因,我目前的尝试是注册一个系统范围的
WH_键盘
hook,它根据我的需要处理截获的击键

我在64位Windows7O/S上运行钩子,这就是问题的开始。很明显,32位Hook DLL会给64位进程带来问题,反之亦然。因此,我生成了包含钩子的库的x86和x64版本,以及钩子的调用程序(调用
SetWindowsHookEx()
),正如文档所示,这两个版本都具有不同的文件名

但是现在呢?如果我将我的64位DLL设置为系统范围的钩子,则所有32位应用程序在聚焦时一按键就开始挂起。当我应用32位钩子时,我的Windows实际上是不可用的,因为
explorer.exe
是64位的。如果我同时设置了这两个钩子,我的系统将有效地处于停滞状态,并在全球范围内展开“咬”战

现在我假设这个问题是由64位挂钩DLL试图注入32位进程等引起的,这当然是没有意义的。但是对于这种情况,
SetWindowsHookEx()
的文档说明如下:

因为钩子在应用程序的上下文中运行,所以它们必须匹配 应用程序的“比特度”。如果32位应用程序安装 全局钩子在64位窗口上,32位钩子被注入到每个窗口中 32位进程(通常的安全边界适用)。在64位中 但是,由于 32位应用程序必须运行钩子代码,系统执行 挂钩应用程序上下文中的挂钩;具体来说,在 称为SetWindowsHookEx。这意味着挂钩应用程序必须 继续泵送消息,否则可能会阻止 64位进程。

我不完全理解文本的粗体部分,但我将其解释为,如果挂钩目标的“比特度”与挂钩的“比特度”不同,那么它将在实际设置挂钩的线程上执行,因此它完全可以执行。此外,这意味着该线程必须仍然处于活动状态,并且可能运行某种消息循环。这是正确的吗?还是我对这件事完全不感兴趣?文档似乎也给出了如何处理我的场景的确切说明:

挂接64位Windows桌面上的所有应用程序 安装,安装32位全局钩子和64位全局钩子, 每一条消息都来自适当的进程,并确保不断地发送消息 在挂钩应用程序中,以避免阻塞正常功能

但是,我无法理解在实施过程中必须做些什么。为了最后展示一些代码,让我们以这个尝试设置系统范围的keyhook的基本示例为例。我想线程的创建代码应该是无关的:

volatile static bool runThread = false;

DWORD WINAPI threadStart(LPVOID lpThreadParameter) {
    HMODULE hMod = LoadLibraryA(is64Bit() ? "keyhook.x64.dll" : "keyhook.x86.dll");
    HHOOK hHook = SetWindowsHookExA(WH_KEYBOARD, (HOOKPROC)GetProcAddress(hMod, "hookProc"), hMod, 0)));

    runThread = true;
    while(runThread) {
        // Message pump? Yes? No? How?
        Sleep(10);
    }

    UnhookWindowsHookEx(hHook);
    FreeLibrary(hMod);
    return 0;
}
钩子本身非常简单-在穿过咬口时足以引起挂起问题:

extern "C" LRESULT hookProc(int code, WPARAM wParam, LPARAM lParam) {
    if(code == HC_ACTION) {
    }

    return CallNextHookEx(nullptr, code, wParam, lParam);
}
我想有些人现在可能会把手放在头上,你可以看出我很少用钩子工作;)

但这正是我问的原因:)

简而言之:如果有人能告诉我如何更改上述示例,使系统范围的keyhook在64位Windows上工作,我将不胜感激。我的问题是,除了钩子之外,还有其他“咬”的应用程序开始挂起,我不知道如何解决这个问题

非常感谢您的帮助

谢谢和问候


好的,我知道问题出在哪里了。也许我的解决方案可以帮助其他遇到同样问题的人:如上所述,文档明确指出

[…]系统执行(32位)挂钩应用程序的(32位)挂钩 上下文特别是在名为SetWindowsHookEx的线程上。 这意味着挂钩应用程序必须继续泵送消息 或者它可能会阻止64位进程的正常运行

我所经历的是提到的阻塞行为,它应该通过消息泵来克服。在我上面的代码示例中,正好缺少了这一部分机制,因为我不知道这应该是一个简单的Windows消息循环(我以前不知道术语“泵”)。我的初始代码中的最终代码段必须如下所示:

volatile static bool runThread = false;

DWORD WINAPI threadStart(LPVOID lpThreadParameter) {
    HMODULE hMod = LoadLibraryA(is64Bit() ? "keyhook.x64.dll" : "keyhook.x86.dll");
    HHOOK hHook = SetWindowsHookExA(WH_KEYBOARD, (HOOKPROC)GetProcAddress(hMod, "hookProc"), hMod, 0)));

    MSG msg;
    runThread = true;
    while(runThread) {
        // Keep pumping...
        PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        Sleep(10);
    }

    UnhookWindowsHookEx(hHook);
    FreeLibrary(hMod);
    return 0;
}
在本例中,我使用非阻塞
peek消息()
而不是
GetMessage()
,因为我希望我的线程不断检查它的终止标志

通过此实现,我的钩子在所有本机64位或WOW64进程中都能按预期工作,没有应用程序在钩子后立即挂断。信息泵是唯一缺失的部分

经过所有这些实验,我得出以下结论——如果我错了,请在评论中纠正我:

当安装系统范围的钩子时,会尝试将给定的钩子DLL注入到每个正在运行的进程中。如果进程的“比特数”与挂钩DLL中的匹配,挂钩过程将作为目标进程中的远程线程执行(与正常工作类似)。如果“比特数”不同,Windows会回退到最初调用
SetWindowsHookEx()
(在我的示例中)的进程和线程