为什么Windows挂钩无法接收某些消息? [英] Why would Windows hooks not receive certain messages?

查看:188
本文介绍了为什么Windows挂钩无法接收某些消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Microsoft不建议将DirectInput用于键盘和鼠标输入.这样,我编写了一个使用SetWindowsHookEx挂接到WndProc和GetMsg的输入管理器类.我相信这些钩子设置得当,尽管它们看起来可能是造成各种问题的原因.

我的WndProc和GetMsg钩子都没有收到实际WndProc正在接收的任何消息.我的输入管理器从没有收到所需的WM_INPUT,WM_ 按钮,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中收到的消息值与我的回调中的消息值不同.

解决方案

我在这里参加聚会已经很晚了,但是我花了很多时间来弄清楚这个问题,希望其他人会发现这很有用. /p>

我的经验结论是DispatchMessage不会触发WH_CALLWNDPROC挂钩.换句话说,在线程的消息队列中发布并经过消息循环(GetMessage-> DispatchMessage)的消息将不会被WH_CALLWNDPROC捕获.它仅使用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*.

Microsoft does not recommend DirectInput for keyboard and mouse input. As such, I've written an input manager class that uses SetWindowsHookEx to hook into WndProc and GetMsg. I believe the hooks are set appropriately, though they look to be the cause of various issues.

Neither my WndProc nor GetMsg hooks receive any of the messages that the actual WndProc is receiving. My input manager never receives the WM_INPUT, WM_BUTTON, WM_MOUSEWHEEL, and WM_KEY* messages that it needs.

What gives?

Partial header:

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);
    };
}

Partial source:

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);
    }
}

I don't include the code for the message handler as it consists of 149 lines, most of which are the switches for the message types. The message values received in the WndProc are not the same as the ones in my callbacks.

解决方案

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);

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

这篇关于为什么Windows挂钩无法接收某些消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