How to return String-Arrays from C++ COM component to C#?

Want to return an array of strings from native COM component to managed code?

You need to declare the string array as SAFEARRAY(VARIANT) in the COM code.

IDL for the function that returns the array of strings for the COM component would look like,

      [id(1)] HRESULT GetStringArray([out] SAFEARRAY(VARIANT)* StrArray);

The C++ implementation of the function should create a Safe Array of variants and initialize each variant with a BSTR as shown below:

STDMETHODIMP CNativeCOMComponent::GetStringArray(SAFEARRAY** pStrArray)
{
   SAFEARRAYBOUND bounds[] = {{2, 0}}; //Array Contains 2 Elements starting from Index '0'

   SAFEARRAY* pSA = SafeArrayCreate(VT_VARIANT,1,bounds); //Create a one-dimensional SafeArray of variants

   long lIndex[1];

   VARIANT var;

   lIndex[0] = 0; // index of the element being inserted in the array

   var.vt = VT_BSTR; // type of the element being inserted

   var.bstrVal = ::SysAllocStringLen( L"The First String", 16 ); // the value of the element being inserted

   HRESULT hr= SafeArrayPutElement(pSA, lIndex, &var); // insert the element

   // repeat the insertion for one more element (at index 1)

   lIndex[0] = 1;

   var.vt = VT_BSTR;

   var.bstrVal = ::SysAllocStringLen( L"The Second String", 17 );

   hr = SafeArrayPutElement(pSA, lIndex, &var);

   *pStrArray = pSA;

   return S_OK;
}

In the above sample we are inserting two BSTR variants into the created Safe Array. Once the Array is filled with the variants (of type VT_BSTR), it can be retrieved from the C# managed code as shown below:

{
   CNativeCOMComponent ComObj = new CNativeCOMComponent();

   Array arr;

   ComObj.GetStringArray(out arr); //arr would now hold the two strings we have sent from the COM code
}

Comments

  • Anonymous
    December 16, 2009
    Excellent!!! Thanks - I was trying to figure out this from last 1 day. You saved lot of my time. Thanks alot!!!!

  • Anonymous
    November 10, 2013
    I have a c++ method as void getVariant(VARIANT vt); { if(vt!=NULL) { int len =sizeof(VARIANT); vt = (VARIANT)CoTaskMemAlloc(sizeof(VARIANT)); VariantInit(vt); vt->vt=VT_ARRAY|VT_R8|VT_BYREF;//VT_R8; SAFEARRAY psa=NULL; //double data[10]; // some sample data to write into the created safearray SAFEARRAYBOUND  Bound; Bound.lLbound   = 0; Bound.cElements = 10; psa = SafeArrayCreate(VT_R8, 1, &Bound); double HUGEP pdFreq; HRESULT hr = SafeArrayAccessData(psa, (void HUGEP FAR)&pdFreq); if (SUCCEEDED(hr)) { // copy sample values from data[] to this safearray for (DWORD i = 0; i < 10; i++) { *pdFreq++ =2.5; } } vt->parray=psa; } } in C# how to get this done and how to get the values on invoking this method. I have tried this but could not get result

  1.   object obj = new object();     getVariant(ref obj); 2.object obj;   getVariant(out obj);
  • Anonymous
    May 20, 2014
    Thanks a ton. This could is still usable today, and is flawless. Thanks a lot again. I was really stuck with this issue from morning.