【问题标题】:How does one setup a pipe between two child processes in Win32?如何在 Win32 中的两个子进程之间设置管道?
【发布时间】:2011-05-17 16:11:37
【问题描述】:

对于我的生活,我无法弄清楚为什么这不起作用。基本上,我创建了将继承位设置为 true 的管道,并创建了两个子进程,并使用 STARTUPINFO 结构根据需要设置输入和输出句柄,但管道似乎已损坏(第二个进程没有写入输出到控制台,即使输出是预期的)

我知道问题不在于我的测试程序 (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;
}

),但我真的不认为这很重要。

【问题讨论】:

    标签: c++ winapi pipe


    【解决方案1】:

    你放错了读写端:)

    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.
    

    【讨论】:

    • 大声笑——我在概念上搞砸了那个好东西。我是从管道的角度考虑的......即“管道从这里读取并写入这里”......但是文档中的观点是从程序的角度来看的,即“你从这里的管道读取并且写到这里的管道”。 :sigh: 谢谢:)
    猜你喜欢
    • 1970-01-01
    • 2014-06-20
    • 2011-06-18
    • 2013-08-28
    • 2015-08-13
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多