May 31st, 2013

Posted messages are processed ahead of input messages, even if they were posted later

Regardless of which interpretation you use, it remains the case that posted messages are processed ahead of input messages. Under the MSDN interpretation, posted messages and input messages all go into the message queue, but posted messages are pulled from the queue before input messages. Under the Raymond interpretation, posted messages and input messages are kept in separate queues, and the message retrieval functions will look first in the posted message queue before looking in the input queue.

Let’s run an experiment to see posted messages get processed ahead of input messages. Start with the new scratch program and make these changes:

#include <strsafe.h>

class RootWindow : public Window { public: virtual LPCTSTR ClassName() { return TEXT(“Scratch”); } static RootWindow *Create();

void AppendText(LPCTSTR psz) { ListBox_SetCurSel(m_hwndChild, ListBox_AddString(m_hwndChild, psz)); }

void AppendFormat(LPCTSTR pszFormat, …) { va_list ap; va_start(ap, pszFormat); TCHAR szMsg[256]; StringCchVPrintf(szMsg, ARRAYSIZE(szMsg), pszFormat, ap); AppendText(szMsg); va_end(ap); }

void LogMessage(const MSG *pmsg) { AppendFormat(TEXT(“%d\t%04x\t%p\t%p”), pmsg->time, pmsg->message, pmsg->wParam, pmsg->lParam); }

… };

LRESULT RootWindow::OnCreate() { m_hwndChild = CreateWindow( TEXT(“listbox”), NULL, LBS_HASSTRINGS | LBS_USETABSTOPS | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL, 0, 0, 0,0, GetHWND(), (HMENU)1, g_hinst, 0); return 0; }

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nShowCmd) { … while (GetMessage(&msg, NULL, 0, 0)) {

switch (msg.message) { case WM_KEYDOWN: prw->AppendText(TEXT(“Sleeping”)); UpdateWindow(prw->GetHWND()); Sleep(1000); prw->AppendText(TEXT(“Posting”)); PostMessage(prw->GetHWND(), WM_USER, 0, 0); break; case WM_KEYUP: case WM_USER: prw->LogMessage(&msg); break; }

TranslateMessage(&msg); DispatchMessage(&msg); … }

This program creates a list box so we can display some output. In the message loop, it sniffs at all the queued messages and does the following:

  • If the message is WM_KEY­UP or WM_USER, then it logs the message timestamp and some parameters.
  • If the message is WM_KEY­DOWN, then it sleeps without processing messages for one second, and then posts a WM_USER message to the main window (which ignores it).

Run this program, and then tap the shift key.

The window gets a WM_KEY­DOWN for the shift key. It sleeps for one second (plenty of time for you to release the shift key), and then posts a WM_USER message.

The WM_USER and WM_KEY­UP messages arrive, and observe via the log window that they arrive out of order. WM_USER message arrived first!

That’s because of the rule that says that posted messages are processed ahead of input messages. (Depending on how you want to look at it, you might say that posted messages are “called out for preferential treatment” in the queue, or you might say that posted messages are placed in a different queue from input messages, and the posted message queue has higher priority.)

Observe also that the timestamp on the WM_USER message is greater than the timestamp on the WM_KEY­UP message, because the key went up before the WM_USER message was posted. Time has gone backward.

Make the following change to our program: Change the message we post from WM_USER to WM_KEY­UP:

      PostMessage(hwnd, WM_KEYUP, 0, 0);

Run the program again, and again tap the shift key. Observe that the posted WM_KEY­UP message is processed ahead of the WM_KEY­UP input message. (You can see the difference because we posted the WM_KEY­UP message with wParam and lParam both zero, whereas the WM_KEY­UP input message has information in those parameters.)

This little demonstration also reinforces some other things we already knew. For example, it once again shows that the input manager does not wiretap your posted messages. If you post a WM_KEY­UP message, it is treated like a posted message not an input message. We saw earlier that posting a keyboard message does not update internal input states. The keyboard shift states are not updated to match your prank call message. If somebody calls Get­Queue­Status, they will not be told that there is input waiting. It will not wake a Msg­Wait­For­Multiple­Objects function that is waiting for QS_INPUT. And as we saw here today, the message gets processed out of order.

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.

0 comments

Discussion are closed.