c# 中的元帅 char[][LENGTH]

Posted

技术标签:

【中文标题】c# 中的元帅 char[][LENGTH]【英文标题】:Marshal char[][LENGTH] in c# 【发布时间】:2018-02-28 13:46:00 【问题描述】:

在 C# 项目中,我很难连接来自外部库的 C++ 函数。我猜这是字符串编组的问题。

在C++中有如下函数:

int compute(const char names[][LENGTH_1], char values[][LENGTH_2], const int n);

目标是提供:

一个只读数组,包含“n”个 LENGTH_1 个字符的字符串 包含“n”个 LENGTH_2 个字符的字符串的可写数组

函数“compute”将根据“names”中指定的内容写入数组“values”。

在C#中尝试了两种不同的函数连接方式

方法一

[DllImport("abcd.dll", EntryPoint="compute", CharSet=CharSet.Ansi)]
internal static extern int Compute(StringBuilder [] names, StringBuilder [] values, int n);

我这样称呼它:

var names = new StringBuilder[number];
var descriptions = new StringBuilder[number];
for (int i = 0; i < number; i++) 
  names[i] = new StringBuilder(LENGTH_1);
  descriptions[i] = new StringBuilder(LENGTH_2);

var error = Compute(names, descriptions, number);

方法二

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=4)]
internal struct StringName

  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)] // LENGTH_1 = 64
  public string msg;


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=4)]
internal struct StringValue

  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] // LENGTH_2 = 128
  public string msg;


[DllImport("abcd.dll", EntryPoint="compute", CharSet=CharSet.Ansi)]
internal static extern int Compute(StringName[] names, ref StringValue[] values, int number);

我这样称呼它:

var names = new StringNames[number];
var values = new StringValue[number];
var error = Compute(names, ref values, number);

结果

它毫无例外地崩溃,程序在“计算”功能上被阻止。我仍然不确定问题是来自字符串还是来自外部库。

【问题讨论】:

为什么要在属性声明中添加Pack?你只是随意尝试一些东西吗?删除您随机尝试的所有内容,并包含您认为应该可以工作的代码。 第二种变体最有可能成功。 ref 是错误的。在第一个参数上使用 [In],在第二个参数上使用 [In, Out]。不清楚调用约定应该是什么。综上所述,我怀疑编组器是否会将字符串编组回来。您可能需要使用一些技巧来完成这项工作。 谢谢!我添加了 Pack=4 因为我之前遇到过问题,但现在你是对的,这不是必需的。我将“ref”更改为 [In, Out],我再也没有崩溃了!但是字符串是空的,你能解释一下“一些技巧来使它工作”吗? 你可以使用一个固定的字节数组来使类型为纯值类型。然后有效载荷将双向编组。您需要包含一个读取和写入有效负载的字符串属性。这迫使您使用unsafe。如果您不想这样做,那么您可以有空结构,但在StructLayout 属性中指定Size。然后,这将确保数据存在并已编组。使用属性再次访问它,该属性的 getter 和 setter 使用 GCHandle 固定结构,然后使用 Marshal 类与字符串进行转换。 如果您有解决问题的方法,请发布答案,请勿编辑您的问题。 【参考方案1】:

David 发现,关键字“ref”是错误的。这是方法 2 的变化。

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
internal struct StringName

  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=LENGTH_1)]
  public string msg;


[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
internal struct StringValue

  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=LENGTH_2)]
  public string msg;


[DllImport("abcd.dll", EntryPoint="compute", CharSet=CharSet.Ansi)]
internal static extern int Compute([In] StringName[] names, [In, Out] StringValue[] values, int number);

我这样称呼它:

var names = new StringNames[number];
// ... here the initialization of "names" ... //
var values = new StringValue[number];
var error = Compute(names, values, number);
// ... here the processing of "values" ... //

【讨论】:

以上是关于c# 中的元帅 char[][LENGTH]的主要内容,如果未能解决你的问题,请参考以下文章

C# 中的元帅“char *”

从 c# 到 c++ 的结构中的元帅结构

VS2010中的元帅结构指针

元帅浮点*到 C#

具有对 C# 的整数引用的元帅结构

在 C# 中元帅 C++ wchar_t**