6

我目前遇到了需要将 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()or SafeArrayCreateVector()

SAFEARRAY* psa
psa = SafeArrayCreate(VT_CLSID, 1, rgsabound);

我得到一个 NULLSAFEARRAY指针,它应该指示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()我得到一个 0x80070057 的 HRESULT(参数不正确)。这可能是因为它也需要VT_CLSID参数

我可以手动填充它SafeArrayAccessData()

GUID* pData = NULL;
hResult = SafeArrayAccessData(*guids, (void**)&pData);

但我从 C# 端收到一个错误:“该值不在预期范围内”

我不确定如何通过 retval 或 out 参数完成将 SAFEARRAY(GUID) 返回到 C# 的所需功能。

看起来应该很简单——在 IDL 中有很多区域我已经在传递 GUID 而没有任何 UDT 或编组。一切正常,直到我需要在 SAFEARRAY 中传递它们。

任何帮助表示赞赏,在此先感谢

4

2 回答 2

5

你是绝对正确的 - 问题是在 VARIANT 或 SAFEARRAY 中都不允许使用 VT_CLSID。它归结为 GUID 不是自动化兼容的类型。

我经常需要做你正在尝试的同样的事情。解决该问题的最简单方法是将 GUID 转换为字符串,然后传递 SAFEARRAY(VT_BSTR)。进行这种转换有点违背常规,但我想你可以认为无论如何都在进行编组,并且这种转换是一种编组。

于 2011-07-29T05:00:53.960 回答
3

执行此操作的方法涉及将 GUID 作为 UDT(用户定义类型)传递。

为此,我们使用将使用 SafeArrayCreateEx 初始化的 VT_RECORD 元素的 SAFEARRAY。但首先,我们必须获得一个指向可以描述类型的 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 );
于 2013-02-17T04:53:14.183 回答