2010-11-30 4 views
2

Pour la vie de moi, je ne peux pas comprendre pourquoi cela ne fonctionne pas. Fondamentalement, j'ai créé le pipe avec le bit inherit défini sur true, et créé deux processus enfants, et utilisé la structure STARTUPINFO pour définir les poignées d'entrée et de sortie comme on aurait besoin, mais le tuyau semble cassé (le second processus n'écrit la console, même si la production est attendue)Comment configurer un canal entre deux processus fils dans Win32?

Je sais que le problème ne réside pas dans mon programme de test (BitTwiddler.exe) parce que j'effectuer la même opération en utilisant cmd.exe, et tout fonctionne comme prévu.

Voici une reproduction minimale de ce que j'ai. Qu'ai-je mal fait?

#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; 
} 

(Dans le cas où quelqu'un est intéressé, BitTwiddler est:

#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; 
} 

), mais je ne pense vraiment pas que les questions.

Répondre

5

Vous avez égaré la lecture et d'écriture extrémités :)

CreatePipe a le prototype

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

Vous ne pouvez pas appeler ReadFile (ou dans votre cas std :: getline) à partir d'une écriture seule poignée , et vice versa. Si vous avez remplacé vos appels std::getline par un simple appel ReadFile, vous obtiendrez une erreur ACCESS_DENIED, confirmant ce fait, puisque votre STD_INPUT_HANDLE dans le processus enfant n'a pas été ouvert pour GENERIC_READ.

Le correctif est comme suit:

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

Peut-être les noms que vous designé sont confus. Si vous les appelez selon les paramètres formels, l'erreur serait plus claire:

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

Lol - J'ai conceptuellement foiré celui-là. Je pensais à partir de la prospective de la pipe ... à savoir "Le tuyau lit d'ici et écrit ici" ... mais la perspective dans les docs sont de la prospective des programmes, à savoir "Vous lisez de la pipe ici et écrivez à la pipe ici ". : soupir: Merci :) –

Questions connexes