C++ 了解低级鼠标和键盘挂钩(win32)
我正在尝试捕获全局鼠标和键盘输入C++ 了解低级鼠标和键盘挂钩(win32),c++,multithreading,winapi,C++,Multithreading,Winapi,我正在尝试捕获全局鼠标和键盘输入 LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0) { if (wParam == WM_RBUTTONDOWN) printf("right mouse down\n"); if (wParam == WM_RBUTTONUP) printf("right mouse up\n"); } return
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0) {
if (wParam == WM_RBUTTONDOWN) printf("right mouse down\n");
if (wParam == WM_RBUTTONUP) printf("right mouse up\n");
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
HHOOK mousehook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);
while(true) {
MSG msg;
if (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
printf("msg recvd\n");
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#ifdef TEST
Sleep(50);
#endif
}
所以这里一切都正常,除非我定义TEST进入睡眠状态,鼠标会变得异常迟钝,如果我突然只允许鼠标每秒更新20次,这可能是意料之中的。在没有睡眠的情况下,我将CPU固定在100%。但现在这还可以(如果我使用GetMessage
,这种情况就会消失)
据我所知,低级钩子的工作方式是将上下文切换到安装它的进程,然后向进程发送某种消息,让它执行钩子回调。不过,让我有点困惑的是,为什么我的程序永远不会打印“msg recvd”,但每当我单击鼠标右键时,它就会打印“鼠标右键下/上”。这使我得出结论,我的MouseHookProc
在peek消息调用期间被调用。它恰好是某种特殊的消息,peek消息
返回0。但是我仍然需要调用PeekMessage
或其他类似的功能
由于我的程序需要做很多事情,我显然无法通过调用另一个需要50毫秒才能返回的函数来减轻我的消息泵送循环(调用PeekMessage
)的负担。如何在执行一些繁重的操作的同时,多线程处理程序以保持鼠标的响应能力?在多线程win32程序中,仍然只有一个消息队列,对吗
更新:在阅读了微软的文档后,我想我知道我应该做什么。我应该在我的应用程序中生成一个线程,调用SetWindowsHookEx
来注册鼠标挂钩,然后在自己的消息循环中闲坐,系统将负责将鼠标更新发送到此线程。它可以在MouseHookProc
中自由地执行任何它想做的事情,我的应用程序的其余部分将独立运行 而不是做:
if (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
printf("msg recvd\n");
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(50);
切换到:
while (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
// Add this potentially...
if (msg.message == WM_QUIT)
break;
printf("msg recvd\n");
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(10);
这将允许您的应用程序继续处理队列中的所有消息,直到队列为空(如无睡眠),然后在应用程序处于“空闲”状态时放弃一些CPU时间。MouseHookProc
应驻留在dll中,否则您无法捕获“全局”输入()
关于循环-您可以这样修改它:
while(true) {
MSG msg;
while (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
printf("msg recvd\n");
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#ifdef TEST
DoStuff();
Sleep(50);
#endif
}
问题是您的消息循环,它会消耗100%的CPU周期,因为您使用了PeekMessage()。Windows知道如何保持钩子活动,即使您不轮询消息,也可以使用GetMessage()解决问题。使用睡眠(1)也可以解决你的问题,但在这里没有必要
我询问您是否将placeMouseHookProc
放在DLL中,因为尝试将其放在EXE中是一个典型错误。我也是很多年前做的
首先,您如何阅读:
SetWindowsHookEx可用于注入
将DLL插入另一个进程。32位
无法将DLL注入到64位
进程,并且不能创建64位DLL
注入32位进程。如果
应用程序需要使用挂钩
在其他过程中,它是必需的
这是一个32位的应用程序调用
设置WindowsHookex以注入32位
DLL转换为32位进程,并
64位应用程序调用
设置WindowsHookex以注入64位
DLL转换为64位进程。32位
和64位DLL必须具有不同的
名字
因此,您必须将其放置在DLL中。确切地说,如果您想同时支持32位和64位平台,您必须实现两个DLL:一个32位和64位DLL。但是为什么呢?以及SetWindowsHookEx
是如何工作的
如果在EXE中执行,代码如下所示
HINSTANCE hinstDLL = LoadLibrary(TEXT("c:\\myapp\\syshook.dll"));
HOOKPROC hkprcMouse = (HOOKPROC)GetProcAddress(hinstDLL, "MouseHookProc");
HHOOK hhookMouse = SetWindowsHookEx(
WH_MOUSE_LL,
hkprcMouse,
hinstDLL,
0);
您向user32.dll发出请求,将syshook.dll插入同一windows工作站上的所有其他进程中(不会将dll注入通过快速用户切换登录的其他用户的服务和进程)。然后user32.dll在不同的进程中调用syshook.dllLoadLibrary
。然后,如果将调用函数MouseHookProc
,则将在处理鼠标消息的进程上下文中调用in。如果进程不是控制台应用程序,则代码如下
printf("right mouse down\n");
不能工作
因此,我希望现在您能解开为什么必须将MouseHookProc
放在DLL中。DLL中是否有MouseHookProc
,EXE中是否有SetWindowsHookEx
和PeekMessage
循环?我想避免插入DLL。系统切换到我的程序来调用它的MouseHookProc
,这似乎更适合我的需要,因此我想使用低级鼠标钩子。据我所知,一个普通的鼠标钩子,如果我希望它是全局的,必须使用DLL方法。一个低级的鼠标钩子不需要DLL,它不像WHU鼠标那样是全局钩子。我想这里可能会有一些混淆。就目前而言,我或多或少已经从这个话题中找到了我需要的一切:不过,感谢您抽出时间来帮助我!这是非常有趣的信息!非常有趣的是,WH\u MOUSE\u LL
是generel DLL注入规则的一个例外。谢谢我建议您使用上的“向Microsoft发送有关此主题的评论”来建议Microsoft更改与中的信息相关的SetWindowsHookEx
的一点文档。您是说,使用鼠标时,它不在DLL中工作,但对于其他消息类型,它必须在DLL中?@rogerdpack Yes。在您的评论中可以看到:“然而,WH_MOUSE_LL钩子并没有注入到另一个进程中。相反,上下文切换回安装钩子的进程,并在其原始上下文中调用它。然后上下文切换回生成事件的应用程序。”所有其他钩子都必须注入(加载)目标进程中的HookProc
代码。它只能与我在回答中描述的DLL一起工作。在旧窗口中