Windows Unicode C++ 流输出失败

2021-12-26 00:00:00 unicode windows c++ stl wofstream

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

I am currently writing an application which requires me to call GetWindowText on arbitrary windows and store that data to a file for later processing. Long story short, I noticed that my tool was failing on Battlefield 3, and I narrowed the problem down to the following character in its window title: http://www.fileformat.info/info/unicode/char/2122/index.htm

所以我创建了一个小测试应用程序,它只执行以下操作:

So I created a little test app which just does the following:

std::wcout << L"u2122";

低,瞧,这会中断程序其余部分的控制台窗口的输出.

Low and behold that breaks output to the console window for the remainder of the program.

当 MessageBoxW 等 API 显示得很好时,为什么 MSVC STL 会在这个字符上窒息(我假设其他人)?

Why is the MSVC STL choking on this character (and I assume others) when APIs like MessageBoxW etc display it just fine?

如何将这些字符打印到我的文件中?

How can I get those characters printed to my file?

在 Windows 7 x64 下的 VC10 和 VC11 上均已测试.

Tested on both VC10 and VC11 under Windows 7 x64.

对不起,帖子结构很差,我在这里扯头发.

Sorry for the poorly constructed post, I'm tearing my hair out here.

谢谢.

最小测试用例

#include <fstream>
#include <iostream>

int main()
{
  {
    std::wofstream test_file("test.txt");
    test_file << L"u2122";
  }

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

预期结果:'?' 字符打印到控制台和文件.观察结果:文件已创建但为空.没有输出到控制台.

Expected result: '?' character printed to console and file. Observed result: File is created but is empty. No output to console.

我已确认我用于控制台的字体能够显示相关字符,并且文件绝对是空的(大小为 0 字节).

I have confirmed that the font I"m using for my console is capable of displaying the character in question, and the file is definitely empty (0 bytes in size).

进一步的调试表明在流中设置了failbit"和badbit".

Further debugging shows that the 'failbit' and 'badbit' are set in the stream(s).

我也尝试过使用 Boost.Locale,即使新的语言环境在所有标准流中全局且明确地灌输,我也遇到了同样的问题.

I have also tried using Boost.Locale and I am having the same issue even with the new locale imbued globally and explicitly to all standard streams.

推荐答案

要写入文件,必须正确设置语言环境,例如要写入为 UTF-8 字符,则必须添加

To write into a file, you have to set the locale correctly, for example if you want to write them as UTF-8 characters, you have to add

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

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

You have to add these 2 include files

#include <codecvt>
#include <locale>

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

To write to the console you have to set the console in the correct mode (this is windows specific) by adding

_setmode(_fileno(stdout), _O_U8TEXT);

(如果您想使用 UTF-8).

(in case you want to use UTF-8).

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

For this you have to add these 2 include files:

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

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

Furthermore you have to make sure that your are using a font that supports Unicode (such as for example Lucida Console). You can change the font in the properties of your console window.

现在完整的程序如下所示:

The complete program now looks like this:

#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";
}

相关文章