{"id":93675,"date":"2016-06-15T07:00:00","date_gmt":"2016-06-15T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=93675"},"modified":"2019-03-13T11:51:02","modified_gmt":"2019-03-13T18:51:02","slug":"20160615-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160615-00\/?p=93675","title":{"rendered":"Raymond&#8217;s complete guide to HSTRING semantics"},"content":{"rendered":"<p>The title of today&#8217;s article is <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/ericlippert\/2003\/09\/12\/erics-complete-guide-to-bstr-semantics\/\">a blatant ripoff of Eric Lippert&#8217;s complete guide to BSTR semantics<\/a>. <\/p>\n<p>I&#8217;m going to start with a lie: An <code>HSTRING<\/code> is a reference-counted Unicode string. <\/p>\n<p>Work with me here. <\/p>\n<p>The string is immutable, and it uses the UTF-16LE encoding, as is traditional in Windows. <\/p>\n<p>Here are the basic operations on <code>HSTRING<\/code>s: <\/p>\n<p><b>WindowsCreateString<\/b> creates an <code>HSTRING<\/code> from a UTF-16LE-encoded buffer and a specified length. The buffer does not require a terminating null. If the buffer contains embedded null characters, then the resulting <code>HSTRING<\/code> will have embedded null characters. (In particular, if you pass a null-terminated string and you include the null terminator in the length, then the resulting string has an embedded null character. Note also that the length is in <code>wchar_t<\/code> code units, not in bytes.) <\/p>\n<p><b>WindowsDuplicateString<\/b> increments the reference count on an <code>HSTRING<\/code>, and returns a new <code>HSTRING<\/code> which you should use to refer to the string. <\/p>\n<p><b>WindowsDeleteString<\/b> decrements the reference count on an <code>HSTRING<\/code>. If the reference count drops to zero, then the string is destroyed. You shouldn&#8217;t use the <code>HSTRING<\/code> after passing it to <b>WindowsDeleteString<\/b>. <\/p>\n<p>There are a small number of string manipulation functions like <b>WindowsSubstring<\/b> and <b>WindowsConcatString<\/b> which create new strings from old strings. The set of operations is rather limited, however. If you want to perform fancy operations on <code>HSTRING<\/code>s, you&#8217;ll probably need to do them yourself. (Of course, if you&#8217;re using a projected language, the <code>HSTRING<\/code> will project as something closer to what your projected language operates on natively, at which point you will most likely have a rich collection of library functions available to do advanced manipulations.) <\/p>\n<p>To access the characters in the <code>HSTRING<\/code>, use the <b>WindowsGetStringRawBuffer<\/b> function, which gives you two things: The return value is a pointer to the first character in the <code>HSTRING<\/code>, and the optional output parameter is the number of code units. The buffer should be treated as read-only because <code>HSTRING<\/code>s are immutable. <\/p>\n<p>The string contents in the buffer are always followed by a null character (which doesn&#8217;t count toward the string length); as a result, you can treat the string buffer as if it were a null-terminated string and get away with it most of the time. <\/p>\n<p>The time you don&#8217;t get away with it is if the string contains embedded null characters. In that case, treating it as a null-terminated string will stop prematurely, mistaking the embedded null for the terminal null. You can use the <b>WindowsStringHasEmbeddedNull<\/b> function to detect whether an <code>HSTRING<\/code> contains an embedded null and reject the operation if you don&#8217;t support embedded nulls. <\/p>\n<p>One of the special rules for <code>HSTRING<\/code> is similar to the corresponding rule for <code>BSTR<\/code>, namely that a null pointer is equivalent to a zero-length string. But <code>HSTRING<\/code> takes it further: Not only is a null pointer equivalent to a zero-length string, but in fact a null pointer <i>is<\/i> the representation of a zero-length string. In other words, if you call <b>WindowsCreateString<\/b> and specify that the string has length zero, then out will come a null pointer. It is legal to assume that a non-null <code>HSTRING<\/code> represents a non-empty string. Conversely, it is legal to test an <code>HSTRING<\/code> against a null pointer to see whether the string is empty. <\/p>\n<p>Okay, so now I cop to the lie: An <code>HSTRING<\/code> is not always a reference-counted string. <\/p>\n<p>There are these things called <a HREF=\"https:\/\/disneyland.disney.go.com\/guest-services\/fastpass\/\">fast-pass<\/a> strings. Fast-pass strings are <code>HSTRING<\/code>s that involve no memory allocation. If you have a buffer that you want to turn into an <code>HSTRING<\/code>, and you promise not to modify the buffer for the lifetime of your <code>HSTRING<\/code>, then you can use the <b>WindowsCreateStringReference<\/b> function to create an <code>HSTRING<\/code> <i>around<\/i> your buffer. The resulting <code>HSTRING<\/code> is a legal <code>HSTRING<\/code>, but instead of allocating memory on the heap for a reference-counted object, it uses the <code>HSTRING_HEADER<\/code> structure which you passed to the <b>WindowsCreateStringReference<\/b> function to store the metadata, and it uses the buffer you passed to the function to store the string contents. <\/p>\n<p>It&#8217;s called a fast-pass string because this special string doesn&#8217;t require any memory allocation, and no data copying occurs. <\/p>\n<p>When you are finished with a fast-pass string, you just abandon the <code>HSTRING<\/code>. The underlying memory for the fast-pass string was provided by you, so you are still on the hook for freeing that memory as appropriate. <\/p>\n<p>The existence of fast-pass strings explains why the <b>WindowsDuplicateString<\/b> function returns you another <code>HSTRING<\/code>: If the original string is fast-pass, then the <b>WindowsDuplicateString<\/b> function needs to convert it to a true reference-counted heap-allocated object, and then it returns an <code>HSTRING<\/code> to that heap-allocated string. (On the other hand, if the <code>HSTRING<\/code> is already a heap-allocated string with a reference count, then the <b>WindowsDuplicateString<\/b> function merely increments the reference count and returns the same <code>HSTRING<\/code> back.)&sup1; <\/p>\n<p>The rules for managing <code>HSTRING<\/code>s therefore go like this: <\/p>\n<ul>\n<li>If you receive an <code>HSTRING<\/code> as a function parameter,     you are welcome to use it as-is until your function returns,     but don&#8217;t call <b>WindowsDeleteString<\/b> on that string,     because you are not the owner of the string.     It was merely lent to you.     (This is the same rule that applies to COM reference counts.)&sup2; \n<li>If you need to keep using the <code>HSTRING<\/code> after the function     returns (say, because you&#8217;re saving it in a member variable),     you must use <code>WindowsDuplicateString<\/code>     and use the duplicate. \n<li>Each call to <b>WindowsCreateString<\/b> or     <b>WindowsDuplicateString<\/b> (or one of the helper functions     that creates a string) should be matched to exactly one     call to <b>WindowsDeleteString<\/b> which is passed the same handle     that <b>WindowsCreateString<\/b> or <b>WindowsDuplicateString<\/b>     returned. <\/ul>\n<p>You can think of fast-pass strings as lazy-heap-allocated strings: They get copied to the heap only if somebody needs to extend the lifetime of the string beyond the lifetime of the function. <\/p>\n<p>The WRL library has wrapper classes for <code>HSTRING<\/code>s: The <code>HString<\/code> class manages an <code>HSTRING<\/code>, and the <code>HStringReference<\/code> manages a fast-pass <code>HSTRING<\/code>. <\/p>\n<p>&sup1; In theory, a debugging version of the <b>WindowsDuplicateString<\/b> function could create a full duplicate of the string anyway. That way, when you have an <code>HSTRING<\/code> leak, you can use heap leak tools to find the code that duplicated the string and failed to destroy it. I don&#8217;t know if this theory actually occurs in practice. <\/p>\n<p>&sup2; COM violates its own rule with the <code>Co&shy;Get&shy;Interface&shy;And&shy;Release&shy;Stream<\/code> function, <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20151023-00\/?p=91291\">and that lapse came back to bite us<\/a>. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s reference-counted, except when it isn&#8217;t.<\/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-93675","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It&#8217;s reference-counted, except when it isn&#8217;t.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93675","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=93675"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93675\/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=93675"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=93675"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=93675"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}