{"id":104138,"date":"2020-08-28T07:00:00","date_gmt":"2020-08-28T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104138"},"modified":"2020-09-09T06:10:10","modified_gmt":"2020-09-09T13:10:10","slug":"20200828-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200828-00\/?p=104138","title":{"rendered":"How do I convert from the C++\/WinRT projection type to the C++\/WinRT implementation type?"},"content":{"rendered":"<p>Last time, we looked at <a title=\"How do I convert from the C++\/WinRT implementation type to the C++\/WinRT projection type?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200827-00\/?p=104133\"> converting from the C++\/WinRT implementation type to the corresponding C++\/WinRT projection type<\/a>. Going from the projection back to the implementation is a little trickier and relies on your own vigilance. There&#8217;s no a priori guarantee that the projected pointer actually refers to your implementation. For example, if all you have is an <code>IInspectable<\/code>, that could be anybody. Even if you have a concrete <code>Sample::Class<\/code>, the projected type could have been implemented by somebody else.\u00b9<\/p>\n<p>But assume that you have other ways of knowing that the <code>IInspectable<\/code> or other projected type really is backed by the implementation you claim. Typically, it&#8217;s because you put it there yourself originally.<\/p>\n<pre>\/\/ Go from the projection to the implementation.\r\nimplementation::Class*p = get_self&lt;implementation::Class&gt;(o);\r\n<\/pre>\n<p>The <code>get_self<\/code> function assumes that the thing you&#8217;re providing is backed by the implementation you specify, and it returns a pointer to the that implementation type. The lifetime of the pointer is controlled by the projected object you obtained the pointer from, so you now have to keep both <code>o<\/code> and <code>p<\/code> around, which can be a hassle.<\/p>\n<p>There&#8217;s a nasty gotcha with <code>get_self<\/code> beyond the fact that you had better have the right implementation: You also have to have the right interface!<\/p>\n<p>If the object you pass is an interface, then the implementation cannot implement that interface multiple times, or there will be an ambiguity over how to convert from that interface to the implementation. This is a problem in standard C++ as well:<\/p>\n<pre>struct B {};\r\nstruct D1 : B {};\r\nstruct D2 : B {};\r\nstruct C : D1, D2 {};\r\n\r\nC* c;\r\nB* b = c; \/\/ error: 'B' is an ambiguous base of 'C'\r\n<\/pre>\n<p>The C++\/WinRT <code>get_self<\/code> function is more restrictive than C++ casts, because it&#8217;s a conversion, not a cast. The thing you&#8217;re converting from must be listed as one of the implemented interfaces.<\/p>\n<pre>struct C : implements&lt;C, ISomething&gt;\r\n{\r\n};\r\n\r\nIInspectable something;\r\nC* p = get_self&lt;C&gt;(something);\r\n\/\/ error: 'static_cast': cannot convert from\r\n\/\/ winrt::impl::producer&lt;D, I, void&gt; *' to 'D *'\r\n\/\/ with D = C, I = IInspectable\r\n<\/pre>\n<p>You can&#8217;t convert from <code>IInspectable<\/code> since the class <code>C<\/code> doesn&#8217;t list <code>IInspectable<\/code> as one of its explicitly-implemented interfaces. (It is an implicitly-implemented interface because <code>IInspectable<\/code> is the base of all Windows Runtime interfaces.)<\/p>\n<p>You can avoid this problem by converting the <code>IInspectable<\/code> to an explicitly-implemented interface first.<\/p>\n<pre>C* p = get_self&lt;C&gt;(something.as&lt;ISomething&gt;());\r\n<\/pre>\n<p>To avoid having to remember what interfaces your object implements, you can use the <code>default_interface<\/code> helper template type.<\/p>\n<pre>C* p = get_self&lt;C&gt;(something.as&lt;winrt::default_interface&lt;C&gt;&gt;());\r\n<\/pre>\n<p>But wait, you&#8217;re not out of the woods yet.<\/p>\n<p>If you mistakenly implement <code>IInspectable<\/code> as well as a Windows Runtime interface, then you run into another ambiguity: If recovering the object from an <code>IInspectable<\/code>, is the <code>IInspectable<\/code> the explicitly-implemented <code>IInspectable<\/code> or the implicitly-implemented <code>IInspectable<\/code> that came along for the ride as a base class of the Windows Runtime interface?<\/p>\n<pre>struct C : implements&lt;C, ISomething, IInspectable&gt;\r\n{\r\n};\r\n\r\nIInspectable something;\r\nC* p = get_self&lt;C&gt;(something); \/\/ 50% chance of working\r\n<\/pre>\n<p>C++\/WinRT assumes that you gave it the <code>IInspectable<\/code> that came from the explicitly-implemented interface, which has a 50% chance of being correct. If it&#8217;s incorrect, you will get the wrong pointer back and corrupt memory and be very sad.<\/p>\n<p>The best way to fix is to &#8220;stop holding it wrong&#8221;. Remove the redundant <code>IInspectable<\/code> from your list of explicitly-implemented interfaces.<\/p>\n<p>A less-good (but still effective) fix is to use the default interface trick we saw above.<\/p>\n<pre>C* p = get_self&lt;C&gt;(something.as&lt;winrt::default_interface&lt;C&gt;&gt;());\r\n<\/pre>\n<p>Note that the value returned by <code>get_self<\/code> is a raw pointer. The lifetime of the object is still controlled by whatever you passed to <code>get_self<\/code>. This can get annoying, since you now have to carry two things around: You need to carry the raw pointer so you can access your implementation, and you need to carry the original object that manages the lifetime. Here&#8217;s a helper function which converts the projected type into a reference-counted <code>com_ptr<\/code>. That way, you don&#8217;t have to carry two objects around. While I&#8217;m at it, I&#8217;ll fix the nasty gotcha (though really, you should just fix it by removing the redundant <code>IInspectable<\/code>).<\/p>\n<pre>template&lt;typename D, typename T&gt;\r\nwinrt::com_ptr&lt;D&gt; as_self(T&amp;&amp; o)\r\n{\r\n    winrt::com_ptr&lt;D&gt; result;\r\n    if constexpr (std::is_same_v&lt;std::remove_reference_t&lt;T&gt;,\r\n                                 winrt::Windows::Foundation::IInspectable&gt;)\r\n    {\r\n        auto temp = o.as&lt;winrt::default_interface&lt;D&gt;&gt;();\r\n        result.attach(winrt::get_self&lt;D&gt;(temp));\r\n        winrt::detach_abi(temp);\r\n    }\r\n    else if constexpr (std::is_rvalue_reference_v&lt;T&amp;&amp;&gt;)\r\n    {\r\n        result.attach(winrt::get_self&lt;D&gt;(o));\r\n        winrt::detach_abi(o);\r\n    }\r\n    else\r\n    {\r\n        result.copy_from(winrt::get_self&lt;D&gt;(o));\r\n    }\r\n\r\n    return result;\r\n}\r\n<\/pre>\n<p>The basic idea is to use <code>get_self<\/code> to obtain the raw pointer and use that pointer to initialize the resulting <code>com_ptr<\/code>. Depending on the circumstances, we might steal the reference count associated with the pointer, or we might just copy it.<\/p>\n<p>If the inbound parameter is an <code>IInspectable<\/code> (either lvalue or rvalue reference), then we are in the gotcha case, and we will make an explicit conversion to the default interface before calling <code>get_self<\/code>. We can use attach\/detach semantics because the temporary default interface is going out of scope soon, so we can steal its reference.<\/p>\n<p>Otherwise, the inbound parameter is something other than <code>IInspectable<\/code>, so we are not in the gotcha case. For rvalue references, we can use use attach\/detach semantics because the rvalue reference allows us to steal its reference. For lvalue references, we use copy semantics because the original retains its reference.<\/p>\n<p>\u00b9 It is legal for a projected type to have multiple implementations. This actually happens on occasion. For example there are different implementations of <code>Pointer\u00adPoint<\/code> depending on which kind of device the point came from. The <code>Pointer\u00adPoint<\/code> itself is a smart pointer to an unknown implementation.<\/p>\n<p>If you aren&#8217;t sure whether the implementation is yours, you can create a private marker interface to identify your own objects.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You have to trust what&#8217;s inside the box.<\/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-104138","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You have to trust what&#8217;s inside the box.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104138","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=104138"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104138\/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=104138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}