{"id":105742,"date":"2021-09-29T07:00:00","date_gmt":"2021-09-29T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105742"},"modified":"2021-09-29T06:52:17","modified_gmt":"2021-09-29T13:52:17","slug":"20210929-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210929-00\/?p=105742","title":{"rendered":"The subtleties of <CODE>Create&shy;Stream&shy;On&shy;HGlobal<\/CODE>, part 2: Suppressing the deletion of an unknown <CODE>HGLOBAL<\/CODE>"},"content":{"rendered":"<p>Last time, <a title=\"The subtleties of Create\u00adStream\u00adOn\u00adHGlobal, part 1: Introduction and basic usage\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210928-00\/?p=105737\"> we looked at the easy case of the <code>Create\u00adStream\u00adOn\u00adHGlobal<\/code> function<\/a>, where you just hand an <code>HGLOBAL<\/code> to the stream and wipe your hands of it.<\/p>\n<p>The weird case is where you pass <code>fDelete\u00adOn\u00adRelease = FALSE<\/code>. For now, let&#8217;s look at the case where you pass a null <code>HGLOBAL<\/code>, but also pass <code>fDelete\u00adOn\u00adRelease = FALSE<\/code>, indicating that you want the stream to create its own <code>HGLOBAL<\/code>, but not to destroy it on destruction.<\/p>\n<p>The typical use case for this pattern is where you create a stream, write to it, and then extract all the data in the form of an <code>HGLOBAL<\/code>. To get the <code>HGLOBAL<\/code> back out, you must call <code>Get\u00adHGlobal\u00adFrom\u00adStream<\/code>. If you don&#8217;t do that, then the <code>HGLOBAL<\/code> inside the stream is leaked, and you have no way to rescue it.<\/p>\n<pre>\/\/ First, the version without RAII types.\r\nHGLOBAL CreateHGlobalFromStuff()\r\n{\r\n    HGLOBAL hglob = nullptr;\r\n    IStream* stream = nullptr;\r\n\r\n    if (SUCCEEDED(\r\n        CreateStreamOnHGlobal(nullptr, FALSE, &amp;stream))) {\r\n        if (FAILED(GetHGlobalFromStream(stream, &amp;hglob))) {\r\n            __fastfail(FAST_FAIL_FATAL_APP_EXIT);\r\n        }\r\n        WriteStuffToStream(stream);\r\n        stream-&gt;Release();\r\n    }\r\n    return hglob;\r\n}\r\n\r\nvoid Sample()\r\n{\r\n    HGLOBAL hglob = CreateHGlobalFromStuff();\r\n    if (hglob) {\r\n        DoStuffWith(hglob); \/\/ maybe put it on the clipboard\r\n        GlobalFree(hglob);\r\n    }\r\n}\r\n<\/pre>\n<p>And with RAII:<\/p>\n<pre>wil::unique_hglobal CreateHGlobalFromStuff()\r\n{\r\n    wil::unique_hglobal hglob;\r\n    wil::com_ptr&lt;IStream&gt; stream;\r\n\r\n    THROW_IF_FAILED(\r\n        CreateStreamOnHGlobal(nullptr, FALSE, &amp;stream));\r\n\r\n    FAIL_FAST_IF_FAILED(\r\n        GetHGlobalFromStream(stream.get(), &amp;hglob));\r\n\r\n    WriteStuffToStream(stream.get());\r\n\r\n    return hglob;\r\n}\r\n\r\nvoid Sample()\r\n{\r\n    wil::unique_hglobal = CreateHGlobalFromStuff();\r\n    DoStuffWith(hglob.get()); \/\/ maybe put it on the clipboard\r\n}\r\n<\/pre>\n<p>The idea here is that you create an <code>HGLOBAL<\/code>-based stream with no initial memory block, which means that the stream object creates its own empty one. From that, you immediately get the inner <code>HGLOBAL<\/code> so you can access the data that is being managed. You do this immediately so that the memory block is held in an RAII type so it won&#8217;t be leaked if something goes wrong later.<\/p>\n<p>You then write stuff to the stream, which causes it to go into the <code>HGLOBAL<\/code>. You then throw the stream away and keep the <code>HGLOBAL<\/code>. The stream&#8217;s destruction does not destroy the <code>HGLOBAL<\/code> because you passed <code>fDelete\u00adOn\u00adRelease = FALSE<\/code>.<\/p>\n<p>Note that there is a bit of a scary place: If <code>Get\u00adHGlobal\u00adFrom\u00adStream<\/code> fails, we are kind of stuck. The <code>HGLOBAL<\/code> inside the stream is going to be leaked, and there&#8217;s nothing we can do about it. Fortunately, <code>Get\u00adHGlobal\u00adFrom\u00adStream<\/code> always succeeds if the stream it was given came from the <code>Create\u00adStream\u00adOn\u00adHGlobal<\/code> function.<\/p>\n<p>The caller takes the resulting <code>HGLOBAL<\/code>, does something with it, and then frees the <code>HGLOBAL<\/code>.<\/p>\n<p>It is crucially important that you keep your eye on the stream. You have to be sure that nobody has extended the lifetime of the stream (by calling <code>Add\u00adRef<\/code>), because you just freed the <code>HGLOBAL<\/code>, and any attempt to use the stream beyond that point will be a use-after-free bug.<\/p>\n<p>One mistake people make with passing <code>fDelete\u00adOn\u00adRelease = FALSE<\/code> is forgetting that they are now responsible for freeing the <code>HGLOBAL<\/code> that is inside the stream. If you passed an <code>HGLOBAL<\/code> of <code>NULL<\/code> when creating the stream, then you must call <code>Get\u00adHGlobal\u00adFrom\u00adStream<\/code> to find out what <code>HGLOBAL<\/code> ended up being allocated for the stream, because it&#8217;s your responsibility to free it.<\/p>\n<pre>\/\/ Do not use! This code leaks the global handle.\r\n\r\nIStream* stream;\r\nif (SUCCEEDED(CreateStreamOnHGlobal(nullptr,\r\n        FALSE, &amp;stream)) {\r\n    WriteStuffToStream(stream);\r\n    ReadStuffFromStream(stream);\r\n    stream-&gt;Release();\r\n}\r\n<\/pre>\n<p>This code is under the the mistaken belief that the <code>fDelete\u00adOn\u00adRelease<\/code> parameter controls not whether the stream frees its internal <code>HGLOBAL<\/code> but rather whether it frees the <code>HGLOBAL<\/code> that was passed in. And since they passed <code>nullptr<\/code> as the incoming <code>HGLOBAL<\/code>, they certainly don&#8217;t want the stream to try to free a null pointer. But that&#8217;s not what <code>fDelete\u00adOn\u00adRelease<\/code> means.<\/p>\n<p>In the case where you aren&#8217;t interested in extending the lifetime of the inner <code>HGLOBAL<\/code> beyond the lifetime of the stream, just pass <code>fDelete\u00adOn\u00adRelease = TRUE<\/code> and let the <code>HGLOBAL<\/code> be destroyed as part of the natural destruction of the stream.<\/p>\n<p>Next time, we&#8217;ll look at what happens if you provide an initial <code>HGLOBAL<\/code> and combine it with <code>fDelete\u00adOn\u00adRelease = FALSE<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You don&#8217;t know what it is, but you said you don&#8217;t want it deleted automatically.<\/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-105742","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You don&#8217;t know what it is, but you said you don&#8217;t want it deleted automatically.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105742","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=105742"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105742\/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=105742"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105742"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105742"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}