MarshalAs嵌套结构

我有两个C ++结构,我必须在从C#调用DLL方法时作为参数发送。

例如,让我们将它们定义为:

struct A { int data; } struct B { int MoreData; A * SomeData; } 

我需要从C#调用的方法具有以下签名:

 int operation (B * data); 

(请注意,我无法控制这些C ++结构和方法。)

在C#中,我将这些结构定义为类:

 [StructLayout(LayoutKind.Sequential)] class A { public int data; } [StructLayout(LayoutKind.Sequential)] class B { public int MoreData; [MarshalAs(UnmanagedType.Struct)] public A SomeData; } 

我创建了一个“调试dll”来从C#调用,以确保在C ++方法中正确接收所有数据。 到目前为止,只有嵌套结构指针之前的数据才能正确发送。

当我尝试从嵌套结构中读取数据(B-> A-> data)时,我收到读取违规错误(AccessViolationException)。

如何编组嵌套结构,以便能够在C ++方法中读取它?

您的C#声明不等效,它会内联生成SomeData字段。 换句话说,等效的原生声明将是:

 struct B { int MoreData; A SomeData; } 

P / Invoke marshaller无法处理指针成员。 这是一个内存管理问题,它拥有指针并且负责删除它是非常模糊的。 要完成这项工作,你必须声明这样的结构:

  struct B { public int MoreData; public IntPtr SomeData; } 

并自己编组。 像这样:

  var b = new B(); b.MoreData = 0x12345678; var a = new A(); a.Data = 0x789abcde; int len = Marshal.SizeOf(a); b.SomeData = Marshal.AllocCoTaskMem(len); try { Marshal.StructureToPtr(a, b.SomeData, false); someFunction(ref b); } finally { Marshal.FreeCoTaskMem(b.SomeData); } 

此代码隐含的是指针由托管代码拥有,并释放内存(FreeCoTaskMem调用)。 如果本机代码复制传递的结构,那么这将是一个问题,它会在尝试取消引用指针时读取错误数据或炸弹。 释放内存也不是一种选择,会产生不可插拔的内存泄漏。 因为本机代码不能使用free()函数来释放它。 如果您最终进入该领域,则必须使用C ++ / CLI语言编写包装器,以便可以使用CRT的malloc()函数。