Ros*_*ost 4 c++ unicode winapi fonts non-unicode
我正在尝试显示Wingdings字体的Unicode字符(它的Unicode TrueType字体仅支持符号字符集).它使用相应的区域操作系统设置在我的Win7/64系统上正确显示:
但是,如果我将系统区域设置切换为俄语,则代码> 127的Unicode字符显示不正确(替换为框).
我的应用程序是在Visual Studio中使用Unicode Charset创建的,它只调用Unicode Windows API函数.
另外我注意到有几个Windows应用程序也会错误地使用符号字体(符号,Wingdings,Webdings等)显示这些字符,例如Notepad,Beyond Compare 3.但是WordPad和MS Office应用程序不会受到影响.
这是最小的代码片段(为简洁起见,跳过了资源清理):
LOGFONTW lf = { 0 };
lf.lfCharSet = SYMBOL_CHARSET;
lf.lfHeight = 50;
wcscpy_s(lf.lfFaceName, L"Wingdings");
HFONT f = CreateFontIndirectW(&lf);
SelectObject(hdc, f);
// First two chars displayed OK, 3rd and 4th aren't (replaced with boxes) if
// Non-Unicode apps language is NOT English.
TextOutW(hdc, 10, 10, L"\x7d\x7e\x81\xfc");
Run Code Online (Sandbox Code Playgroud)
所以问题是:为什么地狱非Unicode应用程序语言设置会影响Unicode应用程序?
什么是显示SYMBOL_CHARSET字体而不依赖于OS系统区域设置的正确(也是最简单)方法?
问题的根本原因是Wingdings字体实际上是非Unicode字体.它部分支持Unicode,因此仍然可以正确显示某些符号.请参阅@Adrian McCarthy的答案,详细了解它是如何在幕后工作的.
另请参阅此处的更多信息:http://www.fileformat.info/info/unicode/font/wingdings 和此处:http://www.alanwood.net/demos/wingdings.html
那么我们可以做些什么来避免这些问题呢?我找到了几种方法:
1.快速而肮脏
回退到ANSI版本的API,如@ user1793036建议:
TextOutA(hdc, 10, 10, "\x7d\x7e\x81\xfc"); // Displayed correctly!
Run Code Online (Sandbox Code Playgroud)
2.快速清洁
使用特殊的Unicode范围F0(专用区域)而不是ASCII字符代码.它受到Wingdings的支持:
TextOutW(hdc, 10, 10, L"\xf07d\xf07e\xf081\xf0fc"); // Displayed correctly!
Run Code Online (Sandbox Code Playgroud)
要探索字体实际支持哪些Unicode符号,可以使用某些字体查看器,例如dp4 Font Viewer
3.缓慢干净,但通用
但是,如果您不知道必须显示哪些字符以及实际使用哪种字体该怎么办?这是最通用的解决方案 - 通过字形绘制文本以避免任何不需要的翻译:
void TextOutByGlyphs(HDC hdc, int x, int y, const CStringW& text)
{
CStringW glyphs;
GCP_RESULTSW gcpRes = {0};
gcpRes.lStructSize = sizeof(GCP_RESULTS);
gcpRes.lpGlyphs = glyphs.GetBuffer(text.GetLength());
gcpRes.nGlyphs = text.GetLength();
const DWORD flags = GetFontLanguageInfo(hdc) & FLI_MASK;
GetCharacterPlacementW(hdc, text.GetString(), text.GetLength(), 0,
&gcpRes, flags);
glyphs.ReleaseBuffer(gcpRes.nGlyphs);
ExtTextOutW(hdc, x, y, ETO_GLYPH_INDEX, NULL, glyphs.GetString(),
glyphs.GetLength(), NULL);
}
TextOutByGlyphs(hdc, 10, 10, L"\x7d\x7e\x81\xfc"); // Displayed correctly!
Run Code Online (Sandbox Code Playgroud)
注意GetCharacterPlacementW()功能用法.由于某些未知原因,类似函数GetGlyphIndicesW()无法返回字符> 127的"不支持"虚拟值.