Thread messages are eaten by modal loops


Thread messages (as generated by the PostThreadMessage function) do not go anywhere when passed to the DispatchMessage function. This is obvious if you think about it, because there is no window handle associated with a thread message. DispatchMessage has no idea what to do with a message with no associated window. It has no choice but to throw the message away.

This has dire consequences for threads which enter modal loops, which any thread with a window almost certainly will do at one time or another. Recall that the traditional modal loop looks like this:

while (GetMessage(&msg, NULL, 0, 0)) {
 TranslateMessage(&msg);
 DispatchMessage(&msg);
}

If a thread message is returned by the GetMessage function, it will just fall through the TranslateMessage and DispatchMessage without any action being taken. Lost forever.

Thread messages are generally to be avoided on threads that create windows, for this very reason. Of course, if you're going to create a window, why not use PostMessage instead, passing that window as the target of the posted message? Since there is now a window handle, the DispatchMessage function knows to give the message to your window procedure. Result: Message not lost.

Comments (3)
  1. Why not add an API to set a per-thread message callback for any thread-only messages? Then DispatchMessage could just call this.

  2. Adrian says:

    This seems related to why the timed message box back in the Modality series of articles didn’t work reliably. See http://blogs.msdn.com/oldnewthing/archive/2005/03/04/385100.aspx

    That article showed how to post a WM_QUIT message to break a modal loop, and then to remove the re-posted WM_QUIT message to keep the application from exiting. Unfortunately for me, it failed to remove the re-posted WM_QUIT because it was occluded by thread messages that were posted to the queue immediately after the modal loop exited.

    They mystery remains as to who would post such a message (and why). The sample application certainly wasn’t doing it. Since it happens reliably on two vanilla Windows XP boxes here at work, I suspect LANdesk Remote Control agent, as that is the only non-standard program running (and the only one I can’t uninstall thanks to our strict IT department).

  3. François says:

    The documentation for PostThreadMessage hints that we should install a thread-specific hook to solve this problem.

    Why not simply always do this ? Even if I am in control of the thread’s implementation, sometimes ‘magic’ modal loops will appear (say I call into this library that uses COM under the covers).

    So maybe the rule is : whenever you PostThreadMessage, you MUST install a hook on the target thread to handle the thread messages ?

Comments are closed.