正在尝试显示和转换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)]
添加这些之后,数据就可以正确通过,而无需进行任何转换。
我认为您正在"破坏"这一行中的字符串:
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