CreateProcess не передает аргументы командной строки - PullRequest
24 голосов
/ 16 июля 2009

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

Обычно я выполняю процесс (процесс .NET) и передаю ему аргументы командной строки, он успешно выполняется CreateProcess (), но CreateProcess () не передает аргументы командной строки

Что я здесь не так делаю ??

int main(int argc, char* argv[])
{
    PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter

    STARTUPINFO StartupInfo; //This is an [in] parameter

    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
    StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field

    LPTSTR cmdArgs = "name@example.com";

    if(CreateProcess("D:\\email\\smtp.exe", cmdArgs, 
        NULL,NULL,FALSE,0,NULL,
        NULL,&StartupInfo,&ProcessInfo))
    { 
        WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
        CloseHandle(ProcessInfo.hThread);
        CloseHandle(ProcessInfo.hProcess);

        printf("Yohoo!");
    }  
    else
    {
        printf("The process could not be started...");
    }

    return 0;
}

РЕДАКТИРОВАТЬ: Эй, еще одна вещь, если я передам мой cmdArgs, как это:

// a space as the first character
LPTSTR cmdArgs = " name@example.com";

Затем я получаю сообщение об ошибке, затем CreateProcess возвращает TRUE, но мой целевой процесс не выполняется.

Object reference not set to an instance of an object

Ответы [ 8 ]

23 голосов
/ 16 июля 2009

Вы должны указать также имя модуля в параметрах: LPTSTR cmdArgs = "App name@example.com"; Это должна быть вся командная строка (включая argv [0]).

17 голосов
/ 17 июля 2009

Если первый параметр CreateProcess() не равен NULL, он будет использовать его для поиска образа для запуска.

Если он равен NULL, он будет анализировать 2-й аргумент, чтобы попытаться запустить исполняемый файл с 1-го токена.

В любом случае среда выполнения C будет использовать второй аргумент для заполнения массива argv. Таким образом, первый токен этого параметра отображается в argv[0].

Вы, вероятно, хотите что-то вроде следующего (я изменил программу smtp.exe на echoargs.exe - простую утилиту, которая мне нужна, чтобы помочь разобраться именно с такой проблемой):

int main(int argc, char* argv[])
{
    PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter

    STARTUPINFO StartupInfo; //This is an [in] parameter
    char cmdArgs[] = "echoargs.exe name@example.com";

    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
    StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field


    if(CreateProcess("C:\\util\\echoargs.exe", cmdArgs, 
        NULL,NULL,FALSE,0,NULL,
        NULL,&StartupInfo,&ProcessInfo))
    { 
        WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
        CloseHandle(ProcessInfo.hThread);
        CloseHandle(ProcessInfo.hProcess);

        printf("Yohoo!");
    }  
    else
    {
        printf("The process could not be started...");
    }

    return 0;
}

Вот вывод, который я получаю из этой программы:

echoargs.exe name@example.com
[0]: echoargs.exe
[1]: name@example.com

Yohoo!
5 голосов
/ 21 июля 2009

Ниже приведена сокращенная версия кода, используемого Zeus IDE для запуска внешних процессов:

bool createProcess(const char *pszTitle, const char *pszCommand)
{
  STARTUPINFO StartInfo;

  memset(&StartInfo, 0, sizeof(StartInfo));

  StartInfo.cb      = sizeof(StartInfo);
  StartInfo.lpTitle = (pszTitle) ? (char *)pszTitle : (char *)pszCommand;

  StartInfo.wShowWindow = SW_NORMAL;
  StartInfo.dwFlags    |= STARTF_USESHOWWINDOW;

  if (CreateProcess(0, (char *)pszCommand, 
                    0, 0, TRUE,
                    CREATE_NEW_PROCESS_GROUP, 0, 0, 
                    &StartInfo, &ProcessInfo))
  {
    lErrorCode = 0;
  }
  else
  {
    lErrorCode = GetLastError();
  }

  return (lErrorCode == 0);
}

pszCommand - это полный путь к исполняемому файлу, имя файла и аргументы, например:

pszCommand = "D:\\email\\smtp.exe name@example.com";

Из того, что я могу сказать, единственное реальное различие между ними состоит в том, что в примере Zeus аргумент dwCreationFlags установлен в значение CREATE_NEW_PROCESS_GROUP .

5 голосов
/ 16 июля 2009

Не похоже, что вы используете CreateProcess правильно, см. http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx.

  • Командная строка для выполнения. Максимальная длина этой строки составляет 32 768 символов, включая завершающий нулевой символ Unicode. Если lpApplicationName имеет значение NULL, часть имени модуля lpCommandLine ограничена символами MAX_PATH.

  • Параметр lpCommandLine может иметь значение NULL. В этом случае в качестве командной строки функция использует строку, указанную lpApplicationName.

  • Если lpApplicationName и lpCommandLine не равны NULL, строка с нулевым символом в конце, на которую указывает lpApplicationName, указывает модуль для выполнения, а строка с нулевым символом в конце, на которую указывает lpCommandLine, указывает командную строку . Новый процесс может использовать GetCommandLine для получения всей командной строки. Консольные процессы, написанные на C, могут использовать аргументы argc и argv для разбора командной строки. Поскольку argv [0] является именем модуля, программисты на C обычно повторяют имя модуля в качестве первого токена в командной строке.

Так что в вашем случае вам нужно это как аргумент команды и, вероятно, следует передать NULL для первого параметра, чтобы получить поведение, которое вы хотите.

// NOTE THE Null-Terminated string too!
LPTSTR cmdArgs = "D:\\email\\smtp.exe name@example.com\0";
2 голосов
/ 16 июля 2009

Попробуйте это:

LPTSTR cmdArgs = "name@example.com";
CString szcmdline("D:\\email\\smtp.exe");
szcmdline += _T(" ") + cmdArgs ;

//Leave first param empty and pass path + argms in 
    if(CreateProcess(NULL, szcmdline, second
1 голос
/ 27 июня 2017

Вы можете добавить пробел в качестве первого символа строки cmdArgs:

LPTSTR cmdArgs = " name@example.com";

Очевидно, что Windows добавляет строку второго аргумента к имени приложения, представленному первым аргументом, и результат передается в качестве аргументов командной строки в исполняемый файл. Таким образом, добавление пробела будет правильно разделять аргументы.

0 голосов
/ 16 июля 2009

Вы не выделяете память для своей строки.

Вместо:

LPTSTR cmdArgs = "name@example.com";

попробовать:

TCHAR cmdArgs[] = "name@example.com";

Edit: затем позвоните:

 CreateProcess("D:\\email\\smtp.exe", &cmdArgs[0], ...

Это создаст локальный массив в стеке и затем передаст указатель на этот массив.

0 голосов
/ 16 июля 2009

Версия этой функции Unicode, CreateProcessW, может изменять содержимое этой строки. Следовательно, этот параметр не может быть указателем на постоянную память (например, константную переменную или литеральную строку) Если этот параметр является константной строкой, функция может вызвать нарушение прав доступа.

Поэтому вы можете попробовать использовать LPTSTR cmdArgs = _tcsdup("name@example.com").

Другая проблема: как целевой процесс читает аргументы? используя argv [0] в качестве имени приложения? Затем вы должны добавить имя приложения в качестве первого параметра.

...