{"id":105838,"date":"2021-10-27T07:00:00","date_gmt":"2021-10-27T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105838"},"modified":"2021-10-27T08:28:15","modified_gmt":"2021-10-27T15:28:15","slug":"20211027-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211027-00\/?p=105838","title":{"rendered":"Giving a single object multiple COM identities, part 2"},"content":{"rendered":"<p>Last time, we looked at <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20211026-00\/?p=105834\"> how you can give a single object multiple COM identities<\/a> so that different clients can maintain references to different parts of the object without knowing about the other parts.<\/p>\n<p>The idea here is that each identity is its own separate collection of <code>IUnknown<\/code> interfaces which are interconnected via <code>Query\u00adInterface<\/code> to each other, but all of the identities share the same <code>AddRef<\/code> and <code>Release<\/code>, so that the lifetime of the collective ends only when all the identities run down.<\/p>\n<p>Our previous implementation gave each embedded identity a pointer to the outer object so it could access the shared <code>AddRef<\/code> and <code>Release<\/code> methods, as well as forward any calls to the outer object for processing.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; margin-left: 1px;\" title=\"Embedded 'this' pointer points back to start of object\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px black; text-align: center;\" rowspan=\"2\">primary vtable<\/td>\n<td rowspan=\"2\">\u25c1<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px black; border-style: solid solid none none; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px black; text-align: center;\">reference count<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border-right: solid 1px black;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px black; text-align: center;\">other data<br \/>\n\u22ee<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border-right: solid 1px black;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px black; border-style: solid none none solid;\">CallbackWrapper<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px black; text-align: center;\">embedded vtable<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border-right: solid 1px black;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px black; border-style: none none solid solid;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px black; text-align: center;\" rowspan=\"2\"><code>m_outer<\/code><\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px black; border-style: none solid solid none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>But it turns out that this pointer is redundant: Recovering the outer object from the embedded object can be done from the embedded object&#8217;s <code>this<\/code> pointer because the embedded object is at a fixed compile-time offset from the start of the outer object. All we have to do is adjust the embedded object&#8217;s <code>this<\/code> pointer to get a pointer to the outer object.<\/p>\n<pre>ULONG CallbackWrapper::AddRef()\r\n{\r\n    Outer* outer =  reinterpret_cast&lt;Outer*&gt;(\r\n        reinterpret_cast&lt;uintptr_t&gt;(this) - offsetof(Outer, m_wrapper));\r\n    return outer-&gt;AddRef();\r\n}\r\n<\/pre>\n<p>One major problem is that the <code>CallbackWrapper<\/code> class doesn&#8217;t know what member name to use as the second parameter to the <code>offsetof<\/code> macro. You could establish a convention that &#8220;Oh, the name must be <code>m_wrapper<\/code>,&#8221; but that would prevent you from having more than one wrapper.<\/p>\n<p>Even if you knew the name of the member variable, you can&#8217;t calculate the offset of a member variable before the type is complete.<\/p>\n<pre>struct Widget final : IWidget, ...\r\n{\r\n    ...\r\n    HRESULT OnCallback();\r\n    CallbackWrapper&lt;&amp;Widget::OnCallback&gt; m_wrapper;\r\n    ...\r\n};\r\n<\/pre>\n<p>At the point <code>Callback\u00adWrapper&lt;;&amp;Widget::OnCallback1&gt;<\/code> is instantiated, not only is the <code>Widget<\/code> type incomplete, it doesn&#8217;t even have a member named <code>m_wrapper<\/code> yet!<\/p>\n<p>But you know what you can do before a type is complete? You can <code>static_cast<\/code> between the type and its base types. The compiler will do the work of calculating and applying the pointer adjustment (once it is known).<\/p>\n<p>So let&#8217;s try it:<\/p>\n<pre>ULONG CallbackWrapper::AddRef()\r\n{\r\n    Outer* outer = static_cast&lt;Outer*&gt;(this);\r\n    return outer-&gt;AddRef();\r\n}\r\n\r\nstruct Widget final : IWidget, CallbackWrapper&lt;&amp;Widget::OnCallback&gt;\r\n{\r\n    ...\r\n    HRESULT OnCallback();\r\n    ...\r\n};\r\n<\/pre>\n<p>This doesn&#8217;t work because we are now talking about <code>Widget::<wbr \/>OnCallback<\/code> before it has been declared. Unfortunately, you cannot forward-declare a member function, so we will have to inject a helper forwarder class. To make it easier to find the ultimate target, we remember it as the nested type name <code>Outer<\/code>.<\/p>\n<pre>template&lt;typename OuterType&gt;\r\nstruct MethodForwarder\r\n{\r\n    using Outer = OuterType;\r\n\r\n    auto outer() { return static_cast&lt;Outer*&gt;(this); }\r\n\r\n    HRESULT OnCallback() { return outer()-&gt;OnCallback(); }\r\n};\r\n\r\nstruct Widget final : IWidget,\r\n    CallbackWrapper&lt;&amp;MethodForwarder&lt;Widget&gt;::OnCallback&gt;,\r\n{\r\n    ...\r\n    HRESULT OnCallback();\r\n    ...\r\n\r\n    HRESULT RegisterCallback()\r\n    {\r\n        SetCallback(this);\r\n    }\r\n};\r\n<\/pre>\n<p>There is a unique conversion from <code>Widget<\/code> to <code>ICallback<\/code> (namely through the <code>CallbackWrapper<\/code>), but if you need multiple callbacks, you&#8217;re in for a lot more typing to resolve the ambiguous conversion:<\/p>\n<pre>template&lt;typename Outer&gt;\r\nstruct MethodForwarder\r\n{\r\n    auto outer() { return static_cast&lt;Outer*&gt;(this); }\r\n\r\n    HRESULT OnCallback1() { return outer()-&gt;OnCallback1(); }\r\n    HRESULT OnCallback2() { return outer()-&gt;OnCallback2(); }\r\n};\r\n\r\nstruct Widget final : IWidget,\r\n    CallbackWrapper&lt;&amp;MethodForwarder&lt;Widget&gt;::OnCallback1&gt;,\r\n    CallbackWrapper&lt;&amp;MethodForwarder&lt;Widget&gt;::OnCallback2&gt;,\r\n{\r\n    ...\r\n    HRESULT OnCallback1();\r\n    HRESULT OnCallback2();\r\n    ...\r\n\r\n    HRESULT RegisterCallback()\r\n    {\r\n        SetCallback1(static_cast&lt;CallbackWrapper&lt;&amp;MethodForwarder&lt;Widget&gt;::OnCallback1&gt;*&gt;\r\n                                                                                  (this));\r\n        SetCallback2(static_cast&lt;CallbackWrapper&lt;&amp;MethodForwarder&lt;Widget&gt;::OnCallback2&gt;*&gt;\r\n                                                                                  (this));\r\n    }\r\n};\r\n<\/pre>\n<p>We can do some things to help a little with the verbosity: We can create a type alias, a variadic aggregator, and a helper function for casting to the correct base class:<\/p>\n<pre>template&lt;auto... Callbacks&gt;\r\nstruct CallbackWrappers : CallbackWrapper&lt;Callbacks&gt;...\r\n{\r\n    template&lt;auto Callback&gt;\r\n    ICallback* GetCallback() {\r\n        return static_cast&lt;CallbackWrapper&lt;Callback&gt;*&gt;(this);\r\n    }\r\n};\r\n\r\nstruct Widget;\r\nusing WidgetForwarder = MethodForwarder&lt;Widget&gt;;\r\n\r\nstruct Widget final : IWidget,\r\n    CallbackWrappers&lt;&amp;WidgetForwarder::OnCallback1,\r\n                     &amp;WidgetForwarder::OnCallback2&gt;\r\n{\r\n    ...\r\n    HRESULT OnCallback1();\r\n    HRESULT OnCallback2();\r\n    ...\r\n\r\n    HRESULT RegisterCallback()\r\n    {\r\n        SetCallback1(GetCallback&lt;&amp;WidgetForwarder::OnCallback1&gt;(this));\r\n        SetCallback2(GetCallback&lt;&amp;WidgetForwarder::OnCallback2&gt;(this));\r\n    }\r\n};\r\n<\/pre>\n<p>An alternative to using the method forwarder would be to split the Widget into two parts, one that contains the bulk of the implementation and one that adds the callbacks.<\/p>\n<pre>struct WidgetImpl : IWidget\r\n{\r\n    ...\r\n    HRESULT OnCallback1();\r\n    HRESULT OnCallback2();\r\n    ...\r\n};\r\n\r\nstruct Widget final : WidgetImpl,\r\n    CallbackWrappers&lt;&amp;WidgetImpl::OnCallback1,\r\n                     &amp;WidgetImpl::OnCallback2&gt;\r\n{\r\n};\r\n<\/pre>\n<p>This alternative version solves one problem but adds a new one: How does <code>Widget\u00adImpl<\/code> access the callbacks? One idea is to use the CRTP pattern to allow <code>WidgetImpl<\/code> to cast to its derived type:<\/p>\n<pre>template&lt;typename D&gt;\r\nstruct WidgetImpl : IWidget\r\n{\r\n    ...\r\n    HRESULT OnCallback1();\r\n    HRESULT OnCallback2();\r\n    ...\r\n};\r\n\r\nstruct Widget final : WidgetImpl&lt;Widget&gt;,\r\n    CallbackWrappers&lt;&amp;WidgetImpl&lt;Widget&gt;::OnCallback1,\r\n                     &amp;WidgetImpl&lt;Widget&gt;::OnCallback2&gt;\r\n{\r\n};\r\n<\/pre>\n<p>But this is just about as clunky, so it doesn&#8217;t really save us much.<\/p>\n<p>We&#8217;re nowhere near done yet, because this still doesn&#8217;t work. We&#8217;ll pick up the investigation next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Trying to develop a slightly more efficient multi-headed snake.<\/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-105838","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Trying to develop a slightly more efficient multi-headed snake.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105838","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=105838"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105838\/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=105838"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105838"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105838"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}