GUID的COM SAFEARRAY从C ++返回到C#

时间:2011-07-28 22:19:27

标签: c# c++ com guid safearray

我目前遇到一个问题,需要将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传递它们。

感谢任何帮助, 提前致谢

2 个答案:

答案 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 );