[英]Using an unmanaged struct from an unmanaged DLL without copying in C#
I have a DLL written in unmanaged language that returns a pointer to a C structure. 我有一个用非托管语言编写的DLL,它返回一个指向C结构的指针。 AC# program must fill in some details into the structure. AC#程序必须在结构中填写一些细节。 Next the same pointer (not a copy) must be given to another method from the same DLL Now the C# program collects the data from the C structure. 接下来,必须将相同的指针(不是副本)从同一DLL提供给另一个方法。现在,C#程序从C结构中收集数据。
The datatype: 数据类型:
[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;
}
Methods: 方法:
[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 );
How can I fill in / read out the memory that is mananged by the DLL (not C#) in my C# program? 如何在我的C#程序中填写/读出由DLL(不是C#)管理的内存?
I tried: 我试过了:
Using 使用
[return: MarshalAs(UnmanagedType.LPStruct)]
instead of IntPtr
. 而不是IntPtr
。 But memory needs to be managed by C# for that which it is not. 但是内存需要由C#管理而不是由内存管理。
Use IntPtr
and Marshal.PtrToStructure
but it tries to copy the memory to another location: 使用IntPtr
和Marshal.PtrToStructure
但它尝试将内存复制到另一个位置:
IntPtr C = CreateContext(1); if (C == null) return; Context Ctx = (Context)Marshal.PtrToStructure(C, typeof( Context ) ); Ctx.Method = 2;
(fails on the PtrToStructure
call with an ExecutionEngineException
). (在带有ExecutionEngineException
的PtrToStructure
调用上失败)。
Try fixing your declarations - eg remove the Size
parameter (but not SizeConst
), and make sure the C code actually provides inline, byval arrays of values that have exactly the right number of entries in them (which is the requirement for UnmanagedType.ByValArray, SizeConst
). 尝试修改声明-例如,删除Size
参数(但不SizeConst
),并确保C代码实际上提供了内联的按字节排列的值数组,这些数组中的条目数量正确(这是UnmanagedType.ByValArray, SizeConst
的要求UnmanagedType.ByValArray, SizeConst
)。 Eg this works for me: 例如,这对我有用:
// 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);
Failing that, try using the Marshal.Write*
methods to write to the memory directly if PtrToStructure
does not work for you. 失败的话,如果PtrToStructure
不适合您,请尝试使用Marshal.Write*
方法直接写入内存。 You can then create a wrapper class that would hold the IntPtr
and provide properties that would trigger the Marshal.Write
- eg 然后,您可以创建一个包装类,该包装类将保存IntPtr
并提供触发Marshal.Write
属性-例如
public UInt16 Status {
get { return unchecked((ushort)Marshal.ReadInt16(m_Ptr, 2)); }
set { Marshal.WriteInt16(m_Ptr, 2, unchecked((short)value)); }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.