正在尝试显示和转换2字节的unicode字符串

本文关键字:字节 unicode 字符串 转换 显示 | 更新日期: 2023-09-27 18:22:37

我在一个C#WPF项目中调用了一个C接口方法。该方法通过StringBuilder返回一个2字节的Unicode(UTF-16,如果我没有弄错的话)字符串。我试图在WPF TextBox控件中显示这个2字节的Unicode字符串,并将其写入.txt文件。

TextBox.txt文件中的结果似乎都不可读。

我尝试过将Unicode(UTF-16)字符串转换为ANSI,但这也不起作用。

下面是DllImport和代码示例,我试图将字符串转换为可读的内容。

[DllImport("cdll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
extern static int ChannelID(int uHandle, uint uChannel, StringBuilder szID);
for (uint i = 0; i <= numChannels - 1; i++)
{
     StringBuilder sbId = new StringBuilder(32);
     ChannelID(_handle, i, sbId);
     string val = "";
     UnicodeEncoding unicode = new UnicodeEncoding();
     val = Encoding.Default.GetString(Encoding.Convert(Encoding.Unicode, Encoding.Default, unicode.GetBytes(sbId.ToString())));
     File.AppendAllText(System.AppDomain.CurrentDomain.BaseDirectory + "dump.txt", sbId.ToString() + " - ", Encoding.Unicode);                
     textBox1.AppendText(val + " - ");
     textBox1.AppendText(sbId.ToString() + " - ");
}

正在从连接了蓝牙的设备中读取字符串。该设备用于测量温度、空气湿度、气压等。。。

因此,输入是一个Unicode字符串,例如°c,屏幕上和txt文件中的输出应该是该字符串的可读版本(例如ansi)。

另一个可能很重要的信息是,C方法最初用于excel Macro VBA项目,因此使用了2字节Unicode编码。

解决方案

这个问题与DllImport中的CharSet无关,而是与CallingConvention有关。在联系了制作C库的人后,他们告诉我他们给了我们一个错误的示例代码。正确的DllImport是这样的:

[DllImport("cdll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]

添加这些之后,数据就可以正确通过,而无需进行任何转换。

正在尝试显示和转换2字节的unicode字符串

我认为您正在"破坏"这一行中的字符串:

val = Encoding.Default.GetString(Encoding.Convert(Encoding.Unicode, Encoding.Default, unicode.GetBytes(sbId.ToString())));

由于.NET完全能够处理双字节unicode字符,因此您想要的字符串应该已经在sbId中,因此理想情况下,以下内容应该有效:

val = sbId.ToString();

当您停在上面的行并检查sbId的值时,调试器会显示什么?

 CharSet = CharSet.Unicode

这就是你出错的地方,它不是Unicode。您必须使用CharSet.Ansi。

unicode字符串需要两个0字节才能终止该字符串。本机代码只生成一个。正常的命运是AccessViolationException,但你通常不会幸运地得到它。在内存中找到两个相邻的二进制零有点太可能了。所以你会得到一个很长的字符串,只是随机的垃圾。

只要声明它的真实情况,CharSet.Ansi。您也不再需要Encoding.Convert()代码了。

由于不清楚预期输出是什么,您仍然可以尝试:

 byte[] bytes = Encoding.UTF8.GetBytes("°c");
 Console.WriteLine(Encoding.ASCII.GetString(bytes));

这将输出作为??c