c++ - IPC 在 Windows 上使用管道

标签 c++ winapi pipe ipc

我的程序调用 cl.exe 并使用管道进行通信。当我试图理解它时,我试图在 Windows 上使用管道搜索 IPC,但找不到太多资源。我发现下面的链接与我的代码有 90% 的相似度,但对每个步骤的描述非常少。

http://support.microsoft.com/en-us/kb/190351

有人可以向我解释一下这个程序中的父子关系是如何工作的吗?为什么使用重复句柄?

代码片段:

{
    HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
    HANDLE hInputWriteTmp,hInputRead,hInputWrite;
    HANDLE hErrorWrite;
    SECURITY_ATTRIBUTES sa;

    // Set up the security attributes struct.
    sa.nLength= sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    // Create the child output pipe.
    if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
    {
        error("Creation of child process output pipe failed");
        return false;
    }

    // Create a duplicate of the output write handle for the std error
    // write handle. This is necessary in case the child application
    // closes one of its std output handles.
    if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
                        GetCurrentProcess(),&hErrorWrite,0,
                        TRUE,DUPLICATE_SAME_ACCESS))
    {
        error("Duplication of child process output pipe failed");
        return false;
    }

    // Create the child input pipe.
    if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
    {
        error("Creation of child process input pipe failed");
        return false;
    }

    // Create new output read handle and the input write handles. Set
    // the Properties to FALSE. Otherwise, the child inherits the
    // properties and, as a result, non-closeable handles to the pipes
    // are created.
    if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
                        GetCurrentProcess(),
                        &hOutputRead, // Address of new handle.
                        0,FALSE, // Make it uninheritable.
                        DUPLICATE_SAME_ACCESS))
    {
        error("Creation of child process read handle failed");
        return false;
    }

    if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
                        GetCurrentProcess(),
                        &hInputWrite, // Address of new handle.
                        0,FALSE, // Make it uninheritable.
                        DUPLICATE_SAME_ACCESS))
    {
        error("Creation of child process write handle failed");
        return false;
    }

    // Close inheritable copies of the handles you do not want to be
    // inherited.
    CloseHandle(hOutputReadTmp);
    CloseHandle(hInputWriteTmp);

    // Get std input handle so you can close it and force the ReadFile to
    // fail when you want the input thread to exit.
    HANDLE hStdIn = NULL;
    if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE )
        TRACE("GetStdHandle");

    STARTUPINFO Si;
    Si.lpDesktop = NULL;
    Si.cb = sizeof(Si);
    Si.lpReserved = NULL;
    Si.lpTitle = NULL;
    Si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW | STARTF_USECOUNTCHARS;
    Si.dwXCountChars = 10;
    Si.dwYCountChars = 8;
    Si.wShowWindow = SW_HIDE;
    Si.cbReserved2 = 0;
    Si.lpReserved2 = NULL;
    Si.hStdOutput = hOutputWrite;
    Si.hStdInput  = hInputRead;
    Si.hStdError  = hErrorWrite;

    PROCESS_INFORMATION Pi;

    // Create and start the child process
    BOOL processCreated = CreateProcess(    NULL,
                        const_cast<char*>(m_command.c_str()),
                        NULL,
                        NULL,
                        TRUE,
                        GetCreationFlags(),
                        NULL,
                        m_workingDir.c_str(),
                        &Si,
                        &Pi);
    if (!processCreated)
    {
        error("Creation of child process failed");
        return false;
    }

    // Close pipe handles (do not continue to modify the parent).
    // You need to make sure that no handles to the write end of the
    // output pipe are maintained in this process or else the pipe will
    // not close when the child process exits and the ReadFile will hang.
    CloseHandle(hOutputWrite);
    CloseHandle(hInputRead);
    CloseHandle(hErrorWrite);

    // Read the child's output.
    if (!ReadAndHandleOutput(hOutputRead))
    {
        // Something went wrong so kill and exit
        CloseHandle(hOutputRead);
        CloseHandle(hInputWrite);
        error("Read of compile process result failed");
        TerminateProcess(Pi.hProcess, -1);
        CloseHandle(Pi.hProcess);
        CloseHandle(Pi.hThread);
        return false;
    }

    CloseHandle(hOutputRead);
    CloseHandle(hInputWrite);

    // Wait for the child process to die
    WaitForSingleObject(Pi.hProcess, INFINITE);

    if (!GetExitCodeProcess(Pi.hProcess, &m_exitCode))
    {
        error("Read of child process exit code failed");
        CloseHandle(Pi.hProcess);
        CloseHandle(Pi.hThread);
        return false;
    }
    CloseHandle(Pi.hProcess);
    CloseHandle(Pi.hThread);
}

最佳答案

CreatePipe - 使用 ZwCreateNamedPipe[CreateNamedPipe]ZwOpenFile [CreateFile(OPEN_EXISTING)] 创建命名管道对。

pair 的一个实例将存在于我们的进程中(没有继承标志),第二个实例将被复制到子进程(必须具有继承标志)。然而我们只有一个通用参数 LPSECURITY_ATTRIBUTES ,我们可以在其中设置继承标志。因此,如果设置了此标志 - 两个实例都将具有继承的属性。这里可以有几种解决方案。我们不能使用CreatePipe,而是直接调用ZwCreateNamedPipeZwOpenFile来正确继承设置。或者我们可以使用 SetHandleInformation 更改继承设置。但是示例的作者选择了最差的(根据逻辑和效率)——使用 DuplicateHandle 为管道实例创建另一个句柄——已经没有继承标志。然后关闭原始 handle 。但是可以使用 DUPLICATE_CLOSE_SOURCE 标志来避免下一次 CloseHandle 调用 - 令人震惊的无知。在调用 CreateProcess 之后 - 继承的句柄被复制到子进程,我们可以在原始进程中关闭它。所以此时我们有 2 个管道 channel 并开始读/写..

关于c++ - IPC 在 Windows 上使用管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29292924/

相关文章:

c++ - 在每种情况下都有意外输出。我的解决方案有什么问题?

c++ - 使用 std::list 作为循环列表是否安全?

winapi - 所有调整大小操作的 Windows 消息

c - 在 C 中读取结构体并将其写入管道

pipe - 如何从标准输入中提取 tar 存档?

c++ - deque::shrink_to_fit内存保证

c++ - 嵌套类的模板模板参数的可变类型模板参数和非类型模板参数如何相互约束?

C#:获取设备实例句柄时出错

delphi - WebBrowser、IPersistStreamInit 和 javascript

Linux无法通过管道获取数据