Why is there a special PostQuitMessage function?


Why is there a special PostQuitMessage function? Because it's not really a posted message.

Commenter A. Skrobov asked, "What's the difference between PostQuitMessage and PostThreadMessage(GetCurrentThreadId, WM_QUIT)?"

They are not equivalent, though they may look that way at first glance. The differences are subtle but significant.

Like the WM_PAINT, WM_MOUSEMOVE, and WM_TIMER messages, the WM_QUIT message is not a "real" posted message. Rather, it is one of those messages that the system generates as if it were posted, even though it wasn't. And like the other messages, the WM_QUIT message is a "low priority" message, generated only when the message queue is otherwise empty.

When a thread calls PostQuitMessage, a flag in the queue state is set that says, "If somebody asks for a message and there are no posted messages, then manufacture a WM_QUIT message." This is just like the other "virtually posted" messages. WM_PAINT messages are generated on demand if there are any invalid regions, WM_MOUSEMOVE messages are generated on demand if the mouse has moved since the last time you checked, and WM_TIMER messages are generated on demand if there are any due timers. And since the message is "virtually posted", multiple calls coalesce, in the same way that multiple paint messages, multiple mouse motions, and multiple timer messages also coalesce.

Why is WM_QUIT handled like a low-priority message?

Because the system tries not to inject a WM_QUIT message at a "bad time"; instead it waits for things to "settle down" before generating the WM_QUIT message, thereby reducing the chances that the program might be in the middle of a multi-step procedure triggered by a sequence of posted messages.

If you PeekMessage(..., PM_NOREMOVE) a WM_QUIT message, this returns a WM_QUIT message but does not clear the flag. The WM_QUIT message virtually "stays in the queue".

As another special behavior, the generated WM_QUIT message bypasses the message filters passed to the GetMessage and PeekMessage functions. If the internal "quit message pending" flag is set, then you will get a WM_QUIT message once the queue goes quiet, regardless of what filter you pass.

By comparison, PostThreadMessage just places the message in the thread queue (for real, not virtually), and therefore it does not get any of the special treatment that a real PostQuitMessage triggers.

Comments (12)
  1. Centaur says:

    There is at least one more reason. PostQuitMessage, IIRC, was supported in Win16, and threads only appeared in Win32.

  2. So is it then not a great idea to use PostThreadMessage(id, WM_QUIT) from a different thread? Not that it would be much trouble to post a custom message that called PostQuitMessage() when handled but I know I’ve used and have seen code that uses PostThreadMessage(WM_QUIT) to shutdown a message based thread queue.

  3. A. Skrobov says:

    To Centaur: before Win32, the function to post a ‘thread message’ was called "PostAppMessage", and took an hTask as parameter.

  4. Mike Parks says:

    I suppose a general solution would be a priority parameter for PostThreadMessage(). Then you could post any message (not just WM_QUIT) as a message that doesn’t get sent until the queue dies down.

  5. Norman Diamond says:

    Now I’m more confused on this issue than I used to be. I can think of two occasions when we want an application to quit:

    (1) The user is telling the application to quit. (This includes the user logging off or whatever, actions which include telling applications to quit.)

    (2) The application detects something to make it know it wants to quit.

    I would figure that in either of these cases, we don’t want to wait for the queue to quiet down. We want each thread to figure out what kind of cleanup it has to do, and do the cleanup, not execute a bunch of attempted operations that should now be aborted or ignored. What is the purpose in waiting for the queue to quiet down?

    Also what should programmers do in cases when we know we don’t want to wait for the queue to quiet down? The only use I’ve seen for this so far is when a application is starting up and we detect some situation in which we want to display a message box, and exit after the user clicks OK (instead of proceeding to handle ordinary messages). There could be other uses that I haven’t seen. It seems that both PostQuitMessage and ordinary Post___Message(___, WM_QUIT) aren’t the recommended way to do it, so what should we do?

    Also why isn’t there a CWnd::PostQuitMessage()? (I think I’m not the first person to ask this question.)

  6. Chris Becke says:

    1. If (the user or the programmer) wants an application to quit, send its windows "WM_CLOSE" messages.

    2. If the application really wants to quit *now*, ExitProcess() is a quick way out.

    3. There is no CWnd::PostQuitMessage() because WM_QUIT messages are posted to the thread, not a window.

    The real question is, why is there no "PostThreadQuitMessage(DWORD threadId)".

  7. Michael J. says:

    I hope this is related: I always wanted to know why Windows apps cannot be terminated using Ctrl+Break like most DOS apps? Well, I can see theat in Win16 this would leave some resources hanging around. But for Win32 resources should be cleaned up pretty robustly if an app goes down, so why not?

  8. Norman Diamond says:

    Monday, November 07, 2005 3:46 AM by Chris Becke

    > 1. If (the user or the programmer) wants

    > an application to quit, send its windows

    > "WM_CLOSE" messages.

    When the user clicks to close a window, that window gets the WM_CLOSE but the application’s other windows don’t.

    > 2. If the application really wants to quit

    > *now*, ExitProcess() is a quick way out.

    You’re right. For some reason I forgot that, despite the dangers of TerminateProcess(), ExitProcess() is safe.

    > 3. There is no CWnd::PostQuitMessage()

    > because WM_QUIT messages are posted to the

    > thread, not a window.

    Hmm, I wonder if I’ve seen that answer before and forgotten (since I’m pretty sure I’ve seen others ask the same question I asked). So, when I called CWnd::PostMessage(___, WM_QUIT), the fact that it happened to work is an unfortunate accident. I should call ExitProcess().

    But in turn that raises the question, why is there an AfxAbort() function for catastrophic termination but no AfxQuit() for normal-but-speedy termination.

  9. James says:

    … because most people wouldn’t want that?

    I presume you mean for it to terminate an application only under certain conditions?

    So my questions:

    * Why isn’t any of this mentioned in the PostQuitMessage documentation? The documentation recommends to use PostQuitMessage over WM_QUIT but offers no rationale why. (And yes, I’m aware that you don’t have direct control over the documentation. But really, rather than having many Microsoft employees writing weblog posts about Windows API minutiae, maybe all your webloggers should just take over/threaten/bribe the documentation group…)

    * Can user messages get similar wait-till-things-die-down behavior?

  10. Exactly how do you propose that I take over/threaten/bribe the documentation group? (The documentation group relies on the development teams to provide the technical information in the first place; it’s not like they can just write the docs without any help. And I suspect they have higher priorities than touching up ancient Win32 documentation.)

  11. James says:

    I don’t know. Ask nicely? =)

    Alas, writing documentation is never anyone’s priority, but it needs to be done. (And surely you have higher priorities than writing weblog entries and responding to inane comments, but yet you do. =) )

    Maybe in the same vein as the month-where-everyone-focuses-on-security-issues, there could be a week where everyone focuses on improving the documentation?

  12. Here’s the scenario – You have a form (StartForm) which has a sub-form (subForm) that contains a WebBrowser

Comments are closed.