Is it possible to return an array of defined interface objects from a C++ COM function (VC6) to a VB6 client? I've scoured the web and haven't been able to come across anything that describes what I need to do. I've seen a lot of passing BSTR and VARIANT types, but I need some way to actually have the client side utilise the interface type that I return inside the array.
What I assume I'll need to do
- Use a SAFEARRAY
- Use the SAFEARRAY with the VT_UNKNOWN type, which in turns means I need to place the objects into the array as IUnknown objects.
From here on in I'm stumped. Is it possible to interpret an IUnknown type in VB6, and somehow turn it into the type that I require? Or am I going about this in the complete wrong way...
Clarification:
The interfaces being placed in the collection are being used to mimic a struct. I essentially need to pass back an array of structs.
I've come up with a solution that is suitable for my purposes, despite not being exactly what I set out in the question.
My solution was to create a COM function that takes a SAFEARRAY as a parameter and modifies it, instead of returning a created array. The VB6 client instantiates the array, and passes it to C++ for populating. I envision that future usage will include a precursor function which VB6 calls to determine the required size of the array. For reference, here's the code snippets:
Interface function:
[id(4), helpstring("method PopulateWithStruct")] HRESULT PopulateWithStruct([in,out]SAFEARRAY (IReturnStruct*)*ppArray, [out,retval] long*plResult);
Where IReturnStruct is an interface containing property values, acting as a struct:
interface IReturnStruct : IDispatch
{
[propget, id(1), helpstring("property num1")] HRESULT num1([out, retval] long *pVal);
[propget, id(2), helpstring("property str1")] HRESULT str1([out, retval] BSTR *pVal);
};
And is implemented by ReturnStruct
[
uuid(843870D0-E3B3-4123-82B4-74DE514C33C9),
helpstring("ReturnStruct Class")
]
coclass ReturnStruct
{
[default] interface IReturnStruct;
};
PopulateWithStruct has the following definition:
STDMETHODIMP CCTestInterface::PopulateWithStruct(SAFEARRAY **ppArray, long *plResult)
{
long lLowerBound = -1;
long lUpperBound = -1;
SafeArrayGetLBound(*ppArray, 1, &lLowerBound);
SafeArrayGetUBound(*ppArray, 1, &lUpperBound);
long lArraySize = lUpperBound - lLowerBound;
VARTYPE type;
SafeArrayGetVartype(*ppArray, &type);
if (lArraySize > 0)
{
for ( int i = lLowerBound; i < lUpperBound; ++i)
{
CComPtr<CReturnStruct> pRetStruct;
HRESULT hr = CoCreateInstance(__uuidof(ReturnStruct), NULL, CLSCTX_ALL, __uuidof(IUnknown), reinterpret_cast<void **>(&pRetStruct));
if (SUCCEEDED(hr))
{
pRetStruct->Initialise();
hr = SafeArrayPutElement(*ppArray, (long*)&i, pRetStruct);
if (FAILED(hr))
{
return hr;
}
pRetStruct.Release();
}
}
SafeArrayUnaccessData(*ppArray);
}
*plResult = 1;
return S_OK;
}
On the VB side:
Dim obj As ATL_SERVICETESTLib.CTestInterface
Set obj = New CTestInterface
Dim Result As Long
Dim RetStructs(3) As ReturnStruct
Result = obj.PopulateWithStruct(RetStructs())
Any comments on this approach?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With