【问题标题】:How do I redirect output to a file with CreateProcess?如何使用 CreateProcess 将输出重定向到文件?
【发布时间】:2011-10-24 11:56:11
【问题描述】:

我尝试使用 CreateProcess 来运行像 hg > test.txt 这样的简单命令。我尝试将字符串作为一个整体运行(而不是将其分成应用程序名称及其参数)。为什么CreateProcess(0, "notepad.exe test.txt", ...) 有效而CreateProcess(0, "hg > test.txt", ...) 无效?

【问题讨论】:

  • CreateProcess 不知道重定向。为什么不使用 system(3) ?让我猜猜:你可以比 system(3) 做得更好。
  • @Seth Carnegie 手册部分。 man 3 system.
  • man 3 system for Windows??
  • @cnicutar 他绝对可以比系统(在 Windows 上)做得更好。系统会启动cmd.exe,加载各种依赖,导致各种不必要的事情发生。
  • @cnicutar:实际上,CreateProcess() 有一个 lpStartupInfo 结构,它接受重定向流的句柄,所以它确实知道重定向。它只是不使用 shell 表示法。

标签: c++ c winapi io-redirection


【解决方案1】:

下面的代码创建了一个无控制台进程,其中 stdout 和 stderr 被重定向到指定的文件。

#include <windows.h>


int _tmain(int argc, _TCHAR* argv[])
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;       

    HANDLE h = CreateFile(_T("out.log"),
        FILE_APPEND_DATA,
        FILE_SHARE_WRITE | FILE_SHARE_READ,
        &sa,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL );

    PROCESS_INFORMATION pi; 
    STARTUPINFO si;
    BOOL ret = FALSE; 
    DWORD flags = CREATE_NO_WINDOW;

    ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
    ZeroMemory( &si, sizeof(STARTUPINFO) );
    si.cb = sizeof(STARTUPINFO); 
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdError = h;
    si.hStdOutput = h;

    TCHAR cmd[]= TEXT("Test.exe 30");
    ret = CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);

    if ( ret ) 
    {
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        return 0;
    }

    return -1;
}

【讨论】:

  • 代码旁边的描述会很方便。至少 cmets
  • 丢失子进程后文件的可能CloseHandle()。
  • hStdInput 不应该是 INVALID_HANDLE_VALUE 而不是 NULL 吗?
  • 顺便说一句,如果你使用 STARTF_USESTDHANDLES 并且不想重定向其中一个句柄,你可以这样做:si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
【解决方案2】:

您不能在传递给CreateProcess 的命令行中使用标准输出重定向。要重定向标准输出,您需要在STARTUPINFO 结构中为输出指定一个文件句柄。

你还犯了另一个更微妙的错误。第二个参数lpCommandLine 必须指向可写内存,因为CreateProcess 会覆盖缓冲区。如果您碰巧使用的是函数的 ANSI 版本,那么您将侥幸逃脱,但对于 Unicode 版本则不行。

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

【讨论】:

  • 他没有把第二个参数指向可写内存不一定是错误的。有可能他编译时没有定义UNICODE,这种情况下CreateProcess就是CreateProcessA,就没有这个要求了。
  • @FrerichRaabe 这是当前 Windows 版本的实现细节。如果您查看 MSDN 文档,您会看到第二个参数的类型是 LPTSTR。无论如何,我在第二段中提出了你提出的观点。
  • @DavidHeffernan:我不认为这是一个实现细节,因为您引用的文档明确提到 ANSI 版本没有这个要求。不过,我主要是在吹毛求疵,因为您首先写了“您也犯了一个错误”,然后您又写了“如果您碰巧使用的是 ANSI 版本”。所以你不知道他是不是做错了,因为你不知道他是不是ANSI版本。
【解决方案3】:

微软有一个如何重定向标准输出的例子: http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx.

【讨论】:

  • 是的,这种工作,但请记住,该示例中有一个错误会阻止 ReadFromPipe 退出。在调用该函数之前,您需要调用:CloseHandle(g_hChildStd_OUT_Wr);。此外,您可能希望等待子进程退出,然后再关闭句柄以进行处理,例如:WaitForSingleObject(piProcInfo.hProcess, INFINITE);
【解决方案4】:

CreateProcess() 启动进程,它不是命令行 itnerpreter。它不知道“>”是什么,也不会为您进行流重定向。您需要自己打开文件 test.txt 并将其句柄传递给 STARTUPINFO 结构内的 CreateProcess: CreateProcess STARTUPINFO

【讨论】:

    【解决方案5】:

    您应该使用参数“/c 命令行”运行进程 cmd.exe。 这会将输出重定向到文件或通过 CreateProcess 组织管道。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-02
      • 2019-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多