Problem in Interprocess Communication using anonymous pipes, when
Hi all,
I am getting some problems with Interprocess communication.
I am providing the codes for Parent and Child processes. Although the code
looks lengthy, but it's very simple. I will describe the problem later.
Parent Process Code:
// Creates two anonymous pipes to the STDIN and STDOUT of the child process
and then creates the Child process
// After that, sends data from a file "1.txt" to the child process' stdin
and then tries to retrieve the output of the child process from it's stdout
which is connected to parent process using an anonymous pipe.
// 1.txt - will contain 2 lines
// My name is Vinayak. <Return>
//
// liveLink.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#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 to
// 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.
// Here one of the parameters as FALSE will make sure that the
// read handle is inheritable
// Ques : Which process is returned when GetCurrentProcess() is called.
// Ans : Since the hild process is not created, the returned process
// must be the parent process
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 to 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.
// Same Questions and answers
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.
fSuccess = CreateChildProcess();
if (! fSuccess)
ErrorExit("Create process failed");
// After process creation, restore the saved STDIN and STDOUT.
// Which will be basically used for the parent process
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(".\\1.txt", 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();
CloseHandle(hInputFile);
if (! CloseHandle(hChildStdinWrDup))
ErrorExit("Close pipe failed\n");
if (!CloseHandle(hChildStdoutWr))
ErrorExit("Closing handle failed");
return 0;
}
BOOL CreateChildProcess()
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bFuncRetn = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
// Set up members of the STARTUPINFO structure.
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
// Create the child process.
bFuncRetn = CreateProcess(NULL,
"C:\\childProcess.exe", // 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
if (bFuncRetn == 0) {
ErrorExit("CreateProcess failed\n");
return 0;
} else {
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bFuncRetn;
}
}
VOID WriteToPipe(VOID)
{
DWORD dwRead = 1, dwWritten = 0;
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;
}
}
VOID ReadFromPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
//BOOL endRead = FALSE;
//BOOL endWrite = FALSE;
BOOL endLoop = FALSE;
for (;;)
{
if (!endLoop)
{
if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE,
&dwRead, NULL) || dwRead == 0)
{
break;
}
// if the number of bytes read is less than
// the Buffer size then there is no need of
// furhter reading from the STD out of the
// child process
if (BUFSIZE > dwRead)
endLoop = TRUE;
if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL))
{
break;
}
}
if (endLoop)
{
break;
}
}
}
VOID ErrorExit (LPTSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
ExitProcess(0);
}
Child Process:
// Simply reads from the console and then prints it.
// childProcess.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
// The code for the child process.
#include <windows.h>
#include <string.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);
scanf("%s", chBuf);
printf("%s", chBuf);
}
Problem:
When executed, WriteToPipe() works nicely, but in ReadFromPipe() the
processes get stuck, when the code reaches ReadFile() function. I guess it
happens due to scanf(). But I don't know how to solve it. Would anyone please
suggest me anything? I will be really grateful.
Thanks in advance.
--
Programmer