{"id":105737,"date":"2021-09-28T07:00:00","date_gmt":"2021-09-28T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105737"},"modified":"2021-09-28T06:35:04","modified_gmt":"2021-09-28T13:35:04","slug":"20210928-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210928-00\/?p=105737","title":{"rendered":"The subtleties of <CODE>Create&shy;Stream&shy;On&shy;HGlobal<\/CODE>, part 1: Introduction and basic usage"},"content":{"rendered":"<p>The <code>Create\u00adStream\u00adOn\u00adHGlobal<\/code> function lets you create a COM <code>IStream<\/code> that uses an <code>HGLOBAL<\/code> memory block as its backing store. It takes two input parameters: an optional <code>HGLOBAL<\/code> that represents the memory block to use, and a flag called <code>fDelete\u00adOn\u00adRelease = FALSE<\/code> that controls whether the stream object frees the <code>HGLOBAL<\/code> when it is destroyed. The initial contents and size of the stream correspond to the initial contents and size of the <code>HGLOBAL<\/code>; if you don&#8217;t pass one, then then the function will create its own from scratch and start with an empty stream.<\/p>\n<p>Sounds simple, right?<\/p>\n<p>It stops being simple when you start exploring the dark corners.<\/p>\n<p>But let&#8217;s start in the brightly-lit area: The normal case where you pass <code>fDelete\u00adOn\u00adRelease = TRUE<\/code>.<\/p>\n<p>Passing <code>fDelete\u00adOn\u00adRelease = TRUE<\/code> represents an ownership transfer. The stream assumes ownership of the <code>HGLOBAL<\/code> you pass in (assuming you passed one at all), and it is free to do with it whatever it likes. When the stream is destroyed, it frees the <code>HGLOBAL<\/code>, too.<\/p>\n<p>The rule in this case is simple: Once you give an <code>HGLOBAL<\/code> to the <code>Create\u00adStream\u00adOn\u00adHGlobal<\/code> function, it&#8217;s not yours any more. Correct usage would be something like this:<\/p>\n<pre>HGLOBAL hglobal = CreateInitialContents();\r\n\r\nIStream* stream = NULL;\r\nif (SUCCEEDED(CreateStreamOnHGlobal(\r\n        hglobal, TRUE, &amp;stream))) {\r\n    hglobal = NULL;     \/\/ Not our HGLOBAL any more\r\n}\r\n<\/pre>\n<p>If you&#8217;re using a smart pointer library, you would perform what is commonly known in Windows as a <code>Detach<\/code> operation, but which the C++ standard library calls <code>release<\/code>, which is not the same as a COM Release, so don&#8217;t get confused.<\/p>\n<pre>wil::unique_hglobal hglobal = CreateInitialContents();\r\n\r\nwil::com_ptr&lt;IStream&gt; stream;\r\nif (SUCCEEDED(CreateStreamOnHGlobal(\r\n        hglobal.get(), TRUE, &amp;stream))) {\r\n    hglobal.release();     \/\/ Not our HGLOBAL any more\r\n}\r\n<\/pre>\n<p>The stream object assumes ownership of the <code>HGLOBAL<\/code> and will treat it as its own personal property. If somebody writes to the stream, it will write to the <code>HGLOBAL<\/code>. If the write extends beyond the end of the <code>HGLOBAL<\/code>, or if somebody calls <code>IStream::SetSize<\/code> to change the size of the stream, then it will resize the <code>HGLOBAL<\/code> correspondingly. But that&#8217;s okay, because you gave up that <code>HGLOBAL<\/code> back when you created the stream. Whatever the stream does with the <code>HGLOBAL<\/code> is no longer your business.<\/p>\n<p>That&#8217;s the easy case.<\/p>\n<p>Next time, we&#8217;ll start looking at the hard case where you pass <code>fDelete\u00adOn\u00adRelease = FALSE<\/code>.<\/p>\n<p><b>Bonus chatter<\/b>: Why does the <code>Create\u00adStream\u00adOn\u00adHGlobal<\/code> function have such dark and shady corners? This function dates back to Windows 3.1, back when a powerful computer had 4MB of memory, and your typical computer had much less. Software development kits cost thousands of dollars, and the expectation was that if you bought one, it was because you were a professional developer who understood how the system worked down to a very low level. Programming was hard because nobody expected it to be easy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Developing the mental model.<\/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-105737","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Developing the mental model.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105737","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=105737"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105737\/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=105737"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105737"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105737"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}