【问题标题】:Trying to show and convert a 2 byte unicode string试图显示和转换一个 2 字节的 unicode 字符串
【发布时间】:2016-02-20 03:24:30
【问题描述】:

我在 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 宏 VBA 项目中使用的,因此使用了这个 2 字节的 Unicode 编码。

解决方案

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

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

添加此数据后,数据正​​确通过,无需进行任何转换。

【问题讨论】:

  • 输入和预期输出是什么?
  • 我已经在我的问题的文件中添加了输入(来自 c 方法的结果)和我期望的输出。
  • 如果方法设法将字符串正确地放入StringBuilder,则根本不需要转换。只需使用szID.ToString() 获取字符串,您可以在写入文件并将其放入文本框中时直接使用它。如果不是,那么你有一些不是 UFT-16 字符串而是其他的东西,所以要转换它你需要知道它是什么。

标签: c# wpf unicode utf-16


【解决方案1】:

我认为你在这一行“破坏”了你的字符串:

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

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

val = sbId.ToString();

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

【讨论】:

  • 当我试图显示我的 stringbuilder 的 ToString() 方法时,我仍然得到一个不可读的刺痛,这就是我开始修补编码转换的原因。但是,有些字符是可读的,例如,一行返回 ppm CO,在这种情况下,CO 是可读的。 ppm 可能是 unicode 字符。
  • 我已经 +1 了你的答案,一旦我从编写我正在使用的 C 库的人那里得到一些反馈,我会将其标记为答案,因为它验证了我的怀疑可能在 C 代码中出错。
  • 正如我所说,我将其标记为答案,问题的实际原因已添加到我的问题中,并提供了正确的解决方案。
【解决方案2】:
 CharSet = CharSet.Unicode

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

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

只要声明它的真正含义,CharSet.Ansi。而且你也不再需要 Encoding.Convert() 代码了。

【讨论】:

  • 这也不起作用,结果类似于使用 CharSet.Unicode。目前,编写我正在使用的 C dll 的人正在研究它,C 代码可能错误地传递了字符串。这里的 cmets 有点验证了这个想法 :)
【解决方案3】:

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

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

这将输出为 ??c

【讨论】:

    猜你喜欢
    • 2012-11-30
    • 2019-05-20
    • 1970-01-01
    • 2017-04-16
    • 2010-10-08
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 2018-07-23
    相关资源
    最近更新 更多