C DLL 中的 PInvoke char* 在 C# 中作为字符串处理。空字符问题
Posted
技术标签:
【中文标题】C DLL 中的 PInvoke char* 在 C# 中作为字符串处理。空字符问题【英文标题】:PInvoke char* in C DLL handled as String in C#. Issue with null characters 【发布时间】:2013-02-22 19:18:21 【问题描述】:C DLL 中的函数如下所示:
int my_Funct(char* input, char* output);
我必须从 C# 应用程序调用它。我通过以下方式做到这一点:
...DllImport stuff...
public static extern int my_Funct(string input, string output);
输入字符串完美地传输到 DLL(我有明显的证据)。函数填写的输出虽然是错误的。我有六进制数据,比如:
3F-D9-00-01
但不幸的是,两个零之后的所有内容都被删除了,只有前两个字节进入我的 C# 应用程序。它发生了,因为(我猜)它被视为空字符并将其作为字符串的结尾。
知道如何摆脱它吗?我试图将它指定为 out IntPtr 而不是字符串,但我不知道之后该怎么处理它。 我试着做之后:
byte[] b1 = new byte[2];
Marshal.Copy(output,b1,0,2);
2 通常应该是字节数组的长度。但我得到了各种各样的错误:比如“请求的范围超出了数组的末尾。”或“试图读取或写入受保护的内存...”
感谢您的帮助。
【问题讨论】:
(1) C# 字符串比字符宽;它们是 2 个字符宽而不是 1 个字符。(2) 此函数返回的 char* 不会具有成为有效 C# 字符串所需的附加结构(即使它具有正确的宽度)。 您需要阅读 COM Interop 和 P/Invoke 以了解如何执行此操作。这样做,并在您对该材料有任何疑问时回电。 pinvoke marshaller 仅支持 C 字符串。当它在 0 之后有重要的字节时,它显然不是 C 字符串。然后它是一个字节 []。但是由于严重的挂断,没有人能弄清楚有多少 个字节是相关的。这个函数也很难从 C 代码中使用,当你 pinvoke 时也不会变得更好。你最好修一下。如果长度是可预测的,请使用 MarshalAs.SizeConst。 【参考方案1】:您对输出字符串的编组不正确。在将数据从托管传递到本机时,在 p/invoke 声明中使用 string
是合适的。但是当数据流向另一个方向时,您不能使用它。相反,您需要使用StringBuilder
。像这样:
[DllImport(...)]
public static extern int my_Funct(string input, StringBuilder output);
然后分配内存用于输出:
StringBuilder output = new StringBuilder(256);
//256 is the capacity in characters - only you know how large a buffer is needed
然后你就可以调用函数了。
int retval = my_Funct(inputStr, output);
string outputStr = output.ToString();
另一方面,如果这些参数中包含空字符,那么您不能将其编组为字符串。那是因为编组器不会编组任何超过空值的东西。相反,您需要将其编组为字节数组。
public static extern int my_Funct(
[In] byte[] input,
[Out] byte[] output
);
这符合你的 C 声明。
然后假设您使用 ANSI 编码将输入字符串转换为这样的字节数组:
byte[] input = Encoding.Default.GetBytes(inputString);
如果您想使用不同的编码,很明显该怎么做。
对于输出,您确实需要分配数组。假设它与输入的长度相同,您可以这样做:
byte[] output = new byte[input.Length];
不知何故,您的 C 函数必须知道数组的长度。我会把这点留给你!
然后就可以调用函数了
int retval = my_Funct(input, output);
然后要将输出数组转换回 C# 字符串,您再次使用 Encoding
类。
string outputString = Encoding.Default.GetString(output);
【讨论】:
以上是关于C DLL 中的 PInvoke char* 在 C# 中作为字符串处理。空字符问题的主要内容,如果未能解决你的问题,请参考以下文章
使用 PInvoke 连接 C/C++ DLL 的调试断言失败