如何使用的PInvoke为C结构数组指针到C#

问题描述:

我想使用的PInvoke马歇尔结构数组另一个结构中从C到C#。据我所知,没有做不到的。结果
所以取而代之,在C结构,我宣布一个PTR我的数组,malloc的。问题:1)如何申报在C#端的等效? 2)我如何分配和使用的C#侧相同呢?

I am trying to use pinvoke to marshall an array of structures inside another structure from C to C#. AFAIK, no can do.
So instead, in the C structure I declare a ptr to my array, and malloc. Problems: 1) How do I declare the equivalent on the C# side? 2) How do I allocate and use the equivalent on the C# side?

//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...
     ?
 }

:不知怎的,我misinter preTED我读到关于C#端​​对象数组固定别处。
我的可以的固定在C数组的大小所以编好了,但后来我开始使用时,对象引用不设置到对象的实例:

: Somehow I misinterpreted what I read elsewhere about fixed array of objects on the c# side. And I can fix the array size in C So compiled ok, but then I get "object reference not set to an instance of an object" when using:

data.B [3]。一个= 4567; 所以,在阅读什么这个错误可能是在其他地方,我添加了此方法:

data.B[3].a = 4567; So, reading elsewhere about what this error might be, I added this method:

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

再次编译OK,但同样的错误味精。

Again, compiled OK, but same error msg.

要名帅这样的C和C#之间的复杂的结构,你有两个选择。

To marshal "complex" structures like this between C and C#, you have a couple of options.

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

In this case, I would highly recommend that you try to embed a fixed array into your C-side structure, as it will simplify the C# side a lot. You can use the MarshalAs attribute to tell C# how much space it needs to allocate in the array at run-time:

// 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#阵列多少内存会在运行时使用,所以你pretty多坚持了手工做的所有编组。 This问题有如何工作的一个很好的破败,但其基本思想是:

If you don't know, or can't specify, a fixed size for your array, then you'll need to do what you did and declare it as a pointer in C. In this case, you cannot tell C# how much memory the array is going to use at run-time, so you're pretty much stuck with doing all of the marshalling by hand. This question has a good rundown of how that works, but the basic idea is:


  1. 您应该一个字段添加到您的结构,包括数组元素的计数(这会让你的生活变得更轻松)

  2. 声明领域的C#为: IntPtr的数据; 有没有属性

  3. 使用 Marshal.SizeOf(typeof运算(A))来获得在非托管内存结构的大小。

  4. 使用 Marshal.PtrToStructure 到一个非托管结构转换为C#

  5. 使用 IntPtr.Add(PTR,sizeofA)移动到下一个结构数组中

  6. 循环,直到你用完了。

  1. You should add a field to your structure that includes a count of the array elements (this will make your life much easier)
  2. Declare the field in C# as: IntPtr data; with no attributes.
  3. Use Marshal.SizeOf(typeof(A)) to get the size of the struct in unmanaged memory.
  4. Use Marshal.PtrToStructure to convert a single unmanaged structure to C#
  5. Use IntPtr.Add(ptr, sizeofA) to move to the next structure in the array
  6. Loop until you run out.