How does one setup a pipe between two child processes in Win32?

孤街醉人 提交于 2020-01-14 00:44:09

问题


For the life of me I can't figure out why this is not working. Basically, I created the pipe with the inherit bit set to true, and created two child processes, and used the STARTUPINFO structure to set the input and output handles as one would need, but the pipe seems broken (the second process writes no output to the console, even though output is expected)

I know the problem does not lie in my test program (BitTwiddler.exe) because I performed the same operation using CMD.exe, and everything works as expected.

Below is a minimal reproduction of what I have. What have I done incorrectly?

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

(In case anyone's interested, BitTwiddler is:

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

), but I really don't think that matters.


回答1:


You misplaced the read and write ends :)

CreatePipe has the prototype

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

You can't call ReadFile (or in your case std::getline) from a Write-only handle, and vice versa. If you replaced your std::getline calls with a simple ReadFile call, you'd get an ACCESS_DENIED error, confirming this fact, since your STD_INPUT_HANDLE in the child process was not opened for GENERIC_READ.

The fix is as follows:

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

Perhaps the names you assigned are confusing. If you called them as per the formal parameters, the error would be clearer:

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


来源:https://stackoverflow.com/questions/4310645/how-does-one-setup-a-pipe-between-two-child-processes-in-win32

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!