[英]Marshalling safearray of safearray from VARIANT in C++ to C#
I'm trying to call a function in .NET from a native library, like this:我正在尝试从本机库中调用 .NET 中的 function ,如下所示:
typedef int (WINAPI* TGetAllObjects)(int hModel, VARIANT& objects);
If you call it in the C++ client, the debugger shows that objects are a safearray of VARIANT
, and each VARIANT
is a safearray of BSTR
.如果在 C++ 客户端中调用它,调试器会显示对象是
VARIANT
的安全数组,每个VARIANT
都是BSTR
的安全数组。
I tried to implement as follows in C#:我尝试在 C# 中实现如下:
public delegate TRetCode TGetAllObjects(int hModel,
[Out,In,MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT )] ref MyStruct[] objects);
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
public string[] Objects;
}
When calling the method, it gives an error:调用方法时报错:
System.Runtime.InteropServices.SafeArrayTypeMismatchException: "Specified array was not of the expected type."
System.Runtime.InteropServices.SafeArrayTypeMismatchException:“指定的数组不是预期的类型。”
Please tell me how to properly organize data marshalling in such a situation.请告诉我在这种情况下如何正确组织数据编组。
Try:尝试:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate int TGetAllObjects(int hModel, ref object objects);
and see EXACTLY what you receive.看看你收到了什么。 The
objects
variable is a VARIANT
, not a SAFEARRAY
. objects
变量是VARIANT
,而不是SAFEARRAY
。 The VARIANT& objects
contains the SAFEARRAY
, it isn't a SAFEARRAY
. VARIANT& objects
包含SAFEARRAY
,它不是SAFEARRAY
。
Then inside your code you can check its type and cast it.然后在您的代码中,您可以检查其类型并进行强制转换。
Ah and note the CallingConvention
( WINAPI
is StdCall
).啊,请注意
CallingConvention
( WINAPI
是StdCall
)。
I've made some tests and it seems the basic VARIANT
"container" is passed correctly.我进行了一些测试,似乎基本的
VARIANT
“容器”已正确传递。 I'll say the truth, I consider a SAFEARRAY
of VARIANT
that are SAFEARRAY
s of BSTR
a weapon that should be included in the banned list by the Geneva Convention.我会说实话,我认为
SAFEARRAY
的VARIANT
是BSTR
的SAFEARRAY
的武器,应该包括在日内瓦公约的禁止名单中。
Some more tests make me think that my solution is the easyest one.更多的测试让我认为我的解决方案是最简单的。 I wasn't able to accept/pass directly a
object[]
or a string[]
, and the received objects
is a object[]
where each element is a string[]
.我无法直接接受/传递
object[]
或string[]
,并且接收到的objects
是object[]
,其中每个元素都是string[]
。 Something like:就像是:
var objects = new object[] { new string[] { "A", "B" }, new string[] { "C", "D" } };
Your "casting" problem你的“铸造”问题
SAFEARRAY
can have the index of the first element != 0
(this to support VB that uses 1-based arrays, arrays, where the first element is 1). SAFEARRAY
可以有第一个元素的索引!= 0
(这是为了支持使用基于 1 的 arrays、arrays 的 VB,其中第一个元素是 1)。 .NET does support this in the category "strange arrays". .NET 在“奇怪的数组”类别中确实支持这一点。 Multidimensional arrays (
string[1, 2]
) and non-0 based arrays are in this category, and they are a pain to handle.多维 arrays (
string[1, 2]
) 和基于非 0 的 arrays 属于这一类,它们很难处理。 Non-zero based arrays more so.基于非零的 arrays 更是如此。
Code to convert the array in your case (where with "convert" I mean: copy it to a standard .NET array of arrays):在您的情况下转换数组的代码(其中“转换”的意思是:将其复制到标准的 .NET 数组数组):
object[] castedObjects = (object[])objects;
string[][] strings = new string[castedObjects.Length][];
for (int i = 0; i < castedObjects.Length; i++)
{
Array ar = (Array)castedObjects[i];
string[] ar2 = new string[ar.Length];
Array.Copy(ar, ar2, ar2.Length);
strings[i] = ar2;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.