Я работал в приложении Windows. Ему необходимо открыть окно, чтобы оно было скомпилировано в подсистеме Windows (
Код: Выделить всё
/SUBSYSTEM:WINDOWSWindows API предоставляет решение для этого: функция AllocConsole, которая, как сказано в документации, "выделяет новую консоль для вызывающего процесса". После его вызова действительно открывается окно консоли, и я могу вывести в него текст после вызова freopen следующим образом:
(Обратите внимание, что freopen > необходим, потому что нам нужно перенаправить все, что мы пишем в стандартный вывод, на «CONOUT$» и т. д.)
Код: Выделить всё
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;
}
Код: Выделить всё
_setmode(_fileno(stdin), _O_U16TEXT);
_setmode(_fileno(stdout), _O_U16TEXT);
_setmode(_fileno(stderr), _O_U16TEXT);
Код: Выделить всё
GetConsoleCPВот в чем проблема: попытка сделать вышеописанное в консольном приложении работает (пока /utf указан флаг -8, подробнее об этом позже), но его нет в приложении для ПК.
Вывод, который я получаю при попытке напечатать L" Тест à" — это T e s t Ó :
T e s t Ó
Обратите внимание, что à — это 0x00E0 в UTF-16, а Ó — это также 0xE0 на кодовой странице 850. Кроме того, по какой-то причине между каждым символом есть странные пробелы (я предполагаю, что это второй байт символа UTF-16).
Это то, что я пробовал и наблюдал на своей машине. :
- По умолчанию строка wchar_t использует UTF-8, это можно изменить, скомпилировав проект с использованием /utf-8 флаг (который, насколько я могу судить, может быть только устанавливается вручную в Свойствах проекта --> C/C++ --> Командная строка в Visual Studio), при этом устанавливается кодировка UTF-16 (мне кажется, что это наоборот?)
- возвращает предыдущий режим перевода. При первом вызове он возвращает 0x4000, что соответствует _O_TEXT - тексту (переведенному), а во второй раз возвращает 0x10000, что должно соответствовать _O_U16TEXT - UTF16 no BOM (переведенному). ), так как я его устанавливаю, но на самом деле это _O_WTEXT - UTF16 (переведено), (описания взяты из комментариев рядом с определениями в fcntl.h. Попытка вручную записать спецификацию в стандартный вывод ничего не дает.
Код: Выделить всё
_setmode - Я пробовал то и это, но ничего не изменилось.
Кроме того, если это поможет, я использую Windows 11 24H2, сборка 26100.2605
Заранее спасибо.
РЕДАКТИРОВАТЬ
В соответствии с просьбой, вот минимальный воспроизводимый пример.
Компилировать для этого вам нужно создать пустой проект C++ в Visual Studio (я использую Visual Studio 2022) и установить в качестве подсистемы значение Windows, изменив этот параметр:
Код: Выделить всё
Project Properties --> Linker --> System --> SubSystemКод: Выделить всё
#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
Подробнее здесь: [url]https://stackoverflow.com/questions/79351425/windowss-allocconsole-doesnt-allow-printing-utf-16-encoded-strings[/url]
Мобильная версия