
{"id":610,"date":"2010-09-30T19:55:44","date_gmt":"2010-09-30T23:55:44","guid":{"rendered":"http:\/\/www.ikriv.com\/blog\/?p=610"},"modified":"2010-09-30T19:55:44","modified_gmt":"2010-09-30T23:55:44","slug":"messageboxes-and-worker-threads","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=610","title":{"rendered":"MessageBoxes and worker threads"},"content":{"rendered":"<p>This will hopefully become a more organized article with code samples, but I need to record my results for now. Here&#8217;s the practical problem I encountered in the application I am wokring on: several message boxes initiated by worker threads would pop up simultaneously confusing the user and wrecking havoc.<\/p>\n<p>So, the task is: you want to display a notification (message box) from a worker thread. Sometimes it is fire-and-forget, sometimes you want to know the answer (&#8220;Do you want to continue? Yes|No&#8221;). I will assume the answer is important, since this is case is more complicated.<\/p>\n<p>Here are some facts that I discovered:<\/p>\n<p><b>Fact #1<\/b>: Dismissing a message box may enable the parent even if there are other pending message boxes. I am not sure what is the exact algorithm here, but if you have multiple message boxes on the screen, there is at least one of them that would re-enable the parent when dismissed. This will render all other message boxes effectively modeless. The user can continue to work on the parent and maybe even create more message boxes.<\/p>\n<p><b>Fact #2<\/b>: Calling MessageBox() from a worker thread effectively converts that thread to a UI thread with the message pump.<\/p>\n<p><b>Fact #3<\/b>: If the UI thread is blocked, MessageBox() will also block, even when called on a worker thread. The reason for that is that MessageBox() internally called DialogBox2() function in user32.dll, which calls NtUserCallHwndParamLock(). I am not sure what that function does, but it blocks if the UI thread does not respond.<\/p>\n<p><b>Fact #4<\/b>: If you use PostMessage (BeginInvoke) or SendMessage (Invoke) to render the message boxes on the UI thread, the message boxes can still appear in parallel. In fact, they become <i>recursive<\/i>. If you look at the call stack it looks like one message box calls another.<\/p>\n<p>This happens because the parent window is not dead while showing a message box: it is just disabled. The message box runs its own message pump, and when another thread sends a message instructing the parent window to show another message box, it will be happily processed, showing the second message box on top of the first.<\/p>\n<p>Bottom line: &#8220;serializing&#8221; message box calls via PostMessage\/SendMessage to the UI thread does not work.<\/p>\n<p><b>Fact #5<\/b>. If the UI thread is blocked while we send it &#8220;show that message box&#8221; messages, the message boxes will appear in sequence, starting with the latest. This puzzled me for a while, but after some research I found the truth. The message boxes are still being called recursively, only they don&#8217;t have a chance to show. Showing a window is a complex process that requires handling multiple WM_ messages. When MessageBox() function is called and starts running the inner message loop, there is no window yet. It will appear a little bit later. However, the first message that is processed in the new loop is a request for another message box, which effectively defers creation of the window until later. Only the last message box in the chain has a chance to display itself. Once it is dismissed, previous message box(es) take turn. <a style=\"display:none\" href=\"http:\/\/www.codeproject.com\/script\/Articles\/BlogFeedList.aspx?amid=1181663\" rel=\"tag\">CodeProject<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This will hopefully become a more organized article with code samples, but I need to record my results for now. Here&#8217;s the practical problem I encountered in the application I <a href=\"https:\/\/ikriv.com\/blog\/?p=610\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[3,4,18],"tags":[],"class_list":["entry","author-ikriv","post-610","post","type-post","status-publish","format-standard","category-dotnet","category-hack","category-win32"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/610","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=610"}],"version-history":[{"count":0,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/610\/revisions"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=610"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=610"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=610"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}