CreateProcess不传递命令行参数

时间:2009-07-16 06:34:52

标签: c++ winapi createprocess

您好我有以下代码,但它没有按预期工作,无法弄清楚问题是什么。

基本上,我正在执行一个进程(一个.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 个答案:

答案 0 :(得分:23)

您应在参数中指定模块名称:LPTSTR cmdArgs = "App name@example.com"; 它应该是整个命令行(包括argv [0])。

答案 1 :(得分:17)

如果CreateProcess()的第一个参数是非NULL,它将使用它来定位要启动的图像。

如果为NULL,它将解析第二个参数以尝试从第一个令牌启动可执行文件。

在任何一种情况下,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!

答案 2 :(得分:5)

看起来您没有正确使用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指向的以null结尾的字符串指定要执行的模块,lpCommandLine指向的以null结尾的字符串指定命令行。新进程可以使用GetCommandLine来检索整个命令行。用C编写的控制台进程可以使用argc和argv参数来解析命令行。因为argv [0]是模块名称,所以C程序员通常会重复模块名称作为命令行中的第一个标记。

因此,在您的情况下,您需要将此作为命令参数,并且应该为第一个参数传递NULL以获得您想要的行为。

// NOTE THE Null-Terminated string too!
LPTSTR cmdArgs = "D:\\email\\smtp.exe name@example.com\0";

答案 3 :(得分:5)

以下是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 价值。

答案 4 :(得分:2)

试试这个:

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

答案 5 :(得分:1)

您可以添加空格作为cmdArgs字符串的第一个字符:

LPTSTR cmdArgs = " name@example.com";

显然,Windows将第二个参数字符串附加到第一个参数表示的应用程序名称,结果作为命令行参数传递给可执行文件。因此,添加空格将正确地分隔参数。

答案 6 :(得分:0)

  

此函数的Unicode版本CreateProcessW可以修改此字符串的内容。因此,此参数不能是只读内存的指针(例如const变量或文字字符串)。如果此参数是常量字符串,则该函数可能会导致访问冲突。

因此,您可以尝试使用LPTSTR cmdArgs = _tcsdup("name@example.com")

另一个问题是:目标进程如何读取参数?使用argv [0]作为应用程序名称?然后你应该将应用程序名称附加为第一个参数。

答案 7 :(得分:0)

您没有为字符串分配内存。

而不是:

LPTSTR cmdArgs = "name@example.com";

尝试:

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

编辑: 然后致电:

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

这将在堆栈上创建一个本地数组,然后将指针传递给该数组。