为什么我的应用程序无法正确显示Unicode字符?

4

我决定将我的win32 c++应用程序转换为Unicode版本,但是当我使用它时,阿拉伯语、中文和日语出现了无法阅读的字母...

首先:

如果我不使用Unicode,在编辑框和窗口标题中可以正确显示阿拉伯语:

HWND hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit", "ا ب ت ث ج ح خ د ذ", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE, 10, 10, 300, 200, hWnd, (HMENU)100, GetModuleHandle(NULL), NULL);

SetWindowText(hWnd, "صباح الخير");

输出看上去正常且工作良好!(不含Unicode)。
  • 带有Unicode:

我在包含标题之前添加了:

#define UNICODE
#include <windows.h

现在在窗口过程中:
case WM_CREATE:{
    HWND hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", L"ا ب ت ث ج ح خ د ذ", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE, 10, 10, 300, 200, hWnd, (HMENU)100, GetModuleHandle(NULL), NULL);

    // Even I send message to change text but I get unreadable characters!
}
break;
case WM_LBUTTONDBLCLK:{
    SendDlgItemMessageW(hWnd, 100, WM_SETTEXT, 0, (LPARAM)L"السلام عليكم"); // Get unreadable characters also
}
break;

正如您所看到的,使用Unicode时控件无法正确显示阿拉伯字符。

  • 重要的是:在创建控件后,我手动使用backspace删除内容。现在如果我手动输入阿拉伯文本,则会成功正确显示?!!!但是为什么使用函数呢?例如SetWindowTextW()

请帮忙解决。谢谢。


3
Win32 API不支持UTF-8编码,只支持ANSI和UTF-16编码。 - Remy Lebeau
1
@WonFeiHong:尝试使用WM_SETFONT为编辑控件分配一个启用Unicode的字体。 - Remy Lebeau
4
@Jodocus:我知道那个。但那并不能解决问题。Won已经在与API交互时使用UTF-16了。在内存中使用UTF-8字符串并将其转换为UTF-16并没有解决任何问题。 - Remy Lebeau
2
@Jodocus:你建议使用UTF-8在这种情况下没有任何帮助。它真正解决的唯一问题是内存使用,除了亚洲语言之外,UTF-16实际上比UTF-8更紧凑。一般来说,UTF-16字符串更容易处理,这就是为什么大多数平台使用UTF-16而不是UTF-8(别让我开始谈论*Nix,在这里它是少数派)。UTF-8有其用途,特别是用于通信,但对于GUI和API来说并不是那么重要。 - Remy Lebeau
@IInspectable 我认为这并不是争论那场特定圣战的地方。但据我所听,人们说外部数据文件(如源代码)应该始终以UTF-8保存(经常还说不应该有BOM),而不是说程序员永远不应该在Windows API或QT等环境中使用UTF-16数据。 - Davislor
显示剩余16条评论
2个回答

10

请确保将源文件保存为带有BOM的UTF-16或UTF-8格式。否则,许多Windows应用程序将默认使用ANSI编码(本地化的Windows代码页)。您还可以检查编译器开关以强制使用UTF-8作为源文件编码。例如,MS Visual Studio 2015的编译器具有/utf-8开关,因此不需要保存带BOM的文件。

以下是一个简单的示例,保存为UTF-8格式,然后保存为带有BOM的UTF-8格式,并使用Microsoft Visual Studio编译器进行编译。请注意,如果硬编码W版本的API并在宽字符串中使用L"",则无需定义UNICODE:

#include <windows.h>

int main()
{
    MessageBoxW(NULL,L"ا ب ت ث ج ح خ د ذ",L"中文",MB_OK);
}

结果(UTF-8)。编译器假设了 ANSI 编码(Windows-1252)并错误地解码了宽字符串。

损坏的图像

结果(带 BOM 的 UTF-8)。编译器检测到 BOM 并使用 UTF-8 解码源代码,从而生成正确的宽字符串数据。

正确的图像

这是一段演示解码错误的 Python 代码:

>>> s='中文,ا ب ت ث ج ح خ د ذ'
>>> print(s.encode('utf8').decode('Windows-1252'))
中文,ا ب ت ث ج ح خ د ذ

1
他做得很对,他确保源代码文件正确编码。BOM在运行时不再相关,那只会产生问题。 - Hans Passant
1
是的,如果编译器支持切换到假定UTF-8,则甚至不需要BOM。您只需确保编译器在解码源代码中的宽字符串时选择正确的编码即可。 - Mark Tolonen
1
@BarmakShemirani 我使用了我发布的内容。C代码保存为UTF-8和带BOM的UTF-8编译器使用微软编译器。听起来你正在尝试使用非Unicode WinAPI。 - Mark Tolonen
1
@Davislor CSV 文件被 Excel 读取需要时间。许多 Windows 应用程序假定没有 BOM 的 ANSI。 - Mark Tolonen
1
@WonFeiHong MSVC6.0编译器无法接受UTF-16文件。上次我尝试过,对于这样的旧编译器,你能做的最好的选择是使用UTF-8字符串字面量,并在运行时使用MultiByteToWideChar转换为UTF-16。 - raymai97
显示剩余11条评论

0

我终于搞定了!

1- 在编译和构建程序之前:我去控制面板将所有设置更改为阿拉伯语(语言),然后重新启动计算机。

2- 通过定义宏UNICODE_UNICODE并禁用多字节字符字符串_MBCS,我设置vc++ 6.0使用Unicode。

正如@Remy Lebeau所建议的那样,我在编译器中选择了Simplified Arabic字体(Unicode字体)。

最后,我将输出entrypoint添加到链接器输出wWinMainCRTStartup中。

现在,我编译和构建程序,将某些按钮设置为更改编辑控件文本为阿拉伯字符串。我得到了我想要的结果!谢谢大家!

  • 在VC++ 14中,我可以轻松定义unicode,没有问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接