{"id":109336,"date":"2024-01-30T07:00:00","date_gmt":"2024-01-30T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109336"},"modified":"2024-01-30T06:50:48","modified_gmt":"2024-01-30T14:50:48","slug":"20240130-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240130-00\/?p=109336","title":{"rendered":"Smoothing over the differences (and defects) in the various implementations of <CODE>IMemory&shy;Buffer<\/CODE>"},"content":{"rendered":"<p>We saw last time that <a title=\"A comparison of various implementations of the Windows Runtime IMemory\u00adBuffer\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240129-00\/?p=109325\"> each unhappy implementation of <code>IMemory\u00adBuffer<\/code> is unhappy in its own way<\/a>. How can you avoid tripping over all of these differences and defects?<\/p>\n<p>Fortunately, all of the implementations satisfy the following minimum requirements:<\/p>\n<ul>\n<li>The underlying memory is freed when the <code>IMemory\u00adBuffer<\/code> and all <code>IMemory\u00adBuffer\u00adReference<\/code>s have been closed or destructed.<\/li>\n<li>The objects are reliable provided you call only one method at a time.<\/li>\n<\/ul>\n<p>We can operate within these minimum requirements and treat it as an external memory buffer that is wrapped inside our <code>Custom\u00adMemory\u00adBuffer<\/code>.<\/p>\n<pre>winrt::array_view&lt;uint8_t&gt; GetView(\r\n    winrt::IMemoryBufferReference const&amp; reference)\r\n{\r\n    uint8_t* buffer;\r\n    uint32_t size;\r\n    winrt::check_hresult(reference.as&lt;\r\n        ABI::Windows::Foundation::IMemoryBufferByteAccess&gt;()-&gt;\r\n        GetBuffer(&amp;buffer, &amp;size));\r\n    return { buffer, size };\r\n}\r\n<\/pre>\n<p>We start with a generally useful function that obtains the buffer behind an <code>IMemory\u00adBuffer\u00adReference<\/code> and returns it in the form of an <code>array_<wbr \/>view&lt;uint8_t&gt;<\/code>.<\/p>\n<pre>\/\/ Takes ownership of the IMemoryBufferReference\r\nwinrt::IMemoryBuffer WrapAsMemoryBuffer(\r\n    winrt::IMemoryBufferReference const&amp; reference)\r\n{\r\n    return CreateCustomMemoryBuffer(\r\n        GetView(reference),\r\n        [reference]\r\n        {\r\n            reference.Close();\r\n        });\r\n}\r\n<\/pre>\n<p>The <code>Wrap\u00adAs\u00adMemory\u00adBuffer<\/code> method takes an <code>IMemory\u00adBuffer\u00adReference<\/code> and wraps it inside our <code>Custom\u00adMemory\u00adBuffer<\/code>. We call <code>GetView<\/code> only once, and it never happens concurrently with the <code>Close<\/code> of the buffer, so we avoid any multithreaded race conditions.<\/p>\n<p>Basically, we treat <code>IMemory\u00adBuffer\u00adReference<\/code> as just another source of memory with a cleanup function. That the memory source happens to be the same family as the wrapper we are producing is just a coincidence.<\/p>\n<pre>\/\/ Does not take ownership of the IMemoryBuffer\r\nwinrt::IMemoryBuffer WrapMemoryBuffer(\r\n    winrt::IMemoryBuffer const&amp; buffer)\r\n{\r\n    return WrapMemoryBuffer(buffer.CreateReference());\r\n}\r\n<\/pre>\n<p>This overload of <code>Wrap\u00adMemory\u00adBuffer<\/code> uses an <code>IMemory\u00adBuffer<\/code> as the source. It just creates a reference from the <code>IMemory\u00adBuffer<\/code> and then wraps that reference.<\/p>\n<p>Note that the <code>IMemory\u00adBuffer<\/code> overload does not take ownership of the <code>IMemory\u00adBuffer<\/code>, since it never closes it. This is a weird asymmetry that is bound to cause confusion. Maybe it should close the <code>IMemory\u00adBuffer<\/code>?<\/p>\n<pre>\/\/ Takes ownership of the IMemoryBuffer\r\nwinrt::IMemoryBuffer WrapMemoryBuffer(\r\n    winrt::IMemoryBuffer const&amp; buffer)\r\n{\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">auto reference = buffer.CreateReference();<\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">buffer.Close();                           <\/span>\r\n    return WrapMemoryBuffer(reference);\r\n}\r\n<\/pre>\n<p>Alternatively, we can ask WIL to close the buffer.<\/p>\n<pre>\/\/ Takes ownership of the IMemoryBuffer\r\nwinrt::IMemoryBuffer WrapMemoryBuffer(\r\n    winrt::IMemoryBuffer const&amp; buffer)\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">auto close = wil::scope_exit([&amp;] { buffer.Close(); });<\/span>\r\n    return WrapMemoryBuffer(buffer.CreateReference());\r\n}\r\n<\/pre>\n<p>But maybe the function name in both cases should be something like <code>Wrap\u00adMemory\u00adBuffer\u00adAnd\u00adTake\u00adOwnership<\/code>? I&#8217;m not sure. You can decide.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Stick to the part that nobody messes up.<\/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-109336","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Stick to the part that nobody messes up.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109336","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=109336"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109336\/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=109336"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109336"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109336"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}