将子进程的stdout重定向到父进程stdin

时间:2014-02-28 06:49:50

标签: c++ windows child-process

我想创建一个Windows控制台应用程序,它将使用命令行启动运行cmd命令shell的子进程,并显示子进程创建的输出。

子进程的输出将由父进程读取,因此我需要将子进程的stdout连接到父进程的stdin。然后,父进程将从其stdin读取子进程的输出,该进程正在将子进程写入其stdout。父进程将子输出显示给父进程stdout

子进程将使用dir命令shell运行Windows cmd命令。

我当前的版本没有显示dir命令输出。父进程不显示system("pause");的输出以外的任何输出。

我的主要流程:

int main(int argc,char* argv[])
{
    HANDLE hStdInRead;
    HANDLE hStdInWrite;

    HANDLE hStdOutRead;
    HANDLE hStdOutWrite;
    HANDLE hStdErrWrite;
    if(!CreatePipe(&hStdInRead,&hStdInWrite,NULL,0))
        return 0;
    if(!CreatePipe(&hStdOutRead,&hStdOutWrite,NULL,0))
        return 0;
    if (!DuplicateHandle(GetCurrentProcess(), hStdOutWrite, GetCurrentProcess(), &hStdErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))  
    {
        return 0;
    }
    STARTUPINFO si;
    ZeroMemory(&si,sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.wShowWindow = SW_SHOW; 
    si.dwFlags =STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
    si.hStdOutput = hStdOutWrite;
    si.hStdError = hStdErrWrite;
    si.hStdInput = hStdInRead;
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));

    LPSTR cmd = new char[256*sizeof(char)];
    strcpy_s(cmd,256,"C:\\Windows\\cmd.exe /c dir");
    if(CreateProcess(NULL,cmd,NULL,NULL,true,0,NULL,NULL,&si,&pi))
    {
        std::cout<<"OK"<<std::endl;
        CloseHandle(hStdOutWrite);
        CloseHandle(hStdInRead);
        char ReadBuff[4096];
        DWORD ReadNum ;
        ZeroMemory(&ReadBuff,4096);
        while(ReadFile(hStdOutRead,ReadBuff,4096,&ReadNum,NULL))
        {   
           std::cout<<ReadBuff<<std::endl;
        }
        WaitForSingleObject(pi.hProcess,INFINITE);
    }
    system("pause");
    return 0;
}

1 个答案:

答案 0 :(得分:3)

您的代码有几个问题,这是一个有效的清理示例。

所做的更改:将管道集合成一个数组并创建枚举以表示具有什么目的,使其比调用“StdOutRead”和“StdOutWrite”更清晰。

创建了一个SECURITY_ATTRIBUTES结构,让我们设置继承管道,并添加代码以防止继承管道的父端一半。

从进程中删除了STARTF_USESTDHANDLES标志。

指定进程执行DIR的目录。

确保在父进程启动后我们关闭所有未使用的句柄。

最后,我让它以块的方式排出io的文件,并将空终结符附加到成功缓冲区的末尾,以便它可以正确输出。

#define WINDOWS_LEAN_AND_MEAN
#include <Windows.h>
#include <tchar.h>

#include <iostream>
#include <thread>
#include <cassert>

enum { ParentRead, ParentWrite, ChildWrite, ChildRead, NumPipeTypes };

int main(int /*argc*/, char* /*argv*/[])
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = nullptr;

    HANDLE pipes[NumPipeTypes];
    if (!CreatePipe(&pipes[ParentWrite], &pipes[ChildRead], &sa, 0))
        return 0;
    if (!CreatePipe(&pipes[ParentRead], &pipes[ChildWrite], &sa, 0))
        return 0;

    // make sure the handles the parent will use aren't inherited.
    SetHandleInformation(pipes[ParentRead], HANDLE_FLAG_INHERIT, 0);
    SetHandleInformation(pipes[ParentWrite], HANDLE_FLAG_INHERIT, 0);

    STARTUPINFO si;
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.wShowWindow = SW_SHOW;
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.hStdOutput = pipes[ChildWrite];
    si.hStdError = pipes[ChildWrite];
    si.hStdInput = pipes[ChildRead];
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

    TCHAR cmd[] = _T("C:\\Windows\\System32\\cmd.exe /c dir c:\\");
    if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
        return 0;

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(pipes[ChildRead]);
    CloseHandle(pipes[ChildWrite]);
    CloseHandle(pipes[ParentWrite]);

    char ReadBuff[4096 + 1];
    DWORD ReadNum;
    for (;;) {
        auto success = ReadFile(pipes[ParentRead], ReadBuff, sizeof(ReadBuff) - 1, &ReadNum, NULL);
        if (!success || !ReadNum)
            break;
        ReadBuff[ReadNum] = 0;
        std::cout << ReadBuff;
    }
    //system("pause");  use Ctrl+F5 or Debug >> Start Without debugging instead.
    return 0;
}