{"id":7313,"date":"2012-06-21T07:00:00","date_gmt":"2012-06-21T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/06\/21\/when-the-default-pushbutton-is-invoked-the-invoke-goes-to-the-top-level-dialog\/"},"modified":"2012-06-21T07:00:00","modified_gmt":"2012-06-21T07:00:00","slug":"when-the-default-pushbutton-is-invoked-the-invoke-goes-to-the-top-level-dialog","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20120621-00\/?p=7313","title":{"rendered":"When the default pushbutton is invoked, the invoke goes to the top-level dialog"},"content":{"rendered":"<p>\nOne quirk of nested dialogs lies in what happens when the user\npresses Enter to invoke the default pushbutton:\nThe resulting\n<code>WM_COMMAND<\/code> message\n<i>goes to the top-level dialog<\/i>,\neven if the default pushbutton belongs to a sub-dialog.\n<\/p>\n<p>\nWhy doesn&#8217;t it send the <code>WM_COMMAND<\/code> to the parent\nof the default pushbutton?\nI mean, the dialog manager knows the handle of the button,\nso it can send the message to the button&#8217;s parent, right?\n<\/p>\n<p>\nWell, the dialog manager knows the handle of <i>a<\/i> button.\nBut not necessarily <i>the<\/i> button.\nRecall that if focus is not on a pushbutton,\nthen the dialog manager sets the default pushbutton\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2012\/06\/19\/10321772.aspx\">\nbased on the control ID returned\nby the <code>DM_GET&shy;DEF&shy;ID<\/code> message<\/a>,\nand it does this by just searching the dialog for a control with that ID.\nIf you have two controls with the same ID, it picks one of them\narbitrarily.\nSo far so bad.\n<\/p>\n<p>\nIt&#8217;s like having two John Smiths living in your house,\none in the second bedroom and one living in the guest\nroom.\nThe post office is very strict and won&#8217;t let you\nwrite\n&#8220;John Smith, Second Bedroom, 1 Main Street&#8221;\nand\n&#8220;John Smith, Guest Room, 1 Main Street.&#8221;\nAll you&#8217;re allowed to write is a name and an address.\nTherefore, all the mail addressed to\n&#8220;John Smith, 1 Main Street&#8221; ends up in a single mailbox\nlabeled\n&#8220;1 Main Street&#8221; and now you have to figure out who gets each\npiece of mail.\n<\/p>\n<p>\nOkay, so we saw that when converting an ID to a window,\nand there are multiple windows with the same ID,\nthe dialog manager will just pick one  arbitrarily.\nAnd if it picks the wrong one,\nit would have sent the <code>WM_COMMAND<\/code> to the wrong\ndialog procedure entirely!\nAt least by sending it to the top-level dialog, it says,\n&#8220;Dude, I think it&#8217;s this window but I&#8217;m not sure, so if you have\nsome really clever way of telling which is which, you can try to sort it out.&#8221;\nAnd now that the <code>WM_COMMAND<\/code> <i>sometimes<\/i>\ngoes to the top-level dialog,\nyou&#8217;re pretty much stuck having it <i>always<\/i> go to the top-level\ndialog for consistency.\nIt&#8217;s better to be consistently wrong in a predictable manner\n(so people can work around it reliably)\nthan to be mostly-right and occasionally-completely-wrong.\n<\/p>\n<p>\nThird rationale:\nBecause you&#8217;re asking for code to be written to handle a case\nthat people shouldn&#8217;t have gotten into in the first place.\n(Namely, duplicate control IDs.)\n<\/p>\n<p>\nWhatever the reason, it&#8217;s something you need to be on the lookout for.\nIf you did everything right and avoided control ID duplication,\nthen the workaround in your\n<code>WM_COMMAND<\/code> handler is straightforward:\n<\/p>\n<pre>\nvoid OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)\n{\n    if (hwndCtl != nullptr)\n    {\n        HWND hwndCtlParent = GetParent(hwndCtl);\n        if (hwndCtlParent != nullptr &amp;&amp;\n            hwndCtlParent != hwnd &amp;&amp;\n            IsChild(hwnd, hwndCtlParent))\n        {\n           FORWARD_WM_COMMAND(hwndCtlParent, id,\n                              hwndCtl, codeNotify, SendMessage);\n           return;\n        }\n    }\n    ... the message was for me after all, so let's handle it...\n    switch (id)\n    {\n    ...\n    }\n}\n<\/pre>\n<p>\nWhen we get the <code>WM_COMMAND<\/code> message,\nwe first check that it really came from one of our direct\nchildren.\nIf not, then we forward the message on to the control&#8217;s\nactual parent.\n(The window that should have gotten the message in the first place\nin an ideal world.)\n<\/p>\n<p>\n<b>Exercise<\/b>:\nUnder what circumstances can the above workaround fail?\n(Not counting the scenario we&#8217;ve spent the past three days discussing.)\n<\/p>\n<p>\nAnyway, back to the question from last time:\nHow does the property sheet manager deal with multiple property sheets\npages having conflicting control IDs?\nIn addition to what we previously discussed,\nanother mitigating factor is that the property sheet manager\nkeeps only one child dialog visible at a time.\nThis takes the hidden child dialogs out of the running for most\ndialog-related activities, such as dialog navigation,\nsince invisible controls cannot be targets of dialog navigation.\nFurthermore, hidden child dialogs are skipped when searching\nfor keyboard accelerators,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2008\/06\/02\/8568490.aspx\">\nthereby avoiding the problem of hidden accelerators<\/a>.\nSo as long as the property sheet manager makes sure that focus\ndoesn&#8217;t stay on a hidden control after a page change,\nthere shouldn&#8217;t be any notifications coming from a hidden child dialog.\nThe only conflicts it needs to worry about are conflicts\nbetween the page and the frame.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One quirk of nested dialogs lies in what happens when the user presses Enter to invoke the default pushbutton: The resulting WM_COMMAND message goes to the top-level dialog, even if the default pushbutton belongs to a sub-dialog. Why doesn&#8217;t it send the WM_COMMAND to the parent of the default pushbutton? I mean, the dialog manager [&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-7313","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>One quirk of nested dialogs lies in what happens when the user presses Enter to invoke the default pushbutton: The resulting WM_COMMAND message goes to the top-level dialog, even if the default pushbutton belongs to a sub-dialog. Why doesn&#8217;t it send the WM_COMMAND to the parent of the default pushbutton? I mean, the dialog manager [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/7313","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=7313"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/7313\/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=7313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=7313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=7313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}