通过Windows管道写入进程STDIN

时间:2012-04-12 08:27:36

标签: c++ windows process pipe

我正在尝试创建一个函数,它将生成一个程序实例,然后将一些数据传递给它的STDIN,然后使用C ++读取进程的输出。我查看了一个位于here的MSDN示例,这对我来说相当混乱,当我尝试使用该示例时,我得到一些讨厌的错误代码,它将无法正常工作。

    HANDLE hWriteOUT, hReadOUT, hWriteIN, hReadIN;
    SECURITY_ATTRIBUTES saPipe = {0};
    PROCESS_INFORMATION procInfo = {0};
    STARTUPINFO procSi;
    DWORD dwWritten, dwRead;
    char buf[512];

    saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
    saPipe.bInheritHandle = TRUE;
    saPipe.lpSecurityDescriptor= NULL;
    CreatePipe(&hReadOUT, &hWriteOUT, &saPipe, 0);
    SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0);
    CreatePipe(&hReadIN, &hWriteIN, &saPipe, 0);
    SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0);

    ZeroMemory(&procSi, sizeof(STARTUPINFO));
    procSi.cb = sizeof(STARTUPINFO);
    procSi.hStdError = hWriteOUT;
    procSi.hStdOutput = hWriteOUT;
    procSi.hStdInput = hReadIN;
    procSi.dwFlags |= STARTF_USESTDHANDLES;

    CreateProcess(NULL, "cmd", NULL, NULL, TRUE, 0, NULL, NULL, &procSi, &procInfo);
    //Gives me an error code of 18 but returns a 1 when a 0 indicates failure.

    WriteFile(hWriteIN, "notepad", sizeof("notepad"), &dwWritten, NULL);
    cout << GetLastError();  //This gives me error code 18 (ERROR_NO_MORE_FILES)
    ReadFile(hReadOUT, buf, 512, &dwRead, NULL);
    cout << buf;  //This prints "Microsoft Windows [version 6.1.7601]
    CloseHandle(hWriteIN);

代码无法将字符串“notepad”传递给cmd.exe,但是在启动命令shell时成功。如果我查看任务管理器,有几个命令提示符生成但没有记事本。此外,ReadFile()函数是唯一似乎有效的函数,但它甚至不是从管道进程(应该生成的记事本)中读取,而是从CMD读取。更糟糕的是,除了它读取的第一行之外,它正在截断所有内容! (CMD打印“Microsoft Windows .... \ n版权所有... \ n C:\ Users \ Foo&gt; ... \ n”但是`ReadFile()只抓取第一行

2 个答案:

答案 0 :(得分:5)

代码的行为符合预期。你似乎有很多误解:

1)如果希望cmd.exe运行它,则需要在命令末尾发送一个ENTER(“\ n”)。通常最好指定要在CreateProcess中运行的命令,例如,您可以将“cmd / c notepad”指定为命令行而不是“cmd”。

2)您已将管道附加到cmd.exe进程的标准输入和输出,因此您当然可以看到该进程的输出。如果您不想查看cmd.exe的输出,请不要运行它;直接运行您想要的应用程序,例如,您可以指定“notepad”作为要运行的命令行。

3)从管道读取时,ReadFile一次只返回一个数据块,因此需要在循环中调用它。

4)记事本是一个GUI过程,所以它无论如何都不使用stdin或stdout。据推测,这只是一个选择不当的示例,您实际上想要运行命令行应用程序?

5)除非特别记录,否则错误代码(由GetLastError返回)仅在函数失败时才有意义。您使用的所有函数都不是这种情况的例外,因此除非函数返回零以指示它已失败,否则检查错误代码没有意义。

答案 1 :(得分:2)

我知道回答这个问题已经太晚了,但你的代码还有其他问题。似乎SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0);SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0);会破坏事情。我不确定原因,但是在尝试运行代码之后,cmd无法读取管道中的值,直到我删除这两行。