COM SAFEARRAY of GUID's returned from C++ to C#
I'm currently running into an issue of needing开发者_Go百科 to pass a SAFEARRAY(GUID) as a return value from C++ to C#.
Currently the C# side is using an Interop dll generated from Tlbimp.exe (Type Library Importer).
The IDL is:
HRESULT GetGuids(
[out]SAFEARRAY(GUID)* guids);
I've also tried [out, retval]
The function signature is:
HRESULT
WINAPI
MyClass::GetGuids(SAFEARRAY** guids)
If I use SafeArrayCreate()
or SafeArrayCreateVector()
:
SAFEARRAY* psa
psa = SafeArrayCreate(VT_CLSID, 1, rgsabound);
I get a NULL SAFEARRAY
pointer, which is supposed to indicate E_OUTOFMEMORY
which is incorrect.
What I did find was that VT_CLSID
is only for Ole property sets and not SAFEARRAY's:
http://poi.apache.org/apidocs/org/apache/poi/hpsf/Variant.html Its indicated that CLSID is
I've also tried the alternate means of constructing the safe array with:
SafeArrayAllocDescriptor()
and SafeArrayAllocData()
.
hResult = SafeArrayAllocDescriptor(1, guids)
hResult = SafeArrayAllocData(*guids);
This lets me create the array, but when populating it with SafeArrayPutElement()
I get an HRESULT of 0x80070057 (The parameter is incorrect). This is probably due to the fact it takes the VT_CLSID
parameter as well
I can populate it manually with SafeArrayAccessData()
GUID* pData = NULL;
hResult = SafeArrayAccessData(*guids, (void**)&pData);
but I get an error from the C# side: "The value does not fall within the expected Range"
I'm not sure how to accomplish the desired functionality of returning a SAFEARRAY(GUID) to C# either by a retval or out parameter.
It seems it should be simple - there are many areas in the IDL where I'm already passing GUID's without any UDT's or marshalling. Everything works fine until I need to pass them in a SAFEARRAY.
Any help is appreciated, Thanks in advance
You're absolutely right - the problem is that VT_CLSID isn't allowed in either VARIANT or SAFEARRAY. It boils down to GUID not being an Automation-compatible type.
I often need to do the same thing that you're trying. The easiest way around the problem is to convert the GUID to a string and then pass SAFEARRAY(VT_BSTR). It goes against the grain somewhat to do this conversion, but I suppose you could take the view that there's marshaling going on anyway and this conversion is a type of marshaling.
The way to do it involves passing GUIDs as a UDT (user defined type).
For that, we use a SAFEARRAY of VT_RECORD elements which will be initialized with SafeArrayCreateEx. But first, we have to get a pointer to IRecordInfo that can describe the type.
Since GUID is defined in the windows/COM headers and has no uuid attached to it, we have to use something else to get an IRecordInfo interface. Basically, the two options are to create a struct that has the same memory layout as GUID in your own TypeLib, or use mscorlib::Guid defined in mscorlib.tlb
#import <mscorlib.tlb> no_namespace named_guids
IRecordInfo* pRecordInfo = NULL;
GetRecordInfoFromGuids( LIBID_mscorlib, 1, 0, 0, __uuidof(Guid), &pRecordInfo );
SafeArrayCreateEx( VT_RECORD, 1, &sab, pRecordInfo );
精彩评论