Watching thread messages disappear

Date:April 27, 2005 / year-entry #107
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20050427-10/?p=35763
Comments:    3
Summary:We saw last time that thread messages are eaten by modal loops. Today we'll illustrate, and then we'll try to fix it next time. Start with our scratch program and make the following changes: #include BOOL IsThreadMessage(MSG *pmsg) { if (pmsg->hwnd == NULL) { switch (pmsg->message) { case WM_APP: MessageBeep(-1); return TRUE; } }...

We saw last time that thread messages are eaten by modal loops. Today we'll illustrate, and then we'll try to fix it next time.

Start with our scratch program and make the following changes:

#include <shellapi.h>

BOOL IsThreadMessage(MSG *pmsg)
{
 if (pmsg->hwnd == NULL) {
  switch (pmsg->message) {
   case WM_APP: MessageBeep(-1); return TRUE;
  }
 }
 return FALSE;
}

// For illustration, we'll post a thread message every two seconds
DWORD CALLBACK ThreadProc(void *lpParameter)
{
 DWORD dwThread = PtrToUint(lpParameter);
 for (;;) {
  Sleep(2000);
  PostThreadMessage(dwThread, WM_APP, 0, 0);
 }
 return 0;
}

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 // Start the timer that posts the thread message
 DWORD dwThread;
 HANDLE hThread = CreateThread(NULL, 0, ThreadProc,
       UintToPtr(GetCurrentThreadId()), 0, &dwThread);
 if (!hThread) return FALSE;
 CloseHandle(hThread);

 // create some content - just to make things interesting
 g_hwndChild = CreateWindow(WC_LISTVIEW, NULL,
                            WS_CHILD | WS_VISIBLE | LVS_ICON, 0, 0, 0, 0,
                            hwnd, (HMENU)1, g_hinst, 0);
    if (!g_hwndChild) return FALSE;
    SHFILEINFO sfi;
    HIMAGELIST himl = (HIMAGELIST)SHGetFileInfo(TEXT("C:\\"), 0,
            &sfi, sizeof(sfi),
            SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_LARGEICON);
    if (!himl) return FALSE;
    ListView_SetImageList(g_hwndChild, himl, LVSIL_NORMAL);
    for (int i = 0; i < 50; i++) {
     LVITEM item;
     item.iItem = i;
     item.iSubItem = 0;
     item.mask = LVIF_TEXT | LVIF_IMAGE;
     item.pszText = sfi.szDisplayName;
     item.iImage = sfi.iIcon;
     if (ListView_InsertItem(g_hwndChild, &item) < 0) return FALSE;
    }
    return TRUE;
}

void OnClose(HWND hwnd)
{
 if (MessageBox(hwnd, TEXT("Really?"), TEXT("Title"),
     MB_YESNO) == IDYES) {
  DestroyWindow(hwnd);
 }
}

// add to window procedure
    HANDLE_MSG(hwnd, WM_CLOSE, OnClose);

    while (GetMessage(&msg, NULL, 0, 0)) {
      if (!IsThreadMessage(&msg)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }

Run this program and notice that it beeps every two seconds, or at least it does most of the time. If you right-click on the caption bar or grab the edge of the window to start resizing it or grab the scollbar or start a drag-selection or display a message box, the beeps stop. That's because all of those actions are modal operations, and the modal message loop is eating the thread messages.

Save this program because we'll come back to it.

The obvious solution is to post the message to the main window itself rather than to the thread. You have a window handle; use it!

DWORD CALLBACK ThreadProc(void *lpParameter)
{
 HWND hwnd = reinterpret_cast<HWND>(lpParameter);
 for (;;) {
  Sleep(2000);
  PostMessage(hwnd, WM_APP, 0, 0);
 }
 return 0;
}

 HANDLE hThread = CreateThread(NULL, 0, ThreadProc,
       reinterpret_cast<void*>(hwnd), 0, &dwThread);

// add to window procedure
 case WM_APP: MessageBeep(-1); return 0;

    while (GetMessage(&msg, NULL, 0, 0)) {
      if (!IsThreadMessage(&msg)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }

Now that that problem has been solved, I'm going to tempt fate and solve the problem the wrong way because I want to illustrate message filters. Next time.


Comments (3)
  1. Ragi says:

    Why not use our new c++ scratch program?

  2. Because this program is simple enough that it doesn’t need it.

  3. Josh Koppang says:

    That explains why the progress bars on dialogs for certain operations in Windows (and other programs) like copying files, etc. Stop when you click and move them. I had always expected something like this, but never really cared to investigate.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index