Home   Index   About
Ultimate Pack


Custom Search
Creating a Child Process with Redirected Input and Output

The example in this topic demonstrates how to create a child process from a console process. It also demonstrates a technique for using anonymous pipes to redirect the child process's standard input and output handles.

The CreatePipe function uses the SECURITY_ATTRIBUTES structure to create inheritable handles to the read and write ends of two pipes. The read end of one pipe serves as standard input for the child process, and the write end of the other pipe is the standard output for the child process. These pipe handles are specified in the SetStdHandle function, which makes them the standard handles inherited by the child process. After the child process is created, SetStdHandle is used again to restore the original standard handles for the parent process.

The parent process uses the other ends of the pipes to write to the child process's input and read the child process's output. The handles to these ends of the pipe are also inheritable. However, the handle must not be inherited. Before creating the child process, the parent process must use DuplicateHandle to create a duplicate of the application-defined hChildStdinWr global variable that cannot be inherited. It then uses CloseHandle to close the inheritable handle. For more information, see Pipes.

The following is the parent process.

#include <stdio.h>

#include <windows.h>

#define BUFSIZE 4096

HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,

hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,

hInputFile, hSaveStdin, hSaveStdout;

BOOL CreateChildProcess(VOID);

VOID WriteToPipe(VOID);

VOID ReadFromPipe(VOID);

VOID ErrorExit(LPTSTR);

VOID ErrMsg(LPTSTR, BOOL);

DWORD main(int argc, char *argv[])

{

SECURITY_ATTRIBUTES saAttr;

BOOL fSuccess;

// Set the bInheritHandle flag so pipe handles are inherited.

saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);

saAttr.bInheritHandle = TRUE;

saAttr.lpSecurityDescriptor = NULL;

// The steps for redirecting child process's STDOUT:

// 1. Save current STDOUT, to be restored later.

// 2. Create anonymous pipe to be STDOUT for child process.

// 3. Set STDOUT of the parent process to be write handle of

// the pipe, so it is inherited by the child process.

// 4. Create a noninheritable duplicate of the read handle and

// close the inheritable read handle.

// Save the handle to the current STDOUT.

hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);

// Create a pipe for the child process's STDOUT.

if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))

ErrorExit("Stdout pipe creation failed\n");

// Set a write handle to the pipe to be STDOUT.

if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))

ErrorExit("Redirecting STDOUT failed");

// Create noninheritable read handle and close the inheritable read

// handle.

fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,

GetCurrentProcess(), &hChildStdoutRdDup , 0,

FALSE,

DUPLICATE_SAME_ACCESS);

if( !fSuccess )

ErrorExit("DuplicateHandle failed");

CloseHandle(hChildStdoutRd);

// The steps for redirecting child process's STDIN:

// 1. Save current STDIN, to be restored later.

// 2. Create anonymous pipe to be STDIN for child process.

// 3. Set STDIN of the parent to be the read handle of the

// pipe, so it is inherited by the child process.

// 4. Create a noninheritable duplicate of the write handle,

// and close the inheritable write handle.

// Save the handle to the current STDIN.

hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);

// Create a pipe for the child process's STDIN.

if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))

ErrorExit("Stdin pipe creation failed\n");

// Set a read handle to the pipe to be STDIN.

if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))

ErrorExit("Redirecting Stdin failed");

// Duplicate the write handle to the pipe so it is not inherited.

fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,

GetCurrentProcess(), &hChildStdinWrDup, 0,

FALSE, // not inherited

DUPLICATE_SAME_ACCESS);

if (! fSuccess)

ErrorExit("DuplicateHandle failed");

CloseHandle(hChildStdinWr);

// Now create the child process.

if (! CreateChildProcess())

ErrorExit("Create process failed");

// After process creation, restore the saved STDIN and STDOUT.

if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))

ErrorExit("Re-redirecting Stdin failed\n");

if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))

ErrorExit("Re-redirecting Stdout failed\n");

// Get a handle to the parent's input file.

if (argc > 1)

hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL,

OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);

else

hInputFile = hSaveStdin;

if (hInputFile == INVALID_HANDLE_VALUE)

ErrorExit("no input file\n");

// Write to pipe that is the standard input for a child process.

WriteToPipe();

// Read from pipe that is the standard output for child process.

ReadFromPipe();

return 0;

}

BOOL CreateChildProcess()

{

PROCESS_INFORMATION piProcInfo;

STARTUPINFO siStartInfo;

// Set up members of STARTUPINFO structure.

ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );

