我有两个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->数据),我收到读取违规错误(AccessViolationException)。
如何编组嵌套结构,以便能够在C ++方法中读取它?
答案 0 :(得分:5)
您的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()函数。