从 C++ 返回的 GUID 的 COM SAFEARRAY到 C#
我目前遇到一个问题,需要将 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你是完全正确的 - 问题是 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.
实现方法包括将 GUID 作为 UDT(用户定义类型)传递。
为此,我们使用 VT_RECORD 元素的 SAFEARRAY,该元素将使用 SafeArrayCreateEx 进行初始化。但首先,我们必须获得一个指向可以描述类型的 IRecordInfo 的指针。
由于 GUID 是在 windows/COM 标头中定义的,并且没有附加 uuid,因此我们必须使用其他东西来获取 IRecordInfo 接口。基本上,这两个选项是创建一个与您自己的 TypeLib 中的 GUID 具有相同内存布局的结构,或者使用 mscorlib.tlb 中定义的 mscorlib::Guid
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