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.
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...
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?
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.
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.
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.
PeekMessage synthesizes create-on-demand messages as necessary. A large category of apps (apps that use solely PeekMessage and never GetMessage) rely on this.