4

我正在尝试使用 pinvoke 编组从 C 到 C# 的另一个结构内的结构数组。AFAIK,没有办法。
因此,相反,在 C 结构中,我向我的数组和 malloc 声明了一个 ptr。问题:1)如何在 C# 端声明等价物?2) 如何在 C# 端分配和使用等价物?

//The C code
typedef struct {
       int a;
       int b; } A;
typedef struct {
      int c;
      // A myStruct[100];    // can't do this, so:
      A *myStruct; } B;

//The c# code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class A{
    int a;
    int b;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class B{
      int c;
      // can't declare array of [100] A structures...
     ?
 }

[编辑]:不知何故,我误解了我在其他地方读到的关于 c# 端的固定对象数组的内容。而且我可以在 C 中修复数组大小所以编译好了,但是在使用时我得到“对象引用未设置为对象的实例”:

data.B[3].a = 4567; 因此,在其他地方阅读此错误可能是什么时,我添加了此方法:

public void initA()
        {
          for (int i = 0; i < 100; i++) { B[i] = new A(); }
        }

同样,编译正常,但同样的错误消息。

4

1 回答 1

5

要在 C 和 C# 之间编组这样的“复杂”结构,您有几个选择。

在这种情况下,我强烈建议您尝试将固定数组嵌入到 C 端结构中,因为它会大大简化 C# 端。您可以使用该MarshalAs属性告诉 C# 在运行时需要在数组中分配多少空间:

// In C:
typedef struct
{
 int a;
 int b;
} A;

typedef struct
{
 int c;
 A data[100];
} B;

// In C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct A 
{
  int a;
  int b;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct B
{
  int c;
  [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
  A[] data = new data[100];
}

如果您不知道或无法指定数组的固定大小,那么您需要执行您所做的并将其声明为 C 中的指针。在这种情况下,您无法告诉 C# 有多少内存该数组将在运行时使用,因此您几乎无法手动完成所有编组。这个问题很好地说明了它的工作原理,但基本思想是:

  1. 您应该在结构中添加一个包含数组元素计数的字段(这将使您的生活更轻松)
  2. 将 C# 中的字段声明为:IntPtr data;没有属性。
  3. 用于Marshal.SizeOf(typeof(A))获取结构在非托管内存中的大小。
  4. 用于Marshal.PtrToStructure将单个非托管结构转换为 C#
  5. 用于IntPtr.Add(ptr, sizeofA)移动到数组中的下一个结构
  6. 循环直到用完为止。
于 2012-08-15T13:32:38.700 回答