通过 Windows 管道写入进程 STDIN

Writing to a process STDIN via Windows pipes

本文关键字:进程 STDIN Windows 管道 通过      更新时间:2023-10-16

我正在尝试创建一个函数,该函数将生成一个程序的实例,然后将一些数据通过管道传输到其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);

该代码无法将字符串"记事本"通过管道传输到 cmd.exe但成功启动命令外壳。如果我在任务管理器中查看,则有几个命令提示符生成的实例,但没有记事本。此外,ReadFile()函数是唯一一个似乎有效的函数,但它甚至不是从管道进程(应该生成的记事本)中读取,而是从 CMD 读取。更糟糕的是,它截断了除第一行之外的所有内容!(CMD 打印"Microsoft Windows.... Copyright... C:\Users\Foo>...",但"ReadFile() 只抓取第一行")

代码的行为符合预期。 您似乎误解了很多事情:

1) 如果您希望 cmd.exe 运行它,则需要在命令末尾发送 ENTER ("")。 通常最好指定要在CreateProcess中运行的命令,例如,您可以指定"cmd/c记事本"作为命令行,而不仅仅是"cmd"。

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

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

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

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

我知道现在回答这个问题有点太晚了,但你的代码也有其他问题。 看来SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0); SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0);会破坏事情。我不确定为什么,但是在尝试运行您的代码后,cmd 无法从管道中读取值,直到我删除这两行。