【问题标题】:How to pass Object array to unmanaged code?如何将对象数组传递给非托管代码?
【发布时间】:2010-07-09 17:49:40
【问题描述】:

我正在尝试将一组对象从 C# 传递到非托管 C++,但似乎没有任何效果。

编译器不会让我假装数组是 IntPtr。将数组转换为 IntPtr 不起作用。我尝试传递固定数据的地址,但这也不起作用。

我只需要传递一个指向数组开头的指针,这变得异常困难。

有什么建议或链接吗?谢谢!

【问题讨论】:

  • 您希望如何从非托管代码中看到该数组(即元素类型是什么)?
  • 我(希望)在 C# 和 C++ 端都有相同的对象定义。被调用函数有一个指向该类型的指针作为参数。
  • 您的意思是 C++ 类定义?它不是那样工作的。 CLR 类的内存布局是实现定义的,您无法从 C++ 中匹配它。您可以做的是让对象实现某个接口,并在非托管大小上提供该接口的非托管定义,然后让 P/Invoke 编组数组。
  • 如果我将 CLR 类更改为结构会更容易吗? (两者都可以在程序中工作。)
  • 如果你的结构本身不包含任何对象引用,并且如果你想要的是一个结构数组而不是引用数组(因为后者是你实际拥有的数组对象),那么,是的,它应该都能正常工作。

标签: c# c++ arrays marshalling unmanaged


【解决方案1】:

终于奏效了:

  1. 传递结构数组而不是对象数组(引用)。
  2. 将“[StructLayout(LayoutKind.Sequential, Pack = 1)]”放在结构定义之前。
  3. 将“[MarshalAs(UnmanagedType.LPWStr)]”放在字符串之前(在结构定义中)以使字符串在 C++ 端显示为宽字符串。
  4. 为 DllImport 声明中的参数声明一个结构数组:“VariableObject[] varObj”。
  5. 将指向类的指针声明为 C++ 端的参数。 (C++ 类反映了 C# 结构。):“VariableObject* varObj”。

【讨论】:

    【解决方案2】:

    你能转换成一个空指针吗?确保对象数组已固定。

    【讨论】:

    • 我试过了:VariableObject[] varObj = new VariableObject[numVarObjects]; GCHandle pinnedData = GCHandle.Alloc(varObj, GCHandleType.Pinned); IntPtr ptr = pinnedData.AddrOfPinnedObject(); Alloc 调用导致:“对象包含非原始或非 blittable 数据。”。
    • 您无法获得指向托管类型的指针。托管类型数组也是托管类型,对象引用也是托管类型。
    【解决方案3】:

    在您的 C#/托管方法签名中,使用 [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]...

    标记输入参数
    [DllImport(...)]
    public void DoTask
        (
            ...,
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] results,
            ...
        );
    

    然后像往常一样调用它。此外,在非托管代码中,您可以修改此数组。我建议您发送一个额外的 int,告诉非托管代码数组的大小是多少,以防止“数组越界”修改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-31
      • 2011-02-27
      • 1970-01-01
      • 2011-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多