{"id":328,"date":"2009-07-23T13:44:13","date_gmt":"2009-07-23T11:44:13","guid":{"rendered":"http:\/\/mariusbancila.ro\/blog\/?p=328"},"modified":"2011-05-20T15:56:34","modified_gmt":"2011-05-20T13:56:34","slug":"net-out-string-to-automation-safearray","status":"publish","type":"post","link":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/","title":{"rendered":".NET out string[] to Automation SAFEARRAY**"},"content":{"rendered":"<p>.NET allows you to expose components as COM and consume them from unmanaged code. There are many references on how to this (and you can only start with <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/zsfww439(VS.71).aspx\" target=\"_blank\">MSDN<\/a>), and I will not talk about that part. What I want to explain here is something different. Suppose you have this interface:<\/p>\n<pre name=\"code\" class=\"csharp\">\r\n[Guid(\"2F8433FE-4771-4037-B6B2-ED5F6585ED04\")]\r\n[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]\r\npublic interface IAccounts\r\n{\r\n      [DispId(1)]\r\n      string[] GetUsers();\r\n}\r\n<\/pre>\n<p>Method GetUsers() returns an array on string representing the user names. But what if you also wanted the user passwords or addresses? Since this is exposed as COM, you cannot return an array of User. But you can return multiple arrays of string. So, how would you deal with out string[]? This is what I want to show you in this tutorial.<\/p>\n<p>This is a .NET interface exposed to COM. It has two methods, GetUsers() that returns an array of string representing user names, and GetUsers2() that returns an array of strings as an output parameters and a bool as return type, indicating whether any user was found.<\/p>\n<pre name=\"code\" class=\"csharp\">\r\nnamespace SampleLibrary\r\n{\r\n   [Guid(\"2F8433FE-4771-4037-B6B2-ED5F6585ED04\")]\r\n   [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]\r\n   public interface IAccounts\r\n   {\r\n      [DispId(1)]\r\n      string[] GetUsers();\r\n\r\n      [DispId(2)]\r\n      bool GetUsers2(out string [] users);\r\n   }\r\n}\r\n<\/pre>\n<p>And this is the implementation:<\/p>\n<pre name=\"code\" class=\"csharp\">\r\nnamespace SampleLibrary\r\n{\r\n   [Guid(\"C4713144-5D29-4c65-BF9C-188B1B7CD2B6\")]\r\n   [ClassInterface(ClassInterfaceType.None)]\r\n   [ProgId(\"SampleLibrary.DataQuery\")]\r\n   public class Accounts : IAccounts\r\n   {\r\n      List&lt; string &gt; m_users;\r\n\r\n      public Accounts()\r\n      {\r\n         m_users = new List&lt; string &gt; {\r\n            \"marius.bancila\",\r\n            \"john.doe\",\r\n            \"anna.kepler\"\r\n         };\r\n      }\r\n\r\n      #region IDataQuery Members\r\n\r\n      public string[] GetUsers()\r\n      {\r\n         return m_users.ToArray();\r\n      }\r\n\r\n      public bool GetUsers2(out string[] users)\r\n      {\r\n         users = m_users.ToArray();\r\n\r\n         return users.Length &gt; 0;\r\n      }\r\n\r\n      #endregion\r\n   }\r\n}\r\n<\/pre>\n<p>Note: If you are trying this example make sure you set the ComVisible attribute to true, either for each type or per assembly (in AssemblyInfo.cs)<\/p>\n<pre name=\"code\" class=\"csharp\">\r\n[assembly: ComVisible(true)]\r\n<\/pre>\n<p>Second, you have to check the &#8220;Register for COM interop&#8221; setting in the Build page of the project properties.<\/p>\n<p>The first thing to do in C++ is importing the .TLB file that was generated by regasm.exe.<\/p>\n<pre name=\"code\" class=\"cpp\">\r\n#import \"SampleLibrary.tlb\"\r\nusing namespace SampleLibrary;\r\n<\/pre>\n<p>If we look in the .TLB file, we can see how the IAccounts interface looks like:<\/p>\n<pre name=\"code\" class=\"cpp\">\r\nstruct __declspec(uuid(\"2f8433fe-4771-4037-b6b2-ed5f6585ed04\"))\r\nIAccounts : IDispatch\r\n{\r\n    \/\/\r\n    \/\/ Wrapper methods for error-handling\r\n    \/\/\r\n\r\n    \/\/ Methods:\r\n    SAFEARRAY * GetUsers ( );\r\n    VARIANT_BOOL GetUsers2 (\r\n        SAFEARRAY * * users );\r\n};\r\n<\/pre>\n<p>The following C++ functions, GetUsers1() retrieves the users users list using method GetUsers() from IAccounts. It puts the users in a CStringArray (notice that this container does not have an assignment operator, so the only way to return such an array is with a reference in the parameters list).<\/p>\n<pre name=\"code\" class=\"cpp\">\r\nvoid GetUsers1(CStringArray&amp; arrUsers)\r\n{\r\n   IAccountsPtr pAccounts(__uuidof(Accounts));\r\n\r\n   SAFEARRAY* sarrUsers = pAccounts-&gt;GetUsers();\r\n\r\n   _variant_t varUsers;\r\n   varUsers.parray = sarrUsers;\r\n   varUsers.vt = VT_ARRAY | VT_BSTR;\r\n\r\n   UnpackBstrArray(varUsers, arrUsers);\r\n   SafeArrayDestroy(sarrUsers);\r\n\r\n   pAccounts-&gt;Release();\r\n}\r\n<\/pre>\n<p>UnpackBstrArray() is a function (see below) that extracts the elements of a SAFEARRAY and adds them to a CStringArray.<\/p>\n<p>Function GetUsers2() uses the second method, GetUsers2() from IAccounts. This needs the address of a pointer to a SAFEARRAY (i.e. SAFEARRAY**) that will hold the values returned by the COM method. This time we have to create an empty SAFEARRAY and then pass its address to the COM method. The rest is similar to the previous case.<\/p>\n<pre name=\"code\" class=\"cpp\">\r\nvoid GetUsers2(CStringArray&amp; arrUsers)\r\n{\r\n   IAccountsPtr pAccounts(__uuidof(Accounts));\r\n\r\n   SAFEARRAYBOUND aDim[1];\r\n   aDim[0].lLbound = 0;\r\n   aDim[0].cElements = 0;\r\n\r\n   SAFEARRAY* sarrUsers = SafeArrayCreate(VT_BSTR, 1, aDim);\r\n\r\n   VARIANT_BOOL ret = pAccounts-&gt;GetUsers2(&amp;sarrUsers);\r\n   if(ret != VARIANT_FALSE)\r\n   {\r\n      _variant_t varUsers;\r\n      varUsers.parray = sarrUsers;\r\n      varUsers.vt = VT_ARRAY | VT_BSTR;\r\n      UnpackBstrArray(varUsers, arrUsers);\r\n   }\r\n\r\n   SafeArrayDestroy(sarrUsers);\r\n\r\n   pAccounts-&gt;Release();\r\n}\r\n<\/pre>\n<p>The helper method UnpackBstrArray() used previous looks like this:<\/p>\n<pre name=\"code\" class=\"cpp\">\r\nvoid UnpackBstrArrayHelper(VARIANT* pvarArrayIn, CStringArray* pstrarrValues)\r\n{\r\n   if (!pstrarrValues || !pvarArrayIn || pvarArrayIn->vt == VT_EMPTY)\r\n      return;\r\n\r\n   pstrarrValues-&gt;RemoveAll();\r\n\r\n   VARIANT* pvarArray = pvarArrayIn;\r\n   SAFEARRAY* parrValues = NULL;\r\n\r\n   SAFEARRAYBOUND arrayBounds[1];\r\n   arrayBounds[0].lLbound = 0;\r\n   arrayBounds[0].cElements = 0;\r\n\r\n   if((pvarArray-&gt;vt & (VT_VARIANT|VT_BYREF|VT_ARRAY)) == (VT_VARIANT|VT_BYREF) && \r\n      NULL != pvarArray-&gt;pvarVal && \r\n      (pvarArray-&gt;pvarVal-&gt;vt & VT_ARRAY))\r\n   {\r\n      pvarArray = pvarArray-&gt;pvarVal;\r\n   }\r\n\r\n   if (pvarArray-&gt;vt & VT_ARRAY)\r\n   {\r\n      if (VT_BYREF &amp; pvarArray-&gt;vt)\r\n         parrValues = *pvarArray-&gt;pparray;\r\n      else\r\n         parrValues = pvarArray-&gt;parray;\r\n   }\r\n   else\r\n      return;\r\n\r\n   if (parrValues != NULL)\r\n   {\r\n      HRESULT hr = SafeArrayGetLBound(parrValues, 1, &amp;arrayBounds[0].lLbound);\r\n      hr = SafeArrayGetUBound(parrValues, 1, (long*)&amp;arrayBounds[0].cElements);\r\n      arrayBounds[0].cElements -= arrayBounds[0].lLbound;\r\n      arrayBounds[0].cElements += 1;\r\n   }\r\n\r\n   if (arrayBounds[0].cElements &gt; 0)\r\n   {\r\n      for (ULONG i = 0; i &lt; arrayBounds[0].cElements; i++)\r\n      {\r\n         LONG lIndex = (LONG)i;\r\n         CString strValue = _T(\"\");\r\n\r\n         VARTYPE vType;\r\n         BSTR bstrItem;\r\n\r\n         ::SafeArrayGetVartype(parrValues, &amp;vType);\r\n         HRESULT hr = ::SafeArrayGetElement(parrValues, &amp;lIndex, &amp;bstrItem);\r\n\r\n         if(SUCCEEDED(hr))\r\n         {\r\n            switch(vType)\r\n            {\r\n            case VT_BSTR:\r\n               strValue = (LPCTSTR)bstrItem;\r\n               break;\r\n            }\r\n\r\n            ::SysFreeString(bstrItem);\r\n         }\r\n\r\n         pstrarrValues-&gt;Add(strValue);\r\n      }\r\n   }\r\n}\r\n\r\nvoid UnpackBstrArray( const _variant_t &amp;var, CStringArray &amp;strarrValues  )\r\n{\r\n   UnpackBstrArrayHelper( &amp;(VARIANT)const_cast&lt; _variant_t & &gt;(var), &amp;strarrValues );\r\n}\r\n<\/pre>\n<p>Attached you can find a demo project (C# and C++) with the complete example show in this tutorial.<\/p>\n<div class=\"wp-block-button\">\n<a  data-e-Disable-Page-Transition=\"true\" class=\"dlm-download-link dlm-download-default wp-block-button__link wp-element-button\" title=\"Version 1.0\" href=\"https:\/\/mariusbancila.ro\/blog\/download\/3487\/?tmstv=1792689972\" rel=\"nofollow\" id=\"download-link-3487\" data-redirect=\"false\" >\n\toutput SAFEARRAY** example\t(<span class=\"dlm-download-count-value\">4871 downloads<\/span>\n\t)\n<\/a>\n<\/div>\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET allows you to expose components as COM and consume them from unmanaged code. There are many references on how to this (and you can only start with MSDN), and I will not talk about that part. What I want to explain here is something different. Suppose you have this interface: [Guid(&#8220;2F8433FE-4771-4037-B6B2-ED5F6585ED04&#8221;)] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface &#8230; <a title=\".NET out string[] to Automation SAFEARRAY**\" class=\"read-more\" href=\"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/\" aria-label=\"Read more about .NET out string[] to Automation SAFEARRAY**\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","advgb_blocks_editor_width":"","advgb_blocks_columns_visual_guide":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[11,7,12,38,8],"tags":[454,451,461,453,275,276],"class_list":["post-328","post","type-post","status-publish","format-standard","hentry","category-csharp","category-c","category-mfc","category-tutorials","category-windows-programming","tag-net","tag-c","tag-com","tag-mfc","tag-safearray","tag-tutorial"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Marius Bancila\"\/>\n\t<meta name=\"keywords\" content=\"c#,c++,mfc,.net,safearray,com,tutorial\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Marius Bancila&#039;s Blog | About code. Mostly on C++\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\".NET out string[] to Automation SAFEARRAY**\" \/>\n\t\t<meta property=\"og:description\" content=\"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2009-07-23T11:44:13+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2011-05-20T13:56:34+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:title\" content=\".NET out string[] to Automation SAFEARRAY**\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++.\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#article\",\"name\":\".NET out string[] to Automation SAFEARRAY**\",\"headline\":\".NET out string[] to Automation SAFEARRAY**\",\"author\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#organization\"},\"datePublished\":\"2009-07-23T13:44:13+02:00\",\"dateModified\":\"2011-05-20T15:56:34+02:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#webpage\"},\"articleSection\":\"C#, C++, MFC, Tutorials, Windows Programming, .NET, C++, COM, MFC, SAFEARRAY, tutorial\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/#listItem\",\"name\":\"IT\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/#listItem\",\"position\":2,\"name\":\"IT\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/#listItem\",\"name\":\"Software\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/#listItem\",\"position\":3,\"name\":\"Software\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/net\\\/#listItem\",\"name\":\".NET\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/#listItem\",\"name\":\"IT\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/net\\\/#listItem\",\"position\":4,\"name\":\".NET\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/net\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/net\\\/csharp\\\/#listItem\",\"name\":\"C#\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/#listItem\",\"name\":\"Software\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/net\\\/csharp\\\/#listItem\",\"position\":5,\"name\":\"C#\",\"item\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/net\\\/csharp\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#listItem\",\"name\":\".NET out string[] to Automation SAFEARRAY**\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/net\\\/#listItem\",\"name\":\".NET\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#listItem\",\"position\":6,\"name\":\".NET out string[] to Automation SAFEARRAY**\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/category\\\/it\\\/software\\\/net\\\/csharp\\\/#listItem\",\"name\":\"C#\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#organization\",\"name\":\"Marius Bancila's Blog\",\"description\":\"About code. Mostly on C++\",\"url\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/#author\",\"url\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/\",\"name\":\"Marius Bancila\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a84dd2831d955c38355ddea55df4df260809b88f36408bc14fd4eab8f7f131c9?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Marius Bancila\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#webpage\",\"url\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/\",\"name\":\".NET out string[] to Automation SAFEARRAY**\",\"description\":\"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++.\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/2009\\\/07\\\/23\\\/net-out-string-to-automation-safearray\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/author\\\/admin\\\/#author\"},\"datePublished\":\"2009-07-23T13:44:13+02:00\",\"dateModified\":\"2011-05-20T15:56:34+02:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/\",\"name\":\"Marius Bancila's Blog\",\"description\":\"About code. Mostly on C++\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/mariusbancila.ro\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":".NET out string[] to Automation SAFEARRAY**","description":"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++.","canonical_url":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/","robots":"max-image-preview:large","keywords":"c#,c++,mfc,.net,safearray,com,tutorial","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#article","name":".NET out string[] to Automation SAFEARRAY**","headline":".NET out string[] to Automation SAFEARRAY**","author":{"@id":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/#author"},"publisher":{"@id":"https:\/\/mariusbancila.ro\/blog\/#organization"},"datePublished":"2009-07-23T13:44:13+02:00","dateModified":"2011-05-20T15:56:34+02:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#webpage"},"isPartOf":{"@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#webpage"},"articleSection":"C#, C++, MFC, Tutorials, Windows Programming, .NET, C++, COM, MFC, SAFEARRAY, tutorial"},{"@type":"BreadcrumbList","@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/#listItem","position":1,"name":"Home","item":"https:\/\/mariusbancila.ro\/blog\/","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/#listItem","name":"IT"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/#listItem","position":2,"name":"IT","item":"https:\/\/mariusbancila.ro\/blog\/category\/it\/","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/#listItem","name":"Software"},"previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/#listItem","position":3,"name":"Software","item":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/#listItem","name":".NET"},"previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/#listItem","name":"IT"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/#listItem","position":4,"name":".NET","item":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/csharp\/#listItem","name":"C#"},"previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/#listItem","name":"Software"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/csharp\/#listItem","position":5,"name":"C#","item":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/csharp\/","nextItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#listItem","name":".NET out string[] to Automation SAFEARRAY**"},"previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/#listItem","name":".NET"}},{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#listItem","position":6,"name":".NET out string[] to Automation SAFEARRAY**","previousItem":{"@type":"ListItem","@id":"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/csharp\/#listItem","name":"C#"}}]},{"@type":"Organization","@id":"https:\/\/mariusbancila.ro\/blog\/#organization","name":"Marius Bancila's Blog","description":"About code. Mostly on C++","url":"https:\/\/mariusbancila.ro\/blog\/"},{"@type":"Person","@id":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/#author","url":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/","name":"Marius Bancila","image":{"@type":"ImageObject","@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/a84dd2831d955c38355ddea55df4df260809b88f36408bc14fd4eab8f7f131c9?s=96&d=mm&r=g","width":96,"height":96,"caption":"Marius Bancila"}},{"@type":"WebPage","@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#webpage","url":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/","name":".NET out string[] to Automation SAFEARRAY**","description":"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++.","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/mariusbancila.ro\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/#breadcrumblist"},"author":{"@id":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/#author"},"creator":{"@id":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/#author"},"datePublished":"2009-07-23T13:44:13+02:00","dateModified":"2011-05-20T15:56:34+02:00"},{"@type":"WebSite","@id":"https:\/\/mariusbancila.ro\/blog\/#website","url":"https:\/\/mariusbancila.ro\/blog\/","name":"Marius Bancila's Blog","description":"About code. Mostly on C++","inLanguage":"en-US","publisher":{"@id":"https:\/\/mariusbancila.ro\/blog\/#organization"}}]},"og:locale":"en_US","og:site_name":"Marius Bancila's Blog | About code. Mostly on C++","og:type":"article","og:title":".NET out string[] to Automation SAFEARRAY**","og:description":"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++.","og:url":"https:\/\/mariusbancila.ro\/blog\/2009\/07\/23\/net-out-string-to-automation-safearray\/","article:published_time":"2009-07-23T11:44:13+00:00","article:modified_time":"2011-05-20T13:56:34+00:00","twitter:card":"summary","twitter:title":".NET out string[] to Automation SAFEARRAY**","twitter:description":"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++."},"aioseo_meta_data":{"post_id":"328","title":".NET out string[] to Automation SAFEARRAY**","description":"Consume .NET COM in C++: how to deal with .NET out string[] as automation SAFEARRAY** in C++.","keywords":[{"label":"C#","value":"C#"},{"label":"C++","value":"C++"},{"label":"MFC","value":"MFC"},{"label":".NET","value":".NET"},{"label":"SAFEARRAY","value":"SAFEARRAY"},{"label":"COM","value":"COM"},{"label":"tutorial","value":"tutorial"}],"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"location":null,"local_seo":null,"breadcrumb_settings":null,"limit_modified_date":false,"ai":null,"created":"2021-03-18 21:14:52","updated":"2025-12-12 07:29:19","seo_analyzer_scan_date":null,"focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"author_meta":{"display_name":"Marius Bancila","author_link":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/"},"featured_img":null,"jetpack_publicize_connections":[],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"Marius Bancila","author_link":"https:\/\/mariusbancila.ro\/blog\/author\/admin\/"},"uagb_comment_info":0,"uagb_excerpt":".NET allows you to expose components as COM and consume them from unmanaged code. There are many references on how to this (and you can only start with MSDN), and I will not talk about that part. What I want to explain here is something different. Suppose you have this interface: [Guid(\"2F8433FE-4771-4037-B6B2-ED5F6585ED04\")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface&hellip;","coauthors":[],"tax_additional":{"categories":{"linked":["<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/net\/csharp\/\" class=\"advgb-post-tax-term\">C#<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/\" class=\"advgb-post-tax-term\">C++<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/c\/mfc\/\" class=\"advgb-post-tax-term\">MFC<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/articles_and_tutorials\/tutorials\/\" class=\"advgb-post-tax-term\">Tutorials<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/windows-programming\/\" class=\"advgb-post-tax-term\">Windows Programming<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">C#<\/span>","<span class=\"advgb-post-tax-term\">C++<\/span>","<span class=\"advgb-post-tax-term\">MFC<\/span>","<span class=\"advgb-post-tax-term\">Tutorials<\/span>","<span class=\"advgb-post-tax-term\">Windows Programming<\/span>"]},"tags":{"linked":["<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/windows-programming\/\" class=\"advgb-post-tax-term\">.NET<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/windows-programming\/\" class=\"advgb-post-tax-term\">C++<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/windows-programming\/\" class=\"advgb-post-tax-term\">COM<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/windows-programming\/\" class=\"advgb-post-tax-term\">MFC<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/windows-programming\/\" class=\"advgb-post-tax-term\">SAFEARRAY<\/a>","<a href=\"https:\/\/mariusbancila.ro\/blog\/category\/it\/software\/windows-programming\/\" class=\"advgb-post-tax-term\">tutorial<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">.NET<\/span>","<span class=\"advgb-post-tax-term\">C++<\/span>","<span class=\"advgb-post-tax-term\">COM<\/span>","<span class=\"advgb-post-tax-term\">MFC<\/span>","<span class=\"advgb-post-tax-term\">SAFEARRAY<\/span>","<span class=\"advgb-post-tax-term\">tutorial<\/span>"]}},"comment_count":"0","relative_dates":{"created":"Posted 17 years ago","modified":"Updated 15 years ago"},"absolute_dates":{"created":"Posted on July 23, 2009","modified":"Updated on May 20, 2011"},"absolute_dates_time":{"created":"Posted on July 23, 2009 1:44 pm","modified":"Updated on May 20, 2011 3:56 pm"},"featured_img_caption":"","series_order":"","jetpack_shortlink":"https:\/\/wp.me\/pYNdv-5i","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/posts\/328","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/comments?post=328"}],"version-history":[{"count":7,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/posts\/328\/revisions"}],"predecessor-version":[{"id":1007,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/posts\/328\/revisions\/1007"}],"wp:attachment":[{"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/media?parent=328"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/categories?post=328"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mariusbancila.ro\/blog\/wp-json\/wp\/v2\/tags?post=328"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}