siStartInfo.cb = sizeof(STARTUPINFO);

// Create the child process.

return CreateProcess(NULL,

"child", // command line

NULL, // process security attributes

NULL, // primary thread security attributes

TRUE, // handles are inherited

0, // creation flags

NULL, // use parent's environment

NULL, // use parent's current directory

&siStartInfo, // STARTUPINFO pointer

&piProcInfo); // receives PROCESS_INFORMATION

}

VOID WriteToPipe(VOID)

{

DWORD dwRead, dwWritten;

CHAR chBuf[BUFSIZE];

// Read from a file and write its contents to a pipe.

for (;;)

{

if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ||

dwRead == 0) break;

if (! WriteFile(hChildStdinWrDup, chBuf, dwRead,

&dwWritten, NULL)) break;

}

// Close the pipe handle so the child process stops reading.

if (! CloseHandle(hChildStdinWrDup))

ErrorExit("Close pipe failed\n");

}

VOID ReadFromPipe(VOID)

{

DWORD dwRead, dwWritten;

CHAR chBuf[BUFSIZE];

HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

// Close the write end of the pipe before reading from the

// read end of the pipe.

if (!CloseHandle(hChildStdoutWr))

ErrorExit("Closing handle failed");

// Read output from the child process, and write to parent's STDOUT.

for (;;)

{

if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead,

NULL) || dwRead == 0) break;

if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL))

break;

}

}

VOID ErrorExit (LPTSTR lpszMessage)

{

fprintf(stderr, "%s\n", lpszMessage);

ExitProcess(0);

}

// The code for the child process.

#include <windows.h>

#define BUFSIZE 4096

VOID main(VOID)

{

CHAR chBuf[BUFSIZE];

DWORD dwRead, dwWritten;

HANDLE hStdin, hStdout;

BOOL fSuccess;

hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

hStdin = GetStdHandle(STD_INPUT_HANDLE);

if ((hStdout == INVALID_HANDLE_VALUE) ||

(hStdin == INVALID_HANDLE_VALUE))

ExitProcess(1);

for (;;)

{

// Read from standard input.

fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);

if (! fSuccess || dwRead == 0)

break;

// Write to standard output.

fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);

if (! fSuccess)

break;

}

}


Last news from Greatis Software

Nostalgia .Net     Nostalgia .Net     .Net is powerful, but not all-powerful, so sometimes we need to use Win32 API for our .Net applications. It's simple enough with Platform Invoke if you have Win32 skill, but we do not always have time to dig the ancient documentation, declare the special types that are compatible with Win32, find the values of the Win32's constants and so on. Nostalgia .Net offers several simple-to-use classes, and components that will allow you to forget about the headache of Win32 and just use the power of Win32 in your application the same way as you use the native. Net classes.  More »

Recommended software for developers

Ultimate Pack for Delphi and C++ Builder     Ultimate Pack     Component pack for Delphi and C++ Builder that contains runtime form designer, runtime object inspector, print suite and much more for the very special price.  More »

Form Designer .Net     Form Designer .Net     Unique runtime form design solution that allows to edit any form in .Net WinForms application at runtime with full source codes for only 300 euro!  More »

Print Suite .Net     Print Suite .Net     Print Suite .Net is a set of components for easy printing texts, images and grids from your WinForms applications. Full C# source codes are available  More »

Gradient Controls .Net     Gradient Controls .Net     Gradient Controls .Net offers controls with gradient background feature. Labels, panels and so on... Full C# source codes are available  More »

iGrid     Greatis iGrid     iGrid plots drawing grid right over your desktop, so you can use it everywhere, with any drawing application without any special plugins for different graphic editors.  More »


All the contacts and projects

Dmitry Vasiliev (just.dmitry)

Related Links

Software for Visual Studio .NET developers
Software for Delphi and C++ Builder developers
Software for Visual Basic 6 developers
Delphi Tips&Tricks
MegaDetailed.NET

More Online Helps

Win32 Programmer's Reference
Win32 Multimedia Programmer's Reference
OLE Programmer's Reference
Microsoft Windows Pen API Programmer's Reference
Microsoft Windows Sockets 2 Reference
Microsoft Windows Telephony API (TAPI) Programmer's Reference
Unix Manual Pages

Free Tech Secrets ;) Copyright © 2008-2012 Free Tech Secrets ;) greatis just4fun network just4fun