Как я могу избежать функций Windows _exec * и _spawn *, разделяющих аргументы в пробелах? - PullRequest
0 голосов
/ 09 ноября 2018

При использовании функции _execv () в консольной программе C ++ для Windows я обнаружил, что аргументы разделяются на пробелы, причем каждая подстрока становится отдельным аргументом в списке аргументов программы exec'd. Предположительно, этого не произойдет до тех пор, пока не будет найдена эта программа, как это происходит, даже если аргумент пути программы содержит пробелы.

Я написал пару программ, которые демонстрируют проблему. То же самое происходит с _spawnv (), а также, если я изменяю вызывающую программу для использования массивов wchar_t и _wexecv ().

Я создаю примеры как проекты консольных приложений для Windows x86 или x64, используя Visual Studio 2017 для Windows 10. Как избежать этой проблемы при использовании одной из этих функций?

// Calling program

#include "pch.h"
#include <iostream>
#include <process.h>

int main()
{
    const char program[] = "C:\\Users\\dummy\\Documents\\Visual Studio 2017\\Projects\\execTest\\x64\\Debug\\testCalled.exe";
    const char* arguments[] = { program, "Hello   World!", nullptr };   // Note the multiple spaces

    for (int a = 0; sizeof(arguments) / sizeof(*arguments) > a && arguments[a]; ++a) {
        std::cerr << "Caller: " << a << " = " << arguments[a] << '\n';
    }
    std::wcerr << '\n';

    auto rc = _execv(program, arguments);

    perror("Exec fail ");
    std::cerr << "return code " << rc <<'\n';
    return rc;
}

// Called program

#include "pch.h"
#include <iostream>

int main( int argc, char** argv)
{
    for (int a = 0; a < argc; ++a) {
        std::cerr << "Called: " << a << " = " << argv[a] << '\n';
    }
    return 0;
}

Output:
Caller: 0 = C:\Users\dummy\Documents\Visual Studio 2017\Projects\execTest\x64\Debug\testCalled.exe
Caller: 1 = Hello   World!

Called: 0 = C:\Users\dummy\Documents\Visual
Called: 1 = Studio
Called: 2 = 2017\Projects\execTest\x64\Debug\testCalled.exe
Called: 3 = Hello
Called: 4 = World!

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

В Unix-подобных системах execve - это системный вызов, который позволяет программе стереть себя с другим, который получает отдельно аргументов, а функция семейства exec напрямую вызывает ее .

В Windows системный API определяет функцию CreateProcess, которая использует имя или путь новой программы (как это делает execve), и одну командную строку, которая создается путем объединения параметров exec.

Это означает, что вы должны заключить параметры, содержащие пробелы, в явные двойные кавычки. Таким образом, путь Windows действительно таков:

const char* arguments[] = { program, "\"Hello   World!\"", nullptr };

Стандарт C не определяет функцию execv, он определяется только в Posix и Windows, несмотря на то, что попытка быть совместимой не является системой Posix, поэтому следует ожидать предостережения ...

0 голосов
/ 09 ноября 2018

(редактировать: избегать использования _execv в Windows, как описано в комментариях)

Чтобы исправить использование _execv, задайте в первом аргументе точный путь. Затем измените второй параметр (arguments), чтобы имя пути указывалось в двойных кавычках (а также в других аргументах, которые пробелятся с пробелом):

char program[] = "c:\\foler name\\path name.exe";

char *arguments[] = { 
        "\"c:\\foler name\\path name.exe\"",
        "\"(x 1)\"", 
        "\"(x 2)\"", 
        nullptr 
};

_execv(program, arguments);

Теперь получатель должен видеть argv[0] как "c:\\foler name\\path name.exe", argv[1] как "(x 1)" ...

Вы также можете использовать CreateProcess и поместить имя программы и аргументы в одну строку.

#include <windows.h>
...

std::string cmd;
cmd += "\"c:\\folder name\\path name.exe\" "; //<- add extra space manually
cmd += "a "; //<- add extra space manually
cmd += "b c d ";
cmd += "\"Hello   World!\" "; //<- add extra space manually

STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcessA(0, cmd.data(), 0, 0, 0, 0, 0, 0, &si, &pi);
//* if cmd.data() is not supported then copy to char buffer

//optional: wait until process is finished
//WaitForSingleObject(pi.hProcess, INFINITE);
//CloseHandle(pi.hProcess);
//CloseHandle(pi.hThread);

Смотри также
Синтаксический анализ аргументов командной строки C ++

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...