我有两个C++结构,我必须在从C#调用DLL方法时作为参数发送.
例如,让我们将它们定义为:
struct A
{
int data;
}
struct B
{
int MoreData;
A * SomeData;
}
Run Code Online (Sandbox Code Playgroud)
我需要从C#调用的方法具有以下签名:
int operation (B * data);
Run Code Online (Sandbox Code Playgroud)
(请注意,我无法控制这些C++结构和方法.)
在C#中,我将这些结构定义为类:
[StructLayout(LayoutKind.Sequential)]
class A
{
public int data;
}
[StructLayout(LayoutKind.Sequential)]
class B
{
public int MoreData;
[MarshalAs(UnmanagedType.Struct)]
public A SomeData;
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个"调试dll"来从C#调用,以确保在C++方法中正确接收所有数据.到目前为止,只有嵌套结构指针之前的数据才能正确发送.
当我尝试从嵌套结构(B-> A-> data)读取数据时,我收到读取违规错误(AccessViolationException).
如何编组嵌套结构,以便我能够在C++方法中读取它?
您的C#声明不等效,它会内联生成SomeData字段.换句话说,等效的原生声明将是:
struct B
{
int MoreData;
A SomeData;
}
Run Code Online (Sandbox Code Playgroud)
P/Invoke marshaller无法处理指针成员.这是一个内存管理问题,它拥有指针并且负责删除它是非常模糊的.要完成这项工作,你必须声明这样的结构:
struct B {
public int MoreData;
public IntPtr SomeData;
}
Run Code Online (Sandbox Code Playgroud)
并自己编组.像这样:
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);
}
Run Code Online (Sandbox Code Playgroud)
此代码隐含的是指针由托管代码拥有,并释放内存(FreeCoTaskMem调用).如果本机代码复制传递的结构,那么这将是一个问题,它会在尝试取消引用指针时读取坏数据或炸弹. 不释放内存也不是一种选择,会产生不可插拔的内存泄漏.因为本机代码不能使用free()函数来释放它.如果您最终进入该领域,则必须使用C++/CLI语言编写包装器,以便可以使用CRT的malloc()函数.
| 归档时间: |
|
| 查看次数: |
2968 次 |
| 最近记录: |