我有一个用非托管语言编写的DLL,它返回一个指向C结构的指针。 C#程序必须在结构中填入一些细节。 接下来必须将同一指针(不是副本)提供给同一DLL中的另一个方法 现在,C#程序从C结构中收集数据。
数据类型:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1, Size = 18 * 2 + 24 * 256)]
public class Context {
public UInt16 Magic;
public UInt16 Method;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2*16)]
public UInt16[] Status;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8*256)]
public Field[] InputFields;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8*256)]
public Field[] OutputFields;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8*256)]
public Field[] MetaData;
}
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode,Pack=1,Size=256)]
public class Field {
public UInt16 Kind;
public UInt16 Status;
public UInt16 Length;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 125)]
public string Data;
}
方法:
[DllImport("x.dll")]
//[return: MarshalAs(UnmanagedType.LPStruct)]
public static extern IntPtr CreateContext ( UInt16 ContextKind );
[DllImport("x.dll")]
public static extern UInt16 DestroyContext ( IntPtr Context );
[DllImport("x.dll")]
public static extern UInt16 Execute ( [In, MarshalAs(UnmanagedType.LPStruct)] Context Context );
如何填写/读出我的C#程序中DLL(而不是C#)所管理的内存?
我试过了:
使用
[return: MarshalAs(UnmanagedType.LPStruct)]
而不是IntPtr
。但是内存需要由C#管理,而不是它。
使用IntPtr
和Marshal.PtrToStructure
,但会尝试将内存复制到其他位置:
IntPtr C = CreateContext(1);
if (C == null) return;
Context Ctx = (Context)Marshal.PtrToStructure(C, typeof( Context ) );
Ctx.Method = 2;
(使用PtrToStructure
ExecutionEngineException
来电失败。
答案 0 :(得分:0)
尝试修改声明 - 例如删除Size
参数(但不是SizeConst
),并确保C代码实际上提供了内嵌的byval数组值,这些值的数组具有恰当的条目数(这是{{{ 1}})。例如。这对我有用:
UnmanagedType.ByValArray, SizeConst
如果失败,请尝试使用// Init array fields (required; supposed to happen on the C side)
ctx.Status = new UInt16[2 * 16];
ctx.InputFields = new Field[8 * 256];
ctx.OutputFields = new Field[8 * 256];
ctx.MetaData = new Field[8 * 256];
// Test data to survive the roundtrip (also supposed to happen on the C side)
ctx.Method = 42;
ctx.InputFields[42] = new Field() { Data = "Hi." };
ctx.OutputFields[42] = new Field() { Data = "Also hi." };
IntPtr buf = Marshal.AllocCoTaskMem(1024 * 100);
Marshal.StructureToPtr(ctx, buf, false);
var ctx_new = new Context();
Marshal.PtrToStructure(buf, ctx_new);
Marshal.FreeCoTaskMem(buf);
Console.WriteLine(ctx_new.Method);
Console.WriteLine(ctx_new.InputFields[42].Data);
Console.WriteLine(ctx_new.OutputFields[42].Data);
方法直接写入内存,如果Marshal.Write*
不适合您。然后,您可以创建一个包含PtrToStructure
的包装类,并提供触发IntPtr
的属性 - 例如。
Marshal.Write