{"id":760,"date":"2011-09-14T09:57:42","date_gmt":"2011-09-13T21:57:42","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=760"},"modified":"2011-09-14T10:25:36","modified_gmt":"2011-09-13T22:25:36","slug":"platform-independence-version-dependencies-in-the-xe2-rtl","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/760\/","title":{"rendered":"Platform Independence Version Dependencies in the XE2 RTL"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>So I have spent about a week now with XE2 and FireMonkey and thought I would share some of the experience so far.<\/p>\n<p>After an initial peek and poke around, the first order of business for me was to migrate some of my existing code to the new RTL.  First on the list was my own testing framework which I have been using for a few years now.  Something which was on the verge of being ready to expose to the harsh light of day but which I had decided to wait until I had an XE2 (and dare I hope&#8230; a cross platform) version before releasing.<\/p>\n<p>So this will be the first in a number of posts dealing with specific things that I have run across.<\/p>\n<p>First up:  Win32\/Win64 cross-platform.<br \/>\n<!--more--><br \/>\nFirst of all, don&#8217;t be too concerned.  The notion that Win64 &#8220;just works&#8221; in Delphi is still valid &#8211; for the most part.  But there are some edge cases that can catch you out, and what I am about to describe is one of those that you may run into, and emphasises some differences that are also useful to be aware of.<\/p>\n<p>In introducing support for Win64, the RTL now declares some Windows API functions differently (more correctly in fact) which serve both to highlight some important aspects of coding for Win32\/Win64 portability but also create some problems if you are writing code intended for use in versions of Delphi earlier than XE2 as well as for XE2 and later.<\/p>\n<p>For example, consider <strong>GetProcessAffinityMask()<\/strong>.  This used to be declared as follows:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nfunction GetProcessAffinityMask(hProcess: THandle;\r\n  var lpProcessAffinityMask, lpSystemAffinityMask: DWORD): BOOL; stdcall;\r\n<\/pre>\n<p>But is now declared thus:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nfunction GetProcessAffinityMask(hProcess: THandle;\r\n  var lpProcessAffinityMask, lpSystemAffinityMask: DWORD_PTR): BOOL; stdcall;\r\n<\/pre>\n<p>You will notice that the two mask parameters are now declared as <strong>DWORD_PTR<\/strong> rather than plain <strong>DWORD<\/strong>.<\/p>\n<p>This <strong>DWORD_PTR<\/strong> type is potentially confusing &#8211; surely a <strong>var<\/strong> parameter is already (under the hood) a pointer, so this declaration is utterly wrong, isn&#8217;t it?<\/p>\n<p>No, it&#8217;s perfectly correct, just potentially a bit misleading.<\/p>\n<h3>What&#8217;s in a (D)WORD ?<\/h3>\n<p><strong>DWORD_PTR<\/strong> is an unsigned integer with &#8220;pointer precision&#8221;.  Or, put another way: a value declared and treated as an unsigned integer which is big enough to safely store a pointer value.  This means that the absolute size (in storage bytes) of a value of this type is dependent upon the platform for which the code is being compiled.<\/p>\n<p>The <strong>_PTR<\/strong> suffix in this type does not indicate that the value <strong>is<\/strong> a pointer, only that it is big enough to <strong>hold<\/strong> a pointer, should you wish to type-cast and use it for that (it&#8217;s still an integer at the end of the day, so it is not assignment compatible with a pointer, just &#8220;size compatible&#8221;.  You will note that in this case, the value being referenced is <strong>NOT<\/strong> a pointer but a simple bit mask where each bit corresponds to a CPU.<\/p>\n<p>So:<\/p>\n<ul>\n<li>Win32: <strong>DWORD_PTR<\/strong> == 32-bit unsigned integer<\/li>\n<li>Win64: <strong>DWORD_PTR<\/strong> == 64-bit unsigned integer<\/li>\n<\/ul>\n<p>To make things just a bit more confusing, although <strong>DWORD_PTR<\/strong> changes size according to &#8220;platform&#8221;, a <strong>DWORD<\/strong> itself is always 32-bit (in Windows at least &#8211; Win32 or Win64, it doesn&#8217;t matter) and still corresponds to the <strong>Cardinal<\/strong> type.<\/p>\n<p>A 64-bit unsigned integer is, in Windows API terms, a <strong>QWORD<\/strong> and in Delphi terms a <strong>UInt64<\/strong>.<\/p>\n<p>In XE2 <strong>DWORD_PTR<\/strong> is synonymous with the new Delphi type <strong>NativeUInt<\/strong>.<\/p>\n<p>This isn&#8217;t a problem if you are only writing new code using these Windows API routines for XE2 and later, you just need to make sure to use the NativeUInt type in such cases.  But if you are writing code to be portable to older versions of Delphi (Win32 only) and\/or are migrating code from those older versions, then this causes a small problem.<\/p>\n<h3>Lead Us Not Into Temptation&#8230;<\/h3>\n<p>Invoke <strong>Code Completion<\/strong> on the parameter list for <strong>GetProcessAffinityMask()<\/strong> and you will be presented not with the verbatim declaration of the parameter types, but what those parameter types mean at the most basic level.  So for example in <strong>Delphi 2010<\/strong> you will be told that the two mask parameters to this function are of type <strong>Cardinal<\/strong> whilst in <strong>XE2<\/strong> you will be informed that they are <strong>NativeUInt<\/strong>.<\/p>\n<p>So assuming you wrote this code some time ago using Delphi 2010, you most likely took the hint from the <strong>Code Completion<\/strong> and declared some <strong>Cardinal<\/strong> variables to allow you to use this function:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nvar\r\n  processMask, systemMask: Cardinal;\r\nbegin\r\n  GetProcessAffinityMask( GetCurrentProcess(), processMask, systemMask );\r\nend;\r\n<\/pre>\n<p>And you were set.  Everything was right with the world.<\/p>\n<p>Then you get your shiny new XE2 license and find that this code no longer compiles, complaining that &#8230;<\/p>\n<p><strong>[DCC Error] E2033 Types of actual and formal var parameters must be identical<\/strong><\/p>\n<p>So you invoke <strong>Code Completion<\/strong> to see what parameter types XE2 expects and discover the new <strong>NativeUInt<\/strong> parameter type.  Accordingly you change your variable declaration, perhaps with a niggly feeling that this might be going to cause you some problems later&#8230;<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nvar\r\n  processMask, systemMask: NativeUInt;\r\nbegin\r\n  GetProcessAffinityMask( GetCurrentProcess(), processMask, systemMask );\r\nend;\r\n<\/pre>\n<p>And lo and behold, everything is once more right with the world so you commit your change and get on with your day.<\/p>\n<p>Then the phone rings.<\/p>\n<p>It&#8217;s your buddy down the hall still using Delphi 2010 and your commit just broke his compiler because Delphi 2010 knows nothing about this &#8220;NativeUInt&#8221; type of which you spoke in XE2.<\/p>\n<p>What to do ?<\/p>\n<h3>Salvation in Type<\/h3>\n<p>Fortunately this case is easily resolved.  Since your buddy is using Delphi 2010 you can &#8211; armed with this knowledge or perhaps after digging through the source code of the declarations for <strong>GetProcessAffinityMask()<\/strong> and coming to the same realisations and conclusions as I &#8211; simply change your variable declarations to <strong>DWORD_PTR<\/strong>.<\/p>\n<p>Even though the Delphi 2010 declaration for this <strong>GetProcessAffinityMask()<\/strong> uses <strong>DWORD<\/strong>, the RTL does also declare <strong>DWORD_PTR<\/strong>, and in Delphi 2010\/Win32 these are fundamentally one and the same thing: <strong>Cardinal<\/strong>.<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nvar\r\n  processMask, systemMask: DWORD_PTR;\r\nbegin\r\n  GetProcessAffinityMask( GetCurrentProcess(), processMask, systemMask );\r\nend;\r\n<\/pre>\n<p>After this change the Delphi 2010 compiler is happy, so too is Delphi XE2 (and so is your buddy down the hall).  \ud83d\ude42<\/p>\n<h3>The Sting in the Tail<\/h3>\n<p>However, there remains a problem if your code is, or may be, used by someone using an even older version of Delphi.  As of Delphi 2006 (and possibly 2007\/2009 also but I haven&#8217;t checked) the <strong>DWORD_PTR<\/strong> type does <strong>not<\/strong> exist.  So if that is the case then you will need a more sophisticated (read: complex\/messy) approach.<\/p>\n<p>That is in fact the situation in my particular case, and I shall demonstrate how I solved it in a future post since it is part of a broader solution to a number of such issues I am running in to.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> So I have spent about a week now with XE2 and FireMonkey and thought I would share some of the experience so far. After an initial peek and poke around, the first order of business for me was to migrate some of my existing code to the new RTL. First on the list was my [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[94,292,27,139,141],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-cg","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":1974,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1974\/","url_meta":{"origin":760,"position":0},"title":"Improved Quality in Delphi &#8211; Yeah Right","date":"28 Oct 2013","format":false,"excerpt":"Here in Aotearoa there is a beer company called \"Tui\", named in turn for a native bird. As well as a series of TV ads voiced by the great Tom Baker, Tui are famous here for their \"Yeah, right!\" billboard ads. I felt compelled to make one for Delphi. I\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/tui.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":924,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/924\/","url_meta":{"origin":760,"position":1},"title":"CFStringRef and TCFString(s)","date":"05 Jul 2012","format":false,"excerpt":"In the comments on yesterdays initial post in a series following the experiences of porting an Objective-C sample to XE2, a number of people have asked why I didn't use the TCFString record type in System.Mac.CFUtils to get the CFStringRef references that I required. The reason is embarrassingly simple. I\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":791,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/791\/","url_meta":{"origin":760,"position":2},"title":"Why Does My OSX FireMonkey App Think It Is a Console App ?","date":"15 Sep 2011","format":false,"excerpt":"Because System.IsConsole is hardwired to TRUE on MAC OS: This is actually also the case for $ifdef LINUX, but nobody is likely to notice that, at least not just yet. :) But it caused me no end of confusion when my FireMonkey app behaved one way on Windows and a\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":735,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/735\/","url_meta":{"origin":760,"position":3},"title":"RAD STUDIO XE2: Launch Event Report","date":"04 Aug 2011","format":false,"excerpt":"Today I was fortunate to be present in Auckland at the World Premier of the launch event for RAD Studio XE2. \u00a0There is so much good to report that I really don't know where to begin, so apologies if this post is a bit of a disorganised ramble. \u00a0But here\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":843,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/843\/","url_meta":{"origin":760,"position":4},"title":"XE2 Update #4 On The Horizon","date":"19 Jan 2012","format":false,"excerpt":"The release notes for Update #4 have appeared online, signalling the imminent arrival no doubt of the update itself. The good news if you are using FireMonkey is that this is a significant update, including functionality for printing. The bad news is that like update #1, this update is not\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":815,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/815\/","url_meta":{"origin":760,"position":5},"title":"Something the XE2 Un\/Installer Should Tell You&#8230;","date":"30 Sep 2011","format":false,"excerpt":"If you are about to install update #1 for Delphi XE2, the first thing you will need to do is uninstall your current version. But beware - the uninstaller doesn't tell you something quite important. When uninstalling a folder in the XE2 Program Files area (\"InstallAware\") cannot be deleted, presumably\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/760"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=760"}],"version-history":[{"count":29,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/760\/revisions"}],"predecessor-version":[{"id":789,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/760\/revisions\/789"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=760"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=760"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=760"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}