GetQueueStatus and the queue state

Raymond Chen

Some time ago, we learned that the Msg­Wait­For­Multiple­Objects function waits only for new events to arrive. In particular, this means that when Msg­Wait­For­Multiple­Objects tells you that an event has arrived, you need to process all of those events before looping back and calling Msg­Wait­For­Multiple­Objects again, because Msg­Wait­For­Multiple­Objects isn’t going to tell you about those old events.¹

It so happens that the Get­Queue­Status function also manipulates the queue status. Each time you call Get­Queue­Status to check a flag, that flag is marked as no longer “new” in the queue status, in the same way that Msg­Wait­For­Multiple­Objects marks the flag as no longer “new” when it wakes up due to a queue status change.

This behavior of Get­Queue­Status is very surprising, because you don’t expect a function called “Get” to have destructive side effects.

The Get­Queue­Status function returns the queue status in two forms, packed into a single 32-bit integer. The low-order 16 bits contain the new queue status bits (the queue status changes since the last time you asked about them), whereas the high-order 16 bits contain the cumulative queue status bits (all the status bits, both old and new). This is explained in the “Return value” section of the documentation, but it’s something that you may read without fully comprehending the consequences.

Therefore, if you want to know if there is (say) any raw input available, either old or new, you need to write

if (HIWORD(GetQueueStatus(QS_RAWINPUT)) & QS_RAWINPUT)

And if you want to drain the raw input, you should use a while loop to keep processing the raw input until the bit goes clear in the high word.

The fact that Get­Queue­Status is a destructive operation is one of those hidden gotchas of the window manager. This sort of atomic “test and clear” operation is common inside the window manager, so they exposed a function that let applications do it too, using the same name that the window manager used internally, so you might say that this function was named while wearing window manager colored glasses: The fact that this is a “test and clear” function is obvious if you work on the window manager, and completely surprising if you don’t.

¹ The Msg­Wait­For­Multiple­Objects­Ex function lets you pass the MWMO_INPUT­AVAILABLE flag to mean, “Also consider old events that haven’t yet been processed.”

1 comment

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

  • a b 0

    Is there a way to post custom coalesceable windows message, like WM_TIMER and WM_PAINT?
    The motivation is basically the same as WM_PAINT, “Combining WM_PAINT messages reduces the number of times a window must redraw the contents of its client area.”, but with custom tasks.
    An imperfect solution is to use MsgWaitForMultipleObjects and SetEvent. But this method is hampered by many internal modal message loops which the application has no control over.
    For example, MsgWaitForMultipleObjects has no chance to run when a window/scrollbar is being dragged or a menu is opened, causing the custom task processing to halt.

Feedback usabilla icon