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

Sio*_*vok 7 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);
    };
}
Run Code Online (Sandbox Code Playgroud)

部分来源:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

小智 6

我似乎无法在你原来的问题下添加评论,这是我更喜欢这样做的地方,但是:

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


Tim*_*imo 5

I'm quite late to the party here, but I just spent so many hours figuring out the same problem, and hopefully someone else will find this useful.

My empirical conclusion is that DispatchMessage does not trigger WH_CALLWNDPROC hooks. In other words, messages that are posted in the thread's message queue and go through the message loop (GetMessage -> DispatchMessage) will not be caught by WH_CALLWNDPROC. It only catches messages sent directly to the window procedure with SendMessage etc.. And when you look at the documentation, that's kinda what it says:

An application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function before calling the window procedure to process a message sent to the thread.

And of course the opposite is true for WH_GETMESSAGE hook. It will catch posted messages but not sent messages. To get all messages you either have to use both hooks, or use subclassing to hook the window procedure directly:

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);
Run Code Online (Sandbox Code Playgroud)

Also, the reason the OP's GetMessage hook wasn't working is probably because lParameter should be casted to MSG* and not CWPSTRUCT*.