{"id":100575,"date":"2018-12-27T07:00:00","date_gmt":"2018-12-27T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=100575"},"modified":"2019-03-13T00:11:37","modified_gmt":"2019-03-13T07:11:37","slug":"20181227-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20181227-00\/?p=100575","title":{"rendered":"<CODE>SHOpenRegStream<\/CODE> does not mix with smart pointers"},"content":{"rendered":"<p>Some time ago, I noted that <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20151023-00\/?p=91291\"><code>Co&shy;Get&shy;Interface&shy;And&shy;Release&shy;Stream<\/code> does not mix with smart pointers<\/a> because it performs an <code>IUnknown::<\/code><code>Release<\/code> of its interface parameter, which messes up all the bookkeeping because smart pointers expect that <i>they<\/i> are the ones which will perform the <code>Release<\/code>. <\/p>\n<p>The other half of the problem is functions like <code>SH&shy;Open&shy;Reg&shy;Stream<\/code> and <code>SH&shy;Open&shy;Reg&shy;Stream2<\/code> which return a COM pointer directly, rather than putting it into an output parameter. When you put them into a smart pointer, the default behavior of the smart pointer is to create a new reference, so it will call <code>AddRef<\/code> upon assignment or construction, and call <code>Release<\/code> upon replacement or destruction. <\/p>\n<pre>\n\/\/ Code in italics is wrong\n\nMicrosoft::WRL::ComPtr&lt;IStream&gt; stream;\n<i>stream = SHOpenRegStream(...);<\/i>\n\nMicrosoft::WRL::ComPtr&lt;IStream&gt; <i>stream(SHOpenRegStream(...));<\/i>\n\nATL::CComPtr&lt;IStream&gt; stream;\n<i>stream = SHOpenRegStream(...);<\/i>\n\nATL::CComPtr&lt;IStream&gt; <i>stream(SHOpenRegStream(...));<\/i>\n\n_com_ptr_t&lt;IStream&gt; stream;\n<i>stream = SHOpenRegStream(...);<\/i>\n\n_com_ptr_t&lt;IStream&gt; <i>stream(SHOpenRegStream(...));<\/i>\n<\/pre>\n<p>All of these operations will take the raw pointer returned by <code>SH&shy;Open&shy;Reg&shy;Stream<\/code>, save it in the smart pointer, and increment the reference count. When the smart pointer is destructed, the reference count will be decremented. <\/p>\n<p>But the object started with a reference count of 1. After storing it in the smart pointer, the reference count is 2, even though there is only one object tracking it. When that object (in this case, the smart pointer) releases its reference, there is still one reference remaining, which nobody is tracking. <\/p>\n<p>You have a memory leak. <\/p>\n<p>The solution is to use the <code>Attach<\/code> method to say, &#8220;Here is an object that I would like you to adopt responsibility for.&#8221; The smart pointer will take the object but will <i>not<\/i> increment the reference count, because you told it, &#8220;I want you to take responsibility for the reference count that I am giving you.&#8221; <\/p>\n<pre>\nMicrosoft::WRL::ComPtr&lt;IStream&gt; stream;\n<font COLOR=\"blue\">stream.Attach(SHOpenRegStream(...));<\/font>\n\nATL::CComPtr&lt;IStream&gt; stream;\n<font COLOR=\"blue\">stream.Attach(SHOpenRegStream(...));<\/font>\n\n_com_ptr_t&lt;IStream&gt; stream;\n<font COLOR=\"blue\">stream.Attach(SHOpenRegStream(...));<\/font>\n\n_com_ptr_t&lt;IStream&gt; stream(SHOpenRegStream(...), <font COLOR=\"blue\">false<\/font>);\n<\/pre>\n<p>The <code>_com_ptr_t<\/code> class has a bonus constructor that takes a boolean parameter that indicates whether the smart pointer should perform an <code>AddRef<\/code> on the pointer. In the case where you want to adopt an existing reference, you pass <code>false<\/code>. <\/p>\n<p>This problem is basically the flip side of the <code>Co&shy;Get&shy;Interface&shy;And&shy;Release&shy;Stream<\/code> problem. Whereas that one results in an over-release, this results in an under-release. <\/p>\n<p>And the root cause of both of them is that they use a calling pattern that doesn&#8217;t conform to COM recommendations. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Old school meets new school, again.<\/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-100575","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, again.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100575","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=100575"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100575\/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=100575"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=100575"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=100575"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}