32

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

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

8 回答 8

27

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

于 2009-07-16T06:51:53.657 回答
22

如果第一个参数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!
于 2009-07-17T01:49:45.450 回答
7

您似乎没有正确使用 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";
于 2009-07-16T06:51:57.493 回答
6

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

于 2009-07-21T05:53:50.317 回答
4

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

LPTSTR cmdArgs = " name@example.com";

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

于 2017-06-26T22:07:45.933 回答
3

尝试这个:

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
于 2009-07-16T06:50:02.567 回答
1

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

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

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

于 2009-07-16T07:06:12.253 回答
-1

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

代替:

LPTSTR cmdArgs = "name@example.com";

尝试:

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

编辑:然后调用:

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

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

于 2009-07-16T07:48:02.717 回答