{"id":35763,"date":"2005-04-27T09:00:10","date_gmt":"2005-04-27T09:00:10","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/04\/27\/watching-thread-messages-disappear\/"},"modified":"2023-08-04T14:49:23","modified_gmt":"2023-08-04T21:49:23","slug":"20050427-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050427-10\/?p=35763","title":{"rendered":"Watching thread messages disappear"},"content":{"rendered":"<p><a title=\"Thread messages are eaten by modal loops\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050426-18\/?p=35783\"> We saw last time that thread messages are eaten by modal loops<\/a>. Today we&#8217;ll illustrate, and then we&#8217;ll try to fix it next time.<\/p>\n<p>Start with our scratch program and make the following changes:<\/p>\n<pre><span style=\"border: solid 1px currentcolor; border-bottom: none;\">#include &lt;shellapi.h&gt;                                                    <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">\u00a0                                                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">BOOL IsThreadMessage(MSG *pmsg)                                          <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">{                                                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> if (pmsg-&gt;hwnd == NULL) {                                               <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">  switch (pmsg-&gt;message) {                                               <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">   case WM_APP: MessageBeep(-1); return TRUE;                            <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">  }                                                                      <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> }                                                                       <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> return FALSE;                                                           <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">}                                                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">\u00a0                                                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">\/\/ For illustration, we'll post a thread message every two seconds       <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">DWORD CALLBACK ThreadProc(void *lpParameter)                             <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">{                                                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> DWORD dwThread = PtrToUint(lpParameter);                                <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> for (;;) {                                                              <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">  Sleep(2000);                                                           <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">  PostThreadMessage(dwThread, WM_APP, 0, 0);                             <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> }                                                                       <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> return 0;                                                               <\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">}                                                                        <\/span>\r\n\r\nBOOL\r\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\r\n{\r\n<span style=\"border: solid 1px currentcolor; border-bottom: none;\"> \/\/ Start the timer that posts the thread message                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> DWORD dwThread;                                                         <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> HANDLE hThread = CreateThread(NULL, 0, ThreadProc,                      <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">       UintToPtr(GetCurrentThreadId()), 0, &amp;dwThread);                   <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> if (!hThread) return FALSE;                                             <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> CloseHandle(hThread);                                                   <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">\u00a0                                                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> \/\/ create some content - just to make things interesting                <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> g_hwndChild = CreateWindow(WC_LISTVIEW, NULL,                           <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">                            WS_CHILD | WS_VISIBLE | LVS_ICON, 0, 0, 0, 0,<\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">                            hwnd, (HMENU)1, g_hinst, 0);                 <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    if (!g_hwndChild) return FALSE;                                      <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    SHFILEINFO sfi;                                                      <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    HIMAGELIST himl = (HIMAGELIST)SHGetFileInfo(TEXT(\"C:\\\\\"), 0,         <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">            &amp;sfi, sizeof(sfi),                                           <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">            SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_LARGEICON);   <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    if (!himl) return FALSE;                                             <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    ListView_SetImageList(g_hwndChild, himl, LVSIL_NORMAL);              <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    for (int i = 0; i &lt; 50; i++) {                                       <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">     LVITEM item;                                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">     item.iItem = i;                                                     <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">     item.iSubItem = 0;                                                  <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">     item.mask = LVIF_TEXT | LVIF_IMAGE;                                 <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">     item.pszText = sfi.szDisplayName;                                   <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">     item.iImage = sfi.iIcon;                                            <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">     if (ListView_InsertItem(g_hwndChild, &amp;item) &lt; 0) return FALSE;      <\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">    }                                                                    <\/span>\r\n    return TRUE;\r\n}\r\n\r\n<span style=\"border: solid 1px currentcolor; border-bottom: none;\">void OnClose(HWND hwnd)                                                  <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">{                                                                        <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> if (MessageBox(hwnd, TEXT(\"Really?\"), TEXT(\"Title\"),                    <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">     MB_YESNO) == IDYES) {                                               <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">  DestroyWindow(hwnd);                                                   <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\"> }                                                                       <\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">}                                                                        <\/span>\r\n\r\n\/\/ add to window procedure\r\n<span style=\"border: solid 1px currentcolor;\">    HANDLE_MSG(hwnd, WM_CLOSE, OnClose);                                 <\/span>\r\n\r\n    while (GetMessage(&amp;msg, NULL, 0, 0)) {\r\n<span style=\"border: solid 1px currentcolor;\">      if (!IsThreadMessage(&amp;msg)) {                                      <\/span>\r\n        TranslateMessage(&amp;msg);\r\n        DispatchMessage(&amp;msg);\r\n<span style=\"border: solid 1px currentcolor;\">      }                                                                  <\/span>\r\n    }\r\n<\/pre>\n<p>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&#8217;s because all of those actions are modal operations, and the modal message loop is eating the thread messages.<\/p>\n<p>Save this program because we&#8217;ll come back to it.<\/p>\n<p>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!<\/p>\n<pre>DWORD CALLBACK ThreadProc(void *lpParameter)\r\n{\r\n <span style=\"border: solid 1px currentcolor;\">HWND hwnd = reinterpret_cast&lt;HWND&gt;(lpParameter);<\/span>\r\n for (;;) {\r\n  Sleep(2000);\r\n  <span style=\"border: solid 1px currentcolor;\">PostMessage(hwnd<\/span>, WM_APP, 0, 0);\r\n }\r\n return 0;\r\n}\r\n\r\n HANDLE hThread = CreateThread(NULL, 0, ThreadProc,\r\n       <span style=\"border: solid 1px currentcolor;\">reinterpret_cast&lt;void*&gt;(hwnd)<\/span>, 0, &amp;dwThread);\r\n\r\n\/\/ add to window procedure\r\n<span style=\"border: solid 1px currentcolor;\"> case WM_APP: MessageBeep(-1); return 0;<\/span>\r\n\r\n    while (GetMessage(&amp;msg, NULL, 0, 0)) {\r\n      <span style=\"border: dashed 1px currentcolor;\">\/\/ <span style=\"text-decoration: line-through;\">if (!IsThreadMessage(&amp;msg)) {<\/span><\/span>\r\n        TranslateMessage(&amp;msg);\r\n        DispatchMessage(&amp;msg);\r\n      <span style=\"border: dashed 1px currentcolor;\">\/\/ <span style=\"text-decoration: line-through;\">}<\/span>                            <\/span>\r\n    }\r\n<\/pre>\n<p>Now that that problem has been solved, I&#8217;m going to tempt fate and solve the problem <i>the wrong way<\/i> because I want to illustrate message filters. Next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A sample program that loses thread messages.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-35763","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A sample program that loses thread messages.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/35763","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=35763"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/35763\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=35763"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=35763"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=35763"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}