简体   繁体   中英

IPC using Pipes on Windows

My program invokes cl.exe and communicates using pipes. When I was trying to understand it, I tried to search about IPC using pipes on windows, but couldn't find much resources. I found below link which is 90% similar to my code, but there is very less description about each steps.

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

Can somebody explains me how the parent and child relationship works in this program? why duplicate handle is used?

Code snippet:

{
    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 - create named pipes pair by using ZwCreateNamedPipe[CreateNamedPipe] and ZwOpenFile [ CreateFile(OPEN_EXISTING)] .

one instance of pair will be live in our process(no not have inherit flag) and second will be duplicated to child process (mast have inherit flag). however we have only one common parameter LPSECURITY_ATTRIBUTES , where we can set inherit flag. as a result if this flag is set - both instances will have the inherited property. here can be several solutions. we can not use CreatePipe , but direct call ZwCreateNamedPipe and ZwOpenFile for just correct inherit settings. or we can change inherit settings by using SetHandleInformation . but author of example select worst (by logic and efficiency) - use DuplicateHandle for create another handle for pipe instance - already without inherit flag. and than close original handle. however can be used DUPLICATE_CLOSE_SOURCE flag for avoid next CloseHandle call - stunning ignorance. after call CreateProcess - inherited handles is duplicated to child process, and we can close it in original process. so at this point we have 2 pipe channels and begin read/write..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM