CDLL中的PInvoke char *在C#中作为String处理.空字符问题 [英] PInvoke char* in C DLL handled as String in C#. Issue with null characters

查看:82
本文介绍了CDLL中的PInvoke char *在C#中作为String处理.空字符问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C DLL中的函数如下:

The function in C DLL looks like this:

int my_Funct(char* input, char* output);

我必须从C#应用程序中调用它.我通过以下方式执行此操作:

I must call this from C# app. I do this in the following way:

...DllImport stuff...
public static extern int my_Funct(string input, string output);

输入字符串完美地传输到了DLL(我对此有明显的证明).函数填写的输出虽然是错误的.我有六个数据,例如:

The input string is perfectly transmitted to the DLL (I have visible proof of that). The output that the function fills out although is wrong. I have hexa data in it, like:

3F-D9-00-01

但是不幸的是,两个零之后的所有内容都被剪切掉了,只有前两个字节进入了我的C#应用​​程序.之所以会发生这种情况,是因为(我想)它将视为空字符,并将其作为字符串的结尾.

But unfortunately everything that is after the two zeros is cut, and only the first two bytes come to my C# app. It happens, because (I guess) it treats as null character and takes it as the end of the string.

任何想法我该如何摆脱它?我试图将其指定为IntPtr而不是字符串,但是之后我不知道该如何处理. 我尝试过以下步骤:

Any idea how could I get rid of it? I tried to specifiy it as out IntPtr instead of a string, but I don't know what to do with it afterwards. I tried to do after:

 byte[] b1 = new byte[2];
 Marshal.Copy(output,b1,0,2);

2通常应为字节数组的长度.但是我遇到了各种各样的错误:例如请求的范围超出了数组的末尾".或尝试读取或写入受保护的内存..."

2 should be normally the length of the byte array. But I get all kind of errors: like "Requested range extends past the end of the array." or "Attempted to read or write protected memory..."

感谢您的帮助.

推荐答案

您对输出字符串的编组不正确.当将数据从托管传递到本地时,在p/invoke声明中使用string是合适的.但是,当数据沿另一个方向流动时,您将无法使用它.相反,您需要使用StringBuilder.像这样:

Your marshalling of the output string is incorrect. Using string in the p/invoke declaration is appropriate when passing data from managed to native. But you cannot use that when the data flows in the other direction. Instead you need to use StringBuilder. Like this:

[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

然后您可以调用该函数.

And then you can call the function.

int retval = my_Funct(inputStr, output);
string outputStr = output.ToString();


另一方面,如果这些参数中包含空字符,则无法将其编组为字符串.那是因为封送员不会封送超过null的任何东西.相反,您需要将其封送为字节数组.


On the other hand, if these parameters have null characters in them then you cannot marshal as string. That's because the marshaller won't marshal anything past the null. Instead you need to marshal it as a byte array.

public static extern int my_Funct(
    [In] byte[] input, 
    [Out] byte[] output
);

与您的C声明匹配.

然后假设您将ANSI编码转换为如下所示的字节数组:

Then assuming the ANSI encoding you convert the input string to a byte array like this:

byte[] input = Encoding.Default.GetBytes(inputString);

如果您想使用其他编码,很明显的方法.

If you want to use a different encoding, it's obvious how to do so.

对于输出,您确实需要分配数组.假设它与输入的长度相同,您将执行以下操作:

And for the output you do need to allocate the array. Assuming it's the same length as the input you would do this:

byte[] output = new byte[input.Length];

以某种方式,您的C函数必须知道数组的长度.我会留给你!

And somehow your C function has got to know the length of the arrays. I'll leave that bit to you!

然后您可以调用该函数

int retval = my_Funct(input, output);

然后将输出数组转换回C#字符串,请再次使用Encoding类.

And then to convert the output array back to a C# string you use the Encoding class again.

string outputString = Encoding.Default.GetString(output);

这篇关于CDLL中的PInvoke char *在C#中作为String处理.空字符问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