【问题标题】:COM SAFEARRAY of GUID's returned from C++ to C#GUID 的 COM SAFEARRAY 从 C++ 返回到 C#
【发布时间】:2011-10-15 12:56:14
【问题描述】:

我目前遇到了需要将 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() 填充它时,我得到一个 0x80070057 的 HRESULT(参数不正确)。这可能是因为它也采用了VT_CLSID 参数

我可以用SafeArrayAccessData()手动填充它

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

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

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

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

任何帮助表示赞赏, 提前致谢

【问题讨论】:

    标签: c# c++ com guid safearray


    【解决方案1】:

    您完全正确 - 问题是 VARIANT 或 SAFEARRAY 中都不允许使用 VT_CLSID。归结为 GUID 不是自动化兼容类型。

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

    【讨论】:

    • 谢谢,所以没有办法做到这一点?我认为这是可能的,因为我已经在使用这种样式:HRESULT SendGuid( [in] GUID guid); 在 idl 的许多地方传递单个 guid。我真的希望保持界面的纯度。避免只使用字符串更具合同性:(
    • 我同意,并且更愿意自己这样做。但是,这是不可能的。原因是 ActiveX/Automation 是 COM 的子集,旨在使后期绑定脚本语言更容易通过 IDispatch 与 COM 对象对话。 SAFEARRAY 和 VARIANT 是此自动化子集的一部分,但 VT_CLSID 不是。您的 SendGuid(GUID) 方法与自动化不兼容,但它仍然是完美的 COM。即使您不希望您的界面与自动化兼容,但一旦使用 SAFEARRAY 类型,您就要付出代价。
    【解决方案2】:

    执行此操作的方法涉及将 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 );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-27
      • 1970-01-01
      • 1970-01-01
      • 2012-05-01
      • 1970-01-01
      • 2012-08-03
      • 1970-01-01
      • 2012-05-04
      相关资源
      最近更新 更多