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

我目前正在使用本教程学习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; 

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

要显示的每个字符串:

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

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

我正在使用:

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

有人对此有所了解吗?

您对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代替charwchar_t ,将所有包含文本的字符串文字包装在_T()宏中,并调用Win32 API MessageBox等非后缀名称。

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

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

最后,整个文章是由显示缺失字符字形的代码提示的(空方框字符是字体缺少特定字符时显示的字形)。 这是因为您的ASCII字符串文字被Win32代码解释为好像它们是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"); 

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

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

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