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 (3)
  1. unknown says:

    Excellent!!!

    Thanks – I was trying to figure out this from last 1 day. You saved lot of my time. Thanks alot!!!!

  2. Hari says:

    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);

  3. SAN says:

    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.

Comments are closed.

Skip to main content