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

Raymond Chen

Raymond

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.

Raymond Chen
Raymond Chen

Follow Raymond   

6 comments

  • Avatar
    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.

    • Avatar
      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.

  • Avatar
    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 Chen
      Raymond Chen

      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.

  • Avatar
    gast 128

    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 period. We now use a timer queue as recommended by MSDN but things would have been simple if there was just a high(er) priority WM_TIMER message.

Leave a comment