Как отправить буфер wstring на стандартный ввод дочернего процесса?

У меня проблемы с записью WString в STDIN дочернего процесса. Если у меня есть только строка символов acii (например: @ WSX3edc), код работает нормально, но если он содержит символ, отличный от ascii (например: @ WSX3edcß), он не работает.

Дочерний процесс - 7zr.exe (версия строки 7Zip cmd). Ввод, который я пишу в STDIN, - это пароль для извлечения файла.

// inject password
wPassword.append(password);
wPassword.append(L"\n"); \\For carriage return
...
DWORD dwBytesToWrite = wPassword.length()*sizeof(wchar_t);
DWORD dwBytesWritten = 0;
char szBuffer[1024] = "\0";
wcstombs(szBuffer, wPassword.c_str(),wcslen(wPassword.c_str())+1);
dwBytesToWrite = strlen(szBuffer);
if (!WriteFile(hInput, szBuffer, dwBytesToWrite, &dwBytesWritten, NULL)) {
    std::cout<<"write file failed"<<GetLastError()<<std::endl;
    goto Cleanup;
}

Запись файла всегда выполняется успешно, но иногда извлечение файла не удается из-за неисправного механизма ввода пароля.

Createprocess для этого выглядит так: (объект si имеет потоки STDIN и STDOUT, установленные ранее с помощью CreatePipe)

if(!CreateProcess((LPWSTR)cmd, (LPWSTR)cmdArgs, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS,
        NULL, NULL, &si, &pi)) {
         std::cout<<"7zr.exe process creation failed "<<GetLastError()<<std::endl;
         goto Cleanup;
}

Примечание. 7zr.exe отлично работает с этим паролем, если мы запустим его из командной строки и вставим этот пароль. Добыча работает нормально.


person gkns    schedule 12.01.2017    source источник


Ответы (2)


Если в узком наборе символов нет соответствующего символа пароля, вы не можете использовать этот подход. Вместо этого найдите параметр 7zr для указания пароля. У меня нет исполняемого файла с именем 7zr, но есть 7z, и команда 7z | find /i "pass" прекрасно работала.


В других новостях:

  • Переменная dwBytesToWrite инициализируется одним значением, которое будет переназначено несколькими строками позже, но не используется.

  • goto Cleanup вообще не подходит для C ++. Если вы хотите гарантированную очистку, используйте деструктор (метод, называемый RAII, прочтите о нем).

  • Венгерская нотация Microsoft с такими префиксами, как sz и dw, вообще мерзость. Однажды, в 1980-х, он поддерживал справочную систему в Microsoft Programmer's Workbench. AFAIK этого продукта не существовало последние 30 лет или около того.

  • Приведение C в (LPWSTR)cmd может легко вызвать ошибку. Используйте const_cast там, где вы хотите использовать константу. Тогда было бы более ясно, что это приведение неверно: вам нужен изменяемый буфер.

  • Вместо того, чтобы сообщать об ошибке стандартному потоку вывода через std::cout, рассмотрите возможность использования стандартного потока ошибок через std::cerr или std::clog. Лучше не выполнять ввод-вывод в том месте, где обнаружен сбой, а генерировать исключение, чтобы вызывающий код мог с ним справиться. Вызывающий код не может удалить уже выводимый результат.

person Cheers and hth. - Alf    schedule 12.01.2017
comment
Если мы добавим пароль к команде отдельно, используя -p, этот пароль можно будет увидеть в инструментах проводника процессов. Это проблема безопасности. следовательно, прямое эхо для стандартного ввода. 7zr.exe отлично работает с этим паролем, если мы запустим его из командной строки и вставим этот пароль. Добыча работает нормально. - person gkns; 12.01.2017
comment
Проблема безопасности должна быть отдельным вопросом. Пожалуйста, не аннулируйте текущие ответы, добавляя это требование к вопросу. Но я отвечу здесь, потому что это так просто: если кто-то контролирует доступ к компьютеру, все ставки отменены. злоумышленник. Все, что остается, - это защититься от обычных пользователей, которые могут случайно ввести пароль и взломать его. Вы можете защититься от этого суровым предупреждением. Ага, это хороший ответ. Потому что это не совсем проблема безопасности. Так же, как Microsoft UAC - это раздражение, не безопасность, а маркетинг. - person Cheers and hth. - Alf; 12.01.2017
comment
Ой. Обратите внимание, что командная строка закодирована в UTF-16. Стандартный входной поток обычно предполагается приложением в кодировке Windows ANSI. Где Windows ANSI - это кодовая страница, указанная функцией GetACP API. - person Cheers and hth. - Alf; 12.01.2017
comment
Спасибо за этот вклад! Он работал после преобразования в OEM CP: WideCharToMultiByte (CP_OEMCP, WC_COMPOSITECHECK | WC_NO_BEST_FIT_CHARS, wPassword.c_str (), -1, mbBuffer, sizeof (mbBuffer), NULL, NULL); - person gkns; 12.01.2017

wcslen(wide) возвращает количество широких символов в своем аргументе wide (см.).

wcstombs(narrow,wide,len) записывает не более len байтов в narrow (см.).

Если бы у нас всегда был один широкий символ = один узкий символ = один байт, не было бы большого смысла иметь две разновидности символов, не так ли?

Как только у вас есть широкий символ, который переводится более чем в один узкий символ, возникает неопределенное поведение.

Поскольку ваш szBuffer имеет фиксированный размер, вы можете также написать

wcstombs(szBuffer, wPassword.c_str(), sizeof(szBuffer));
person n. 1.8e9-where's-my-share m.    schedule 12.01.2017
comment
не повезло. с модификацией sizeof (szBuffer). Также я не понял неопределенного поведения, вы имеете в виду, что мы не должны пытаться делать что-то подобное? - person gkns; 12.01.2017
comment
В вашем коде более одной проблемы, я указал только на одну, о которой другой ответ не упоминает. - person n. 1.8e9-where's-my-share m.; 12.01.2017