Ich habe gearbeitet in einer Windows-Anwendung. Es muss ein Fenster geöffnet werden, damit es unter dem Windows-Subsystem kompiliert wird (
Code: Select all
/SUBSYSTEM:WINDOWS
Die Windows-API bietet die Lösung dafür: die AllocConsole-Funktion, die, wie es in der Dokumentation heißt, „dem aufrufenden Prozess eine neue Konsole zuweist“. Nach dem Aufruf wird tatsächlich ein Konsolenfenster geöffnet, und ich kann darauf drucken, nachdem ich freopen wie folgt aufgerufen habe:
(Beachten Sie, dass freopen wird benötigt, weil wir alles, was wir in stdout schreiben, in „CONOUT$“ usw. umleiten müssen.)
Code: Select all
bool AttachCon() {
if (AllocConsole() == FALSE) {
return false;
}
FILE *tmp;
_wfreopen_s(&tmp, L"CONIN$", L"r", stdin);
_wfreopen_s(&tmp, L"CONOUT$", L"w", stdout);
_wfreopen_s(&tmp, L"CONOUT$", L"w", stderr);
return true;
}
Code: Select all
_setmode(_fileno(stdin), _O_U16TEXT);
_setmode(_fileno(stdout), _O_U16TEXT);
_setmode(_fileno(stderr), _O_U16TEXT);
Code: Select all
GetConsoleCP
Hier liegt das Problem: Der Versuch, das oben Gesagte in einer Konsolenanwendung auszuführen, funktioniert (solange die /utf -8-Flag angegeben ist, dazu später mehr), in der Desktop-Anwendung jedoch nicht.
Die Ausgabe, die ich erhalte, wenn ich versuche, L zu drucken" Test à" ist T e s t Ó :
T e s t Ó
Beachten Sie, dass à in UTF-16 0x00E0 ist und Ó auch 0xE0 in Codepage 850. Außerdem gibt es aus irgendeinem Grund seltsame Leerzeichen zwischen den einzelnen Zeichen (ich gehe davon aus, dass es sich um das zweite Byte des UTF-16-Zeichens handelt).
Das habe ich bisher auf meinem Rechner versucht und beobachtet :
- Standardmäßig verwendet ein wchar_t-String UTF-8, dies kann durch Kompilieren des Projekts mit dem /utf-8 Flagge (was meines Wissens nur möglich ist kann durch manuelles Festlegen unter Projekteigenschaften --> C/C++ --> Befehlszeile in Visual Studio festgelegt werden. Dadurch wird die Kodierung auf UTF-16 gesetzt (kommt mir irgendwie rückwärts vor?)
gibt den vorherigen Übersetzungsmodus zurück. Beim ersten Aufruf wird 0x4000 zurückgegeben, was _O_TEXT – Text (übersetzt) entspricht, und beim zweiten Mal wird 0x10000 zurückgegeben, was _O_U16TEXT – UTF16 no BOM (übersetzt) entsprechen sollte ), da ich es so einstelle, aber es ist eigentlich _O_WTEXT - UTF16 (übersetzt), (die Beschreibungen stammen aus den Kommentaren neben den Definitionen in fcntl.h. Der Versuch, eine Stückliste manuell nach stdout zu schreiben führt zu nichts.
Code: Select all
_setmode
- Ich habe dies und das versucht, aber nichts hat sich geändert.
Wenn es hilft, verwende ich Windows 11 24H2 Build 26100.2605
Vielen Dank im Voraus.
BEARBEITEN
Wie gewünscht, hier ein minimal reproduzierbares Beispiel.
Um dies zu kompilieren Sie müssen ein leeres C++-Projekt in Visual Studio erstellen (ich verwende Visual Studio 2022) und Sie müssen das Subsystem auf Windows setzen, indem Sie diese Einstellung ändern:
Code: Select all
Project Properties --> Linker --> System --> SubSystem
Code: Select all
#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#include
#include
static constexpr wchar_t WINDOW_CLASS[] = L"Test";
static constexpr wchar_t WINDOW_NAME[] = L"Test Window";
bool AttachCon(void) {
if (AllocConsole() == FALSE) {
return false;
}
fflush(stdin);
fflush(stdout);
fflush(stderr);
FILE *tmp;
_wfreopen_s(&tmp, L"CONIN$", L"r", stdin);
_wfreopen_s(&tmp, L"CONOUT$", L"w", stdout);
_wfreopen_s(&tmp, L"CONOUT$", L"w", stderr);
// Nothing changes when doing this
HANDLE hConIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
HANDLE hConOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
SetStdHandle(STD_INPUT_HANDLE, hConIn);
SetStdHandle(STD_OUTPUT_HANDLE, hConOut);
SetStdHandle(STD_ERROR_HANDLE, hConOut);
// SetConsoleMode returns FALSE so this does nothing
// DWORD console_mode;
// if (GetConsoleMode(hConOut, &console_mode)) {
// SetConsoleMode(hConOut, console_mode | ENABLE_VIRTUAL_TERMINAL_INPUT);
// }
if (_setmode(_fileno(stdin), _O_U16TEXT) == -1) {
// Handle error
}
if (_setmode(_fileno(stdout), _O_U16TEXT) == -1) {
// Handle error
}
if (_setmode(_fileno(stderr), _O_U16TEXT) == -1) {
// Handle error
}
// Sets the output encoding to UTF-8, I need UTF-16
// SetConsoleOutputCP(65001);
// Both of these print wrong?
wchar_t str[] = L"Test à";
wprintf(L"%ls\n", str);
std::wcout