如何在 C# 中 PInvoke 另一个结构内的结构数组

Posted

技术标签:

【中文标题】如何在 C# 中 PInvoke 另一个结构内的结构数组【英文标题】:How to PInvoke in C# an array of structs inside another struct 【发布时间】:2017-01-10 11:12:45 【问题描述】:

在 C#.NET 中,我尝试使用此签名从 C++ 程序集(无法访问源代码)中 PInvoke 方法

result_code get_values(values_report_type *values_report)

其中values_report 是指向values_report_type 结构的指针,其中包含我正在查询的值,这些值由该方法返回。结构如下所示:

typedef struct
    int countOfValues;
    values_type* values;
    const char* name;
 values_report_type;

其中values 是结构values_type数组

这就是我认为的问题所在:我正在处理的 C++ 程序集除了定义之外没有提供关于 values_type 结构内容的任何信息

typedef struct values_type_struct *values_type

根据文档,这种隐私是故意的。

所以,我的 C# PInvoke 现在看起来像这样:

[DllImport("MyLibrary.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern result_code get_values(out values_report_type values_report);

internal struct values_report_type
    int countOfValues;
    IntPtr values;
    string name;

这很好,并给了我一个指向 values 结构的指针,但我需要的是访问 values_type 结构的数组并获取指向数组中每个项目的指针(指向每个项目的指针是我所需要的,因为我没有结构内容的定义)。但我想不出一种方法来实现这一点,特别是因为库限制了我对那个结构的描述(甚至没有给出长度)。在 C++ 中,countOfValues 定义的每个项目就像 values_report.values[0] 之类的东西,但我不知道在将其编组到 .NET 时如何让它工作。

有没有办法通过编组在 C# 中解决这个问题?

【问题讨论】:

values 不是struct 的数组。它是一个指向struct values_type_struct指针 数组。你打算如何处理values 中的元素?阅读values[i] 很容易(IntPtr Value = Marshal.ReadIntPtr(values_report.values, i*IntPtr.Size)),接下来发生的事情尚不清楚。 我在 unix 操作系统上工作了很长时间,并多次阅读了整个 UNIX 手册。您必须能够确定每条记录的结束位置的任何结构/数组。通过固定大小的对象、结构中的长度属性或终止字符(如 '\0' \0'。唯一的问题是当 countOfValues 为零时,它看起来像一个 '\0'。因此,在数组的开头,您可能需要添加要发送的数组数量的整数。 @DavidHeffernan SDK 中有更多方法使用指向values_type_struct 元素的指针来执行计算。所以基本上,我无法查看结构的内容,但我可以将指向它的指针发送到另一种计算和转换方法。 听起来不错。如果是这样,那么它就是所谓的不透明指针。在那种情况下,我认为您现在拥有所需的东西。 我能想到的最佳解决方案是尝试生成一个values_type 对象数组,方法是使用Marshal.Copy 将其转换为字节数组,然后将其输入BinarySerializer。唯一的问题是,为了进行编组,您需要知道要获取的内存量的大小,因此您还需要知道数组的大小(可能由 countOfValues 给出)作为values_type 对象的大小(不太明显)。 【参考方案1】:

values 不是结构数组。它是一个指向结构的 指针 数组。

基于 cmets,并查看代码,您似乎没有 struct 本身的定义。这就是所谓的不透明指针。您不需要知道结构体的大小,只需处理指向结构体的指针,然后将其传回库即可。

像这样从数组中读取不透明的指针值:

IntPtr Value = Marshal.ReadIntPtr(values_report.values, i*IntPtr.Size);

这将获得第 ith 值。

【讨论】:

我可能遗漏了一些东西,但我没有看到 values 是结构指针数组的位置。我只是看到它的类型为values_type*。现在我的 C/C++ 有点初级,但我认为这是指向 single values_type 的指针,它也可以用来表示 values_types 的数组。 values_type** 不会表示指针数组吗? typedef struct values_type_struct *values_type。所以values_type 是指向结构体的指针。 啊,我明白了。我不习惯寻找 typedef。 :P

以上是关于如何在 C# 中 PInvoke 另一个结构内的结构数组的主要内容,如果未能解决你的问题,请参考以下文章

C# PInvoke 传递出 unsigned char*

C# PInvoke 结构与类访问冲突

将带有结构字段的结构从 c++ 返回到 c# pinvoke

反向 PInvoke 并创建一个完整的非托管 C# 程序

从 C# 线程内的非托管 dll 运行函数

C#和C++传递结构体