为什么Windows挂钩不会收到某些消息?

时间:2011-01-27 16:56:15

标签: windows hook messages wndproc setwindowshookex

Microsoft不建议使用DirectInput进行键盘和鼠标输入。因此,我编写了一个输入管理器类,它使用SetWindowsHookEx挂钩到WndProc和GetMsg。我认为钩子设置得恰当,但它们看起来是各种问题的原因。

我的WndProc和GetMsg挂钩都没有收到实际WndProc正在接收的任何消息。我的输入管理器永远不会收到它需要的WM_INPUT,WM_ BUTTON ,WM_MOUSEWHEEL和WM_KEY *消息。

是什么给出了?

部分标题:

namespace InputManager
{
    class CInputManager
    {
        HWND m_Window;
        HHOOK m_WndProcHook;
        HHOOK m_GetMessageHook;
        static LRESULT CALLBACK WindowsProcedureHookProcedure(int Code, WPARAM WParameter, LPARAM LParameter);
        static LRESULT CALLBACK GetMessageHookProcedure(int Code, WPARAM WParameter, LPARAM LParameter);
        static LRESULT CALLBACK MessageHandler(HWND Window, UINT Message, WPARAM wParameter, LPARAM lParameter);
    };
}

部分来源:

namespace InputManager
{
    bool CInputManager::Initialize(HWND Window)
    {
        m_Window = Window;

        // Hook into the sent messages of the target window to intercept input messages.
        m_WndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, &(WindowsProcedureHookProcedure), NULL, GetCurrentThreadId());
        // Hook into the posted messages of the target window to intercept input messages.
        m_GetMessageHook = SetWindowsHookEx(WH_GETMESSAGE, &(GetMessageHookProcedure), NULL, GetCurrentThreadId());

        // Register mouse device for raw input.
        RAWINPUTDEVICE RawInputDevice;
        RawInputDevice.usUsagePage = HID_USAGE_PAGE_GENERIC; 
        RawInputDevice.usUsage = HID_USAGE_GENERIC_MOUSE; 
        RawInputDevice.dwFlags = RIDEV_INPUTSINK;   
        RawInputDevice.hwndTarget = m_Window;
        return RegisterRawInputDevices(&(RawInputDevice), 1, sizeof(RawInputDevice));
    }

    void CInputManager::Shutdown()
    {
        // Unhook from the posted messages of the target window.
        UnhookWindowsHookEx(m_GetMessageHook);
        // Unhook from the sent messages of the target window.
        UnhookWindowsHookEx(m_WndProcHook);
    }

    LRESULT CALLBACK CInputManager::WindowsProcedureHookProcedure(int nCode, WPARAM wParameter, LPARAM lParameter)
    {
        if(nCode == HC_ACTION)
        {
            // Forward to message handler.
            CWPSTRUCT* Message = reinterpret_cast<CWPSTRUCT*>(lParameter);
            MessageHandler(Message->hwnd, Message->message, Message->wParam, Message->lParam);
        }
        return CallNextHookEx(NULL, nCode, wParameter, lParameter);
    }

    LRESULT CALLBACK CInputManager::GetMessageHookProcedure(int nCode, WPARAM wParameter, LPARAM lParameter)
    {
        if(nCode == HC_ACTION)
        {
            // Forward to message handler.
            CWPSTRUCT* Message = reinterpret_cast<CWPSTRUCT*>(lParameter);
            MessageHandler(Message->hwnd, Message->message, Message->wParam, Message->lParam);
        }
        return CallNextHookEx(NULL, nCode, wParameter, lParameter);
    }
}

我没有包含消息处理程序的代码,因为它包含149行,其中大多数是消息类型的开关。 WndProc中收到的消息值与我的回调中的消息值不同。

3 个答案:

答案 0 :(得分:6)

我似乎无法在您的原始问题下添加评论,而我希望将其放在此处,但是:

从你想要做的事情来看,WH_KEYBOARD和WH_MOUSE钩子不是更合适吗?

答案 1 :(得分:4)

我来这里参加派对已经很晚了,但我花了这么多时间来解决同样的问题,希望其他人会觉得这很有用。

我的实证结论是DispatchMessage不会触发WH_CALLWNDPROC挂钩。换句话说,WH_CALLWNDPROC将不会捕获在线程的消息队列中发布并通过消息循环(GetMessage - &gt; DispatchMessage)的消息。它只会使用SendMessage等将消息发送直接捕获到窗口过程中。当你查看文档时,它就是它所说的:

  

与SetWindowsHookEx函数一起使用的应用程序定义或库定义的回调函数。系统在调用窗口过程之前调用此函数以处理消息已发送到该线程。

当然,WH_GETMESSAGE钩子的情况恰恰相反。它将捕获已发布的消息,但不会发送消息。要获取所有消息,您必须使用两个钩子,或使用子类直接挂钩窗口过程:

WNDPROC realProc;
LRESULT CALLBACK hookProc(HWND h, UINT msg, WPARAM wp, LPARAM lp)
{
  return CallWindowProc(realProc, h, msg, wp, lp);
}
...
realProc = (WNDPROC)SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)hookProc);

此外,OP的GetMessage挂钩无效的原因可能是因为lParameter应该投放到MSG*而不是CWPSTRUCT*

答案 2 :(得分:0)

我曾经遇到过类似的问题。我不太害羞它是什么(我认为它在PreTranslateMessage的某个地方被消耗了,但我并不害羞)但我知道我是如何发现它的:

我自己创建了一条消失的消息,然后通过MFC调试它。如果我记得正确,我只是回到错误的BOOLEAN。但是,这种方法可能会为您提供实际的线索。