试图显示和转换一个 2 字节的 unicode 字符串
Trying to show and convert a 2 byte unicode string
我在 C# WPF 项目中调用了一个 C 接口方法。方法 returns 一个 2 字节的 Unicode(UTF-16,如果我没记错的话)字符串通过 StringBuilder
。我试图在 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 宏 VBA 项目,因此使用了这个 2 字节的 Unicode 编码。
解决方案
问题与 DllImport
中的 CharSet 无关,而与 CallingConvention 有关。在联系了制作 C 库的人后,他们告诉我他们给了我们一个错误的示例代码。正确的DllImport
是这个:
[DllImport("cdll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
添加这个之后数据就可以正确通过了,不需要做任何转换。
由于不清楚预期的输出是什么,您仍然可以尝试:
byte[] bytes = Encoding.UTF8.GetBytes("°c");
Console.WriteLine(Encoding.ASCII.GetString(bytes));
这给出了输出 ??c
我认为你是 "destroying" 这一行中的字符串:
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() 代码。
我在 C# WPF 项目中调用了一个 C 接口方法。方法 returns 一个 2 字节的 Unicode(UTF-16,如果我没记错的话)字符串通过 StringBuilder
。我试图在 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 宏 VBA 项目,因此使用了这个 2 字节的 Unicode 编码。
解决方案
问题与 DllImport
中的 CharSet 无关,而与 CallingConvention 有关。在联系了制作 C 库的人后,他们告诉我他们给了我们一个错误的示例代码。正确的DllImport
是这个:
[DllImport("cdll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
添加这个之后数据就可以正确通过了,不需要做任何转换。
由于不清楚预期的输出是什么,您仍然可以尝试:
byte[] bytes = Encoding.UTF8.GetBytes("°c");
Console.WriteLine(Encoding.ASCII.GetString(bytes));
这给出了输出 ??c
我认为你是 "destroying" 这一行中的字符串:
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() 代码。