我有两个 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 编组器无法处理作为指针的成员。这是一个内存管理问题,谁拥有该指针并负责删除它是非常模糊的。为了使这项工作正常进行,您必须像这样声明结构:
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 调用)。如果本机代码复制传递的结构,那么这将是一个问题,当它尝试取消引用指针时,它将读取错误数据或炸弹。Not释放内存也不是一个选项,这会产生不可插入的内存泄漏。因为本机代码无法使用free()函数来释放它。如果您最终陷入了这个雷区,那么您将必须用 C++/CLI 语言编写一个包装器,以便您可以使用 CRT 的 malloc() 函数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)