MouseHookProc和Sleep()

时间:2014-12-25 11:39:53

标签: c++ winapi

所以我试图让MouseHook工作。我需要在WM_LBUTTONUP发生时进行注册。

HHOOK MouseHook;
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam){

    PKBDLLHOOKSTRUCT k = (PKBDLLHOOKSTRUCT)(lParam);

    if (wParam == WM_LBUTTONUP)
    {
        Msg(":)");
    }
    return CallNextHookEx(0, nCode, wParam, lParam);
}

...

MouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, hInstance, 0);

...

MSG msg;
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

现在问题是如果我在程序中的任何地方调用Sleep()它会冻结鼠标。 我怎么能绕过这个?是否可以在一个单独的线程中运行钩子?

2 个答案:

答案 0 :(得分:2)

这是因为低级键盘和鼠标挂钩需要消息泵命令才能在事件上调用挂钩过程。当您调用Sleep时,它会阻止线程处理消息队列。发生这种情况时,无法调用挂钩过程,并且窗口挂钩机制将阻塞,直到下次执行消息泵为止。

您确实可以在单独的线程中管理钩子,因为钩子回调是在安装钩子的线程的上下文中执行的。您还应确保不从挂钩回调中调用Sleep或执行除必要之外的任何操作,否则系统可能会自动删除它。来自Remarks section of MSDN documentation on LowLevelMouseProc

  

在安装它的线程的上下文中调用此钩子。通过向安装了挂钩的线程发送消息来进行调用。因此,安装钩子的线程必须有一个消息循环。

     

<强> ...

     

钩子过程应该在比以下注册表项中的LowLevelHooksTimeout值中指定的数据条目更短的时间内处理消息:HKEY_CURRENT_USER \ Control Panel \ Desktop

     

该值以毫秒为单位。如果挂钩过程超时,系统会将消息传递给下一个挂钩。但是,在Windows 7及更高版本中,无需调用即可静默删除挂钩。应用程序无法知道钩子是否被移除。

示例:

#include <windows.h>
#include <iostream>

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    std::cout << "hook called" << std::endl;
    return CallNextHookEx(0, nCode, wParam, lParam);
}

DWORD WINAPI ThreadProc(void*)
{
    SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

int main()
{
    CreateThread(NULL, 0, ThreadProc, NULL, 0, 0);
    Sleep(20000);
}

答案 1 :(得分:1)

在注册它的线程的上下文中调用低级别挂钩。因此,从另一个线程注册钩子。您将需要该线程来为其挂起消息队列以使其工作。

更大的问题是您在主线程中调用Sleep。这将阻止您的UI响应。你需要停止这样做。