Windows Unicode C ++ Stream Output Failure

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg skriver for øjeblikket en ansøgning, der kræver, at jeg kalder GetWindowText på vilkårlig vinduer og gem disse data til en fil til senere behandling. Lang historie kort, jeg har bemærket, at mit værktøj svigtede på Battlefield 3, og jeg indsnævrede problemet ned til følgende tegn i sin vinduetitel:
http://www.fileformat.info/info/unicode/char/2122/index.htm[16]


Så jeg lavede en lille test app, som netop gør følgende:


std::wcout << L"u2122";


Lav og se, der bryder output til konsolvinduet for resten af ​​programmet.


Hvorfor staver MSVC STL på denne karakter (og jeg antager andre), når API'er som MessageBoxW osv. Viser det helt fint?


Hvordan kan jeg få disse tegn udskrivet til min fil?


Testet på både VC10 og VC11 under Windows 7 x64.


Undskyld for det dårligt konstruerede indlæg, jeg slår mit hår ud her.


Tak.


REDIGERE:


Minimal test sag


#include <fstream>
#include <iostream>

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

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


Forventet resultat: '™' tegn udskrevet til konsol og fil.
Observeret resultat: Filen er oprettet, men er tom. Ingen udgang til konsol.


Jeg har bekræftet, at den skrifttype, jeg bruger til min konsol, er i stand til at vise det pågældende tegn, og filen er helt tom (0 bytes i størrelse).


REDIGERE:


Yderligere debugging viser, at 'failbit' og 'badbit' er sat i strømmen/strømmerne.


REDIGERE:


Jeg har også forsøgt at bruge Boost.Locale, og jeg har det samme problem, selv med den nye lokalitet, der gennemsøges globalt og eksplicit til alle standardstrømme.

Bedste reference


For at skrive til en fil skal du indstille lokaliteten korrekt, for eksempel hvis du vil skrive dem som UTF-8 tegn, skal du tilføje


const std::locale utf8\_locale
            = std::locale(std::locale(), new std::codecvt\_utf8<wchar\_t>());
test\_file.imbue(utf8\_locale);


Du skal tilføje disse 2 inkludere filer


#include <codecvt>
#include <locale>


For at skrive til konsollen skal du indstille konsollen i den korrekte tilstand (dette er Windows-specifikke) ved at tilføje


\_setmode(\_fileno(stdout), \_O\_U8TEXT);


(hvis du vil bruge UTF-8).


Til dette skal du tilføje disse 2 inkludere filer:


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


Desuden skal du sørge for, at du bruger en skrifttype, der understøtter Unicode (som f.eks. Lucida Console). Du kan ændre skrifttypen i egenskaberne for dit konsolvindue.


Det komplette program ser nu ud som dette:


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

Andre referencer 1


Bruger du altid std::wcout eller bruger du nogle gange std::cout? Blanding af disse vundet 't arbejde. Selvfølgelig siger fejlbeskrivelsen' kvælning 'slet ikke hvilket problem du observerer. Jeg tror, ​​at dette er et andet problem for den, der bruger filer.


Da der ikke er nogen egentlig beskrivelse af problemet, tager det noget af en krystalkugle efterfulgt af et skud i mørket for at ramme problemet ... Da du vil have Unicode-tegn fra din fil, skal du sørge for, at den filstrøm du bruger, bruger en std::locale, hvis std::codecvt<...> facet faktisk konverteres til en passende Unicode-kodning.

Andre referencer 2


Jeg har lige testet GCC (versioner 4.4 til 4.7) og MSVC 10, som alle udviser dette problem.


Lige brudt er wprintf, hvilket gør så lidt som C ++ stream API.


Jeg testede også den rå Win32 API for at se, om intet andet var årsag til fejlen, og det virker:


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


Hvilket skriver β til konsollen (hvis du indstiller cmd 's skrifttype til noget som Lucida Console).


Konklusion: wchar\_t output er forfærdeligt brudt i begge store C ++ Standard bibliotek implementeringer.

Andre referencer 3


Selv om de store tegnstrømme tager Unicode som input, er det ikke, hvad de producerer som output - tegnene går gennem en konvertering. Hvis et tegn ikke kan være repræsenteret i den kodning, som det konverteres til, fejler outputet.