{"id":36393,"date":"2005-02-22T07:00:00","date_gmt":"2005-02-22T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/02\/22\/modality-part-3-the-wm_quit-message\/"},"modified":"2005-02-22T07:00:00","modified_gmt":"2005-02-22T07:00:00","slug":"modality-part-3-the-wm_quit-message","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050222-00\/?p=36393","title":{"rendered":"Modality, part 3: The WM_QUIT message"},"content":{"rendered":"<p>\nAfter\n<a href=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/02\/18\/376080.aspx\">\nour two quick introductions<\/a>\n<a href=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/02\/21\/377337.aspx\">\nto modality<\/a>,\nwe&#8217;re now going to dig in a little deeper.\n<\/p>\n<p>\nThe trick with modality is that when you call a modal function,\nthe responsibility of message dispatch is handled by that function\nrather than by your main program.  Consequently, if you have\ncustomized your main program&#8217;s message pump, those customizations\nare lost once you lose control to a modal loop.\n<\/p>\n<p>\nThe other important thing about modality is that a\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/Windowing\/Windows\/WindowReference\/WindowMessages\/WM_QUIT.asp\">\n<code>WM_QUIT<\/code> message<\/a> always breaks the modal loop.\nRemember this in your own modal loops!  If ever\nyou call\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/Windowing\/MessagesandMessageQueues\/MessagesandMessageQueuesReference\/MessagesandMessageQueuesFunctions\/PeekMessage.asp\">\nthe <code>PeekMessage<\/code> function<\/a>\nor\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/Windowing\/MessagesandMessageQueues\/MessagesandMessageQueuesReference\/MessagesandMessageQueuesFunctions\/GetMessage.asp\">\nThe [typo fixed 10:30am] <code>GetMessage<\/code> function<\/a> and get\na <code>WM_QUIT<\/code>\nmessage, you must not only exit your modal loop, but\nyou must also re-generate the <code>WM_QUIT<\/code> message\n(via\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/WinUI\/WindowsUserInterface\/Windowing\/MessagesandMessageQueues\/MessagesandMessageQueuesReference\/MessagesandMessageQueuesFunctions\/PostQuitMessage.asp\">\nthe <code>PostQuitMessage<\/code> message<\/a>)\nso the next outer layer will see the <code>WM_QUIT<\/code> message\nand do its cleanup as well.  If you fail to propagate\nthe message, the next outer layer will not know that it\nneeds to quit, and the program will seem to &#8220;get stuck&#8221;\nin its shutdown code, forcing the user to\nterminate the process the hard way.\n<\/p>\n<p>\nIn a later series, we&#8217;ll see how this convention surrounding\nthe <code>WM_QUIT<\/code> message is useful.\nBut for now, here&#8217;s\nthe basic idea of how your modal loops should re-post\nthe quit message to the next outer layer.\n<\/p>\n<pre>\nBOOL WaitForSomething(void)\n{\n  MSG msg;\n  BOOL fResult = TRUE; \/\/ assume it worked\n  while (!SomethingFinished()) {\n    if (GetMessage(&amp;msg, NULL, 0, 0)) {\n      TranslateMessage(&amp;msg);\n      DispatchMessage(&amp;msg);\n    } else {\n      \/\/ We received a WM_QUIT message; bail out!\n      CancelSomething();\n      \/\/ Re-post the message that we retrieved\n      PostQuitMessage(msg.wParam);\n      fResult = FALSE; \/\/ quit before something finished\n      break;\n    }\n  }\n  return fResult;\n}\n<\/pre>\n<p>\nSuppose your program starts some operation and then calls\n<code>WaitForSomething()<\/code>.\nWhile waiting for something to finish, some other part of your\nprogram decides that it&#8217;s time to exit.\n(Perhaps the user clicked on a &#8220;Quit&#8221; button.)\nThat other part of the program will call\n<code>PostQuitMessage(wParam)<\/code>\nto indicate that the message loop should terminate.\n<\/p>\n<p>\nThe posted quit message will first be retrieved by the\n<code>GetMessage<\/code> in the <code>WaitForSomething<\/code> function.\nThe <code>GetMessage<\/code> function returns <code>FALSE<\/code> if\nthe retrieved message is a <code>WM_QUIT<\/code> message.\nIn that case, the &#8220;else&#8221; branch of the conditional is taken, which\ncancels the &#8220;Something&#8221; operation in progress, then posts\nthe quit message back into the message queue for the next\nouter message loop to handle.\n<\/p>\n<p>\nWhen <code>WaitForSomething<\/code> returns, control presumably will fall\nback out into the program&#8217;s main message pump.  The main message\npump will then retrieve the <code>WM_QUIT<\/code> message and do its\nexit processing before finally exiting the program.\n<\/p>\n<p>\nAnd if there were additional layers of modality between\n<code>WaitForSomething<\/code> and the program&#8217;s main message pump,\neach of those layers would retrieve the <code>WM_QUIT<\/code> message,\ndo their cleanup, and then re-post the <code>WM_QUIT<\/code> message\n(again, via <code>PostQuitMessage<\/code>) before exiting the loop.\n<\/p>\n<p>\nIn this manner, the <code>WM_QUIT<\/code> message gets handed from modal\nloop to modal loop, until it reaches the outermost loop, which\nterminates the program.\n<\/p>\n<p>\n&#8220;But wait,&#8221; I hear you say.  &#8220;Why do I have to do all this\nfancy <code>WM_QUIT<\/code> footwork?  I could just have a private little\nglobal variable named something like <code>g_fQuitting<\/code>.  When\nI want the program to quit, I just set this variable, and all\nof my modal loops check this variable and exit prematurely if it\nis set.  Something like this:\n<\/p>\n<pre>\n<i>BOOL MyWaitForSomething(void) \/\/ code in italics is wrong\n{\n  MSG msg;\n  while (!SomethingFinished()) {\n    if (g_fQuitting) {\n    CancelSomething();\n      return FALSE;\n    }\n    if (GetMessage(&amp;msg, NULL, 0, 0)) {\n      TranslateMessage(&amp;msg);\n      DispatchMessage(&amp;msg);\n    }\n  }\n  return TRUE;\n}<\/i>\n<\/pre>\n<p>\nAnd so I can solve the problem of the nested quit without needing\nto do all this <code>PostQuitMessage<\/code> rigamarole.&#8221;\n<\/p>\n<p>\nAnd you&#8217;d be right, if you controlled every single modal loop in\nyour program.\n<\/p>\n<p>\nBut you don&#8217;t.\n<\/p>\n<p>\nFor example, when you call\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/winui\/windowsuserinterface\/windowing\/dialogboxes\/dialogboxreference\/dialogboxfunctions\/dialogbox.asp\">\nthe <code>DialogBox<\/code> function<\/a>,\nthe dialog box code\nruns its own private modal loop to do the dialog box UI until\nyou get around to calling\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/winui\/windowsuserinterface\/windowing\/dialogboxes\/dialogboxreference\/dialogboxfunctions\/enddialog.asp\">\nthe <code>EndDialog<\/code> function<\/a>.  And whenever the user\nclicks on any of your menus, Windows runs its own private\nmodal loop to do the menu UI.  Indeed, even the resizing of\nyour application&#8217;s window is handled by a Windows modal loop.\n<\/p>\n<p>\nWindows, of course, has no knowledge of your little\n<code>g_fQuitting<\/code> variable, so it has no idea that you want\nto quit.  It is the <code>WM_QUIT<\/code> message that serves this\npurpose of co-ordinating the intention to quit among separate\nparts of the system.\n<\/p>\n<p>\nNotice that this convention regarding the <code>WM_QUIT<\/code>\nmessage cuts both ways.  You can use this convention to cause\nmodal loops to exit (we&#8217;ll see more of this later), but it also\nobliges you to respect this convention so that\n<strong>other<\/strong> components (including the window manager itself)\ncan get your modal loops to exit.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After our two quick introductions to modality, we&#8217;re now going to dig in a little deeper. The trick with modality is that when you call a modal function, the responsibility of message dispatch is handled by that function rather than by your main program. Consequently, if you have customized your main program&#8217;s message pump, those [&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,143],"class_list":["post-36393","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code","tag-modality"],"acf":[],"blog_post_summary":"<p>After our two quick introductions to modality, we&#8217;re now going to dig in a little deeper. The trick with modality is that when you call a modal function, the responsibility of message dispatch is handled by that function rather than by your main program. Consequently, if you have customized your main program&#8217;s message pump, those [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36393","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=36393"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36393\/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=36393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=36393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=36393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}