Question

I want to create a Windows console application that will start a child process running the cmd command shell with a command line and display the output created by the child process.

The output from the child process is to be read by the parent process so I need to connect the stdout of the child process to the stdin of the parent process. The parent process will then read from its stdin the output from the child process which the child is writing to its stdout. The parent process will display the child output to the parent's stdout.

The child process will run the Windows dir command with the cmd command shell.

My current version is not displaying the dir command output. The parent process is not displaying any output other than the output from the system("pause");.

My main process:

int main(int argc,char* argv[])
{
    HANDLE hStdInRead;
    HANDLE hStdInWrite;

    HANDLE hStdOutRead;
    HANDLE hStdOutWrite;
    HANDLE hStdErrWrite;
    if(!CreatePipe(&hStdInRead,&hStdInWrite,NULL,0))
        return 0;
    if(!CreatePipe(&hStdOutRead,&hStdOutWrite,NULL,0))
        return 0;
    if (!DuplicateHandle(GetCurrentProcess(), hStdOutWrite, GetCurrentProcess(), &hStdErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))  
    {
        return 0;
    }
    STARTUPINFO si;
    ZeroMemory(&si,sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.wShowWindow = SW_SHOW; 
    si.dwFlags =STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
    si.hStdOutput = hStdOutWrite;
    si.hStdError = hStdErrWrite;
    si.hStdInput = hStdInRead;
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));

    LPSTR cmd = new char[256*sizeof(char)];
    strcpy_s(cmd,256,"C:\\Windows\\cmd.exe /c dir");
    if(CreateProcess(NULL,cmd,NULL,NULL,true,0,NULL,NULL,&si,&pi))
    {
        std::cout<<"OK"<<std::endl;
        CloseHandle(hStdOutWrite);
        CloseHandle(hStdInRead);
        char ReadBuff[4096];
        DWORD ReadNum ;
        ZeroMemory(&ReadBuff,4096);
        while(ReadFile(hStdOutRead,ReadBuff,4096,&ReadNum,NULL))
        {   
           std::cout<<ReadBuff<<std::endl;
        }
        WaitForSingleObject(pi.hProcess,INFINITE);
    }
    system("pause");
    return 0;
}
Était-ce utile?

La solution

There are several things wrong with your code, here's a cleaned up example that works.

Changes made: Consolidated the pipe set into one array and created enums to denote which has what purpose, makes it a lot clearer than calling something "StdOutRead" and "StdOutWrite".

Created a SECURITY_ATTRIBUTES structure to let us set up the pipes for inheritance, and added code to prevent the parent-side halves of the pipes being inherited.

Removed the STARTF_USESTDHANDLES flag from the process.

Specified a directory for the process to perform it's DIR on.

Ensured that we close all the handles we're not using once the process is started in the parent.

Lastly, I made it drain the file of io in chunks and append the null terminator to the end of a successful buffer so that it can output properly.

#define WINDOWS_LEAN_AND_MEAN
#include <Windows.h>
#include <tchar.h>

#include <iostream>
#include <thread>
#include <cassert>

enum { ParentRead, ParentWrite, ChildWrite, ChildRead, NumPipeTypes };

int main(int /*argc*/, char* /*argv*/[])
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = nullptr;

    HANDLE pipes[NumPipeTypes];
    if (!CreatePipe(&pipes[ParentWrite], &pipes[ChildRead], &sa, 0))
        return 0;
    if (!CreatePipe(&pipes[ParentRead], &pipes[ChildWrite], &sa, 0))
        return 0;

    // make sure the handles the parent will use aren't inherited.
    SetHandleInformation(pipes[ParentRead], HANDLE_FLAG_INHERIT, 0);
    SetHandleInformation(pipes[ParentWrite], HANDLE_FLAG_INHERIT, 0);

    STARTUPINFO si;
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.wShowWindow = SW_SHOW;
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.hStdOutput = pipes[ChildWrite];
    si.hStdError = pipes[ChildWrite];
    si.hStdInput = pipes[ChildRead];
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

    TCHAR cmd[] = _T("C:\\Windows\\System32\\cmd.exe /c dir c:\\");
    if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
        return 0;

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(pipes[ChildRead]);
    CloseHandle(pipes[ChildWrite]);
    CloseHandle(pipes[ParentWrite]);

    char ReadBuff[4096 + 1];
    DWORD ReadNum;
    for (;;) {
        auto success = ReadFile(pipes[ParentRead], ReadBuff, sizeof(ReadBuff) - 1, &ReadNum, NULL);
        if (!success || !ReadNum)
            break;
        ReadBuff[ReadNum] = 0;
        std::cout << ReadBuff;
    }
    //system("pause");  use Ctrl+F5 or Debug >> Start Without debugging instead.
    return 0;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top