One danger of the MsgWaitForMultipleObjects
function is calling it when there are already messages waiting to be processed, because MsgWaitForMultipleObjects
returns only when there is a new event in the queue.
In other words, consider the following scenario:
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)
returnsTRUE
indicating that there is a message.- Instead of processing the message, you ignore it and call
MsgWaitForMultipleObjects
.
This wait will not return immediately, even though there is a message in the queue. That’s because the call to PeekMessage
told you that a message was ready, and you willfully ignored it. The MsgWaitForMultipleObjects
message tells you only when there are new messages; any message that you already knew about doesn’t count.
A common variation on this is the following:
MsgWaitForMultipleObjects
returns that there is a message.- You call
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)
and process that message. - You call
MsgWaitForMultipleObjects
to wait for more messages.
If it so happens that there were two messages in your queue, the MsgWaitForMultipleObjects
does not return immediately, because there are no new messages; there is an old message you willfully ignored, however.
When MsgWaitForMultipleObjects
tells you that there is a message in your message queue, you have to process all of the messages until PeekMessage
returns FALSE
, indicating that there are no more messages.
Note, however, that this sequence is not a problem:
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)
returnsFALSE
indicating that there is no message.- A message is posted into your queue.
- You call
MsgWaitForMultipleObjects
and include theQS_ALLPOSTMESSAGE
flag.
This wait does return immediately, because the incoming posted message sets the “There is a new message in the queue that nobody knows about” flag, which QS_ALLPOSTMESSAGE
matches and therefore causes MsgWaitForMultipleObjects
to return immediately.
The MsgWaitForMultipleObjectsEx
function lets you pass the MWMO_INPUTAVAILABLE
flag to indicate that it should check for previously-ignored input.
Armed with this knowledge, explain why the observed behavior with the following code is “Sometimes my program gets stuck and reports one fewer record than it should. I have to jiggle the mouse to get the value to update. After a while longer, it falls two behind, then three…”
// Assume that there is a worker thread that processes records and // posts a WM_NEWRECORD message for each new record. BOOL WaitForNRecords(HANDLE h, UINT cRecordsExpected) { MSG msg; UINT cRecords = 0; while (true) { switch (MsgWaitForMultipleObjects(1, &h, FALSE, INFINITE, QS_ALLINPUT)) { case WAIT_OBJECT_0: DoSomethingWith(h); // event has been signalled break; case WAIT_OBJECT_1: // we have a message - peek and dispatch it if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } if (SendMessage(hwndNotify, WM_GETRECORDCOUNT, 0, 0) >= cRecordsExpected) { return TRUE; // we got enough records } break; default: return FALSE; // unexpected failure } } }
0 comments