{"id":104275,"date":"2020-09-24T07:00:00","date_gmt":"2020-09-24T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104275"},"modified":"2020-09-23T20:21:16","modified_gmt":"2020-09-24T03:21:16","slug":"20200924-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200924-00\/?p=104275","title":{"rendered":"Inside C++\/WinRT: How does C++\/WinRT represent ABI types?"},"content":{"rendered":"<p>C++\/WinRT offers a high-level interface to the the low-level Windows Runtime ABI (application binary interface). It does this without any dependency on the Windows header files, which means that it needs some way to talk about the ABI types without actually using the ABI types. How does this work?<\/p>\n<p>C++\/WinRT sets up a collection of types which run parallel to the ABI types defined in the system header files. The types are not the same, but they are equivalent at the ABI level, meaning that they have identical binary representations.<\/p>\n<p>When you work in C++\/WinRT, there are three (sometimes four) versions of every type, listed here in decreasing order of popularity:<\/p>\n<ul>\n<li>C++\/WinRT projected types.<\/li>\n<li>C++\/WinRT implementation types.<\/li>\n<li>C++\/WinRT ABI-equivalent types.<\/li>\n<li>System-defined ABI types. (Not used by C++\/WinRT.)<\/li>\n<\/ul>\n<p>In practice, you will be spending nearly all of your time with C++\/WinRT projected types. If you are implementing C++\/WinRT classes, then you will also have to deal with C++\/WinRT implementation types.<\/p>\n<p>But you will rarely have to deal with C++\/WinRT ABI-equivalent types or the underlying system-defined ABI types. Those come into play only when you are interoperating at the ABI layer, and that&#8217;s typically something you let the C++\/WinRT library do for you.<\/p>\n<p>But I&#8217;m going to discuss it anyway, because you may on occasion find yourself having to work at the ABI layer.<\/p>\n<p>Here&#8217;s how it works for scalar types:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>System<\/th>\n<th colspan=\"2\">C++\/WinRT<\/th>\n<\/tr>\n<tr>\n<th>ABI<\/th>\n<th>ABI<\/th>\n<th>Projection<\/th>\n<\/tr>\n<tr>\n<td><code>BYTE<\/code><\/td>\n<td colspan=\"2\"><code>uint8_t<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>INT16<\/code><\/td>\n<td colspan=\"2\"><code>int16_t<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>UINT16<\/code><\/td>\n<td colspan=\"2\"><code>uint16_t<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>INT32<\/code><\/td>\n<td colspan=\"2\"><code>int32_t<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>UINT32<\/code><\/td>\n<td colspan=\"2\"><code>uint32_t<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>INT64<\/code><\/td>\n<td colspan=\"2\"><code>int64_t<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>UINT64<\/code><\/td>\n<td colspan=\"2\"><code>uint64_t<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>FLOAT<\/code><\/td>\n<td colspan=\"2\"><code>float<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>DOUBLE<\/code><\/td>\n<td colspan=\"2\"><code>double<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>boolean<\/code><\/td>\n<td colspan=\"2\"><code>bool<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>WCHAR<\/code><\/td>\n<td colspan=\"2\"><code>char16_t<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>GUID<\/code><\/td>\n<td colspan=\"2\"><code>winrt::guid<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>enum<\/code><\/td>\n<td><code>int32_t<\/code><br \/>\n<code>uint32_t<\/code><\/td>\n<td><code>enum<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>HSTRING<\/code><\/td>\n<td><code>void*<\/code><\/td>\n<td><code>winrt::hstring<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>HRESULT<\/code><\/td>\n<td><code>int32_t<\/code><\/td>\n<td><code>winrt::hresult<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>For enumerations, the C++\/WinRT ABI type is <code>int32_t<\/code>, unless the enumeration is a flags enumeration, in which case the C++\/WinRT ABI type is <code>uint32_t<\/code>.<\/p>\n<p>The C++\/WinRT ABI structures take the form of structures where each member has its corresponding C++\/WinRT ABI type. For example,<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th style=\"vertical-align: middle; width: 2em;\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">System<\/span><\/th>\n<th>ABI<\/th>\n<td><tt>struct<br \/>\n{<br \/>\n\u00a0INT16 Value1;<br \/>\n\u00a0HSTRING Value2;<br \/>\n\u00a0SomeEnum Value3;<br \/>\n};<\/tt><\/td>\n<\/tr>\n<tr>\n<th style=\"vertical-align: middle; width: 2em;\" rowspan=\"2\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">C++\/WinRT<\/span><\/th>\n<th>ABI<\/th>\n<td><tt>struct<br \/>\n{<br \/>\n\u00a0int16_t Value1;<br \/>\n\u00a0void* Value2;<br \/>\n\u00a0int32_t Value3;<br \/>\n};<\/tt><\/td>\n<\/tr>\n<tr>\n<th>Projection<\/th>\n<td><tt>struct<br \/>\n{<br \/>\n\u00a0int16_t Value1;<br \/>\n\u00a0hstring Value2;<br \/>\n\u00a0SomeEnum Value3;<br \/>\n};<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><!-- horizontal version doesn't fit in narrow layout\n\n<TABLE CLASS=\"cp3\" BORDER=1 CELLSPACING=0 CELLPADDING=3\n    STYLE=\"border-collapse: collapse\">\n<TR>\n    \n<TH>System<\/TH>\n\n    \n<TH COLSPAN=2>C++\/WinRT<\/TH>\n<\/TR>\n<TR>\n    \n<TH>ABI<\/TH>\n\n    \n<TH>ABI<\/TH>\n\n    \n<TH>Projection<\/TH>\n<\/TR>\n<TR>\n    \n<TD><TT>struct<BR>\n        {<BR>\n        &nbsp;INT16 Value1;<BR>\n        &nbsp;HSTRING Value2;<BR>\n        &nbsp;SomeEnum Value3;<BR>\n        };<\/TT><\/TD>\n\n    \n<TD><TT>struct<BR>\n        {<BR>\n        &nbsp;int16_t Value1;<BR>\n        &nbsp;void* Value2;<BR>\n        &nbsp;int32_t Value3;<BR>\n        };<\/TT><\/TD>\n\n    \n<TD><TT>struct<BR>\n        {<BR>\n        &nbsp;int16_t Value1;<BR>\n        &nbsp;hstring Value2;<BR>\n        &nbsp;SomeEnum Value3;<BR>\n        };<\/TT><\/TD>\n<\/TR>\n<\/TABLE>\n\n--><\/p>\n<p>If the structure contains another structure, then the rule is applied recursively.<\/p>\n<p>Finally, C++\/WinRT interfaces are represented in the C++\/WinRT ABI by a pure virtual class whose members are the interface methods, but with all parameters converted to their C++\/WinRT ABI types. For example,<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th style=\"vertical-align: middle; width: 2em;\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">System<\/span><\/th>\n<th>ABI<\/th>\n<td><tt>struct ISomething : ::IInspectable<br \/>\n{<br \/>\n\u00a0virtual HRESULT<br \/>\n\u00a0\u00a0Method1(INT32 param1) = 0;<br \/>\n\u00a0virtual HRESULT<br \/>\n\u00a0\u00a0Method2(HSTRING* result) = 0;<br \/>\n};<\/tt><\/td>\n<\/tr>\n<tr>\n<th style=\"vertical-align: middle; width: 2em;\" rowspan=\"2\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">C++\/WinRT<\/span><\/th>\n<th>ABI<\/th>\n<td><tt>struct ISomething : inspectable_abi<br \/>\n{<br \/>\n\u00a0virtual int32_t<br \/>\n\u00a0\u00a0Method1(int32_t param1) = 0;<br \/>\n\u00a0virtual int32_t<br \/>\n\u00a0\u00a0Method2(void** result) = 0;<br \/>\n};<\/tt><\/td>\n<\/tr>\n<tr>\n<th>Projection<\/th>\n<td><tt>struct ISomething : winrt::IInspectable<br \/>\n{<br \/>\n\u00a0void Method1(int32_t param1);<br \/>\n\u00a0winrt::hstring Method2();<br \/>\n};<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><!-- horizontal version doesn't fit in narrow layout\n\n<TABLE CLASS=\"cp3\" BORDER=1 CELLSPACING=0 CELLPADDING=3\n    STYLE=\"border-collapse: collapse\">\n<TR>\n    \n<TH>System<\/TH>\n\n    \n<TH COLSPAN=2>C++\/WinRT<\/TH>\n<\/TR>\n<TR>\n    \n<TH>ABI<\/TH>\n\n    \n<TH>ABI<\/TH>\n\n    \n<TH>Projection<\/TH>\n<\/TR>\n<TR>\n    \n<TD><TT>struct ISomething : ::IInspectable<BR>\n        {<BR>\n        &nbsp;virtual HRESULT<BR>\n        &nbsp;&nbsp;Method1(INT32 param1) = 0;<BR>\n        &nbsp;virtual HRESULT<BR>\n        &nbsp;&nbsp;Method2(HSTRING* result) = 0;<BR>\n        };<\/TT><\/TD>\n\n    \n<TD><TT>struct ISomething :: inspectable_abi<BR>\n        {<BR>\n        &nbsp;virtual int32_t<BR>\n        &nbsp;&nbsp;Method1(int32_t param1) = 0;<BR>\n        &nbsp;virtual int32_t<BR>\n        &nbsp;&nbsp;Method2(void** result) = 0;<BR>\n        };<\/TT><\/TD>\n\n    \n<TD><TT>struct ISomething : winrt::IInspectable<BR>\n        {<BR>\n        &nbsp;void Method1(int32_t param1);<BR>\n        &nbsp;winrt::hstring Method2();<BR>\n        };<\/TT><\/TD>\n<\/TABLE>\n\n--><\/p>\n<p>These different versions are placed in separate namespaces.<\/p>\n<p>The System ABI puts metadata-defined types in the <code>ABI<\/code> namespace. For example, <code>Windows.Foundation.Point<\/code> is defined in the System ABI as <code>ABI::Windows::Foundation::Point<\/code>. (Metadata types are the types defined in the <code>.winmd<\/code> metadata files. Fundamental types like the basic integer types, <code>HSTRING<\/code>, <code>IUnknown<\/code>, and <code>IInspectable<\/code> are not defined in metadata and reside in the global namespace.)<\/p>\n<p>The C++\/WinRT ABI puts metadata-defined types in the <code>winrt::impl<\/code> namespace, often as anonymous types. You need to know that they exist, and what they look like, but you aren&#8217;t expected to be using them directly.<\/p>\n<p>The C++\/WinRT projection puts metadata-defined types in the <code>winrt<\/code> namespace. For example, <code>Windows.Foundation.Point<\/code> is defined in the C++\/WinRT projection as <code>winrt::Windows::Foundation::Point<\/code>.<\/p>\n<p>The <code>winrt::impl<\/code> namespace contains internal implementation details, and that&#8217;s where the <code>abi<\/code> template type hangs out. Its job is to convert C++\/WinRT types into their corresponding C++\/WinRT ABI types. For any projected type <code>T<\/code>, the type <code>winrt::impl::abi&lt;T&gt;::type<\/code> is the corresponding C++\/WinRT ABI type. You shouldn&#8217;t be using this template directly, but I&#8217;m mentioning it so that when you find yourself single-stepping through the C++\/WinRT library, you&#8217;ll know what that weird <code>abi<\/code> template is.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hiding in the internal <CODE>impl::abi<\/CODE> template.<\/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":[25],"class_list":["post-104275","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Hiding in the internal <CODE>impl::abi<\/CODE> template.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104275","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=104275"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104275\/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=104275"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104275"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104275"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}