2010-11-30 51 views
2

對於我的生活,我無法弄清楚爲什麼這不起作用。基本上,我創建了一個繼承位設置爲true的管道,並創建了兩個子進程,並使用STARTUPINFO結構來設置輸入和輸出句柄,但是管道似乎已經損壞(第二個進程沒有寫入輸出控制檯,即使輸出是預期的)如何在Win32中的兩個子進程之間設置管道?

我知道問題不在於我的測試程序(BitTwiddler.exe),因爲我使用CMD.exe執行相同的操作,並且所有內容都按預期工作。

下面是我所擁有的最低限度的重現。我做錯了什麼?

#include "windows.h" 

int main() 
{ 
    PROCESS_INFORMATION piSource, piDest; 
    HANDLE hPipeIn, hPipeOut; 
    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); 
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); 
    STARTUPINFOW suSource, suDest; 
    ZeroMemory(&suSource, sizeof(suSource)); 
    ZeroMemory(&suDest, sizeof(suDest)); 
    suSource.cb = suDest.cb = sizeof(STARTUPINFOW); 
    suSource.dwFlags = suDest.dwFlags = STARTF_USESTDHANDLES; 
    SECURITY_ATTRIBUTES sa; 
    sa.nLength = sizeof(sa); 
    sa.lpSecurityDescriptor = 0; 
    sa.bInheritHandle = TRUE; 
    if (CreatePipe(&hPipeIn, &hPipeOut, &sa, 0) == 0) 
    { 
     return GetLastError(); 
    } 
    suSource.hStdInput = hIn; 
    suSource.hStdError = suSource.hStdOutput = hPipeIn; 
    suDest.hStdInput = hPipeOut; 
    suDest.hStdError = suDest.hStdOutput = hOut; 
    std::wstring cmdLineA(L"BitTwiddler 1"), cmdLineB(L"BitTwiddler 0"); 
    cmdLineA.push_back(0); cmdLineB.push_back(0); 
    if (CreateProcessW(0, &cmdLineA[0], 0, 0, TRUE, 0, 0, 0, &suSource, &piSource) == 0) 
    { 
     return GetLastError(); 
    } 
    CloseHandle(piSource.hThread); 
    if (CreateProcessW(0, &cmdLineB[0], 0, 0, TRUE, 0, 0, 0, &suDest, &piDest) == 0) 
    { 
     return GetLastError(); 
    } 
    CloseHandle(piDest.hThread); 
    HANDLE hArray[2]; 
    hArray[0] = piSource.hProcess; 
    hArray[1] = piDest.hProcess; 
    WaitForMultipleObjects(2, hArray, TRUE, INFINITE); 
    CloseHandle(hArray[0]); 
    CloseHandle(hArray[1]); 
    return 0; 
} 

(如果任何人的興趣,BitTwiddler是:

#include <windows.h> 
#include <sstream> 
#include <iostream> 
#include <string> 

int main(int argc, char *argv[]) 
{ 
    std::size_t opt = 0; 
    argc--; argv++; 
    if (argc == 0) 
    { 
     return 0; 
    } 
    else 
    { 
     std::istringstream converter(*argv); 
     converter >> opt; 
    } 
    switch(opt) 
    { 
    case 0: 
     { 
      std::wstring currentLine; 
      while(std::getline(std::wcin, currentLine)) 
      { 
       std::wcout << "Got somepin: " << currentLine << std::endl; 
      } 
     } 
     break; 
    case 1: 
     for (;;) 
     { 
      std::wcout << L"Hello World!" << std::endl; 
      Sleep(1000); 
     } 
     break; 
    case 2: 
     return -1; 
    default: 
     std::wcout << "Unknown option."; 
     return 0; 
    } 
    return 0; 
} 

),但我真的不認爲問題。

回答

5

你放錯位置的讀取和寫入結束:)

CreatePipe具有從一個只寫處理原型

BOOL CreatePipe(
    PHANDLE hReadPipe, // can only read from this 
    PHANDLE hWritePipe, // can only write to this 
    LPSECURITY_ATTRIBUTES lpPipeAttributes, 
    DWORD nSize 
); 

不能調用ReadFile(或你的情況的std ::函數getline) ,反之亦然。如果您用簡單的ReadFile來電代替std::getline來電,則會出現ACCESS_DENIED錯誤,以確認此事實,因爲子進程中的STD_INPUT_HANDLE未打開爲GENERIC_READ

修復的方法是如下:

suSource.hStdError = suSource.hStdOutput = hPipeOut; // must be the write pipe! 
suDest.hStdInput = hPipeIn; // must be the read pipe. 

也許你指定的名稱混亂。如果你按照正式參數打電話給他們,錯誤會更清楚:

suSource.hStdError = suSource.hStdOutput = hReadPipe; // clearly wrong. 
suDest.hStdInput = hWritePipe; // as above -- expects a read-handle. 
+0

哈哈 - 我在概念上搞砸了那個好東西。我從管道的預期中思考......即「管道從這裏讀取並在此寫入」......但文檔中的觀點來自於程序的前景,即「您從管道中讀取和在這裏寫入管道「。 :感嘆:謝謝:) – 2010-11-30 15:24:59

相關問題