почему CreateProcessW () не выполняет предоставленную команду? - PullRequest
0 голосов
/ 18 марта 2020

Чтобы представить минимальный воспроизводимый код, я написал код для удаления файла из заданного местоположения с помощью CreateProcessW (). Файл не удаляется. Некоторая помощь была бы очень полезна для понимания того, почему это не работает.

dprintf(("Error %d", GetLastError()));
STARTUPINFO si = { sizeof(STARTUPINFO), 0 };
si.cb = sizeof(si);
PROCESS_INFORMATION pi = { 0 };
LPWSTR AppName = L"C:\\Windows\\System32\\cmd.exe";
string bstr = "C:\\Windows\\System32\\cmd.exe /C del"+trans_loc+"a.rtf";
LPWSTR Command = new WCHAR[bstr.length()];
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, NULL, 0);
MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, Command, wchars_num);
DWORD res = CreateProcessW(AppName, Command, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi);

WaitForSingleObject(pi.hProcess, INFINITE);

определение TRANSCRIPT_LOCATION "C: \ Users \ Administrator \ Desktop \", это местоположение файла, который нужно удалить

GetLastError () продолжает возвращать 50 (ERROR_NOT_SUPPORTED) и значение res = 1

Ответы [ 2 ]

2 голосов
/ 18 марта 2020

Моя первая мысль:

LPWSTR Command = new WCHAR[bstr.length()];

не правильно. Возможно

LPWSTR Command = new WCHAR[bstr.length() + 1];

сработает. Лучшая альтернатива - использовать wchars_num для выделения памяти.

вместо

LPWSTR Command = new WCHAR[bstr.length()];
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, NULL, 0);
MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, Command, wchars_num);
DWORD res = CreateProcessW(AppName, Command, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi);

использовать

int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, NULL, 0);
LPWSTR Command = new WCHAR[wchars_num];
MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), -1, Command, wchars_num);
DWORD res = CreateProcessW(AppName, Command, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi);

Вторая проблема заключается в том, что, возможно, вы пропущен пробел при составлении команды del.

string bstr = "C:\\Windows\\System32\\cmd.exe /C del " + trans_loc + "a.rtf";
//                                                  ^^
1 голос
/ 18 марта 2020

Я вижу ряд проблем с вашим кодом:

  • LPWSTR AppName = L"C:\\Windows\\System32\\cmd.exe"; не компилируется в C ++ 11 и более поздних версиях. Вам нужно (и следует ) использовать вместо LPCWSTR, поскольку строковый литерал представляет собой const данные, а LPCWSTR - указатель на const данные WCHAR, а LPWSTR - указатель в не- const данные WCHAR.

  • В string bstr = "C:\\Windows\\System32\\cmd.exe /C del"+trans_loc+"a.rtf"; пропущен необходимый пробел между командой del и именем файла, который нужно удалить.

  • В LPWSTR Command = new WCHAR[bstr.length()]; вы не выделяете достаточно места для нулевого терминатора. Кроме того, вы не должны использовать bstr.length() для преобразованной длины в любом случае, потому что нет гарантии, что преобразованная строка не будет больше, чем исходная строка. Вы должны вызвать MultiByteToWideChar() один раз с выходным буфером NULL, чтобы вычислить фактическую конвертированную длину (которую вы делаете), ТОГДА выделить память (которую вы НЕ делаете - вы выделяете слишком рано!), ТО вызывать MultiByteToWideChar() снова, чтобы выполнить фактическое преобразование.

  • Вы просачиваете выделенную память (вы не звоните delete[] Command;). Я бы предложил использовать std::wstring или std::vector<WCHAR> вместо new WCHAR[].

  • Вы говорите, что res устанавливается в 1, что означает CreateProcessW() на самом деле успешно при выполнении cmd.exe (теперь, если cmd.exe успешно при выполнении вашей команды, это другой вопрос - используйте GetExitCodeProcess(), чтобы выяснить это), и, следовательно, возвращаемое значение GetLastError() это бессмысленно ! Конечно, имеет смысл звонить GetLastError() до , звонить CreateProcessW()

  • Вы звоните WaitForSingleObject() независимо от того, удастся ли CreateProcessW() или нет.

Попробуйте вместо этого:

