{"id":112023,"date":"2026-01-29T07:00:00","date_gmt":"2026-01-29T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112023"},"modified":"2026-01-29T08:56:56","modified_gmt":"2026-01-29T16:56:56","slug":"20260129-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260129-00\/?p=112023\/","title":{"rendered":"How can I retain access to the data in a <CODE>SAFEARRAY<\/CODE> after my method returns?"},"content":{"rendered":"<p>The original problem our customer had was that <a title=\"Why did I lose the data even though I called SafeArrayAddRef?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260128-00\/?p=112021\"> the data in a <code>SAFEARRAY<\/code> disappeared even though they had called <code>Safe\u00adArray\u00adAdd\u00adRef<\/code><\/a>. We learned why this is the case, but we still have to solve the customer&#8217;s problem: How can they extend the lifetime of a <code>SAFEARRAY<\/code> beyond the method that received it?<\/p>\n<p>The <code>SAFEARRAY<\/code> is a unique-owner object. Once the owner calls <code>Safe\u00adArray\u00adDestroy<\/code>, the array is gone. You can extend the lifetime of the memory with <code>Safe\u00adArray\u00adAdd\u00adRef<\/code>, but the data itself has vanished. The purpose of extending the lifetime of the memory is not to let you keep using the array, but rather to avoid accessing freed memory in case an array is destroyed out from under you.<\/p>\n<p>If you don&#8217;t want the owner to call <code>Safe\u00adArray\u00adDestroy<\/code>, you have to convince the current owner to let you take ownership. Then <i>you<\/i> become the one responsible for calling <code>Safe\u00adArray\u00adDestroy<\/code>, and you can do that when you are finished with the array.<\/p>\n<p>One way I thought of was to have the caller pass a <code>VARIANT<\/code> as an in\/out parameter. On the way in, it contains a <code>SAFEARRAY<\/code>. You can then detach the <code>parray<\/code> from the variant and reset the variant&#8217;s type to <code>VT_EMPTY<\/code>. Detaching the <code>parray<\/code> lets you take ownership of the array, and setting the type to <code>VT_EMPTY<\/code> tells the caller that it no longer has an array.<\/p>\n<p>Recall that the original intent was to allow the method to continue operating on the array after returning, while still avoiding the cost of having to create a separate copy of the array. Taking the parameter as an in\/out variant makes it clear that the method might decide to change the array to something else, so if the caller still needs the data in the array, it had better pass a copy of the data, so that it can still use the original. So in that case, you didn&#8217;t really avoid the copy; you simply moved the copy into the caller. But in the case that the caller was going to destroy the array anyway, it could put the array in the variant, and if the method destroys the array as part of the method call, then no big deal. The array was getting destroyed anyway.<\/p>\n<p>This isn&#8217;t a great solution, but at least it&#8217;s something.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Find a way to take ownership.<\/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-112023","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Find a way to take ownership.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112023","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=112023"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112023\/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=112023"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112023"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112023"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}