{"id":105680,"date":"2021-09-13T07:00:00","date_gmt":"2021-09-13T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105680"},"modified":"2021-09-13T07:15:18","modified_gmt":"2021-09-13T14:15:18","slug":"20210913-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210913-00\/?p=105680","title":{"rendered":"The C++\/WinRT <CODE>query_<WBR>interface_<WBR>tearoff<\/CODE> extension point, and using it for COM aggregation"},"content":{"rendered":"<p>The C++\/WinRT library&#8217;s <code>implements<\/code> template does the heavy lifting of implementing COM classes. One of the extension points is a method called <code>query_<wbr \/>interface_<wbr \/>tearoff<\/code>. This method is called as part of the implementation of the <code>IUnknown::<wbr \/>Query\u00adInterface<\/code> method if the caller is asking for an interface that wasn&#8217;t declared as part of the <code>implements<\/code> type parameter list. This gives you a chance to support additional interfaces.<\/p>\n<p>From its name, it&#8217;s apparent that the primary use case for this is <a href=\"https:\/\/www.codeguru.com\/cpp\/com-tech\/atl\/performance\/article.php\/c3613\/ATL-TearOff-Interfaces.htm\"> COM tear-off interfaces<\/a>. But you can use it for any scenario where you want to support an interface that you didn&#8217;t list in your <code>implements<\/code>. For example, the interface might be dynamically-generated. But today we&#8217;re going to use it for <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/win32\/com\/aggregation\"> COM aggregation<\/a>.<\/p>\n<p>Let&#8217;s say that we want to aggregate the free-threaded marshaler. Yes, I know that C++\/WinRT does this automatically, but let&#8217;s do it manually just to show how it&#8217;s done.<\/p>\n<pre>struct MyFreeThreaded :\r\n    winrt::implements&lt;MyFreeThreaded, ::IAgileObject, winrt::non_agile&gt;\r\n{\r\n  winrt::IUnknown m_ftm;\r\n\r\n  MyFreeThreaded()\r\n  {\r\n    winrt::check_hresult(CoCreateFreeThreadedMarshaler(this, m_ftm.put()));\r\n  }\r\n\r\n  int32_t query_interface_tearoff(winrt::guid const&amp; id, void** object)\r\n        const noexcept override\r\n  {\r\n    if (id == winrt::guid_of&lt;::IMarshal&gt;()) {\r\n      return m_ftm.as(id, object);\r\n    }\r\n    return E_NOINTERFACE;\r\n  }\r\n};\r\n<\/pre>\n<p>The <code>My\u00adFree\u00adThreaded<\/code> object implements <code>IAgile\u00adObject<\/code>, which is a marker interface for free-threaded objects. It also uses the <code>winrt::non_agile<\/code> marker to tell C++\/WinRT not to implement free-threading support for this object. Because we&#8217;re about to do it manually!<\/p>\n<p>We declare a member variable <code>m_ftm<\/code> which holds the free-threaded marshaler. At construction we create the free-threaded marshaler passing ourselves as the controlling unknown. This makes the free-threaded marshaler act as if it were part of our object, and it will forward all interface requests back to the main object. However, the <code>IUnknown<\/code> produced by <code>Co\u00adCreate\u00adFree\u00adThreaded\u00adMarshaler<\/code> is a special one that does not delegate its <code>IUnknown::<wbr \/>Query\u00adInterface<\/code> method. This lets you access the interfaces of the aggregated object. (Without it, any attempt to obtain an interface from the aggregated object would just be forwarded back to the outer object.)<\/p>\n<p>To complete the circle, we forward requests for <code>IMarshal<\/code> into the free-threaded marshaler by overriding <code>query_<wbr \/>interface_<wbr \/>tearoff<\/code>. That way, if somebody asks for <code>IMarshal<\/code>\u2014and by <i>somebody<\/i> I mean <i>COM itself<\/i>\u2014we forward the request into the aggregated object, which says &#8220;Free-threaded marshaler at your service!&#8221;<\/p>\n<p>An important detail of implementing your own <code>query_<wbr \/>interface_<wbr \/>tearoff<\/code> is that you should return <code>E_NOINTERFACE<\/code> (or forward to the base class) if you don&#8217;t handle the interface.<\/p>\n<p>That&#8217;s a pretty quick rundown of doing COM aggregation in C++\/WinRT. It&#8217;ll come in handy in a few months.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For adding your own <CODE>QueryInterface<\/CODE> magic.<\/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-105680","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>For adding your own <CODE>QueryInterface<\/CODE> magic.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105680","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=105680"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105680\/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=105680"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105680"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105680"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}