2014-02-28 193 views
0

我想创建一个Windows控制台应用程序,该应用程序将启动一个子进程,并使用命令行运行cmd命令行并显示子进程创建的输出。将子进程的标准输出重定向到父进程标准输入

子进程的输出将由父进程读取,因此我需要将子进程的stdout连接到父进程的stdin。然后,父进程将从它的stdin中读取子进程写到其stdout的子进程的输出。父进程会将子输出显示给父级stdout

子进程将运行带有cmd命令外壳的Windows dir命令。

我当前的版本不显示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; 
} 
+0

您是否知道父进程阻塞的位置? – cup

回答

3

有几件事情你的代码错误,这里是一个可行的清理例子。

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

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

从进程中删除了STARTF_USESTDHANDLES标志。

指定进程执行目录的目录。

确保我们关闭了所有我们没有使用的句柄,一旦父进程启动。

最后,我让它以块的形式排出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; 
} 
+0

非常感谢! – Ericzhang88120

相关问题