SetWindowsHookEx 挂接到每个 运行 程序
SetWindowsHookEx hooking into every running program
我编写了一个小的 DLL,它被注入到游戏中以应用运行时修复。我决定添加一些键盘监听器:
while (1)
if (AsyncKeyState(...)) (...)
然而,这占用了 CPU 的使用,并引入了一些明显的卡顿。因此,我决定使用 MSDN 通过 SetWindowsHookExA
和 KeyboardProc
回调建议的回调方法。起初,我是 运行 通过 SetWindowsHookExA(WH_Keyboard, KeyboardProc, NULL, 0)
的方法,但收到错误代码 ERROR_HOOK_NEEDS_HMOD (0x594)
。所以我把我的代码改成了这样:
bool APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpRes)
{
HHOOK hook_ = nullptr;
switch (reason)
{
case DLL_PROCESS_ATTACH:
if (!(hook_ = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hModule, 0)))
{
char x[100];
sprintf(x, "Failed To Hook Keyboard FN: 0x%X", GetLastError());
MessageBox(NULL, x, "Error", MB_ICONERROR);
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
UnhookWindowsHookEx(hook_);
break;
}
return true;
}
这不再报错了,我的 hooking Keyboard 功能运行良好。然而,一个意想不到的副作用是来自所有 运行 应用程序的所有键盘捕获都被忽略了。
我注意到来自 MSDN 的这句话,所以我将它添加到我的代码中:
If code is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_KEYBOARD hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.
这解决了键盘问题,但现在出现了另一个问题,即我无法删除我创建的 DLL。当我尝试删除它时,它说“dll is 运行 in Explorer.exe”。当我杀死 explorer.exe
时,它说“dll 是 运行 in SteamHelper.exe”。当我杀死 steamhelper.exe
时,它说“dll is 运行 in Chrome.exe”。这表明我已经以某种方式连接到每个 运行 应用程序?
我无法解决这个问题,也找不到任何帮助。非常感谢任何见解!
您正在挂钩每个应用程序进程,因为您正在通过将 SetWindowsHookEx()
的 dwThreadId
参数设置为 0 来 全局安装挂钩 :
dwThreadId
Type: DWORD
The identifier of the thread with which the hook procedure is to be associated. For desktop apps, if this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread. For Windows Store apps, see the Remarks section.
相反,您应该将该参数设置为您要为其挂钩事件的游戏线程的实际线程 ID。
我编写了一个小的 DLL,它被注入到游戏中以应用运行时修复。我决定添加一些键盘监听器:
while (1)
if (AsyncKeyState(...)) (...)
然而,这占用了 CPU 的使用,并引入了一些明显的卡顿。因此,我决定使用 MSDN 通过 SetWindowsHookExA
和 KeyboardProc
回调建议的回调方法。起初,我是 运行 通过 SetWindowsHookExA(WH_Keyboard, KeyboardProc, NULL, 0)
的方法,但收到错误代码 ERROR_HOOK_NEEDS_HMOD (0x594)
。所以我把我的代码改成了这样:
bool APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpRes)
{
HHOOK hook_ = nullptr;
switch (reason)
{
case DLL_PROCESS_ATTACH:
if (!(hook_ = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hModule, 0)))
{
char x[100];
sprintf(x, "Failed To Hook Keyboard FN: 0x%X", GetLastError());
MessageBox(NULL, x, "Error", MB_ICONERROR);
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
UnhookWindowsHookEx(hook_);
break;
}
return true;
}
这不再报错了,我的 hooking Keyboard 功能运行良好。然而,一个意想不到的副作用是来自所有 运行 应用程序的所有键盘捕获都被忽略了。 我注意到来自 MSDN 的这句话,所以我将它添加到我的代码中:
If code is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_KEYBOARD hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.
这解决了键盘问题,但现在出现了另一个问题,即我无法删除我创建的 DLL。当我尝试删除它时,它说“dll is 运行 in Explorer.exe”。当我杀死 explorer.exe
时,它说“dll 是 运行 in SteamHelper.exe”。当我杀死 steamhelper.exe
时,它说“dll is 运行 in Chrome.exe”。这表明我已经以某种方式连接到每个 运行 应用程序?
我无法解决这个问题,也找不到任何帮助。非常感谢任何见解!
您正在挂钩每个应用程序进程,因为您正在通过将 SetWindowsHookEx()
的 dwThreadId
参数设置为 0 来 全局安装挂钩 :
dwThreadId
Type: DWORD
The identifier of the thread with which the hook procedure is to be associated. For desktop apps, if this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread. For Windows Store apps, see the Remarks section.
相反,您应该将该参数设置为您要为其挂钩事件的游戏线程的实际线程 ID。