2016-07-11 2 views
3

Я работаю над кросс-платформенным проектом с использованием Qt. В Windows я хочу передать некоторые символы Юникода (например, путь к файлу, содержащий китайские символы) в качестве аргументов при запуске приложения из командной строки. Затем используйте эти аргументы для создания QCoreApplication.Как преобразовать LPWSTR в char * с кодировкой UTF-8

По некоторым причинам, мне нужно использовать CommandLineToArgvW, чтобы получить список аргументов, как это:

LPWSTR * argvW = CommandLineToArgvW(GetCommandLineW(), &argc); 

Я понимаю, на современной ОС Windows, LPWSTR фактически wchar_t* который 16bit и использует UTF-16 кодировке.

Хотя если я хочу инициализировать QCoreApplication, требуется только char*, но не wchar_t*. QCoreApplication

Таким образом, вопрос: как я могу безопасно преобразовать LPWSTR возвращаемый CommandLineToArgvW() функции к char* без потери кодировки UNICODE (то есть китайские иероглифы еще китайские иероглифы, например)?

Я пробовал много разных способов, но безуспешно:

1:

std::string const argvString = boost::locale::conv::utf_to_utf<char>(argvW[0]) 

2:

int res; 
    char buf[0x400]; 
    char* pbuf = buf; 
    boost::shared_ptr<char[]> shared_pbuf; 

    res = WideCharToMultiByte(CP_UTF8, 0, pcs, -1, buf, sizeof(buf), NULL, NULL); 

3: Преобразовать в QString, а затем преобразовать в UTF-8.

ETID: Проблема решена. Широкий характер UTF-16 для преобразования UTF-8 char действительно отлично работает без проблем со всеми этими тремя подходами. И в Visual Studio, чтобы правильно просмотреть строку UTF-8 в отладке, необходимо добавить спецификатор формата после имени наблюдаемой переменной (см.: https://msdn.microsoft.com/en-us/library/75w45ekt.aspx). Это та часть, которую я пропустил, и заставил меня думать, что мое преобразование строк было неправильным.

Реальная проблема здесь на самом деле при вызове QCoreApplication.arguments(), возвращаемый QString строится QString::fromLocal8Bit(), что приведет к кодирующим вопросам Windows, когда аргументы командной строки содержат символы Юникода. Обходной путь всегда необходим для извлечения аргументов командной строки в Windows, всегда вызывайте Windows API CommandLineToArgvW() и конвертируйте 16-битный UTF-16 wchar_t * (или LPWSTR) в 8-битный символ UTF-8 * (одним из три способа, упомянутые выше).

+0

Как вы узнали о завершении вашего вызова на "QCoreApplication"? То есть вы говорите, что хотите, чтобы «китайские иероглифы все еще были китайскими иероглифами». Итак, как вы говорите, что их больше нет. Покажите нам код, который, учитывая соответствующую функцию преобразования, вы ожидаете работать. –

+1

В соответствии с документацией Qt автоматически использует 'CommandLineToArgvW' для вас, * если * вы передаете измененные аргументы конструктору' QCoreApplication'. В нем не указано, что именно «модифицировано» означает, но, по-видимому, цель состоит в том, чтобы просто работать для обычного кода, который просто слепо пересылает аргументы «main», но чтит пожелание клиентского кода, если есть какая-либо разница. См. Http://doc.qt.io/qt-5/qcoreapplication.html#arguments –

+0

Возможный дубликат [Windows Unicode командной строки argv] (http://stackoverflow.com/questions/4101864/windows-unicode-commandline-argv) –

ответ

2

Вы должны иметь возможность использовать функции QString. Например

QString str = QString::fromUtf16((const ushort*)argvW[0]); 
::MessageBoxW(0, (const wchar_t*)str.utf16(), 0, 0); 

При использовании WideCharToMultiByte, передать нуль для выходного буфера и длины выходного буфера. Это расскажет вам, сколько символов вам нужно для выходного буфера. Например:

const wchar_t* wbuf = argvW[0]; 
int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, 0, 0, 0, 0); 

std::string buf(len, 0); 

WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, &buf[0], len,0,0); 
QString utf8; 
utf8 = QString::fromUtf8(buf.c_str()); 
::MessageBoxW(0, (const wchar_t*)utf8.utf16(), 0, 0); 

Та же информация должна быть доступна в QCoreApplication::arguments.Например, запустить этот код с аргументом Unicode и увидеть результат:

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 
    QString filename = QString::fromUtf8("ελληνική.txt"); 
    QFile fout(filename); 
    if (fout.open(QIODevice::WriteOnly | QIODevice::Text)) 
    { 
     QTextStream oss(&fout); 
     oss.setCodec("UTF-8"); 
     oss << filename << "\n"; 
     QStringList list = a.arguments(); 
     for (int i = 0; i < list.count(); i++) 
      oss << list[i] << "\n"; 
    } 
    fout.close(); 
    return a.exec(); 
} 

Обратите внимание, что в приведенном выше примере имя файла внутренне преобразуется в UTF-16, это сделано с помощью Qt. WinAPI использует UTF-16, а не UTF-8

+0

Конструктор 'QCoreApplication' не принимает' QString' для аргументов командной строки. –

+0

Я предложил использовать 'QString' для преобразования UTF-16/UTF-8. 'CommandLineToArgvW' - это WinAPI, он будет иметь правильный контент и может быть преобразован и передан как UTF-8' char'. –

+0

Я должен был быть более ясным: 'QCoreApplication' принимает только символы символов ANSI. См. Мой ответ для объяснения. –

2

Qt внутренне обертывает int main(), извлекает и анализирует аргументы командной строки Unicode (через CommandLineToArgvW) перед выполнением любого из ваших кодов. Полученные анализируемые данные преобразуются в локальный формат UTF-8 как char **argv через эквивалент QString::toLocal8Bit().

Используйте QCoreApplication::arguments() для извлечения аргументов Unicode. Кроме того, полезная заметка из документов:

В Windows список построен из параметров argc и argv только в том случае, если модифицированные параметры argv/argc передаются конструктору. В этом случае могут возникнуть проблемы с кодированием.

+0

Итак, вы предполагаете, что всякий раз, когда задействован Юникод, никогда не следует использовать Windows Command 'CommandLineToArgvW()' для извлечения аргументов argv и передать их в QCoreApplication? Тогда что тогда будет правильным? – Wayee

+0

@Wayee Смотрите мое обновление. Просто вызовите 'QCoreApplication :: arguments()' для получения необходимых данных. –

+0

QStringList, возвращаемый вызовом 'QCoreApplication :: arguments()' на самом деле тот, который вы передали 'QApplication', когда вы его построили. Моя задача - передать правильную строку юникода для построения 'QApplication'. Чтобы быть ясным, в MAC OS вызов 'QApplication (0, nullptr)' будет достаточным, чтобы отобразить аргументы консоли. Но в Windows это просто отправит пустой список аргументов для создания 'QApplication'. – Wayee

Смежные вопросы