c++ – wcout in WinXP using MinGW w64

Question:

How to output non-ASCII text using std::wcout on Windows XP when using MinGW w64 for compilation? Already looked at a bunch of similar questions, but none of this works. _setmode(_fileno(stdout), _O_U16TEXT) returns -1, compiling with -municode doesn't help – the message is printed to the first non-ASCII character. (full command: i686-w64-mingw32-g++ -mconsole -municode -static ). On the other hand, here's the code:

int wmain() {
    DWORD _;
    std::wstring ws = L"кошка\n";
    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.size(), &_, nullptr);
    return 0;
}

prints the message correctly, but I would like to use wcout. Maybe there is a way?

Answer:

A temporary solution: write your own std::wstreambuf that would output strings through WriteConsoleW and read through ReadConsoleW . Then objects of these classes can be placed in wcout and wcin and then they will work correctly with non-ASCII text.

This code can be placed in a .cpp file and simply added to the project.

#include <iostream>
#include <windows.h>
#include <vector>

class MyWriteBuf:public std::wstreambuf{
public:
    MyWriteBuf(DWORD handle):std::wstreambuf(), _handle(handle){
    }
protected:
    virtual std::streamsize xsputn(const wchar_t* s, std::streamsize num) override {
        std::copy(s, s + num,
                  std::back_inserter(_buffer));
        return num;
    }
    virtual int sync() override {
        if (!_buffer.empty()) {
            std::wstring str(_buffer.cbegin(), _buffer.cend());
            DWORD _;
            WriteConsoleW(GetStdHandle(_handle), str.c_str(), str.size(), &_, nullptr);
            _buffer.clear();
        }
        return 0;
    }
private:
    DWORD _handle;
    std::vector<wchar_t> _buffer;
};

class MyReadBuf:public std::wstreambuf{
public:
    MyReadBuf():std::wstreambuf(){
        setg(_chars, _chars+BUF_SIZE, _chars+BUF_SIZE);
    }
protected:
    int_type underflow() override {
        DWORD num_read;
        ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), _chars, BUF_SIZE, &num_read, nullptr);
        setg(_chars, _chars, _chars+num_read);
        return (int_type)(_chars[0]);
    }
private:
    const static uint8_t BUF_SIZE=10;
    wchar_t _chars[BUF_SIZE];
};

int static_init(){
    MyWriteBuf *buf_out=new MyWriteBuf(STD_OUTPUT_HANDLE);
    MyWriteBuf *buf_err=new MyWriteBuf(STD_ERROR_HANDLE);
    MyReadBuf *buf_in=new MyReadBuf();
    std::wcout.rdbuf(buf_out);
    std::wcerr.rdbuf(buf_err);
    std::wcin.rdbuf(buf_in);
    return 0;
}

int global_t=static_init();
Scroll to Top