IPC在Windows上使用Pipes

时间:2015-03-27 03:45:07

标签: 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);
}

1 个答案:

答案 0 :(得分:0)

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

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