我目前遇到一个问题,需要将SAFEARRAY(GUID)作为返回值从C ++传递给C#。
目前C#端正在使用从Tlbimp.exe(类型库导入程序)生成的Interop dll。
IDL是:
HRESULT GetGuids(
[out]SAFEARRAY(GUID)* guids);
我也试过[out,retval]
功能签名是:
HRESULT
WINAPI
MyClass::GetGuids(SAFEARRAY** guids)
如果我使用SafeArrayCreate()
或SafeArrayCreateVector()
:
SAFEARRAY* psa
psa = SafeArrayCreate(VT_CLSID, 1, rgsabound);
我得到一个NULL SAFEARRAY
指针,该指针应该表示E_OUTOFMEMORY
不正确。
我找到的是VT_CLSID
仅适用于Ole属性集而不是SAFEARRAY:
http://poi.apache.org/apidocs/org/apache/poi/hpsf/Variant.html它表示CLSID是
我还尝试过使用以下方法构建安全数组的替代方法:
SafeArrayAllocDescriptor()
和SafeArrayAllocData()
。
hResult = SafeArrayAllocDescriptor(1, guids)
hResult = SafeArrayAllocData(*guids);
这让我可以创建数组,但是当用SafeArrayPutElement()
填充它时,我得到的HRESULT为0x80070057(参数不正确)。这可能是因为它需要VT_CLSID
参数
我可以使用SafeArrayAccessData()
GUID* pData = NULL;
hResult = SafeArrayAccessData(*guids, (void**)&pData);
但是我从C#端收到错误: “该值不在预期的范围内”
我不确定如何通过retval或out参数完成将SAFEARRAY(GUID)返回给C#的所需功能。
看起来它应该很简单 - IDL中有很多区域我已经在没有任何UDT或编组的情况下传递GUID。一切正常,直到我需要在SAFEARRAY传递它们。
感谢任何帮助, 提前致谢
答案 0 :(得分:5)
你是绝对正确的 - 问题是VARIANT或SAFEARRAY中不允许使用VT_CLSID。归结为GUID不是自动化兼容类型。
我经常需要做同样的事情。解决此问题的最简单方法是将GUID转换为字符串,然后传递SAFEARRAY(VT_BSTR)。这种转换在某种程度上与谷物相反,但我认为你可以认为无论如何都会进行编组,这种转换是一种编组。
答案 1 :(得分:3)
执行此操作的方法涉及将GUID作为UDT(用户定义的类型)传递。
为此,我们使用了一个VT_RECORD元素的SAFEARRAY,它将使用SafeArrayCreateEx进行初始化。但首先,我们必须得到一个可以描述类型的IRecordInfo指针。
由于GUID是在windows / COM头中定义的,并且没有附加uuid,因此我们必须使用其他东西来获取IRecordInfo接口。基本上,这两个选项是在您自己的TypeLib中创建一个与GUID具有相同内存布局的结构,或者使用mscorlib.tlb中定义的mscorlib :: Guid
#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 );