{"id":103398,"date":"2020-02-05T07:00:00","date_gmt":"2020-02-05T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103398"},"modified":"2022-11-24T06:30:23","modified_gmt":"2022-11-24T14:30:23","slug":"20200205-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200205-00\/?p=103398","title":{"rendered":"The various patterns for passing C-style arrays across the Windows Runtime ABI boundary"},"content":{"rendered":"<p>The Windows Runtime supports C-style arrays. These are contiguous blocks of memory that consist of multiple consecutive instances of the same type. (This is not to be confused with a Windows Runtime <i>vector<\/i>, which is an interface that resembles an array but which does not require any particular storage format.)<\/p>\n<p>Arrays are kind of weird, because they aren&#8217;t &#8220;objects&#8221; (there is no identity), but they aren&#8217;t scalars either (they are variable-sized). And there are multiple patterns for passing these arrays across the ABI boundary, depending on who is allocating the memory, whether the size is known to the caller, and whether the memory is being passed into or out of the function.<\/p>\n<ul>\n<li><i>PassArray<\/i>: The caller passes a read-only array, and the implementation reads from it.<\/li>\n<li><i>FillArray<\/i>: The caller passes a write-only array, and the implementation fills it with data.<\/li>\n<li><i>ReceiveArray<\/i>: The implementation allocates a block of memory for the array and the caller receives a pointer to that block of memory, as well as the number of elements in the array.<\/li>\n<\/ul>\n<p>Here&#8217;s a table, since people tend to like tables.<\/p>\n<table style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th rowspan=\"2\">\u00a0<\/th>\n<th rowspan=\"2\">PassArray<\/th>\n<th rowspan=\"2\">FillArray<\/th>\n<th colspan=\"2\">ReceiveArray<\/th>\n<\/tr>\n<tr>\n<th>Parameter<\/th>\n<th>Return value<\/th>\n<\/tr>\n<tr>\n<th>Allocated by<\/th>\n<td>Caller<\/td>\n<td>Caller<\/td>\n<td>Callee<\/td>\n<td>Callee<\/td>\n<\/tr>\n<tr>\n<th>Size<\/th>\n<td>Caller decides<\/td>\n<td>Caller decides<\/td>\n<td>Callee decides<\/td>\n<td>Callee decides<\/td>\n<\/tr>\n<tr>\n<th>Freed by<\/th>\n<td>Caller<\/td>\n<td>Caller<\/td>\n<td>Caller<\/td>\n<td>Caller<\/td>\n<\/tr>\n<tr>\n<th>Allocator<\/th>\n<td>Caller decides<\/td>\n<td>Caller decides<\/td>\n<td>COM allocator<\/td>\n<td>COM allocator<\/td>\n<\/tr>\n<tr>\n<th>Policy<\/th>\n<td>Read-only<\/td>\n<td>Write-only<\/td>\n<td>Write-only<\/td>\n<td>Write-only<\/td>\n<\/tr>\n<tr>\n<th>IDL<\/th>\n<td style=\"font-size: 80%;\"><code>void M(T[] value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0\u00a0ref T[] value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0\u00a0out T[] value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>T[] M();<\/code><\/td>\n<\/tr>\n<tr>\n<th>ABI<\/th>\n<td style=\"font-size: 80%;\"><code>HRESULT M(<br \/>\n              \u00a0\u00a0UINT32 size,<br \/>\n              \u00a0\u00a0_In_reads_(size)<br \/>\n              \u00a0\u00a0T* value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>HRESULT M(<br \/>\n              \u00a0\u00a0UINT32 size,<br \/>\n              \u00a0\u00a0_Out_writes_all_(<br \/>\n              \u00a0\u00a0\u00a0\u00a0size) T* value);<\/code><\/td>\n<td style=\"font-size: 80%;\" colspan=\"2\"><code>HRESULT M(<br \/>\n              \u00a0\u00a0_Out_ UINT32* size,<br \/>\n              \u00a0\u00a0_Outptr_result_buffer_all_(<br \/>\n              \u00a0\u00a0\u00a0\u00a0*size) T** value);<\/code><\/td>\n<\/tr>\n<tr>\n<th>C++\/WinRT<\/th>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0array_view&lt;T const&gt;<br \/>\n\u00a0value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0array_view&lt;T&gt; value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0\u00a0com_array&lt;T&gt;&amp;<br \/>\n\u00a0\u00a0value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>com_array&lt;T&gt; M();<\/code><\/td>\n<\/tr>\n<tr>\n<th>C++\/CX<\/th>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0\u00a0const Array&lt;T&gt;^<br \/>\n\u00a0\u00a0value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0\u00a0WriteOnlyArray&lt;T&gt;^<br \/>\n\u00a0\u00a0value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0\u00a0Array&lt;T&gt;&amp;<br \/>\n\u00a0\u00a0value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>Array&lt;T&gt;^ M();<\/code><\/td>\n<\/tr>\n<tr>\n<th>C#<\/th>\n<td style=\"font-size: 80%;\"><code>void M(T[] value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>void M(T[] value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>void M(<br \/>\n\u00a0\u00a0out T[] value);<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>T[] M();<\/code><\/td>\n<\/tr>\n<tr>\n<th>VB<\/th>\n<td style=\"font-size: 80%;\"><code>Sub M(value As T[])<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>Sub M(value As T[])<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>Sub M(ByRef value<br \/>\n\u00a0\u00a0As T[])<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>Function M()<br \/>\n\u00a0\u00a0As T[]<\/code><\/td>\n<\/tr>\n<tr>\n<th>JS<\/th>\n<td style=\"font-size: 80%;\"><code>function M(value<br \/>\n\u00a0\u00a0: TypedArray)<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>function M(value<br \/>\n\u00a0\u00a0: TypedArray)<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>function M()<br \/>\n\u00a0: TypedArray<\/code><\/td>\n<td style=\"font-size: 80%;\"><code>Function M()<br \/>\n\u00a0: TypedArray<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>I gave the JavaScript prototypes in TypeScript notation so I could annotate the data types. The case of an <code>out<\/code> parameter in JavaScript is a bit more complicated than it looks. I&#8217;ll save that topic for <a title=\"How does JavaScript represent output parameters in the Windows Runtime\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221124-00\/?p=107448\"> another day<\/a>.<\/p>\n<p>Note that in the case of PassArray, the formal parameter at the ABI level is not declared <code>const T*<\/code>, even though the buffer is read-only.<\/p>\n<p><b>Update<\/b>: &#8220;Freed by&#8221; and &#8220;Allocator&#8221; rows <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201203-00\/?p=104507\"> added later<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s not an object, but not a scalar either.<\/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-103398","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It&#8217;s not an object, but not a scalar either.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103398","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=103398"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103398\/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=103398"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103398"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103398"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}