我试图从Wingdings字体显示Unicode字符(它的Unicode TrueType字体仅支持符号字符集)。 它使用相应的区域操作系统设置在我的Win7 / 64系统上正确显示:
但如果我将系统区域设置切换为俄语,则代码为>的Unicode字符127显示不正确(替换为方框)。
我的应用程序是在Visual Studio中使用Unicode Charset创建的,它只调用Unicode Windows API函数。
另外我注意到有几个Windows应用程序也会错误地使用符号字体(符号,Wingdings,Webdings等)显示这样的字符,例如记事本,超越比较3.但写字板和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");
所以问题是:为什么地狱非Unicode应用程序语言设置会影响Unicode应用程序?
在不依赖于OS系统区域设置的情况下显示SYMBOL_CHARSET
字体的正确(且最简单)方法是什么?
答案 0 :(得分:5)
问题的根本原因是Wingdings字体实际上是非Unicode 字体。它部分支持Unicode,因此仍然可以正确显示某些符号。请参阅 @Adrian McCarthy 的答案,了解有关它如何在幕后工作的详细信息。
另请参阅此处的详细信息:http://www.fileformat.info/info/unicode/font/wingdings 在这里:http://www.alanwood.net/demos/wingdings.html
那么我们可以做些什么来避免这些问题呢?我找到了几种方法:
<强> 1。快速&amp;脏强>
回到ANSI版API,建议 @ user1793036 :
TextOutA(hdc, 10, 10, "\x7d\x7e\x81\xfc"); // Displayed correctly!
<强> 2。快速&amp;清洁强>
使用特殊的Unicode范围F0
(Private Use Area)而不是ASCII字符代码。它得到了Wingdings的支持:
TextOutW(hdc, 10, 10, L"\xf07d\xf07e\xf081\xf0fc"); // Displayed correctly!
为了探索字体实际支持哪些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!
注意GetCharacterPlacementW()
函数用法。由于某些未知原因,类似的函数GetGlyphIndicesW()
无法为chars&gt;返回'notpported'虚拟值。 127。
答案 1 :(得分:4)
以下是我的想法:
Wingdings字体没有Unicode映射(cmap表?)。 (您可以使用charmap.exe查看此信息:Character set
下拉控件显示为灰色。)
对于没有Unicode映射的字体,我认为Windows假定它依赖于“非Unicode应用程序的语言”设置。
当这是英文时,Windows(可能)使用代码页1252,所有值都映射到自己。
当这是俄语时,Windows(可能)使用代码页1251,然后尝试重新映射它们。
代码页1251中的'\x81'
值映射到U+0403
,这显然不存在于字体中,因此您会得到一个框。同样,'\xFC'
映射到U+044C
。
我认为如果你使用带有ExtTextOutW
标志的ETO_GLYPH_INDEX
,Windows就不会尝试解释这些值,只是将它们视为字体中的字形索引。但这种假设是错误的。
但是,还有另一个名为ETO_IGNORELANGUAGE
的标志,它是保留的,但从经验上看,似乎可以解决问题。