{"id":35993,"date":"2005-04-01T06:57:00","date_gmt":"2005-04-01T06:57:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/04\/01\/the-dialog-manager-part-4-the-dialog-loop\/"},"modified":"2005-04-01T06:57:00","modified_gmt":"2005-04-01T06:57:00","slug":"the-dialog-manager-part-4-the-dialog-loop","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050401-00\/?p=35993","title":{"rendered":"The dialog manager, part 4: The dialog loop"},"content":{"rendered":"<p>\nThe dialog loop is actually quite simple. At its core,\nit&#8217;s just<\/p>\n<pre>\nwhile (&lt;dialog still active&gt; &amp;&amp;\n       GetMessage(&amp;msg, NULL, 0, 0, 0)) {\n if (!IsDialogMessage(hdlg, &amp;msg)) {\n  TranslateMessage(&amp;msg);\n  DispatchMessage(&amp;msg);\n }\n}\n<\/pre>\n<p>\nIf you want something fancier in your dialog loop,\nyou can take the loop above and tinker with it.\n<\/p>\n<p>\nBut let&#8217;s start from the beginning.\nThe work happens in DialogBoxIndirectParam.\n(<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/03\/29\/403298.aspx\">You should already know by now how to convert all\nthe other DialogBoxXxx functions into DialogBoxIndirectParam<\/a>.)\n<\/p>\n<pre>\nINT_PTR WINAPI DialogBoxIndirectParam(\n    HINSTANCE hinst,\n    LPCDLGTEMPLATE lpTemplate, HWND hwndParent,\n    DLGPROC lpDlgProc, LPARAM lParam)\n{\n \/*\n  * App hack!  Some people pass GetDesktopWindow()\n  * as the owner instead of NULL.  Fix them so the\n  * desktop doesn't get disabled!\n  *\/\n if (hwndParent == GetDesktopWindow())\n  hwndParent = NULL;\n<\/pre>\n<p>\nThat&#8217;s right, we start with an app hack.\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/02\/24\/79212.aspx\">\nThe problem of passing GetDesktopWindow() instead of NULL\nwas discussed\nin an earlier entry<\/a>.\nSo many people make this mistake that we had to put this app hack\ninto the core OS.  It would be pointless to make a shim for it\nsince that would mean that thousands of apps would need to be shimmed.\n<\/p>\n<p>\nSince only top-level windows can be owners, we have to\ntake the putative <code>hwndParent<\/code>\n(which might be a child window) and walk up the window hierarchy\nuntil we find a top-level window.<\/p>\n<pre>\n if (hwndParent)\n  hwndParent = GetAncestor(hwndParent, GA_ROOT);\n<\/pre>\n<p>\nWith that second app hack out of the way, we create the dialog.\n<\/p>\n<pre>\n HWND hdlg = CreateDialogIndirectParam(hinst,\n               lpTemplate, hwndParent, lpDlgProc,\n               lParam);\n<\/pre>\n<p>\nNote: As before, I am going to ignore error checking and\nvarious dialog box esoterica because it would just be\ndistracting from the main point of this entry.\n<\/p>\n<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/02\/18\/376080.aspx\">\nModal windows disable their parent<\/a>, so do it here.\n<\/p>\n<pre>\n BOOL fWasEnabled = EnableWindow(hwndParent, FALSE);\n<\/pre>\n<p>\nWe then fall into the dialog modal loop:\n<\/p>\n<pre>\n MSG msg;\n while (&lt;dialog still active&gt; &amp;&amp;\n        GetMessage(&amp;msg, NULL, 0, 0)) {\n  if (!IsDialogMessage(hdlg, &amp;msg)) {\n   TranslateMessage(&amp;msg);\n   DispatchMessage(&amp;msg);\n  }\n }\n<\/pre>\n<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/02\/22\/378018.aspx\">\nPer the convention on quit messages<\/a>, we re-post any\nquit message we may have received so the next outer\nmodal loop can see it.\n<\/p>\n<pre>\n if (msg.message == WM_QUIT) {\n  PostQuitMessage((int)msg.wParam);\n }\n<\/pre>\n<p>\n(Astute readers may have noticed an uninitialized\nvariable bug: If EndDialog was called during\nWM_INITDIALOG handling, then msg.message is never set.\nI decided to ignore this fringe case for expository purposes.)\n<\/p>\n<p>\nNow that the dialog is complete, we clean up.\n<a HREF=\"http:\/\/weblogs.asp.net\/oldnewthing\/archive\/2004\/02\/27\/81155.aspx\">\nRemember to enable the owner before destroying the\nowned dialog<\/a>.\n<\/p>\n<pre>\nif (fWasEnabled)\n EnableWindow(hwndParent, TRUE);\nDestroyWindow(hdlg);\n<\/pre>\n<p>\nAnd that&#8217;s all. Return the result.\n<\/p>\n<pre>\n return &lt;value passed to EndDialog&gt;;\n}\n<\/pre>\n<p>\nCongratulations, you are now an expert on dialog boxes.\nTomorrow we&#8217;ll look at how you can put this new expertise\nto good use.\n<\/p>\n<p>\nExercise: Find a way to sneak through the two layers of\n<code>hwndParent<\/code> parameter &#8220;repair&#8221; and end up with\na dialog box whose owner is the desktop window.\nExplain the dire consequences of this scenario.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The dialog loop is actually quite simple. At its core, it&#8217;s just while (&lt;dialog still active&gt; &amp;&amp; GetMessage(&amp;msg, NULL, 0, 0, 0)) { if (!IsDialogMessage(hdlg, &amp;msg)) { TranslateMessage(&amp;msg); DispatchMessage(&amp;msg); } } If you want something fancier in your dialog loop, you can take the loop above and tinker with it. But let&#8217;s start from the [&hellip;]<\/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-35993","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The dialog loop is actually quite simple. At its core, it&#8217;s just while (&lt;dialog still active&gt; &amp;&amp; GetMessage(&amp;msg, NULL, 0, 0, 0)) { if (!IsDialogMessage(hdlg, &amp;msg)) { TranslateMessage(&amp;msg); DispatchMessage(&amp;msg); } } If you want something fancier in your dialog loop, you can take the loop above and tinker with it. But let&#8217;s start from the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/35993","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=35993"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/35993\/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=35993"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=35993"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=35993"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}