but it remains a mystery why Liaomi's system works differently. 
Hi Biterider,
Prologue>Version 12.0.0 has been superseded by the latest version of the
Unicode Standard -
https://unicode.org/versions/Unicode12.0.0/All Chapters and Appendices Together:
• Full Text pdf for Viewing (14 MB) -
http://www.unicode.org/versions/Unicode12.0.0/UnicodeStandard-12.0.pdfCoded Character Sets, History and Development :
https://archive.org/details/mackenzie-coded-char-setshttps://archive.org/download/mackenzie-coded-char-sets/Mackenzie_CodedCharSets.pdfWriting Unicode programs - GoAsm manual -
http://www.godevtool.com/GoasmHelp/Unicode.htmMain partWhy Non-Unicode apps system locale makes Unicode fonts with symbol charset displayed incorrectly? -
https://stackoverflow.com/questions/21383099/why-non-unicode-apps-system-locale-makes-unicode-fonts-with-symbol-charset-displThe root cause of the problem is that
Wingdings font is actually non-Unicode font. It supports Unicode partially, so some symbols are still displayed correctly. See
@Adrian McCarthy's answer for details about how it's probably works under the hood.
Also see more info here:
http://www.fileformat.info/info/unicode/font/wingdings and here:
http://www.alanwood.net/demos/wingdings.htmlSo what can we do to avoid such problems? I found several ways:
1. Quick & dirtyFall back to ANSI version of API, as @user1793036 suggested:
TextOutA(hdc, 10, 10, "\x7d\x7e\x81\xfc"); // Displayed correctly!
2. Quick & cleanUse special
Unicode range F0 (Private Use Area - https://en.wikipedia.org/wiki/Private_Use_Areas) instead of ASCII character codes. It's supported by Wingdings:
TextOutW(hdc, 10, 10, L"\xf07d\xf07e\xf081\xf0fc"); // Displayed correctly!
To explore which Unicode symbols are actually supported by font some font viewer can be used, e.g. dp4 Font Viewer
3. Slow & clean, but genericBut what to do if you don't know which characters you have to display and which font actually will be used? Here is most universal solution - draw text by glyphs to avoid any undesired translations:
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!
Note GetCharacterPlacementW() function usage. For some unknown reason similar function GetGlyphIndicesW() would not work returning 'unsupported' dummy values for chars > 127.
@Adrian McCarthy'sHere's what I think is happening:
The Wingdings font doesn't have Unicode mappings (a cmap table?). (You can see this by using charmap.exe: the Character set drop down control is grayed out.)
For fonts without Unicode mappings, I think Windows assumes that it depends on the "Language for Non-Unicode applications" setting.
When that's English, Windows (probably) uses code page 1252, and all the values map to themselves.
When that's Russian, Windows (probably) uses code page 1251, and then
tries to remap them.
The '\x81' value in code page 1251 maps to U+0403, which obviously doesn't exist in the font, so you get a box. Similarly the, '\xFC' maps to U+044C.
I assumed that if you used ExtTextOutW with the ETO_GLYPH_INDEX flag, Windows wouldn't try to interpret the values at all and just treat them as glyph indexes into the font. But that assumption is wrong.
However, there is another flag called ETO_IGNORELANGUAGE, which is reserved, but, empirically, it seems to solve the problem.
user1793036I recall that on a Unicode build of my app some symbols would get the rectangle glyph, where in the Ansi build they would display fine. When I searched online I discovered that WingDings is only partially supported in Unicode. My solution was to draw each character using DrawTextA. This worked for me because I was only drawing individual characters.RostUnfortunately ETO_IGNORELANGUAGE is not working, still same boxes are drawn.