{"id":6233,"date":"2012-10-29T07:00:00","date_gmt":"2012-10-29T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/10\/29\/in-the-conversion-to-64-bit-windows-why-were-some-parameters-not-upgraded-to-size_t\/"},"modified":"2012-10-29T07:00:00","modified_gmt":"2012-10-29T07:00:00","slug":"in-the-conversion-to-64-bit-windows-why-were-some-parameters-not-upgraded-to-size_t","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20121029-00\/?p=6233","title":{"rendered":"In the conversion to 64-bit Windows, why were some parameters not upgraded to SIZE_T?"},"content":{"rendered":"<p>\nJames wonders\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/07\/20\/10040074.aspx#10042836\">\nwhy many functions kept <code>DWORD<\/code> for parameter\nlengths instead of upgrading to <code>SIZE_T<\/code> or\n<code>DWORD_PTR<\/code><\/a>.\n<\/p>\n<p>\nWhen updating the interfaces for 64-bit Windows,\nthere were a few guiding principles.\nHere are two of them.\n<\/p>\n<ul>\n<li>Don&#8217;t change an interface unless you really need to.\n<li>Do you really need to?\n<\/ul>\n<p>\nChanging an interface causes all sorts of problems when porting.\nFor example, if you change the parameters to a COM interface,\nthen you introduce a breaking change in everybody who implements it.\nConsider this hypothetical interface:\n<\/p>\n<pre>\n\/\/ namedobject.idl\ninterface INamedObject : IUnknown\n{\n    HRESULT GetName([out, string, sizeof(cchBuf)] LPWSTR pszBuf,\n                    [in] DWORD cchBuf);\n};\n<\/pre>\n<p>\nAnd here&#8217;s a hypothetical implementation:\n<\/p>\n<pre>\n\/\/ contoso.cpp\nclass CContosoBasicNamedObject : public INamedObject\n{\n    ...\n    HRESULT GetName(LPWSTR pszBuf, DWORD cchBuf)\n    {\n        return StringCchPrintfW(pszBuf, cchBuf, L\"Contoso\");\n    }\n    ...\n};\n<\/pre>\n<p>\nOkay, now it&#8217;s time to 64-bit-ize this puppy.\nSo you do the natural thing: Grow the\n<code>DWORD<\/code> parameter\nto <code>DWORD_PTR<\/code>.\nSince\n<code>DWORD_PTR<\/code> maps to <code>DWORD<\/code>\non 32-bit systems, this is a backward-compatible change.\n<\/p>\n<pre>\n\/\/ namedobject.idl\ninterface INamedObject : IUnknown\n{\n    HRESULT GetName([out, string, sizeof(cchBuf)] LPWSTR pszBuf,\n                    [in] DWORD<font COLOR=\"red\">_PTR<\/font> cchBuf);\n};\n<\/pre>\n<p>\nThen you recompile the entire operating system and find that\nthe compiler complains,\n&#8220;Cannot instantiate abstract class: CContosoBasicNamedObject.&#8221;\nOh, right, that&#8217;s because the\n<code>INamed&shy;Object::Get&shy;Name<\/code> method\nin the implementation no longer matches the method in the\nbase class,\nso the method in the base class is not overridden.\nFortunately, you have access to the source code for\n<code>contoso.cpp<\/code>, and you can apply the appropriate fix:\n<\/p>\n<pre>\n\/\/ contoso.cpp\nclass CBasicNamedObject : public INamedObject\n{\n    ...\n    HRESULT GetName(LPWSTR pszBuf, DWORD_<font COLOR=\"red\">PTR<\/font> cchBuf)\n    {\n        return StringCchPrintfW(pszBuf, cchBuf, L\"Basic\");\n    }\n    ...\n};\n<\/pre>\n<p>\nYay, everything works again.\nA breaking change led to a compiler error, which led you\nto the fix.\nThe only consequence (so far) is that the number of\n&#8220;things in code being ported from 32-bit Windows to 64-bit Windows\nneeds to watch out for&#8221;\nhas been incremented by one.\nOf course,\ntoo much of this incrementing, and the list of things becomes\nso long that developers are going to throw up their hands and say\n&#8220;Porting is too much work, screw it.&#8221;\nDon&#8217;t forget,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2012\/09\/13\/10348876.aspx\">\nthe number of breaking API changes in the\nconversion from 16-bit to 32-bit Windows was only 117<\/a>.\n<\/p>\n<p>\nYou think you fixed the problem, but you didn&#8217;t.\nBecause there&#8217;s another class elsewhere in the Contoso project.\n<\/p>\n<pre>\nclass CSecureNamedObject : public CBasicNamedObject\n{\n    ...\n    HRESULT GetName(LPWSTR pszBuf, DWORD cchBuf)\n    {\n        if (IsAccessAllowed())\n        {\n            return CBasicNamedObject::GetName(pszBuf, cchBuf);\n        }\n        else\n        {\n            return E_ACCESSDENIED:\n        }\n    }\n}\n<\/pre>\n<p>\nThe compiler did not raise an error on\n<code>CSecure&shy;Named&shy;Object<\/code> because that\nclass is not abstract.\nThe\n<code>INamed&shy;Object::Get&shy;Name<\/code> method\nfrom the <code>INamed&shy;Object<\/code> interface\nis implemented by <code>CBasic&shy;Named&shy;Object<\/code>.\nAll abstract methods have been implemented,\nso no &#8220;instantiating abstract class&#8221; error.\n<\/p>\n<p>\nOn the other hand, the <code>CSecure&shy;Named&shy;Object<\/code>\nmethod <i>wanted<\/i> to override the base method,\nbut since its parameter list didn&#8217;t match,\nit ended up creating a separate method rather than an override.\n(The <code>override<\/code> pseudo-keyword not yet having been standardized.)\nAs a result, when somebody calls the\n<code>INamed&shy;Object::Get&shy;Name<\/code> method\non your\n<code>CSecure&shy;Named&shy;Object<\/code>,\nthey don&#8217;t get the one with the security check,\nbut rather the one from\n<code>CBasic&shy;Named&shy;Object<\/code>.\nResult: Security check bypassed.\n<\/p>\n<p>\nThese are the worst types of breaking changes:\nThe ones where the compiler doesn&#8217;t tell you that something is wrong.\nYour code compiles,\nit even basically runs,\nbut it doesn&#8217;t run <i>correctly<\/i>.\nNow, sure, the example I gave would have been uncovered\nin security testing,\nbut I chose that just for drama.\nGo ahead and substitute something much more subtle.\nLike say,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2006\/10\/24\/868544.aspx\">\ninvalidating the entire desktop when you pass\n<code>NULL<\/code> to\n<code>Invalidate&shy;Rect<\/code><\/a>.\n<\/p>\n<p>\nOkay, so let&#8217;s look back at those principles.\nDo we really need to change this interface?\nThe only case where expanding to\n<code>SIZE_T<\/code> would make a difference is if\nan object had a name longer than 2 billion characters.\nIs that a realistic end-user scenario?\nNot really.\nTherefore, don&#8217;t change it.\n<\/p>\n<p>\nRemember,\nyou want to make it <i>easier<\/i> for people to port\ntheir program to 64-bit Windows, not harder.\nThe goal is <i>make customers happy<\/i>, not\n<i>create the world&#8217;s most architecturally\npure operating system<\/i>.\nAnd customers aren&#8217;t happy when the operating system\ncan&#8217;t run their programs\n(because every time the vendor try to port it, they keep stumbling\nover random subtle behavior changes that break their program).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>James wonders why many functions kept DWORD for parameter lengths instead of upgrading to SIZE_T or DWORD_PTR. When updating the interfaces for 64-bit Windows, there were a few guiding principles. Here are two of them. Don&#8217;t change an interface unless you really need to. Do you really need to? Changing an interface causes all sorts [&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-6233","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>James wonders why many functions kept DWORD for parameter lengths instead of upgrading to SIZE_T or DWORD_PTR. When updating the interfaces for 64-bit Windows, there were a few guiding principles. Here are two of them. Don&#8217;t change an interface unless you really need to. Do you really need to? Changing an interface causes all sorts [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6233","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=6233"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6233\/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=6233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=6233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=6233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}