简体   繁体   English

从 C++ 到 C# 中的 VARIANT 编组 safearray 的 safearray

[英]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 ).啊,请注意CallingConventionWINAPIStdCall )。

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.我会说实话,我认为SAFEARRAYVARIANTBSTRSAFEARRAY的武器,应该包括在日内瓦公约的禁止名单中。

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[] ,并且接收到的objectsobject[] ,其中每个元素都是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM