我目前无法在 Windows 7 64 位操作系统上使用全局键挂钩。现在我知道 Stackoverflow 上已经有很多关于这个主题的主题了,但是没有一个能给我一个我可以使用的答案,或者我不太明白这些主题是如何解决这个问题的。
因此,我将尝试解释我正在努力解决的问题,并希望任何人都可以帮助我或为我指明正确的方向。
基本上,我的目标是拦截 CTRL+C 和 CTRL+V 键盘输入,以实现一种剪贴板管理器。出于这个原因,我目前的尝试是注册一个系统范围的WH_KEYBOARD
钩子,它可以根据我的需要处理截获的击键。
我在 64 位 Windows 7 O/S 上运行挂钩,这就是问题开始的地方。对我来说很明显 32 位 Hook DLL 会导致 64 位进程出现问题,反之亦然。出于这个原因,我生成了包含钩子的库的 x86 和 x64 版本,以及钩子的调用者(调用者SetWindowsHookEx()
),两者都具有不同的文件名,如文档所示。
但是现在呢?如果我将我的 64 位 DLL 设置为系统范围的钩子,则所有 32 位应用程序只要我在聚焦时按下一个键就会开始挂起。当我应用 32 位挂钩时,我的 Windows 实际上无法使用,因为它explorer.exe
是 64 位的。如果我设置了两个钩子,我的系统就会陷入停顿状态,从而引发一场全球性的“比特”斗争。
现在我假设问题出在例如试图注入 32 位进程的 64 位挂钩 DLL 等等,这当然是毫无意义的。但是对于这种情况,文档SetWindowsHookEx()
说明如下:
因为钩子在应用程序的上下文中运行,所以它们必须与应用程序的“位数”相匹配。如果 32 位应用程序在 64 位 Windows 上安装全局挂钩,则 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 上工作,我将不胜感激。我的问题是某些具有除钩子之外的其他“位数”的应用程序开始挂起,我不知道如何解决这个问题。
很感谢任何形式的帮助!
谢谢并恭祝安康
葡萄干