代码之家  ›  专栏  ›  技术社区  ›  Steven Lu

了解低级鼠标和键盘挂钩(win32)

  •  13
  • Steven Lu  · 技术社区  · 16 年前

    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
    }
    

    #define TEST 放入 Sleep GetMessage

    据我所知,低级钩子的工作方式是将上下文切换到安装它的进程,然后向进程发送某种消息,让它执行钩子回调。不过,让我有点困惑的是,为什么我的程序永远不会打印“msg recvd”,但每当我单击鼠标右键时,它就会打印“鼠标右键向下/向上”。这使我得出结论,我的 MouseHookProc 正在调用 PeekMessage Peek消息 返回0。但是我仍然需要打电话 Peek消息 或者其他类似的。

    由于我的程序需要做很多事情,我显然无法权衡我的消息泵循环(调用 )通过调用另一个需要50毫秒才能返回的函数。如何在执行一些繁重的操作的同时,多线程处理程序以保持鼠标的响应能力?在多线程win32程序中,仍然只有一个消息队列,对吗?

    更新:在阅读了微软的文档后,我想我知道我应该做什么。我应该在我的应用程序中生成一个线程来调用 SetWindowsHookEx 注册鼠标钩子,然后坐在自己的消息循环中,系统将负责将鼠标更新发送到此线程。它将可以在未来自由地做任何它想做的事情 老鼠屋

    4 回复  |  直到 16 年前
        1
  •  14
  •   Community Mohan Dere    9 年前

    问题是您的消息循环,它会消耗100%的CPU周期,因为您使用PeekMessage()。Windows知道如何保持钩子活动,即使您不轮询消息,也可以使用GetMessage()解决问题。使用睡眠(1)也能解决你的问题,但在这里没有必要。

    Why must SetWindowsHookEx be used with a windows message queue

        2
  •  6
  •   Oleg    16 年前

    MouseHookProc 在DLL中,由于试图将其放入EXE中,这是一个典型的错误。我也是很多年前做的。

    http://msdn.microsoft.com/en-us/library/ms644990.aspx :

    SetWindowsHookEx可以用来注入 将DLL导入另一个进程。32位 进程,并且不能创建64位DLL 注入32位进程。如果 应用程序需要使用挂钩 在其他过程中,它是必需的 SetWindowsHookEx注入32位 64位应用程序调用 设置WindowsHookex以注入64位 将DLL转换为64位进程。32位 名字。

    所以你必须放在一个动态链接库里。确切地说,如果您想同时支持32位和64位平台,就必须实现两个DLL:一个32位和64位DLL。但为什么呢?怎么做 SetWindowsHookEx 作品?

    HINSTANCE hinstDLL = LoadLibrary(TEXT("c:\\myapp\\syshook.dll"));
    HOOKPROC hkprcMouse = (HOOKPROC)GetProcAddress(hinstDLL, "MouseHookProc");
    HHOOK hhookMouse = SetWindowsHookEx( 
                        WH_MOUSE_LL,
                        hkprcMouse,
                        hinstDLL,
                        0); 
    

    你给 用户32.dll 请求注入你的 用户32.dll LoadLibrary 到 系统挂钩.dll 在不同的过程中。如果函数 老鼠屋 将在处理鼠标消息的进程的上下文中调用。如果进程不是控制台应用程序

    printf("right mouse down\n");
    

    不能工作。

    老鼠屋 在DLL中。

        3
  •  3
  •   Reed Copsey    16 年前

    而不是:

    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时间。

        4
  •  3
  •   Dark    16 年前

    MouseHookProc 应该驻留在dll中,否则无法捕获“全局”输入( http://msdn.microsoft.com/en-us/library/ms997537.aspx

    关于循环-可以这样修改:

    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
    }