STARTUPINFO si = {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {};

std::string bstr = "C:\\Windows\\System32\\cmd.exe /C del \"" + trans_loc + "a.rtf\"";

int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), bstr.length(), NULL, 0);
if (wchars_num == 0)
{
    dprintf(("MultiByteToWideChar Error %d", GetLastError()));
}
else
{
    std::vector<WCHAR> Command(wchars_num + 1);
    MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), bstr.length(), Command.data(), wchars_num);

    if (!CreateProcessW(nullptr, Command.data(), nullptr, nullptr, FALSE, DETACHED_PROCESS, nullptr, nullptr, &si, &pi))
    {
        dprintf(("CreateProcessW Error %d", GetLastError()));
    }
    else
    {
        WaitForSingleObject(pi.hProcess, INFINITE);

        DWORD dwExitCode = 0;
        GetExitCodeProcess(pi.hProcess, &dwExitCode);
        dprintf(("cmd.exe Exit Code %d", dwExitCode));

        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    }
}

Или, если вы используете Windows 10 build 17035 или более поздней версии и включили «Beta: используйте Unicode UTF-8 для Параметр "поддержка языков по всему миру" в ваших настройках Windows (или, если trans_loc не содержит символов, отличных от ASCII, не относящихся к языку пользователя), тогда преобразование MultiByteToWideChar() вообще не требуется:

STARTUPINFO si = {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {};

std::string Command = "C:\\Windows\\System32\\cmd.exe /C del \"" + trans_loc + "a.rtf\"";

if (!CreateProcessA(nullptr, const_cast<char*>(Command.c_str()), nullptr, nullptr, FALSE, DETACHED_PROCESS, nullptr, nullptr, &si, &pi))
{
    dprintf(("CreateProcessA Error %d", GetLastError()));
}
else
{
    WaitForSingleObject(pi.hProcess, INFINITE);

    DWORD dwExitCode = 0;
    GetExitCodeProcess(pi.hProcess, &dwExitCode);
    dprintf(("cmd.exe Exit Code %d", dwExitCode));

    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
}

При этом лучше было бы просто использовать std::wstring вместо std::string для начала:

STARTUPINFO si = {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {};

// make sure trans_loc is std::wstring instead of std::string...
std::wstring bstr = L"C:\\Windows\\System32\\cmd.exe /C del \"" + trans_loc + L"a.rtf\"";

if (!CreateProcessW(nullptr, Command.data(), nullptr, nullptr, FALSE, DETACHED_PROCESS, nullptr, nullptr, &si, &pi))
{
    dprintf(("CreateProcessW Error %d", GetLastError()));
}
else
{
    WaitForSingleObject(pi.hProcess, INFINITE);

    DWORD dwExitCode = 0;
    GetExitCodeProcess(pi.hProcess, &dwExitCode);
    dprintf(("cmd.exe Exit Code %d", dwExitCode));

    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
}

Конечно, самое простое решение - просто не использовать cmd.exe / C del вообще, но вместо этого используйте DeleteFileW():

// make sure trans_loc is std::wstring instead of std::string...
std::wstring bstr = trans_loc + L"a.rtf";

if (!DeleteFileW(bstr.c_str()))
{
    dprintf(("DeleteFileW Error %d", GetLastError()));
}

Или, если вы настаиваете на использовании кодировки UTF-8 std::string:

std::string bstr = trans_loc + "a.rtf";

int wchars_num = MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), bstr.length(), NULL, 0);
if (wchars_num == 0)
{
    dprintf(("MultiByteToWideChar Error %d", GetLastError()));
}
else
{
    std::vector<WCHAR> wstr(wchars_num + 1);
    MultiByteToWideChar(CP_UTF8, 0, bstr.c_str(), bstr.length(), wstr.data(), wchars_num);

    if (!DeleteFileW(wstr.c_str()))
    {
        dprintf(("DeleteFileW Error %d", GetLastError()));
    }
}

Или, если вы используете Windows 10 с включенной поддержкой UTF-8 (или, если trans_loc не содержит никаких символов, отличных от ASCII, не относящихся к языку пользователя):

std::string bstr = trans_loc + "a.rtf";

if (!DeleteFileA(bstr.c_str()))
{
    dprintf(("DeleteFileA Error %d", GetLastError()));
}
...