Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 了解低级鼠标和键盘挂钩(win32)_C++_Multithreading_Winapi - Fatal编程技术网

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)也可以解决你的问题,但在这里没有必要


我询问您是否将place
MouseHookProc
放在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.dll
LoadLibrary
。然后,如果将调用函数
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一起工作。在旧窗口中