The window manager needs a message pump in order to call you back unexpectedly

There are a bunch of different ways of asking the window manager to call you when something interesting happens. Some of them are are in response to things that you explicitly asked for right now. The enumeration functions are classic examples of this. If you call EnumWindows and pass a callback function, then that callback is called directly from the enumerator.

On the other hand, there is a much larger class of things that are in response either to things that happen on another thread, or in response to things that happen on your thread, but not as a direct result of an immediate request. For example, if you use the SendMessageCallback function, and the window manager needs to trigger your callback, the window manager needs a foot in the door of your thread in order to get control. It can't just interrupt code arbitrarily; that way lies madness. So we're looking for some way the window manager can regain control of the CPU at a time when the program is in a stable, re-entrant state.

That foot in the door for the window manager is the message pump. That's the one component that the window manager can have some confidence that the program is going to call into periodically. This solves the first problem: How do I get control of the CPU.

Furthermore, it's a known quantity for programs that when you call GetMessage or PeekMessage, incoming sent messages are dispatched, so your program had better be in a stable, re-entrant state when you call those functions. That solves the second problem: How do I get control of the CPU when the program is in a stable state?

Take-away: When you register a callback with the window manager, you need to pump messages. Otherwise, the window manager has no way of calling you back.

Related: The alertable wait is the non-GUI analog to pumping messages.

Comments (8)
  1. Joshua says:

    Async signals are some nasty hairball any way you cut it.

    There was this old program back in the day that used CLI() and STI() functions to control signal dispatch (named after assembly instructions they didn't actually use).

    The general idea is still the same, set a flag in the signal handler that is checked periodically. On Windows, this also opens the hairball that is CancelPendingIO that Raymond's been blogging about a lot recently.

    Coincidence? I think not.

  2. Gabe says:

    Should the words "Take-away" be a link to…/10097857.aspx

    [Sure why not. -Raymond]
  3. Anthony Wieser says:

    Wow, I thought English was my native language, but I can't for the life of me figure out the documentation on this. OK, I'm an old timer, and I see this wasn't introduced until windows 2000.

    I used to think that SendMessage sent a message to the windowproc (and if cross process waited to get in, presumably by waiting on a sync object of some sort), and PostMessage just added it to the message queue.

    The documentation…/ms644951(v=VS.85).aspx

    says "Sends the specified message to a window or windows.  It calls the window procedure for the specified window and returns immediately"

    Surely calling the window procedure means entering WndProc, so that can't be what's going on.

    Does it actually add the message to some internal queue of messages, that GetMessage/PeekMessage delivers on the next call?

    [Understanding the message pump is one of the things I consider a prerequisite to reading Friday entries. -Raymond]
  4. Joshua says:


    SendMessage dispatches internally to the same thread but does a synchronous (your thread is blocked) postmessage-like operation for cross-thread (and therefore cross-process).

  5. Henning Makholm says:

    Anthony: I think it is reasonably clear, given what Raymond explained not too long ago about how cross-thread SendMessage works. You will recall that sent messages are always handled in the window's owning thread. If SendMessage is called from a different thread/process, it blocks until the receiving thread has processed the message and produced a return value. Evidently there's an internal queue involved here, but it is separate from from the one that is pumped by the GetMessage loop — except that a thread that is blocked in GetMessage will handle sent messages transparently without returning. Now, SendMessageCallback enters a message into the same internal queue, but does not bother to wait for the message to be processed before it returns. Instead a user-specified callback will be called when the return value from the window is ready.

    If anything, this may be easier to understand for old-timers who remember the bad old days when all windows (in all applications!) shared a single thread. Back then, the distinction between SendMessage and PostMessage was clear and simple, and all the subsequent complexity can be understood as an attempt to retrofit old interfaces to a multi-threaded world without breaking too much existing code. But how easy is it for a newcomer these days to grasp the essential difference between PostMessage and SendNotifyMessage, let alone understand why one would want to have both ones available?

  6. Henke37 says:

    Some thoughts about SendMessage. Assume a message pump that calls IsDialogMessage. Now ask yourself the question, is SendMessage compatible with this? What if SendMessage was used to send a message that IsDialogMessage should have processed?

    The question becomes easy when you consider what IsDialogMessage does, it sends the message to the right function. I propose that SendMessage will end up running the same function, because it is the window procedure for the dialog box.

    [Um, no. See exhaustive discussion of dialog box message loops in my book or in the archives. -Raymond]
  7. Anthony Wieser says:

    Looking some more, I found Raymond's 2004 post:…/266664.aspx

    "The various ways of sending a message"

    Following the documentation from there to…/ms644953

    "SendNotifyMessage Function"

    I see that the behaviour on the same thread is specified to some degree, just missing from the docs of SendMessageCallback.

  8. Arno says:

    A cause of frequent grief for us are messages dispatched inside PeekMessage called from the OLE modal loop that is running while dispatching COM calls. In general, an application making such calls is not in a "stable reentrant state". It is currently calling a component after all. WM_CANCELMODE for example can arrive at any time from this modal loop, and IMessageFilter is powerless preventing it. Raymond, do you have any suggestion how this should be handled?

Comments are closed.