Windows Unicode C ++stream输出失败

我目前正在编写一个应用程序,它要求我在任意窗口上调用GetWindowText,并将这些数据存储到一个文件中供以后处理。 长话短说,我注意到我的工具在“战地风云3”上失败了,我把它缩小到窗口标题中的下列字符: http : //www.fileformat.info/info/unicode/char/2122/index。 HTM

所以我创build了一个小testing应用程序,只是做了以下几点:

std::wcout << L"\u2122"; 

低,看到输出到控制台窗口剩余的程序。

为什么MSVC STL窒息这个字符(我假设其他人),如MessageBoxW等API显示它就好了?

我怎样才能把这些字符打印到我的文件?

Windows 7 x64下testingVC10和VC11。

对不起,这个build设不好的职位,我正在把我的头发撕在这里。

谢谢。

编辑:

最小的testing用例

 #include <fstream> #include <iostream> int main() { { std::wofstream test_file("test.txt"); test_file << L"\u2122"; } std::wcout << L"\u2122"; } 

预期结果:打印到控制台和文件的“™”字符。 观察结果:文件被创build但是是空的。 没有输出到控制台。

我已经确认,我用于我的控制台的字体能够显示有问题的字符,并且文件肯定是空的(0字节大小)。

编辑:

进一步的debugging表明在stream中设置了'failbit'和'badbit'。

编辑:

我也尝试过使用Boost.Locale,即使在新的语言环境被全局灌注并明确指向所有标准stream的情况下,我也遇到了同样的问题。

要写入文件,必须正确设置区域设置,例如,如果要将它们编写为UTF-8字符,则必须添加

 const std::locale utf8_locale = std::locale(std::locale(), new std::codecvt_utf8<wchar_t>()); test_file.imbue(utf8_locale); 

你必须添加这2个包含文件

 #include <codecvt> #include <locale> 

要写入控制台,您必须通过添加,以正确的模式(这是特定于Windows)设置控制台

 _setmode(_fileno(stdout), _O_U8TEXT); 

(如果你想使用UTF-8)。

为此,您必须添加这2个包含文件:

 #include <fcntl.h> #include <io.h> 

此外,您必须确保您使用的是支持Unicode的字体(例如Lucida控制台)。 您可以在控制台窗口的属性中更改字体。

完整的程序现在看起来像这样:

 #include <fstream> #include <iostream> #include <codecvt> #include <locale> #include <fcntl.h> #include <io.h> int main() { const std::locale utf8_locale = std::locale(std::locale(), new std::codecvt_utf8<wchar_t>()); { std::wofstream test_file("c:\\temp\\test.txt"); test_file.imbue(utf8_locale); test_file << L"\u2122"; } _setmode(_fileno(stdout), _O_U8TEXT); std::wcout << L"\u2122"; } 

你总是使用std::wcout或者你有时使用std::cout 混合这些将无法正常工作。 当然,错误描述“窒息”根本不说你观察到什么问题。 但是,我怀疑这是使用文件的问题。

由于没有真正的问题描述,需要一些水晶球,然后在黑暗中击中问题…因为你想从你的文件中获取Unicode字符请确保你正在使用的文件流使用一个std::localestd::codecvt<...>方面实际上转换为适当的Unicode编码。

我刚刚测试了GCC(版本4.4到4.7)和MSVC 10,都显示出这个问题。

同样是破坏的是wprintf ,它和C ++流API一样小。

我也测试了原始的Win32 API,看看是否没有其他的东西导致失败,这个工程:

 #include <windows.h> int main() { HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE); DWORD n; WriteConsoleW( stdout, L"\u03B2", 1, &n, NULL ); } 

β写到控制台(如果你把cmd的字体设置成Lucida Console)。

结论:在大型C ++标准库实现中, wchar_t输出被严重破坏。

虽然宽字符流将Unicode作为输入,但这不是他们产生的输出 – 字符经过转换。 如果一个字符不能被转换成的编码表示,输出失败。