{"id":26243,"date":"2007-06-27T10:00:00","date_gmt":"2007-06-27T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/06\/27\/those-who-do-not-understand-the-dialog-manager-are-doomed-to-reimplement-it-badly\/"},"modified":"2007-06-27T10:00:00","modified_gmt":"2007-06-27T10:00:00","slug":"those-who-do-not-understand-the-dialog-manager-are-doomed-to-reimplement-it-badly","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20070627-00\/?p=26243","title":{"rendered":"Those who do not understand the dialog manager are doomed to reimplement it, badly"},"content":{"rendered":"<p>\nA customer wanted to alter the behavior of a multi-line edit control\nso that it did not treat a press of the Tab key as a request to insert\na tab character but rather treated it as a normal dialog navigation key.\nThe approach the customer took was to subclass the edit control\nand intercept the Tab key:\n<\/p>\n<pre>\nLRESULT CALLBACK SubclassWndProc(\n    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n  switch (uMsg) {\n  case WM_KEYDOWN:\n    if (wParam == VK_TAB) {\n      \/\/ Pressed the TAB key - tab to next control\n      SetFocus(GetNextDlgTabItem(\n                     GetParent(hwnd), hwnd, FALSE));\n      return 0; \/\/ message handled\n    }\n  }\n  return CallWindowProc(...);\n}\n<\/pre>\n<p>\nThere are many things wrong with this approach.\nYou can spend quite a lot of time nitpicking the little\ndetails,\nhow this code\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/08\/02\/205624.aspx\">\nfails to set focus in a dialog box properly<\/a>,\nhow it fails to take nested dialogs into account,\nhow it fails to handle the Shift+Tab navigation key,\nhow it blatantly assumes that the control is part of a dialog\nbox in the first place!\nBut all of these little details are missing the big picture:\nInstead of fighting against the dialog manager and\nreimplementing all the parts we want to keep and ignoring the\nparts we want to skip, we should be working <i>with<\/i> the\ndialog manager and expressing our intentions in the manner\nthe dialog manager expects.\n<\/p>\n<p>\nIt&#8217;s the difference between ordering a hamburger without pickles\nand ordering a hamburger with pickles, and then carefully picking\nthe pickles off the burger when you get it.\n<\/p>\n<p>\nIn this case, we want to prevent the edit control from saying\n&#8220;Give me the Tab key.&#8221;\n<!-- backref: dlgc -->\nWe saw last time<\/a> that this is done either by\n(1)&nbsp;setting the <code>DLGC_WANTTAB<\/code> dialog code\nor by (2)&nbsp;responding\nwith <code>DLGC_WANTMESSAGE<\/code> when given a Tab key message.\nTherefore, to tell the dialog manager to not to treat the tab key\nspecially, just turn off those two behaviors.\n<\/p>\n<pre>\nLRESULT CALLBACK SubclassWndProc(\n    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n  LRESULT lres;\n  switch (uMsg) {\n  case WM_GETDLGCODE:\n    lres = CallWindowProc(...);\n    lres &amp;= ~DLGC_WANTTAB;\n    if (lParam &amp;&amp;\n        ((MSG *)lParam)-&gt;message == WM_KEYDOWN &amp;&amp;\n        ((MSG *)lParam)-&gt;wParam == VK_TAB) {\n      lres &amp;= ~DLGC_WANTMESSAGE;\n    }\n    return lres;\n  }\n  return CallWindowProc(...);\n}\n<\/pre>\n<p>\nAfter asking the original control what behavior it thinks it wants,\nwe turn off the <code>DLGC_WANTTAB<\/code> flag; this takes care of\npart&nbsp;(1).\nNext, we check whether the message is a press of the Tab key.\nIf so, then we turn the <code>DLGC_WANTMESSAGE<\/code> flag off;\nthis takes care of part&nbsp;(2).\n<\/p>\n<p>\nThis is certainly less code than would need to have been written\nto address all of the little concerns noted earlier,\nand it does it by completely sidestepping the task of trying\nto emulate the dialog manager and instead just cooperating with\nthe dialog manager to get the behavior you want.\nThis principle of &#8220;If you know how a system is meant to work,\nyou can work with it rather than against it, and everybody will be\nhappier for it&#8221;\nis something I&#8217;ve been trying to convey through this web site\nand\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2006\/12\/07\/1233002.aspx\">\nmy book<\/a>.\nKnowing how something was intended to be used allows you to be\na more effective programmer.\n<\/p>\n<p>\n<b>Exercise<\/b>:\nWhy didn&#8217;t we just write this instead?\n<\/p>\n<pre>\nLRESULT CALLBACK SubclassWndProc(\n    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n  LRESULT lres;\n  switch (uMsg) {\n  case WM_GETDLGCODE:\n    lres = CallWindowProc(...);\n    lres &amp;= ~DLGC_WANTTAB;\n    if (<font COLOR=\"blue\">wParam == VK_TAB<\/font>) {\n      lres &amp;= ~DLGC_WANTMESSAGE;\n    }\n    return lres;\n  }\n  return CallWindowProc(...);\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A customer wanted to alter the behavior of a multi-line edit control so that it did not treat a press of the Tab key as a request to insert a tab character but rather treated it as a normal dialog navigation key. The approach the customer took was to subclass the edit control and intercept [&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-26243","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A customer wanted to alter the behavior of a multi-line edit control so that it did not treat a press of the Tab key as a request to insert a tab character but rather treated it as a normal dialog navigation key. The approach the customer took was to subclass the edit control and intercept [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/26243","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=26243"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/26243\/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=26243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=26243"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=26243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}