November 8th, 2019

Can I force a WM_TIMER message to be generated when the timer comes due, even if the message queue is not idle?

Normally, WM_TIMER messages for due timers are generated only if the message queue is empty, which puts them very close to the bottom of the message priority list. But what if you want to give the timer message the same priority as posted messages?

You may have a background task that, under periods of high activity, posts a lot of work to the UI thread. During those busy periods, WM_TIMER messages won’t be generated because the message queue is never empty. But you want the timer to run so you can update some UI, like,`say, a progress meter.

Some time ago, we discussed the problem of a message queue filled with unprocessed WM_TIMER messages. We can take that understanding of how these timer messages can be forced to be created, and we can use that power for good, rather than for evil.

The work items that are posted to the UI thread can force a timer message to be generated if a timer is due:

void ForceTimerMessagesToBeCreatedIfNecessary()
{
    MSG msg;
    PeekMessage(&msg, nullptr, WM_TIMER, WM_TIMER, PM_NOREMOVE);
}

The filtered Peek­Message will look for a WM_TIMER message in the queue. If one is found, then it is copied to the msg (which we discard), but it is not removed from the message queue (PM_NO­REMOVE) so it will be processed by the main message pump.

If one is not found, the system will see if any timers are due, and if so, it will synthesize a WM_TIMER message and insert it into the queue, and then return a copy.

If there are no timer messages in the queue, and no timer is due, then nothing happens.

Note that this mechanism does not suffer from timer message build-up because it generates a timer message only if there isn’t one already. It could trigger systimer message build-up, but that won’t be a problem provided that your main message pump is pumping all messages.

The message build-up problem exists when you force the synthesis of messages and steadfastly refuse to process them. So don’t do that.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

6 comments

Discussion is closed. Login to edit/delete existing comments.

  • gast128

    We needed something like this a couple of years ago. Basically if the GUI was too busy with painting, the timer message didn't came through since WM_PAINT has a higher priority. We then switched to multimedia timers with the additional architectural overhead of getting the message in the GUI thread. Unfortunately that gave us a bug report since it has only a limited time range and sometimes the application had to wait for a longer...

    Read more
  • Vadim Zeitlin

    Is PM_NOREMOVE really necessary here or is it used just for convenience of not having to process the timer message right here? I.e. will a message be still synthesized if this flag is omitted?

    • Raymond ChenMicrosoft employee Author

      It’s just for the convenience of not having to process it now and avoid having two different code paths for timer messages. The message is left in the queue for the message pump to deal with, as if it were generated in the conventional manner.

  • aidtopia

    This feels like we’re depending on non-contractual behavior, specifically, that the PeekMessage will synthesize an actual entry and stuff it in the queue if some “timer-expired” flag is set. I could imagine implementations that don’t do it that way, e.g., just fill out the MSG and leave the “timer-expired” flag alone. I don’t see anything in PeekMessage’s documentation that seems to promise the behavior this relies on.

    • SpecLad

      I think that if your application is well-written, it will still work even if PeekMessage doesn’t put a real message in the queue. It just won’t update the UI in time.

    • Raymond ChenMicrosoft employee Author

      PeekMessage synthesizes create-on-demand messages as necessary. A large category of apps (apps that use solely PeekMessage and never GetMessage) rely on this.