{"id":91291,"date":"2015-10-23T07:00:00","date_gmt":"2015-10-23T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20151023-00\/?p=91291\/"},"modified":"2019-03-13T12:20:59","modified_gmt":"2019-03-13T19:20:59","slug":"20151023-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20151023-00\/?p=91291","title":{"rendered":"CoGetInterfaceAndReleaseStream does not mix with smart pointers"},"content":{"rendered":"<p>One horrible gotcha of the <code>Co&shy;Get&shy;Interface&shy;And&shy;Release&shy;Stream<\/code> function is that <i>it releases the stream<\/i>. This is a holdover from the old days before smart pointers. The function released the stream to save you from having to call <code>Release<\/code> yourself. But nowadays, everybody is using smart pointers, so you never had to type <code>Release<\/code> to begin with. The problem is that you can fall into a double-<code>Release<\/code> situation without realizing it. <\/p>\n<pre>\n\/\/ Code in italics is wrong\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  Microsoft::WRL::ComPtr&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  <i>CoGetInterfaceAndReleaseStream(stream.Get(), iid, ppv);<\/i>\n}\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  ATL::CComPtr&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  <i>CoGetInterfaceAndReleaseStream(stream, iid, ppv);<\/i>\n}\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  _com_ptr_t&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  <i>CoGetInterfaceAndReleaseStream(stream, iid, ppv);<\/i>\n}\n\nstruct Releaser\n{\n    void operator()(IUnknown* p) { if (p) p-&gt;Release(); }\n};\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  IStream* rawStream;\n  GetTheStream(&amp;rawStream);\n  std::unique_ptr&lt;IStream, Releaser&gt; stream(rawStream);\n  <i>CoGetInterfaceAndReleaseStream(stream.get(), iid, ppv);<\/i>\n}\n<\/pre>\n<p>All of the code fragments above look completely natural, and they all have a bug because the smart pointer object <code>stream<\/code> is going to call <code>Release<\/code> at destruction, which will double-release the pointer because <code>Co&shy;Get&shy;Interface&shy;And&shy;Release&shy;Stream<\/code> <i>already released it<\/i>. <\/p>\n<p>This type of bug is really hard to track down. <\/p>\n<p>One way to fix this is to call the function and tell the smart pointer class that you are transferring ownership of the stream to the function. <\/p>\n<pre>\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  Microsoft::WRL::ComPtr&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  CoGetInterfaceAndReleaseStream(<font COLOR=\"blue\">stream.Detach()<\/font>, iid, ppv);\n}\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  ATL::CComPtr&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  CoGetInterfaceAndReleaseStream(<font COLOR=\"blue\">stream.Detach()<\/font>, iid, ppv);\n}\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  _com_ptr_t&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  CoGetInterfaceAndReleaseStream(<font COLOR=\"blue\">stream.Detach()<\/font>, iid, ppv);\n}\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  IStream* rawStream;\n  GetTheStream(&amp;rawStream);\n  std::unique_ptr&lt;IStream, Releaser&gt; stream(rawStream);\n  CoGetInterfaceAndReleaseStream(<font COLOR=\"blue\">stream.release()<\/font>, iid, ppv);\n}\n<\/pre>\n<p>Another way to fix this is to simply stop using <code>Co&shy;Get&shy;Interface&shy;And&shy;Release&shy;Stream<\/code> with smart pointers, because the function was designed for dumb pointers. For smart pointers, use <code>Co&shy;Unmarshal&shy;Interface<\/code>. <\/p>\n<pre>\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  Microsoft::WRL::ComPtr&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  <font COLOR=\"blue\">CoUnmarshalInterface<\/font>(stream.Get(), iid, ppv);\n}\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  ATL::CComPtr&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  <font COLOR=\"blue\">CoUnmarshalInterface<\/font>(stream, iid, ppv);\n}\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  _com_ptr_t&lt;IStream&gt; stream;\n  GetTheStream(&amp;stream);\n  <font COLOR=\"blue\">CoUnmarshalInterface<\/font>(stream, iid, ppv);\n}\n\nvoid GetTheInterface(REFIID iid, void** ppv)\n{\n  IStream* rawStream;\n  GetTheStream(&amp;rawStream);\n  std::unique_ptr&lt;IStream, Releaser&gt; stream(rawStream);\n  <font COLOR=\"blue\">CoUnmarshalInterface<\/font>(stream.get(), iid, ppv);\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Old school meets new school.<\/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-91291","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Old school meets new school.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91291","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=91291"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91291\/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=91291"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=91291"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=91291"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}