2014-02-28 182 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

相關問題