C ++ строка в wstring печатает неправильно, не могу получить Unicode путь - PullRequest
0 голосов
/ 12 января 2019
#include <iostream>
#include <Windows.h>
#include <locale>
#include <string>
#include <codecvt>
typedef wchar_t* LPWSTR, *PWSTR;

template <typename Facet>
struct deletable_facet : Facet
{
    using Facet::Facet;
};

int main(int argc, char *argv[])
{
    std::cout << argv[0] << std::endl;

    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    //std::wcout << converter.from_bytes(argv[0]) << std::endl; // range error


    std::wstring_convert<deletable_facet<std::codecvt<wchar_t, char, std::mbstate_t>>> conv;
    std::wstring ns = conv.from_bytes(argv[0]);
    std::wcout << ns << std::endl;

    wchar_t filename[MAX_PATH];
    //GetModuleFileName(NULL,filename,MAX_PATH); // cant convert wstring_t* to char*
    GetModuleFileNameW(NULL,filename,MAX_PATH);
    std::wcout << filename << std::endl;


    getchar();
    return 0;
}

Выход:

 C:\Users\luka\Desktop\ⁿ?icΣ\unicode.exe
 C:\Users\luka\Desktop\ⁿ?icΣ\unicode.exe
 C:\Users\luka\Desktop\ⁿ

Фактическое имя папки: üлicä

Я пробовал много разных способов уже около 2 часов, и, насколько я видел, люди предлагали GetModuleFileName, но, как вы можете видеть, это возвращает ошибку преобразования (typedef wchar_t * LPWSTR, * PWSTR; не исправляет ее).

Так есть ли способ получить текущий путь к папке в юникоде и перевести остальные входные аргументы в юникод (нелатинские символы)

Ответы [ 4 ]

0 голосов
/ 15 января 2019

Почему вы печатаете LPWSTR и PWSTR вручную? windows.h уже справляется с этим.

В любом случае, как @ n.m. в комментариях аргументы для main() НЕ кодируются в UTF-8 в Windows, поэтому преобразование не-ASCII-символов с использованием преобразователя UTF8-> UTF16 не даст правильного вывода. Вместо этого используйте функцию Win32 MultiByteToWideChar() для преобразования аргументов, используя CP_ACP в качестве кодовой страницы для преобразования. Или используйте wmain() вместо этого, который предоставляет аргументы как wchar_t* вместо char*.

Это даст вам данные, которые вы хотите. Затем вам просто нужно разобраться с проблемой вывода Unicode на консоль. Как указывают другие ответы, консоль Windows по умолчанию не поддерживает вывод UTF-16 через std::wcout, поэтому вам нужно перепрыгнуть через несколько дополнительных циклов, чтобы заставить его работать правильно (в StackOverflow есть много других вопросов по этой проблеме).

0 голосов
/ 12 января 2019

Использование GetModuleFileName правильно. Вы должны увидеть ожидаемый результат с MessageBoxW(0, filename, 0, 0);

Проблема в печати L"üлicä" на консоли Windows.

Попробуйте напечатать "üлicä" на консоли:

int main(int argc, char *argv[])
{
    DWORD count;
    std::wstring str = GetCommandLineW() + (std::wstring)L"\n";
    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str.c_str(), str.size(), &count, 0);
    MessageBoxW(0, str.c_str(), 0, 0);

    wchar_t filename[MAX_PATH];
    GetModuleFileNameW(0, filename, MAX_PATH);
    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), filename, wcslen(filename), &count, 0);
    return 0;
}

В Visual Studio вы также можете использовать _setmode, чтобы включить использование std::wcout/std::wcin

У вас также есть дополнительная точка входа wmain(int argc, wchar_t *argv[]), которая обеспечивает argv в кодировке UTF16.

Точка входа main обеспечивает argv в кодировке ANSI (не кодировке UTF8). ANSI может потерять информацию, в отличие от Unicode.

0 голосов
/ 13 января 2019

Вот пример, который работает с Windows. Вам нужно будет найти правильные настройки компилятора / компоновщика для поддержки wmain на MinGW, но это будет работать. _setmode позволяет записывать Unicode непосредственно в терминал и должен работать, пока шрифт поддерживает символы. В моем примере я использую китайский язык, который поддерживает мой шрифт:

#include <Windows.h>
#include <iostream>
#include "fcntl.h"
#include "io.h"

int wmain(int argc, wchar_t* argv[])
{
    _setmode(_fileno(stdout), _O_U16TEXT);
    std::wcout << argv[0] << std::endl;

    wchar_t filename[MAX_PATH];
    GetModuleFileNameW(NULL,filename,MAX_PATH);
    std::wcout << filename << std::endl;

    return 0;
}

Выход:

马克.exe
C:\üлicä\马克.exe
0 голосов
/ 12 января 2019

Это, вероятно, связано не с программой, а с консолью. Я предлагаю вам попробовать вывести в файл и проверить правильность кодировки.

Вы можете сделать это, используя freopen:

int main(int argc, char *argv[]){ freopen("output-file-name.txt", "w", stdout); /*rest of code*/ }

Если проблема не устранена, попробуйте использовать Visual Studio вместе с _setmode(..., _O_U16TEXT) непосредственно перед использованием wcout, как описано здесь: https://stackoverflow.com/a/9051543/9541897

...