我目前正在使用 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"
在运行时不可读,因为它们显示为小方块,就像代码页不是正确的那样或类似的东西。当我运行教程时,所有字符串都正确显示。我倾向于完全坚持教程所说的内容,以帮助我把事情做好,而且它的教学法很好。反正!...
我正在使用:
任何人都有这方面的线索吗?
答案 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在编译时由宏映射到MessageBoxA
或MessageBoxW
,具体取决于是否定义了预处理程序符号UNICODE
。
此映射无法修复字符串文字,因此它们还引入了一个宏来指定字符串文字,这些文字要么是窄的,要么是宽的,具体取决于UNICODE
,以及匹配的typedef,以便可以将变量声明为抓住他们的指针。
因此,为了获得Win16的最佳可移植性,您可以#include <tchar.h>
使用TCHAR
代替char
或wchar_t
,将所有包含文本的字符串文字换行_T()
宏,并使用非MessageBox
等非后缀名称调用Win32 API。
然而,这不是一个完美的解决方案。在您的代码需要操作或计算将向用户显示的字符串的那一刻,您发现编写在TCHAR
制度中完全可移植的代码是很困难的。操作TCHAR
的所有标准字符串函数都有替换,但很难通过自动化测试验证您是否正确使用它们,以便代码可以编译并在有{和1}的情况下正常工作定义。
如果今天编写新的Win32代码,我的建议是在项目中定义UNICODE,添加一个检查,确定它是在一个公共头文件中真正定义的,并使用UNICODE
字符串和L""
所有包装调用的风格明确。
最后,整个文章是由显示缺失字符字形的代码提示的(空方框字符是字体缺少特定字符时显示的字形)。这是因为您的ASCII字符串文字被Win32代码解释为好像它们是UTF-16LE,因此字符串“Exit”将被视为两个Unicode字符,W
和U+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中描述。