{"id":106757,"date":"2022-06-16T07:00:00","date_gmt":"2022-06-16T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106757"},"modified":"2022-06-16T06:54:11","modified_gmt":"2022-06-16T13:54:11","slug":"20220616-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220616-00\/?p=106757","title":{"rendered":"The skeleton marshaler that does default marshaling"},"content":{"rendered":"<p>Last time, we took <a title=\"An initial look at the mechanics of how COM marshaling is performed\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220615-00\/?p=106753\"> an initial look at the mechanics of how COM marshaling is performed<\/a>. Today, we&#8217;ll build a custom marshaler that provides no custom behavior. This sounds silly, but it&#8217;s useful because we can use it as a starting point for custom behavior.<\/p>\n<pre>struct MyClass : public IMarshal \/* ... and other interfaces *\/\r\n{\r\n    \/\/ QueryInterface, AddRef, and Release left as an exercise\r\n\r\n    IUnknown* CastToUnknown() { return static_cast&lt;IMarshal*&gt;(this); }\r\n\r\n    STDMETHODIMP GetUnmarshalClass(\r\n        REFIID riid, void* pv, DWORD dwDestContext,\r\n        void* pvDestContext, DWORD mshlflags,\r\n        CLSID *clsid)\r\n    {\r\n        ComPtr&lt;IMarshal&gt; marshal;\r\n        RETURN_IF_FAILED(CoGetStandardMarshal(riid, CastToUnknown(), dwDestContext,\r\n                                              pvDestContext, mshlflags, &amp;marshal));\r\n        RETURN_IF_FAILED(marshal-&gt;GetUnmarshalClass(riid, pv, dwDestContext,\r\n                                              pvDestContext, mshlflags, clsid));\r\n        return S_OK;\r\n    }\r\n\r\n    STDMETHODIMP GetMarshalSizeMax(\r\n        REFIID riid, void* pv, DWORD dwDestContext,\r\n        void* pvDestContext, DWORD mshlflags,\r\n        LPDWORD size)\r\n    {\r\n        ComPtr&lt;IMarshal&gt; marshal;\r\n        RETURN_IF_FAILED(CoGetStandardMarshal(riid, CastToUnknown(), dwDestContext,\r\n                                              pvDestContext, mshlflags, &amp;marshal));\r\n        RETURN_IF_FAILED(marshal-&gt;GetMarshalSizeMax(riid, pv, dwDestContext,\r\n                                              pvDestContext, mshlflags, size));\r\n        return S_OK;\r\n    }\r\n\r\n    STDMETHODIMP MarshalInterface(\r\n        IStream* pstm,\r\n        REFIID riid, void* pv, DWORD dwDestContext,\r\n        void* pvDestContext, DWORD mshlflags)\r\n    {\r\n        ComPtr&lt;IMarshal&gt; marshal;\r\n        RETURN_IF_FAILED(CoGetStandardMarshal(riid, CastToUnknown(), dwDestContext,\r\n                                              pvDestContext, mshlflags, &amp;marshal));\r\n        RETURN_IF_FAILED(marshal-&gt;MarshalInterface(pstm, riid, pv, dwDestContext,\r\n                                              pvDestContext, mshlflags));\r\n        return S_OK;\r\n    }\r\n<\/pre>\n<p>The interfaces on the marshaling side ask the system, &#8220;Hey, what marshaler would you have used for this object if it didn&#8217;t do custom marshaling?&#8221;\u00b9 The <code>MyClass<\/code> object will probably implement interfaces beyond <code>IMarshal<\/code>, so we can&#8217;t just pass <code>this<\/code> because that will result in an ambiguous conversion. We provide a custom <code>CastToUnknown()<\/code> method that picks one of the <code>IUnknown*<\/code> base classes arbitrarily. If you&#8217;re using WRL, then the <code>CastToUnknown()<\/code> method has been provided for you; otherwise, you get to write one of your own.\u00b2<\/p>\n<p>The methods on the unmarshaling and cleanup side are even simpler: Your unmarshaling and cleanup functions will never be called, because the unmarshaling and cleanup are performed by the unmarshal class, which we delegated to the standard marshaler. Therefore, you can just return &#8220;Huh? Shouldn&#8217;t ever get here.&#8221;<\/p>\n<pre>    STDMETHODIMP UnmarshalInterface(IStream* pstm, REFIID riid, void** ppv)\r\n    {\r\n        *ppv = nullptr;\r\n        return E_UNEXPECTED;\r\n    }\r\n\r\n    STDMETHODIMP ReleaseMarshalData(IStream* pstm)\r\n    {\r\n        return E_UNEXPECTED;\r\n    }\r\n\r\n    STDMETHODIMP DisconnectObject(DWORD dwReserved)\r\n    {\r\n        return E_UNEXPECTED;\r\n    }\r\n};\r\n<\/pre>\n<p>Next time, we&#8217;ll take this skeleton and use it to implement marshal-by-value.<\/p>\n<p>\u00b9 The <code>Co\u00adGet\u00adStandard\u00adMarshal<\/code> function probes the provided object&#8217;s unmarshal class, which creates recursion because it will call <code>Get\u00adUnmarshal\u00adClass<\/code> again, which we delegate back out to the standard marshaler. Fortunately, the system has a recursion detector and figures that if the call to the <code>Co\u00adGet\u00adStandard\u00adMarshal<\/code> function, then the object&#8217;s <code>IMarshal<\/code> is just trying to delegate to the standard one.<\/p>\n<p>\u00b2 You are probably not going to implement any interfaces that derive from <code>IMarshal<\/code>, so the version provided here will probably work fine: The cast to <code>IMarshal*<\/code> is almost certainly unambiguous. However, I hid it inside a call to <code>CastToUnknown<\/code> so that it won&#8217;t look like I&#8217;m saying &#8220;Oh, the second parameter to <code>Co\u00adGet\u00adStandard\u00adMarshal<\/code> must be an <code>IMarshal*<\/code>. It doesn&#8217;t. It just needs to be an <code>IUnknown*<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Starting with a marshaler that has no special features.<\/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-106757","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Starting with a marshaler that has no special features.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106757","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=106757"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106757\/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=106757"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106757"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106757"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}