首页 > 解决方案 > PostMessage:未收到消息

问题描述

我正在寻找一些关于我可以解决的问题的反馈,但想更好地理解。我有一些多线程代码,其中工作线程使用 Win32 API PostMessage 函数将消息发布到主 UI 线程以更新 TreeView。尽管我的日志显示 PostMessage 成功返回,但某些发布的消息有时无法通过 UI 线程的消息泵出现。

由于在某些情况下存在模态消息泵,我已经找到了许多关于如果我在消息泵中做了一些时髦的事情会发生这种情况的解释,但我没有做任何时髦的事情。

我认为(但想确认)我的问题是由于在 UI 线程的生命周期中过早调用 PostMessage 造成的。我的 WinMain 调用 CreateWindowEx 来创建它的主窗口,并且该窗口的 WM_CREATE 处理程序间接启动后台线程,这些线程将相当快地使用主窗口的 HWND 调用 PostMessage,甚至可能在 WM_CREATE 处理程序完成之前,很可能在 WinMain 的消息泵之前已启动。

即使 PostMessage 返回成功,在这种情况下是否有可能/可能会丢失某些消息?在测试中,我确定在工作线程调用 PostMessage 之前添加一个小的延迟 (Sleep(50)) 足以防止任何消息丢失。但是,我不相信这可以解决根本问题,所以想知道我是否需要继续挖掘。

编辑:

我的所有代码中只有一个消息循环,除了调用通常的 TranslateAccelerator 等之外,它并没有做任何不寻常的事情:

 // Enter the message loop
 while (GetMessage (&msg, NULL, 0, 0)) {
   if (!TranslateMDISysAccel(hwndClient, &msg) && !TranslateAccelerator (hwndFrame, hAccel, &msg)) {
     TranslateMessage (&msg) ;
     DispatchMessage (&msg) ;
   }
 }

标签: c++windowsmultithreadingwinapi

解决方案


由于在某些情况下存在模态消息泵,我已经找到了许多关于如果我在消息泵中做了一些时髦的事情会发生这种情况的解释,但我没有做任何时髦的事情。

模态循环不会丢弃窗口消息,除非它们编码错误并且不会像应有的那样将未知消息传递给TranslateMessage()/ 。DispatchMessage()

我认为(但想确认)我的问题是由于在 UI 线程的生命周期中过早调用 PostMessage 造成的。

如果是这种情况,那只PostMessage()会失败,但您已经排除了这种可能性。一旦线程调用任何user32.dll函数,消息队列就会被创建并且可以开始接收消息,即使队列没有被立即轮询。

即使 PostMessage 返回成功,在这种情况下是否有可能/可能会丢失某些消息?

不,还有其他事情正在发生。要么您的消息循环错误地过滤消息,要么格式错误的模式循环正在丢弃消息,或者您只是发布到错误的HWND. 很难说,因为您没有显示任何代码。

在测试中,我确定在工作线程调用 PostMessage 之前添加一个小的延迟 (Sleep(50)) 足以防止任何消息丢失。

在这 50 毫秒内,您的主线程通常在做什么?听起来您的 UI 代码中的某些内容在此期间正在接收和丢弃您发布的消息。

另一方面,线程如何知道HWND要发布到哪个?您的WM_CREATE处理程序是将其hwnd参数传递给线程,还是依赖于HWND返回的线程CreateWindowEx()?在后一种情况下,如果在退出PostMessage()之前调用应该会失败。CreateWindowEx()除非您的接收HWND变量最初是未初始化的并且包含一个随机的非空值,该值被PostMessage()解释为HWND系统上其他地方的有效值。


推荐阅读