My C# method needs to be invoked from C++
Originally my C# method takes a parameter of type double[], but when calling from C++ it becomes a SAFEARRAY
In C++
Continuing on @Liton's answer, I want to stress his last sentence, i.e. ATL's CComSafeArray
. It really can save you a lot of typing. CComSafeArray
has C++ constructors, destructors, operator overloads including one for [ ] that gives you an read / write reference to any element in the SAFEARRAY
. In short, you can really focus on your business logic and needn't worry about the SAFEARRAY
plumbing:
#include <atlbase.h>
#include <atlsafe.h>
// ...
CComSafeArray<double> arr(10);
arr[0] = 2.0;
arr[1] = 3.0;
arr[2] = 5.0;
// ...
At the very least, even if you're not going to use CComSafeArray
it's worthwhile to deconstruct its source code in <atlsafe.h>
giving you better insight on the what, when, why and how on SAFEARRAY
functions.
Following is the code to create a safearray in C++.
#include<oaidl.h>
void CreateSafeArray(SAFEARRAY** saData)
{
double data[10]; // some sample data to write into the created safearray
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = 10;
*saData = SafeArrayCreate(VT_R8, 1, &Bound);
double HUGEP *pdFreq;
HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
// copy sample values from data[] to this safearray
for (DWORD i = 0; i < 10; i++)
{
*pdFreq++ = data[i];
}
SafeArrayUnaccessData(*saData);
}
}
Free the pointer when you are finished like the following code-
SAFEARRAY* saData;
CreateSafeArray(&saData); // Create the safe array
// use the safearray
...
...
// Call the SafeArrayDestroy to destroy the safearray
SafeArrayDestroy(saData);
saData = NULL; // set the pointer to NULL
If you use ATL for C++, then better use CComSafeArray declared in "atlsafe.h". This is wrapper for SAFEARRAY. link text
Passing SAFEARRAYs is not recommended. It is recommended to place the SAFEARRAY into a VARIANT. Further, the SAFEARRAY should hold VARIANT data. This gives the best of all worlds and makes passing VARIANT SAFEARRAY of VARIANTs more useful to other languages. E.g. C++ to VB / C# (Note it is up to the caller to free/destroy the SAFEARRAY)
Building on the previous code
// A VARIANT holding a SAFEARRAY of VARIANTs
VARIANT vRet;
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = 10;
SAFEARRAY * psaData = SafeArrayCreate(VT_VARIANT, 1, &Bound);
VARIANT HUGEP * pData = NULL;
HRESULT hr = SafeArrayAccessData(psaData, (void HUGEP * FAR *)&pData);
if (SUCCEEDED(hr))
{
for (short i = 0; i < 10; ++i,++pData)
{
::VariantInit(pData);
pData->vt = VT_I2;
pData->iVal = i;
}
SafeArrayUnaccessData(psaData);
}
vRet.vt = VT_ARRAY | VT_VARIANT;
vRet.parray = psaData;