{"id":112025,"date":"2026-01-30T07:00:00","date_gmt":"2026-01-30T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112025"},"modified":"2026-01-30T15:02:46","modified_gmt":"2026-01-30T23:02:46","slug":"20260130-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260130-00\/?p=112025","title":{"rendered":"Why not store the <CODE>SAFEARRAY<\/CODE> reference count as a hidden allocation next to the <CODE>SAFEARRAY<\/CODE>?"},"content":{"rendered":"<p>When I described <a title=\"A digression on the design and implementation of SafeArrayAddRef and extending APIs in general\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260127-00\/?p=112018\"> how <code>Safe\u00adArray\u00adAdd\u00adRef<\/code> keeps its reference count in a side table<\/a>, commenter Koro Unhallowed wondered <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260127-00\/?p=112018&amp;commentid=143776#comment-143776\"> why we couldn&#8217;t store the reference count either before or after the formal <code>SAFEARRAY<\/code> structure<\/a>. Commenter Peter Cooper Jr. suspected that <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260127-00\/?p=112018&amp;commentid=143779#comment-143779\"> there might be cases where applications assumed how much memory a <code>SAFEARRAY<\/code> occupied<\/a>.<\/p>\n<p>And indeed that is the case.<\/p>\n<p>Not all <code>SAFEARRAY<\/code>s are created by the <code>Safe\u00adArray\u00adCreate<\/code> function. I&#8217;ve seen code that declared and filled out their own <code>SAFEARRAY<\/code> structure. In those cases, the code allocates exactly <code>sizeof(SAFEARRAY)<\/code> bytes and doesn&#8217;t allocate any bonus data for the reference count.<\/p>\n<p>Indeed, there three flags <a href=\"https:\/\/learn.microsoft.com\/windows\/win32\/api\/oaidl\/ns-oaidl-safearray\"> in the <code>fFeatures<\/code> member<\/a> for these &#8220;bring your own <code>SAFEARRAY<\/code>&#8221; structures.<\/p>\n<table class=\"cp3\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><code>FADF_AUTO<\/code><\/td>\n<td>An array that is allocated on the stack.<\/td>\n<\/tr>\n<tr>\n<td><code>FADF_STATIC<\/code><\/td>\n<td>An array that is statically allocated.<\/td>\n<\/tr>\n<tr>\n<td><code>FADF_EMBEDDED<\/code><\/td>\n<td>An array that is embedded in a structure.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>These flag indicate that the array was not created by <code>Safe\u00adArray\u00adCreate<\/code> but rather was constructed manually by the caller in various ways.\u00b9<\/p>\n<p>Note that if you pass a <code>SAFEARRAY<\/code> with one these flags to <code>Safe\u00adArray\u00adAdd\u00adRef<\/code>, it will still increment the reference count, but you don&#8217;t get a data pointer back because the caller does not control the lifetime of the <code>SAFEARRAY<\/code>. The lifetime of the <code>SAFEARRAY<\/code> is controlled by the lifetime of the <code>SAFEARRAY<\/code> variable on the stack (<code>FADF_AUTO<\/code>), in the DLL&#8217;s global data segment (<code>FADF_STATIC<\/code>), or in the enclosing object (<code>FADF_EMBEDDED<\/code>).<\/p>\n<p>This means that our earlier suggestion to wrap the <code>SAFEARRAY<\/code> inside an in\/out <code>VARIANT<\/code> runs into trouble if the <code>SAFEARRAY<\/code> is one of these types of arrays with externally-controlled lifetime. For those, you have no choice but to copy the data.<\/p>\n<p>\u00b9 The documentation is, however, ambiguous about what &#8220;the array&#8221; refers to. Is it referring to the <code>SAFEARRAY<\/code> structure itself? Or is it referring to the data pointed to by the <code>pvData<\/code> member?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The case of &#8220;Bring your own <CODE>SAFEARRAY<\/CODE>.&#8221;<\/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-112025","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The case of &#8220;Bring your own <CODE>SAFEARRAY<\/CODE>.&#8221;<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112025","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=112025"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112025\/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=112025"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112025"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112025"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}