如何使用的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:
- 您应该一个字段添加到您的结构,包括数组元素的计数(这会让你的生活变得更轻松)
- 声明领域的C#为:
IntPtr的数据;
有没有属性 - 使用
Marshal.SizeOf(typeof运算(A))
来获得在非托管内存结构的大小。 - 使用
Marshal.PtrToStructure
到一个非托管结构转换为C# - 使用
IntPtr.Add(PTR,sizeofA)
移动到下一个结构数组中 - 循环,直到你用完了。
- You should add a field to your structure that includes a count of the array elements (this will make your life much easier)
- Declare the field in C# as:
IntPtr data;
with no attributes. - Use
Marshal.SizeOf(typeof(A))
to get the size of the struct in unmanaged memory. - Use
Marshal.PtrToStructure
to convert a single unmanaged structure to C# - Use
IntPtr.Add(ptr, sizeofA)
to move to the next structure in the array - Loop until you run out.