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;
}
I创建了一个“调试 dll”以从 C# 调用,以确保在 C++ 方法中正确接收所有数据。到目前为止,只有嵌套结构指针之前的数据被正确发送。
当我尝试从嵌套结构 (B->A->data) 读取数据时,出现读取冲突错误 (AccessViolationException)。
如何封送嵌套结构以便能够在 C++ 方法中读取它?
I have two C++ structures that I have to send as parameters when calling a DLL method from C#.
For example, lets define them as:
struct A
{
int data;
}
struct B
{
int MoreData;
A * SomeData;
}
A method that I need to call from C# has the following signature:
int operation (B * data);
(Please note that I do not have the control over these C++ structures nor methods. )
In C# I define these structures as classes:
[StructLayout(LayoutKind.Sequential)]
class A
{
public int data;
}
[StructLayout(LayoutKind.Sequential)]
class B
{
public int MoreData;
[MarshalAs(UnmanagedType.Struct)]
public A SomeData;
}
I have created a "debugging dll" to call from C# in order to ensure all the data is received correctly in C++ methods. So far only the data that comes before the nested structure pointer is sent correctly.
When I try to read data from the nested structure (B->A->data) I get a read violation error (AccessViolationException).
How can I marshal the nested structure so I will be able to read it in the C++ method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的 C# 声明并不等效,它会内联生成 SomeData 字段。换句话说,等效的本机声明是:
P/Invoke 编组器无法处理作为指针的成员。这是一个内存管理问题,谁拥有该指针并负责删除它是非常模糊的。为了使这项工作完全正常,您必须像这样声明结构:
并自己编组它。像这样:
这段代码隐含的是该指针由托管代码拥有,并且它释放内存(FreeCoTaskMem 调用)。如果本机代码复制传递的结构,那么这将是一个问题,当它尝试取消引用指针时,它将读取错误数据或炸弹。 不释放内存也不是一个选项,这会产生不可插入的内存泄漏。因为本机代码无法使用free()函数来释放它。如果您最终陷入了这个雷区,那么您将必须用 C++/CLI 语言编写一个包装器,以便您可以使用 CRT 的 malloc() 函数。
Your C# declaration is not equivalent, it generates the SomeData field inline. In other words, the equivalent native declaration would be:
The P/Invoke marshaller cannot deal with a member that's a pointer. It is a memory management problem, it is very murky who owns the pointer and is responsible for deleting it. To make this work at all, you have to declare the structure like this:
And marshal it yourself. Like this:
Implicit in this code is that the pointer is owned by the managed code and that it releases the memory (FreeCoTaskMem call). If the native code copies the passed structure then this will be a problem, it is going to read bad data or bomb when it tries to dereference the pointer. Not freeing the memory isn't an option either, that produces an unpluggable memory leak. Because the native code cannot use the free() function to release it. If you end up in that mine field then you will have to write a wrapper in the C++/CLI language so that you can use the CRT's malloc() function.