{"id":6613,"date":"2012-09-13T07:00:00","date_gmt":"2012-09-13T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/09\/13\/wm_ctlcolor-vs-getfileversioninfosize-just-because-somebody-else-screwed-up-doesnt-mean-youre-allowed-to-screw-up-too\/"},"modified":"2012-09-13T07:00:00","modified_gmt":"2012-09-13T07:00:00","slug":"wm_ctlcolor-vs-getfileversioninfosize-just-because-somebody-else-screwed-up-doesnt-mean-youre-allowed-to-screw-up-too","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20120913-00\/?p=6613","title":{"rendered":"WM_CTLCOLOR vs GetFileVersionInfoSize: Just because somebody else screwed up doesn&#039;t mean you&#039;re allowed to screw up too"},"content":{"rendered":"<p>\nIn a discussion of\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2007\/07\/31\/4138786.aspx\">\nthe now-vestigial <code>lpdwHandle<\/code> parameter\nto the <code>Get&shy;File&shy;Version&shy;Info&shy;Size<\/code> function<\/a>,\nNeil asks,\n&#8220;<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2007\/07\/31\/4138786.aspx#4153782\">Weren&#8217;t there sufficient API differences\n(e.g. WM_CTLCOLOR) between Win16 and Win32 to justify\nchanging the definitions to eliminate the superfluous handle?<\/a>&#8221;\n<\/p>\n<p>\nThe goal of Win32 was to provide as much backward compatibility with\nexisting 16-bit source code as can be practically achieved.\nNot all of the changes were successful in achieving this goal,\nbut just because one person fails to meet that goal doesn&#8217;t mean\nthat everybody else should abandon the goal, too.\n<\/p>\n<p>\nThe Win32 porting tool PORTTOOL.EXE scanned for things\nwhich had changed and inserted comments saying things like\n<\/p>\n<ul>\n<li>&#8220;No Win32 API equivalent&#8221; &#8212; these were for the 25 functions\n    which were very tightly coupled to the 16-bit environment,\n    like selector management functions.<\/p>\n<li>&#8220;Replaced by OtherFunction&#8221; &#8212; these were used for the 38\n    functions which no longer existed in Win32, but for which\n    corresponding function did exist, but the parameters were\n    different so a simple search-and-replace was not sufficient.<\/p>\n<li>&#8220;Replaced by XYZ system&#8221; &#8212; these were for functions that\n    used an interface that was completely redesigned:\n    the 16 old sound functions that buzzed your tinny PC speaker\n    being replaced by the new multimedia system,\n    and the 8 profiling functions.<\/p>\n<li>&#8220;This function is now obsolete&#8221; &#8212; these were for the 16 functions\n    that no longer had any effect, like\n    <code>Global&shy;LRU&shy;Newest<\/code> and\n    <code>Limit&shy;EMS&shy;Pages<\/code>.<\/p>\n<li>&#8220;wParam\/lParam repacking&#8221; &#8212; these were for the 21 messages that\n    packed their parameters differently.<\/p>\n<li>Special remarks for eight functions whose parameters changed\n    meaning and therefore required special attention.<\/p>\n<li>A special comment just for window procedures.\n<\/ul>\n<p>\nIf you add it up, you&#8217;ll see that this makes for a total of 117\nbreaking changes.\nAnd a lot of these changes were in rarely-used parts of Windows\nlike the selector-management stuff, the PC speaker stuff,\nthe profiling stuff, and the serial port functions.\nThe number of breaking changes that affected typical\ndevelopers was more like a few dozen.\n<\/p>\n<p>\nNot bad for a total rewrite of an operating system.\n<\/p>\n<p>\nIf somebody said,\n&#8220;Hey, you should port to this new operating system.\nHere&#8217;s a list of 117 things you need to change,&#8221;\nyou&#8217;re far more likely to respond,\n&#8220;Okay, I guess I can do that,&#8221;\nthan if somebody said,\n&#8220;Here&#8217;s a list of 3,000 things you need to change.&#8221;\nEspecially if some of the changes were\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/12\/07\/10244820.aspx#10245410\">\nnot absolutely necessary, but were added merely to annoy you<\/a>.\n(I would argue that the handling of many GDI functions\nlike <code>Move&shy;To<\/code>\nfell into the <i>added merely to annoy you<\/i> category,\nbut at least\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2009\/07\/20\/9840597.aspx\">\na simple macro<\/a>\nsmooths over most of the problems.)\n<\/p>\n<p>\nOne of the messages that required special treatment was\n<code>WM_COMMAND<\/code>.\nIn 16-bit Windows, the parameters were as follows:\n<\/p>\n<table BORDER=\"1\" CELLPADDING=\"3\" STYLE=\"border: solid black .75pt;border-collapse: collapse\">\n<tr>\n<td><code>WPARAM<\/code><\/td>\n<td><code>int nCode<\/code><\/td>\n<\/tr>\n<tr>\n<td ROWSPAN=\"2\"><code>LPARAM<\/code><\/td>\n<td><code>HWND hwndCtl<\/code> (low word)<\/td>\n<\/tr>\n<tr>\n<td><code>int id<\/code> (high word)<\/td>\n<\/tr>\n<\/table>\n<p>\nObserve that this message violated the rule that\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/11\/25\/55850.aspx\">\nhandle-sized things go in the <code>WPARAM<\/code><\/a>.\nAs a result, this parameter packing method could not be maintained\nin Win32.\nIf it had been packed as\n<\/p>\n<table BORDER=\"1\" CELLPADDING=\"3\" STYLE=\"border: solid black .75pt;border-collapse: collapse\">\n<tr>\n<td><code>WPARAM<\/code><\/td>\n<td><code>HWND hwndCtl<\/code><\/td>\n<\/tr>\n<tr>\n<td ROWSPAN=\"2\"><code>LPARAM<\/code><\/td>\n<td><code>int id<\/code> (low word)<\/td>\n<\/tr>\n<tr>\n<td><code>int nCode<\/code> (high word)<\/td>\n<\/tr>\n<\/table>\n<p>\nthen the message would have ported cleanly to Win32.\nBut Win32 handles are 32-bit values,\nso there&#8217;s no room for both an <code>HWND<\/code>\nand an integer in a 32-bit <code>LPARAM<\/code>;\nas a result, the message had to be repacked in Win32.\n<\/p>\n<p>\nThe <code>WM_CTL&shy;COLOR<\/code> message was an extra special\ncase of a message that required changes,\nbecause it was the only one\nthat changed in a way that required more than just mechanical\ntwiddling of the way the parameters were packaged.\nInstead,\nit got split out into several messages, one for each type of\ncontrol.\n<\/p>\n<p>\nIn 16-bit Windows, the\nparameters to the <code>WM_CTL&shy;COLOR<\/code> message were\nas follows:\n<\/p>\n<table BORDER=\"1\" CELLPADDING=\"3\" STYLE=\"border: solid black .75pt;border-collapse: collapse\">\n<tr>\n<td><code>WPARAM<\/code><\/td>\n<td><code>HDC hdc<\/code><\/td>\n<\/tr>\n<tr>\n<td ROWSPAN=\"2\"><code>LPARAM<\/code><\/td>\n<td><code>HWND hwndCtl<\/code> (low word)<\/td>\n<\/tr>\n<tr>\n<td><code>int type<\/code> (high word)<\/td>\n<\/tr>\n<\/table>\n<p>\nThe problem with this message was that it had <i>two<\/i> handle-sized\nvalues.\nOne of them went into the <code>WPARAM<\/code>,\nlike all good handle-sized parameters,\nbut the second one was forced to share a bunk bed with the type code\nin the <code>LPARAM<\/code>.\nThis arrangement didn&#8217;t survive in Win32 because handles expanded\nto 32-bit values,\nbut unlike\n<code>WM_COMMAND<\/code>,\nthere was nowhere to put the now-ousted <code>type<\/code>,\nsince both the <code>WPARAM<\/code> and <code>LPARAM<\/code> were full\nwith the two handles.\nSolution:\nEncode the type code in the message number.\nThe <code>WM_CTL&shy;COLOR<\/code> message became a collection\nof messages, all related by the formula\n<\/p>\n<pre>\nWM_CTLCOLOR<u>type<\/u> = WM_CTLCOLORMSGBOX + CTLCOLOR_<u>type<\/u>\n<\/pre>\n<p>\nThe <code>WM_CTL&shy;COLOR<\/code> message was the bad boy\nin the compatibility contest,\nfalling pretty badly on its face.\n(How many metaphors can I mix in one article?)\n<\/p>\n<p>\nBut just because there&#8217;s somebody who screwed up doesn&#8217;t mean\nthat you&#8217;re allowed to screw up too.\nIf there was a parameter that didn&#8217;t do anything any more,\njust declare it a reserved parameter. That way, you didn&#8217;t have to go\nonto the &#8220;wall of shame&#8221; of functions that didn&#8217;t port cleanly.\nThe\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2007\/07\/31\/4138786.aspx\">\n<code>Get&shy;File&shy;Version&shy;Info&shy;Size<\/code> function<\/a>\nkept its vestigial <code>lpdwHandle<\/code> parameter,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/06\/15\/156022.aspx\">\n<code>Win&shy;Main<\/code> kept its vestigial <code>hPrev&shy;Instance<\/code>\nparameter<\/a>,\nand\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/larryosterman\/archive\/2007\/02\/08\/why-was-the-ability-to-specify-an-allocator-during-coinitialize-removed-from-the-system.aspx\">\n<code>Co&shy;Initialize<\/code> kept its vestigial <code>lpReserved<\/code>\nparameter<\/a>.\n<\/p>\n<p>\nThis also explains why significant effort was made in the\n32-bit to 64-bit transition not to make breaking changes\njust because you can.\nAs much as practical, porting issues were designed in such a way\nthat they could be detected at compile time.\nIntroducing gratuitous changes in behavior makes the porting\nprocess harder than it needs to be.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In a discussion of the now-vestigial lpdwHandle parameter to the Get&shy;File&shy;Version&shy;Info&shy;Size function, Neil asks, &#8220;Weren&#8217;t there sufficient API differences (e.g. WM_CTLCOLOR) between Win16 and Win32 to justify changing the definitions to eliminate the superfluous handle?&#8221; The goal of Win32 was to provide as much backward compatibility with existing 16-bit source code as can be practically [&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":[2],"class_list":["post-6613","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>In a discussion of the now-vestigial lpdwHandle parameter to the Get&shy;File&shy;Version&shy;Info&shy;Size function, Neil asks, &#8220;Weren&#8217;t there sufficient API differences (e.g. WM_CTLCOLOR) between Win16 and Win32 to justify changing the definitions to eliminate the superfluous handle?&#8221; The goal of Win32 was to provide as much backward compatibility with existing 16-bit source code as can be practically [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6613","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=6613"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6613\/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=6613"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=6613"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=6613"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}