我的字符集有什么问题(Win32 API)

时间:2010-12-13 21:15:07

标签: c menu winapi windows-messages

我目前正在使用 this tutorial 学习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;

这是在我的switch函数中的WndProc块内部,它处理从消息循环接收的Windows消息。

要显示的每个字符串:

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

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

我正在使用:

  1. Microsoft Visual Studio 2008团队系统;
  2. 使用RDP的Microsoft Windows Server 2003;
  3. 本地操作系统是Windows Vista Ultimate。
  4. 任何人都有这方面的线索吗?

2 个答案:

答案 0 :(得分:6)

Unicode与Windows ANSI字符编码存在问题。从历史上看,Windows使用扩展的ASCII,他们错误地命名为ANSI。这带来了对代码页的需求,因为即使是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代替charwchar_t,将所有包含文本的字符串文字换行_T()宏,并使用非MessageBox等非后缀名称调用Win32 API。

然而,这不是一个完美的解决方案。在您的代码需要操作或计算将向用户显示的字符串的那一刻,您发现编写在TCHAR制度中完全可移植的代码是很困难的。操作TCHAR的所有标准字符串函数都有替换,但很难通过自动化测试验证您是否正确使用它们,以便代码可以编译并在有{和1}的情况下正常工作定义。

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

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

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

U+7469

但您应该拥有以下其中一项:

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

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

答案 1 :(得分:4)

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

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