{"id":10593,"date":"2011-05-23T07:00:00","date_gmt":"2011-05-23T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/05\/23\/if-its-possible-to-do-something-then-its-possible-to-do-something-wrong\/"},"modified":"2011-05-23T07:00:00","modified_gmt":"2011-05-23T07:00:00","slug":"if-its-possible-to-do-something-then-its-possible-to-do-something-wrong","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110523-00\/?p=10593","title":{"rendered":"If it&#039;s possible to do something, then it&#039;s possible to do something WRONG"},"content":{"rendered":"<p>\nOnce you make it possible to do something,\nyou have to accept that you also made it possible to do something <i>wrong<\/i>.\n<\/p>\n<p>\nWhen the window manager was originally designed,\nit made it possible for programs to override many standard behaviors.\nThey could handle the <code>WM_NC&shy;HIT&shy;TEST<\/code> message\n<a HREF=\"http:\/\/support.microsoft.com\/kb\/320687\">\nso a window can be dragged by grabbing any part of the window,\nnot just the caption bar<\/a>.\nThey could handle the <code>WM_NC&shy;PAINT<\/code> message\nto draw custom title bars.\nThe theory was that making all of these things possible\npermitted smart people to do clever things.\n<\/p>\n<p>\nThe downside is that it also permits stupid people to do dumb things.\n<\/p>\n<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/01\/24\/7213752.aspx#7225416\">\nChanging the window procedure model from\n<i>call <code>Def&shy;Window&shy;Proc<\/code> to get default behavior<\/i>\nto\n<i>return whether you handled the message<\/i><\/a>\nwouldn&#8217;t have helped.\nFirst of all, the handled\/not-handled model is too restrictive:\nIt requires you to do <i>everything<\/i> (handled)\nor <i>nothing<\/i> (not handled).\nThere is no option to do <i>a little bit<\/i>.\n(Imagine if C++ didn&#8217;t let you call the base class implementation\nof an overridden method.)\n<\/p>\n<p>\nDoing <i>a little bit<\/i> is a very common pattern.\nThe <code>WM_NC&shy;HITTEST<\/code> technique mentioned above,\nfor example, uses the default hit-testing implementation,\nand then tweaks the result slightly:\n<\/p>\n<pre>\ncase WM_NCHITTEST:\n \/\/ call base class first\n lres = DefWindowProc(hwnd, uMsg, wParam, lParam);\n \/\/ tweak the result\n if (lres == HTCLIENT) lres = HTCAPTION;\n return lres;\n<\/pre>\n<p>\nHow would you do this with the handled\/not-handled model?\n<\/p>\n<pre>\ncase WM_NCHITTEST:\n if (not handling this message would have resulted in HTCLIENT) {\n  lres = HTCAPTION;\n  handled = TRUE;\n } else {\n  handled = FALSE;\n }\n break;\n<\/pre>\n<p>\nThe trick about that bit in parentheses is that it requires\nthe research department to finish the final details on that\ntime machine they&#8217;ve been working on.\nIt&#8217;s basically saying, &#8220;Return <i>not handled<\/i>,\nthen follow the message until handling is complete\nand if the final result is <code>HTCLIENT<\/code>,\nthen fire up the time machine and rewind to this point\nso I can change my mind and return <i>handled<\/i> instead.&#8221;\n<\/p>\n<p>\nAnd even if the research department comes through with that\ntime machine,\nthe handled\/not-handled model doesn&#8217;t even solve the original problem!\n<\/p>\n<p>\nThe original problem was people failing to call\n<code>Def&shy;Window&shy;Proc<\/code>\nwhen they decided that they didn&#8217;t want to handle a message.\nIn the handled\/not-handled model, the equivalent problem would be\npeople returning <code>handled = TRUE<\/code> unconditionally.\n<\/p>\n<pre>\nBOOL NewStyleWindowProc(HWND hwnd, UINT uMsg,\n WPARAM wParam, LPARAM lParam, LRESULT&amp; lres)\n{\n BOOL handled = TRUE;\n switch (uMsg) {\n case WM_THIS: ...; break;\n case WM_THAT: ...; break;\n \/\/ no \"default: handled = FALSE; break;\"\n }\n return handled;\n}\n<\/pre>\n<p>\n(Side note: The dialog manager uses the handled\/not-handled model,\nand\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/11\/07\/55619.aspx#55623\">\nsome people would prefer that it use the\n<code>Def&shy;Xxx&shy;Proc<\/code> model<\/a>,\nso you might say &#8220;We tried that, and some people didn&#8217;t like it.&#8221;)\n<\/p>\n<p>\nThis topic raises another one of those &#8220;No matter what you do,\nsomebody will call you an idiot&#8221; dilemmas.\nOn the one side, there&#8217;s the\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/01\/24\/7213752.aspx#7230191\">\n<i>Windows should perform extra testing at runtime to\ndetect bad applications<\/i><\/a> school,\nand on the other side, there&#8217;s the\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2007\/07\/17\/3903614.aspx#3918131\">\n<i>Windows should get rid of all the code whose sole purpose\nin life is to detect bad applications<\/i><\/a> school.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Once you make it possible to do something, you have to accept that you also made it possible to do something wrong. When the window manager was originally designed, it made it possible for programs to override many standard behaviors. They could handle the WM_NC&shy;HIT&shy;TEST message so a window can be dragged by grabbing any [&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":[26],"class_list":["post-10593","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>Once you make it possible to do something, you have to accept that you also made it possible to do something wrong. When the window manager was originally designed, it made it possible for programs to override many standard behaviors. They could handle the WM_NC&shy;HIT&shy;TEST message so a window can be dragged by grabbing any [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/10593","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=10593"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/10593\/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=10593"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=10593"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=10593"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}