使用SetWindowsHookEx的WH_KEYBOARD钩子如何获取消息对应目标窗口的hwnd?
解决方案
核心实现逻辑
你当前使用的是绑定指定线程的WH_KEYBOARD钩子,钩子回调执行时会运行在目标线程的上下文环境中,这种场景下直接调用Win32 API GetFocus()即可获取到当前接收键盘消息的窗口句柄,这个方案比GetForegroundWindow()精准度高很多,不受前台窗口状态影响。
如果需要覆盖跨进程通过SendMessage发送给目标线程非焦点窗口的键盘消息场景,更稳妥的方案是改用WH_CALLWNDPROC线程钩子,该钩子的专属结构体CWPSTRUCT直接携带消息目标窗口的hwnd字段,完全匹配你的需求。
代码修改示例
#include <Windows.h> HHOOK hookHandle = nullptr; LRESULT CALLBACK messageHandler(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= HC_ACTION) { // 执行时处于目标线程上下文,GetFocus返回当前线程接收键盘输入的窗口句柄 HWND targetHwnd = GetFocus(); if (targetHwnd != nullptr) { // 此处填写targetHwnd的处理逻辑 } } // 必须调用下一个钩子,否则会中断消息传递 return CallNextHookEx(hookHandle, nCode, wParam, lParam); } // 原messageDispatcher逻辑保持不变即可 DWORD WINAPI messageDispatcher(LPVOID thread) { hookHandle = SetWindowsHookEx(WH_KEYBOARD, messageHandler, GetModuleHandle(nullptr), *reinterpret_cast<DWORD*>(thread)); if (!hookHandle) { return GetLastError(); } MSG message{}; while (GetMessage(&message, 0, 0, 0) > 0) { TranslateMessage(&message); DispatchMessage(&message); } UnhookWindowsHookEx(hookHandle); return 0; }
特殊场景适配方案
如果需要捕获所有发送给目标线程任意窗口的键盘消息(包括非队列的SendMessage发送的键盘消息),可以改用WH_CALLWNDPROC钩子,实现逻辑如下:
LRESULT CALLBACK callWndProcHandler(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= HC_ACTION) { CWPSTRUCT* cwp = reinterpret_cast<CWPSTRUCT*>(lParam); // 过滤键盘相关消息 if (cwp->message == WM_KEYDOWN || cwp->message == WM_KEYUP || cwp->message == WM_CHAR) { HWND targetHwnd = cwp->hwnd; // 直接拿到消息目标窗口句柄 WPARAM keyCode = cwp->wParam; // 此处填写你的处理逻辑 } } return CallNextHookEx(hookHandle, nCode, wParam, lParam); } // 初始化钩子时修改钩子类型即可 hookHandle = SetWindowsHookEx(WH_CALLWNDPROC, callWndProcHandler, GetModuleHandle(nullptr), targetThreadId);
内容的提问来源于stack exchange,提问作者August Vishnevsky
相关产品推荐
相关产品推荐

