2012-04-12 146 views
3

我正在嘗試創建一個函數,該函數將產生一個程序實例,然後將一些數據輸入到它的STDIN中,然後使用C++讀取該進程的輸出。我看過一個位於here的MSDN示例,這對我來說很困惑,當我嘗試使用該示例時,出現了一些令人討厭的錯誤代碼,它不起作用。通過Windows管道寫入進程STDIN

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 .... \ n Copyright ... \ n C:\ Users \ Foo> ... \ n」但是ReadFile()只抓取第一行)

回答

5

代碼行爲如預期。有一些事情你似乎誤解了:如果你想讓cmd.exe運行它,你需要在命令結尾處發送一個ENTER(「\ n」)。通常,最好在CreateProcess中指定要運行的命令,例如,可以將「cmd/c notepad」指定爲命令行而不是「cmd」。

2)您已將管道連接到cmd.exe進程的標準輸入和輸出,所以當然您會看到該進程的輸出。如果您不想查看cmd.exe的輸出,請不要運行它;直接運行您想要的應用程序,例如,您可以指定「記事本」作爲要運行的命令行。

3)從管道讀取數據時,ReadFile一次只返回一個數據塊,因此需要在循環中調用它。

4)記事本是一個GUI過程,所以它不會使用標準輸入或標準輸出。據推測,這只是一個選擇不好的例子,你實際上想要運行一個命令行應用程序? 5)除特別說明外,錯誤代碼(由GetLastError返回)僅在函數失敗時纔有意義。你所使用的函數都不是這種情況的例外,所以檢查錯誤代碼是沒有意義的,除非函數返回0來表明它失敗了。

2

我知道回答這個問題還爲時尚晚,但代碼中還存在其他問題。看來SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0);SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0);將打破東西。我不知道爲什麼,但在嘗試運行你的代碼之後,cmd無法讀取管道中的值,直到我刪除這兩行代碼。

+0

我錯過了那一個。第一次調用應該可以,但第二次調用應該是'hWINININ'而不是'hReadIN',因爲'hReadIN'句柄應該被子進程繼承。 – 2012-10-25 19:55:28