winapi - 未收到 WH_KEYBOARD_LL 处理程序 PostThreadMessage 消息的 SetWindowsHookEx?
问题描述
我设置了一个处理程序来在短时间内捕捉击键,同时为窗口使用私人消息循环。虽然它有效,但如果我尝试PostThreadMessage
窗口永远不会收到消息?
回调看起来像(我尝试了其他消息,这个示例带有私人消息):
LRESULT CALLBACK LLKeyboardHookProc(int ncode, WPARAM wp, LPARAM lp)
{
if (ncode == HC_ACTION) {
if (wp==WM_KEYDOWN) {
KBDLLHOOKSTRUCT *kbs=reinterpret_cast<KBDLLHOOKSTRUCT*>(lp);
if (kbs->vkCode==VK_ESCAPE) {
PostThreadMessage (GetCurrentThreadId(), UWM_MYCLOSEMESSAGE, 0, 0);
}
}
}
return CallNextHookEx(0, ncode, wp, lp);
}
HHOOK kbhook = SetWindowsHookEx(WH_KEYBOARD_LL, LLKeyboardHookProc, GetModuleHandle(NULL), 0);
WS_EX_LAYERED
窗口的消息循环如下所示:
while (IsWindow(hwnd)) {
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
// let MFC do its idle processing
LONG lIdle=0;
while (AfxGetApp()->OnIdle(lIdle++));
WaitMessage();
}
// clean up
UnhookWindowsHookEx(kbhook);
我现在将其更改为使用 volatile 变量来关闭窗口,但我真的很想给它发送一条消息。如果没有锁,使用全局 HWND 就不是线程安全的,所以不想那样做。
PS我确实检查了 PostThreadMessage 结果,它不是 FALSE(添加它们时没有调试消息),所以它似乎将它发布在某个地方。
解决方案
PostThreadMessage()
将线程消息发布到队列,而不是窗口消息。您的消息循环忽略线程消息,仅调度窗口消息。窗口永远不会看到线程消息,因此您需要直接在消息循环中处理此类消息,例如:
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.hwnd == NULL && msg.message == UWM_MYCLOSEMESSAGE) { // <-- add this
// do something...
}
else {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
然而,正如 Hans Passant 在评论中所说:
当您还创建了一个窗口时,永远不要使用 PostThreadMessage(),像调整窗口大小这样简单的事情会导致消息丢失。
Raymond Chen 发表了几篇关于这个主题的博客文章:
为什么 PostThreadMessage 发布的消息会消失?
您可以尝试使用WH_MSGFILTER
钩子,就像 Raymond 演示的那样。但解决此问题的最佳方法是根本不发布线程消息,而是发布窗口消息。让您的键盘挂钩使用PostMessage()
(甚至SendMessage()
)到HWND
您的应用程序拥有的一个,然后您可以在该窗口的消息过程中处理该消息。
推荐阅读
- go - Gorm Count 预加载字段
- powershell - 如何将“字符串”添加到“字符串 []”变量?
- bash - 例如,选择编号为“file.00001”到“file.00431”的文件
- php - 无法发送肥皂请求 - 无效的 API 命名空间 -
- java - 如何为多个观察者实现不同的行为?
- python - Python正则表达式匹配给定字符串中的多个模式
- javascript - REST API 从 XMLHttpRequest 接收“null”-与 Postman 相同的请求有效吗?
- sitecore - Sitecore 多语言 - 将项目解析为 InternalLinkField 会转换其语言
- sql - 在 SQL 中查找实体的第一个和最后一个条目的最有效方法是什么?
- unicode - CQL 转义 \xa0