【问题标题】:Hook WH_GETMESSAGE message挂钩 WH_GETMESSAGE 消息
【发布时间】:2019-04-08 10:37:19
【问题描述】:

我正在尝试从我的班级挂钩WH_GETMESSAGE 以确定特定窗口调整大小的时刻。但是,似乎没有设置钩子。

我尝试挂钩的类:

class WindowDisplayHelper : // public ...
{    
public:
    // some other public methods here
    void SetMsgHook();
protected:
    LRESULT CALLBACK GetMsgProcHook(int code, WPARAM wParam, LPARAM lParam);
    static LRESULT CALLBACK MsgPoc(int code, WPARAM wParam, LPARAM lParam);
private:
    // some other private members there
    HWND m_windowHandle;
    bool m_isWindowResizing = false;
    static HHOOK m_msgHook;
    static WindowsDisplayHelperMasterWindow* m_pThis;
};

.cpp 文件:

WindowDisplayHelper* WindowDisplayHelper ::m_pThis = nullptr;
HHOOK WindowDisplayHelper ::m_msgHook = NULL;

void WindowDisplayHelper ::SetMsgHook()
{
    m_pThis = this;
    m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, 0);
}

LRESULT CALLBACK WindowDisplayHelper::MsgPoc(int code, WPARAM wParam, LPARAM lParam)
{
    if (m_pThis != nullptr)
    {
        return m_pThis->GetMsgProcHook(code, wParam, lParam);
    }
    return CallNextHookEx(0, code, wParam, lParam);
}

LRESULT CALLBACK WindowDisplayHelper::GetMsgProcHook(int code, WPARAM wParam, LPARAM lParam)
{
    DUMPER_INFO("Hooked");
    if (code < 0)
    {
        return CallNextHookEx(0, code, wParam, lParam);
    }
    MSG* lpmsg = (MSG*)lParam;
    DUMPER_INFO("Hooked for HWND: %p. Current window %p", lpmsg->hwnd, m_windowHandle);
    if (lpmsg->hwnd != m_windowHandle)
    {
        return CallNextHookEx(0, code, wParam, lParam);
    }
    if (lpmsg->message == WM_ENTERSIZEMOVE && !m_isWindowResizing)
    {
        DUMPER_INFO("Start window resizing");
        m_isWindowResizing = true;
    }
    else if (lpmsg->message == WM_EXITSIZEMOVE && m_isWindowResizing)
    {
        DUMPER_INFO("Stop window resizing");
        m_isWindowResizing = false;
    }

    return CallNextHookEx(0, code, wParam, lParam);
}

这是我创建 WindowDisplayHelper 对象的方法:

bool DisplayManager::CreateWindowDisplay(TDisplayId displayId, void * windowHandle)
{
    auto helper = boost::make_shared<WindowDisplayHelper>(windowHandle);
    helper->SetMsgHook();
    AddDisplayHelper(displayId, helper);

    return true;
}

虽然我在创建对象后调用了 SetMsgHook(),但似乎没有设置钩子,因为我在日志文件中看不到任何调试输出,并且 m_isWindowResizing 变量始终 == false。所以问题是为什么我的钩子不起作用? 谢谢。

【问题讨论】:

  • 尝试在SetWindowsHookEx调用上设置threadId
  • 另外,钩子程序似乎总是会转发到为其设置的最后一个窗口.. (m_pThis) - 这是故意的吗?
  • 使用 m_pThis 是因为我不能使用非静态函数作为 SetWindowsHookEx 参数,所以我使用带有静态指针的静态函数。从SetWindowsHookEx 文档中可以看出,该函数应该在 ThreadId = 0 的情况下工作,但我会尝试通过调用 GetCurrentThreadId 来设置 ThreadId
  • 使用 GetCurrentThreadId 没有帮助
  • @rudolfninja "我不能将非静态函数用作SetWindowsHookEx 参数" - 如果您使用 thunk 进行回调,则可以。但这是大多数编码人员不知道如何使用的高级技术。 “该函数应该与 ThreadId = 0 一起使用” - 这需要钩子代码驻留在一个 DLL 中,然后注入到其他进程中,因为钩子回调在每个检索线程的上下文中运行窗口消息。这意味着您需要单独的 DLL 来挂钩 32 位和 64 位进程。

标签: c++ winapi hook


【解决方案1】:
m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, 0);

这一行产生一个 ERROR_HOOK_NEEDS_HMOD (1428) system error。这意味着不能在没有模块句柄的情况下设置非本地挂钩。如果将dwThreadId 参数设置为零,则挂钩过程与在与调用线程相同的桌面上运行的所有现有线程相关联。这是一个非加载挂钩,您需要指定一个有效的hmod 参数。正如@Remy Lebeau 指出的那样,您需要将钩子代码放在DLL中。

或者正如@rudolfninja 指出的那样,使用GetCurrentThreadId() 设置一个有效的dwThreadId 参数。

我使用以下代码基于 Windows 桌面应用程序模板进行测试。有用。你可以试一试。

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    // ...

    HHOOK m_msgHook = SetWindowsHookEx(WH_GETMESSAGE, MsgPoc, NULL, GetCurrentThreadId());
    DWORD errCode = GetLastError();

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK MsgPoc(int code, WPARAM wParam, LPARAM lParam)
{
    OutputDebugString(L"Hooked");
    if (code < 0)
    {
        return CallNextHookEx(0, code, wParam, lParam);
    }
    MSG* lpmsg = (MSG*)lParam;
    //OutputDebugString("Hooked for HWND: %p. Current window %p", lpmsg->hwnd, m_windowHandle);
    if (lpmsg->hwnd != m_windowHandle)
    {
        return CallNextHookEx(0, code, wParam, lParam);
    }
    if (lpmsg->message == WM_ENTERSIZEMOVE && !m_isWindowResizing)
    {
        OutputDebugString(L"Start window resizing");
        m_isWindowResizing = true;
    }
    else if (lpmsg->message == WM_EXITSIZEMOVE && m_isWindowResizing)
    {
        OutputDebugString(L"Stop window resizing");
        m_isWindowResizing = false;
    }

    return CallNextHookEx(0, code, wParam, lParam);
}

【讨论】:

  • 如果我理解正确,在您的示例中使用非类成员函数(作为lpfn 参数)。但我需要修改和检查 HOOKPROC 内部的类成员(m_isWindowResizing 和 m_windowHandle)。因此,如果我使用GetCurrentThreadId() 设置dwThreadId 并使HOOKPROC 成为非类成员,是否可以以某种方式将this 指针传递给HOOKPROC 以修改类对象?
  • @rudolfninja 您的钩子不起作用,因为您没有成功注册它,正如我在回答中指出的那样。至于如何修改类对象,这是一个 C++ 编程问题,您可以打开一个新问题来关注这一点。
猜你喜欢
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 2015-03-09
相关资源
最近更新 更多