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]的主要内容,如果未能解决你的问题,请参考以下文章