1

我目前正在使用本教程学习 Win32 ,但我很难处理我显示的字符。

以这段代码为例,它在创建时向我的窗口添加了一个菜单:

    case WM_CREATE: {
            HMENU hMenu, hSubMenu;
            HICON hIcon, hIconSm;

            hMenu = CreateMenu();
            hSubMenu = CreatePopupMenu();

            AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit");
            AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "File");

            hSubMenu = CreatePopupMenu();
            AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&GO");
            AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Stuff");

            SetMenu(hwnd, hMenu);

            hIcon = LoadImage(NULL, "Stuff.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);

            if (hIcon)
                SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
            else
                MessageBox(hwnd, "Could not load large icon!", "Load Error", MB_OK | MB_ICONERROR);

            hIconSm = LoadImage(NULL, "Stuff.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);

            if(hIconSm)
                SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
            else
                MessageBox(hwnd, "Could not load small icon!", "Load Error", MB_OK | MB_ICONERROR);
        }
        break;

那是在我的函数中处理从消息循环接收到的 Windows 消息的switch块内。WndProc

要显示的每个字符串:

"Exit"
"File"
"&GO"
"&Stuff"

在运行时不可读,因为它们显示为小方块,就像代码页不是正确的那样或类似的东西。当我运行教程时,所有字符串都正确显示。我倾向于完全按照教程所说的来帮助我把事情做好,而且它的教学法很好。反正!...

我在用着:

  1. Microsoft Visual Studio 2008 团队系统;
  2. 使用 RDP 的 Microsoft Windows Server 2003;
  3. 本地操作系统是 Windows Vista Ultimate。

有人知道吗?

4

2 回答 2

8

您遇到了 Unicode 与 Windows ANSI 字符编码的问题。从历史上看,Windows 使用了他们错误地命名为 ANSI 的扩展 ASCII。这带来了对代码页的需求,因为即使是 8 位字符也无法提供足够的代码点来表示所有欧洲书写系统,更不用说世界其他地方了。在开发 Win32 时,他们选择 Unicode 作为首选字符集。(实际上,他们确定了 Unicode 字符集的 UTF-16LE 编码,但现在这个细节并不完全相关。)然而,有太多的现有代码需要考虑,要求从 Win16 移植到 Win32 也需要更改所有字符串的字符编码。

他们的解决方案很聪明(有些人认为它太聪明了)。每个接受字符串的 Win32 API 入口点都有两种形式。第一种风格采用 ANSI 字符串并在内部处理到 UTF-16LE 的转换。第二种(现在是首选)风格直接采用 UTF-16LE 字符串。他们还与 Visual C 团队合谋将其定义wchar_t为 16 位类型,并确保L""字符串文字使用从 ASCII 文本到 UTF-16LE 的映射。

为了使现有 Win16 代码的移植变得容易,MessageBox函数和所有其他接受字符串的 Win32 API 在编译时通过宏映射到MessageBoxAMessageBoxW取决于是否UNICODE定义了预处理器符号。

此映射无法修复字符串文字,因此他们还引入了一个宏来指定要根据 变窄或变宽的字符串文字UNICODE,以及匹配的 typedef 以便可以声明变量以保存指向它们的指针。

因此,为了获得与 Win16 之间的最佳可移植性,您将#include <tchar.h>使用TCHAR代替charor wchar_t,将所有包含文本的字符串文字包装在_T()宏中,并使用非后缀名称调用 Win32 API,例如MessageBox.

然而,这并不是一个完美的解决方案。当您的代码需要操作或计算将显示给用户的字符串时,您会发现很难编写在该TCHAR机制中完全可移植的代码。操作 s 的所有标准字符串函数都有替代品TCHAR,但很难通过自动化测试来验证您是否正确使用了它们,以便代码在有和没有UNICODE定义的情况下都能正确编译和工作。

如果今天编写新的 Win32 代码,我的建议是在项目中定义 UNICODE,添加一个检查它是否真的定义在一个公共头文件中,并明确使用L""字符串和W所有包装调用的风格。

最后,整篇文章由显示缺失字符字形的代码提示(空方框字符是字体缺失特定字符时显示的字形)。发生这种情况是因为 Win32 代码将您的 ASCII 字符串文字解释为好像它们是 UTF-16LE,因此字符串“Exit”将被视为两个 Unicode 字符U+7845U+7469,它们都是统一的汉字表意文字。除非您安装了 Han 字体,否则两者都不太可能出现在系统上的任何字体中,因此您会得到丢失的字符字形。

发生这种情况是因为您将包装宏与 ASCII 字符串文字混合在一起。你有:

AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit");

但您应该具备以下条件之一:

AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, _T("Exit"));
AppendMenuA(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit");
AppendMenuW(hSubMenu, MF_STRING, ID_FILE_EXIT, L"Exit");

我更喜欢推荐最后一个例子。

于 2010-12-13T21:53:16.033 回答
4

由于对小方块的所有应有的陌生感,您的代码是错误的。它不符合 Unicode。您应该在所有字符串前加上 L(如在 L"string" 中)并将编译设置更改为 Unicode(这使得 windows 函数接受 UTF-16 编码)。这是 Windows 本机编码,这就是在 Windows 上完成文本的方式。

另一种方法是使用宽 API 并在调用 API 时转换为 UTF-16。它在http://utf8everywhere.org中有描述。

于 2010-12-13T21:22:36.033 回答