2010-11-30 26 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

相关问题