{"id":103702,"date":"2020-04-24T07:00:00","date_gmt":"2020-04-24T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103702"},"modified":"2020-04-24T08:39:10","modified_gmt":"2020-04-24T15:39:10","slug":"20200424-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200424-00\/?p=103702","title":{"rendered":"How do I use C++\/WinRT to implement a classic COM interface that derives from another classic COM interface?"},"content":{"rendered":"<p>The C++\/WinRT library can be used to implement both Windows Runtime interfaces as well as classic COM interfaces. One feature of classic COM that is absent (intentionally) from the Windows Runtime is interface derivation. If you&#8217;re writing a class that needs to implement a derived COM interface, how do you express it? (The WRL library calls this a &#8220;chained interface&#8221;.)<\/p>\n<p>For concreteness, let&#8217;s suppose that you are implementing <code>IFileSystemBindData<\/code> and <code>IFileSystemBindData2<\/code>.<\/p>\n<p>The na\u00efve way is to say that you implement both interfaces:<\/p>\n<pre>struct MyFileSystemBindData :\r\n    implements&lt;MyFileSystemBindData,\r\n        <span style=\"color: blue;\">IFileSystemBindData,\r\n        IFileSystemBindData2<\/span>&gt;\r\n{\r\n    \/\/ IFileSystemBindData\r\n    HRESULT SetFindData(const WIN32_FIND_DATAW* pfd) override;\r\n    HRESULT GetFindData(WIN32_FIND_DATAW* pfd) override;\r\n\r\n    \/\/ IFileSystemBindData2\r\n    HRESULT SetFileID(LARGE_INTEGER liFileID) override;\r\n    HRESULT GetFileID(LARGE_INTEGER *pliFileID) override;\r\n    HRESULT SetJunctionCLSID(REFCLSID clsid) override;\r\n    HRESULT GetJunctionCLSID(CLSID *pclsid) override;\r\n};\r\n<\/pre>\n<p>If you do this, you get ambiguous cast errors because the <code>Query\u00adInterface<\/code> provided by the <code>implements<\/code> template ends up doing something like this:<\/p>\n<pre>if (is_guid_of&lt;IFileSystemBindData&gt;(iid)) {\r\n  *result = static_cast&lt;IFileSystemBindData*&gt;(this);\r\n} else if (is_guid_of&lt;IFileSystemBindData2&gt;(iid)) {\r\n  *result = static_cast&lt;IFileSystemBindData2*&gt;(this);\r\n}\r\n<\/pre>\n<p>The cast to <code>IFileSystemBindData*<\/code> is ambiguous because the compiler can&#8217;t tell whether you want the <code>IFileSystemBindData<\/code> that is the immediate base class, or whether you want the <code>IFileSystemBindData<\/code> that is the base class of the <code>IFileSystemBindData2<\/code> interface.<\/p>\n<p>But you didn&#8217;t need to do that anyway. The COM interfaces derive from each other, so you probably want them to share a vtable. Declaring that you implement both interfaces means that you get two vtables (one for each interface) rather than a shared vtable.<\/p>\n<p>The way to define your object is to say that you implement only the derived interface:<\/p>\n<pre>struct MyFileSystemBindData :\r\n    implements&lt;MyFileSystemBindData,\r\n        <span style=\"color: blue;\">IFileSystemBindData2<\/span>&gt;\r\n{\r\n    ...\r\n};\r\n<\/pre>\n<p>This gets rid of the ambiguous cast, because there is now only one way to get a <code>IFileSystemBindData<\/code>.<\/p>\n<p>However, you also need to get the <code>Query\u00adInterface<\/code> to respond to <code>IID_IFileSystemBindData<\/code>.<\/p>\n<p>To do that, you can overload the <code>winrt::is_guid_of<\/code> function so that a check for <code>IFileSystemBindData2<\/code> includes a test for <code>IFileSystemBindData<\/code>.<\/p>\n<pre>namespace winrt\r\n{\r\n  template&lt;&gt;\r\n  bool is_guid_of&lt;IFileSystemBindData2&gt;(guid const&amp; id) noexcept\r\n  {\r\n    return is_guid_of&lt;IFileSystemBindData2, IFileSystemBindData&gt;(id);\r\n  }\r\n}\r\n<\/pre>\n<p>This takes advantage of the variadic template overload of <code>is_guid_of<\/code> introduced in <a href=\"https:\/\/github.com\/microsoft\/xlang\/pull\/107\"> PR 107<\/a>.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You can specialize <CODE>guid_of<\/CODE>.<\/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-103702","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You can specialize <CODE>guid_of<\/CODE>.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103702","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=103702"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103702\/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=103702"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103702"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103702"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}