{"id":1719,"date":"2016-09-27T10:00:00","date_gmt":"2016-09-27T08:00:00","guid":{"rendered":"https:\/\/alax.info\/blog\/?p=1719"},"modified":"2016-09-24T20:00:23","modified_gmt":"2016-09-24T18:00:23","slug":"c-import-and-x64-builds","status":"publish","type":"post","link":"https:\/\/alax.info\/blog\/1719","title":{"rendered":"C++ #import and x64 builds"},"content":{"rendered":"<p>I already wrote <a href=\"https:\/\/alax.info\/blog\/1561\">earlier on 32\/64-bit issues with Visual Studio<\/a>. The problems are not frequent but when they happen they are pretty confusing. Here is another one today.<\/p>\n<p>C++ code is simple:<\/p>\n<pre><code>    #import \"libid:59941706-0000-1111-2222-7EE5C88402D2\" raw_interfaces_only no_namespace\r\n\r\n    CComPtr&lt;IObject&gt; pObject;\r\n    ATLENSURE_SUCCEEDED(pObject.CoCreateInstance(__uuidof(Object)));\r\n    BYTE* pnData;\r\n    ATLENSURE_SUCCEEDED(pObject-&gt;Method((ULONG_PTR) (BYTE*) pnData));\r\n<\/code><\/pre>\n<p>A COM method returns a pointer to data &#8211; pretty straightforward, what could have gone wrong?<\/p>\n<p>COM server vendor designed the library for easy .NET integration and defined the pointer argument as an integer value. They suppose the values to be used further with <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.runtime.interopservices.marshal(v=vs.110).aspx\">System.Runtime.InteropServices.Marshal<\/a> class.<\/p>\n<p>32-bit builds worked well and 64-bit builds experienced memory access violations. An attempt to consume the COM server from C# project showed the same problem: unexpected exception in the call.<\/p>\n<p>The problem is that cross-compiler importing COM type library using LIBID takes 32-bit library even when it builds 64-bit code. This is the problem for both C++ <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/8etzzkb6.aspx\"><code>#import \"libid:...\"<\/code><\/a> and .NET COM reference using the identifier.<\/p>\n<p>The type library imports as the following IDL in 32-bits:<\/p>\n<pre><code>[id(1)]\r\nHRESULT Method(\r\n                [in] unsigned long bufPtr);\r\n<\/code><\/pre>\n<p>It is supposed that 64-bit builds get the following import:<\/p>\n<pre><code>[id(1)]\r\nHRESULT Method(\r\n                [in] uint64 bufPtr);\r\n<\/code><\/pre>\n<p>Effectively though, 64-bit builds get the 32-bit import and the argument which is supposed to carry casted pointer value is truncated to 32-bits, <code>ULONG<\/code> type. Cast to <code>ULONG_PTR<\/code> in 64-bit C++ code is, of course, not helpful since it&#8217;s trimmed anyway further fitting the IDL argument type.<\/p>\n<p>The same happens with C# build.<\/p>\n<p>It was developer&#8217;s choice to publish ordinal type argument, they wanted this to be &#8220;better&#8221; and ended up in bitness mess. If the argument remained a pointer type in the IDL then even incorrect bitness would not necessarily result in value truncation.<\/p>\n<p>All together it is unsafe to import [an untrusted] type library using LIBID when it comes to 64-bit builds. It&#8217;s 32-bit library to be taken and it can result in incorrect import. Instead, such build should explicitly point to 64-bit type library, for example:<\/p>\n<pre><code>#if defined(_WIN64)\r\n    #import \"Win64\\ThirdParty.DLL\" raw_interfaces_only no_namespace\r\n#else\r\n    \/\/#import \"libid:59941706-0000-1111-2222-7EE5C88402D2\" raw_interfaces_only no_namespace\r\n    #import \"Win32\\ThirdParty.DLL\" raw_interfaces_only no_namespace\r\n#endif\r\n<\/code><\/pre>\n<p>Too bad! <code>libid<\/code> looked so nice and promising.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I already wrote earlier on 32\/64-bit issues with Visual Studio. The problems are not frequent but when they happen they are pretty confusing. Here is another one today. C++ code is simple: #import &#8220;libid:59941706-0000-1111-2222-7EE5C88402D2&#8221; raw_interfaces_only no_namespace CComPtr&lt;IObject&gt; pObject; ATLENSURE_SUCCEEDED(pObject.CoCreateInstance(__uuidof(Object))); BYTE* pnData; ATLENSURE_SUCCEEDED(pObject-&gt;Method((ULONG_PTR) (BYTE*) pnData)); A COM method returns a pointer to data &#8211; pretty straightforward,&hellip; <\/p>\n<p><a class=\"moretag\" href=\"https:\/\/alax.info\/blog\/1719\">Read the full article<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[538,536,38,95,537,58],"class_list":["post-1719","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-net","tag-bitness","tag-c","tag-com","tag-interoperability","tag-visual-studio"],"_links":{"self":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts\/1719","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/comments?post=1719"}],"version-history":[{"count":0,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/posts\/1719\/revisions"}],"wp:attachment":[{"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/media?parent=1719"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/categories?post=1719"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alax.info\/blog\/wp-json\/wp\/v2\/tags?post=1719"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}