通过Windows管道写入进程STDIN

use*_*545 3 c++ windows pipe process

我试图创建一个函数,它将生成一个程序的实例,然后将一些数据传递到它的STDIN,然后使用C++读取进程的输出.我查看了一个位于此处的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);
Run Code Online (Sandbox Code Playgroud)

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

Har*_*ton 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返回)仅在函数失败时才有意义.您使用的所有函数都不是这种情况的例外,因此除非函数返回零以指示它已失败,否则检查错误代码没有意义.