{"id":104639,"date":"2021-01-01T07:00:00","date_gmt":"2021-01-01T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104639"},"modified":"2021-01-01T07:14:05","modified_gmt":"2021-01-01T15:14:05","slug":"20210101-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210101-00\/?p=104639","title":{"rendered":"I&#8217;d like an IUnknown, I know you have many, I&#8217;ll take any of them"},"content":{"rendered":"<p>A concrete implementation of a COM object may implement multiple interfaces. If you have a pointer to the concrete implementation, and you pass to a function that expects an <code>IUnknown<\/code>, you will probably get an error complaining that <code>IUnknown<\/code> is an ambiguous base, or that there is an ambiguous conversion to <code>IUnknown<\/code>.<\/p>\n<pre>void DoSomething(IUnknown* unk);\r\n\r\nclass MyClass : public IFred, public IBarney\r\n{\r\n    ...\r\n\r\n    void SomeMethod()\r\n    {\r\n        DoSomething(this); \/\/ fails to compile\r\n    }\r\n};\r\n\r\nusing namespace Microsoft::WRL;\r\n\r\nclass MyWrlClass :\r\n    RuntimeClass&lt;RuntimeClassFlags&lt;ClassicCom&gt;,\r\n                 IFred, IBarney&gt;\r\n{\r\n    ...\r\n    void SomeMethod()\r\n    {\r\n        DoSomething(this); \/\/ fails to compile\r\n    }\r\n};\r\n\r\n<\/pre>\n<p>The problem is that when you call <code>DoSomething(this)<\/code>, the compiler doesn&#8217;t know whether you want to pass the <code>IUnknown<\/code> that is a base class of <code>IFred<\/code>, or the <code>IUnknown<\/code> that is a base class of <code>IBarney<\/code>.<\/p>\n<p>What we know and the compiler doesn&#8217;t know is that it doesn&#8217;t matter which one you pass. They are functionally equivalent. (The only time you are particular about which one you get is if you are trying to get the canonical unknown, but that is typically only something needed by the <code>Query\u00adInterface<\/code> method.)<\/p>\n<p>The usual solution is to cast the implementation pointer to one of the interfaces that it unambiguously implements, and then let the compiler convert that interface pointer to <code>IUnknown<\/code>. This does require you to know which interfaces the object implements, which could be a source of fragility if the object gains or loses interfaces over time.<\/p>\n<p>From a code size point of view, you want to choose the interface that is the first base class, assuming that the first base class is an interface. That way, the conversion is a nop.<\/p>\n<pre>        DoSomething(static_cast&lt;IFred&gt;(this));\r\n<\/pre>\n<p>If you use the WRL template library to create your COM objects, then there&#8217;s a handy helper function: <code>CastToUnknown<\/code>. This takes the implementation pointer and casts it to <code>IUnknown<\/code>, saving you the trouble of having to decide which of the many possible paths to <code>IUnknown<\/code> to use. This is a protected method, so you can use it from within the class, but not from the outside.<\/p>\n<pre>class MyWrlClass :\r\n    RuntimeClass&lt;RuntimeClassFlags&lt;ClassicCom&gt;,\r\n                 IFred, IBarney&gt;\r\n{\r\n    ...\r\n    void SomeMethod()\r\n    {\r\n        DoSomething(this<span style=\"color: blue;\">-&gt;CastToUnknown()<\/span>);\r\n    }\r\n};\r\n\r\nvoid SomeFunction(MyWrlClass* p)\r\n{\r\n  \/\/ this doesn't compile\r\n  DoSomething(p-&gt;CastToUnknown());\r\n}\r\n<\/pre>\n<p>The call to <code>Cast\u00adTo\u00adUnknown<\/code> from the <code>Some\u00adFunction<\/code> is disallowed because the <code>Cast\u00adTo\u00adUnknown<\/code> method is protected.<\/p>\n<p>But you could choose to unprotected it.<\/p>\n<pre>class MyWrlClass :\r\n    RuntimeClass&lt;RuntimeClassFlags&lt;ClassicCom&gt;,\r\n                 IFred, IBarney&gt;\r\n{\r\npublic:\r\n    <span style=\"color: blue;\">using RuntimeClass::CastToUnknown;<\/span>\r\n    ...\r\n};\r\n<\/pre>\n<p>The <code>using<\/code> statement imports the base class&#8217;s <code>Cast\u00adTo\u00adUnknown<\/code> method, and since the <code>using<\/code> statement is in the <code>public<\/code> section, the imported function is now <code>public<\/code>.<\/p>\n<p>But really, the point of this article is to call out the existence of the <code>Cast\u00adTo\u00adUnknown<\/code> method. It&#8217;s really handy when you need it, such as when you want to extend your object&#8217;s lifetime:<\/p>\n<pre>Callback&lt;ISomething&gt;(\r\n    [<span style=\"color: blue;\">lifetime = ComPtr&lt;IUnknown&gt;(this-&gt;CastToUnknown())<\/span>]()\r\n    {\r\n      ...\r\n    });\r\n<\/pre>\n<p>Unfortunately, it&#8217;s still quite a bit of a mouthful. You can factor it out to avoid having to type the whole thing out all the time.<\/p>\n<pre>template&lt;typename T&gt; ComPtr&lt;T&gt; AsComPtr(T* p) { return p; }\r\n\r\nCallback&lt;ISomething&gt;(\r\n    [<span style=\"color: blue;\">lifetime = AsComPtr(this)<\/span>]()\r\n    {\r\n      ...\r\n    });\r\n<\/pre>\n<p>Note that this isn&#8217;t quite the same as the previous version because the resulting <code>ComPtr<\/code> is a <code>ComPtr&lt;MyWrlClass&gt;<\/code> rather than a <code>ComPtr&lt;IUnknown&gt;<\/code>, but that works just as well for the purpose of extending the object&#8217;s lifetime.<\/p>\n<p>WRL was written when the latest version of the C++ language was C++11, so it doesn&#8217;t doesn&#8217;t have access to <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/class_template_argument_deduction\"> CTAD<\/a>. If CTAD were around, it could have had a deduction guide:<\/p>\n<pre>template&lt;typename T&gt; ComPtr(T*) -&gt; ComPtr&lt;T&gt;;\r\n<\/pre>\n<p>That would avoid the need for the <code>AsComPtr<\/code> helper function.<\/p>\n<pre>Callback&lt;ISomething&gt;(\r\n    [<span style=\"color: blue;\">lifetime = ComPtr(this)<\/span>]()\r\n    {\r\n      ...\r\n    });\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Taking the first one is as good as any other.<\/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-104639","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Taking the first one is as good as any other.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104639","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=104639"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104639\/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=104639"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104639"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104639"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}