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

发布于 2024-11-27 00:41:33 字数 1526 浏览 2 评论 0原文

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

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

I'm currently running into an issue of needing 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

开始看清了 2024-12-04 00:41:33

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

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

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.

清风疏影 2024-12-04 00:41:33

实现方法包括将 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 );

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 );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文