gpt4 book ai didi

c# - MarshalAs 嵌套结构

转载 作者:行者123 更新时间:2023-12-05 01:48:54 27 4
gpt4 key购买 nike

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

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

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 字段。换句话说,等效的 native 声明将是:

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 调用)。如果 native 代码复制传递的结构,那么这将是一个问题,它会在尝试取消引用指针时读取错误数据或炸弹。 释放内存也不是一个选项,它会产生不可插入的内存泄漏。因为 native 代码无法使用 free() 函数来释放它。如果您最终进入那个雷区,那么您将不得不用 C++/CLI 语言编写一个包装器,以便您可以使用 CRT 的 malloc() 函数。

关于c# - MarshalAs 嵌套结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3914802/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com