从C#调用C函数,该函数接受调用者分配的结构数组

我有以下C结构

struct XYZ { void *a; char fn[MAX_FN]; unsigned long l; unsigned long o; }; 

我想从C#调用以下函数:

 extern "C" int func(int handle, int *numEntries, XYZ *xyzTbl); 

其中xyzTbl是由调用者分配的大小为numEntires的XYZ数组

我已经定义了以下C#结构:

 [StructLayoutAttribute(Sequential, CharSet = CharSet.Ansi)] public struct XYZ { public System.IntPtr rva; [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 128)] public string fn; public uint l; public uint o; } 

和方法:

  [DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)] public static extern Int32 func(Int32 handle, ref Int32 numntries, [MarshalAs(UnmanagedType.LPArray)] XYZ[] arr); 

然后我尝试调用该函数:

 XYZ xyz = new XYZ[numEntries]; for (...) xyz[i] = new XYZ(); func(handle,numEntries,xyz); 

当然它不起作用。 有人能说清楚我做错了吗?

 [StructLayoutAttribute(Sequential, CharSet = CharSet.Ansi)] public struct XYZ { public System.IntPtr rva; [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 128)] public string fn; public uint l; public uint o; } 

那些uint不应该是ulong吗? 另外,MAX_FN是128吗?

 XYZ xyz = new XYZ[numEntries]; for (...) xyz[i] = new XYZ(); 

XYZ是一个值类型(struct),因此这里的第二行是冗余的(结构总是被初始化)

  [DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)] public static extern Int32 func(Int32 handle, ref Int32 numntries, [MarshalAs(UnmanagedType.LPArray)] XYZ[] arr); 

[MarshalAs(UnmanagedType.LPArray)]是冗余的,编译器会看到它是一个struct数组。

检查一下: Marshal C ++ struct array into C# ,可能会有所帮助。

我会手动编组。 首先,使xyzTbl成为IntPtr

 [DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)] public static extern Int32 func(Int32 handle, ref Int32 numntries, IntPtr xyzTb); 

而不是像你正在做的那样分配XYZ数组 – 分配足够的非托管内存来存储表。

 IntPtr unmanaged = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XYZ)) * numEntries); 

调用你的func(handle, ref numEntries, unmanaged); 然后,工作是将非托管内存解组为托管类型。

 IntPtr[] entries = new IntPtr[numEntries]; List xyz = new List(); Marshal.Copy(unmanaged, entries, 0, numEntries); foreach (IntPtr entry in entries) xyz.Add(Marshal.PtrToStructure(entry, typeof(XYZ))); Marsha.FreeHGlobal(unmanaged); 

当您拥有托管结构时,我不相信您可以使用LPArray 。 只需将其取出,然后使用[In][Out] (如果需要)。

IIRC,如果你使用LPArray ,那会尝试将指针传递给第一个元素,这是非法的,因为结构不是blittable。 您需要完全删除[MarshalAs(...)]


编辑:

我不记得了,但你可能需要在传递它们之前初始化字符串字段…当我有机会时我会检查它。