// This is an example which will explain the communication between
// the parent process (Master process) and a child process
// (Slave process). The code makes a use of handle inheritance to pass
// the pipe's handle to the child process.
// The code has been developed on WIN-98 and tested on WIN98/2000.
// Code by Dinesh Ahuja, Aug 09, 2003.
/****************************************************************/
// Compiler Settings
// Before executing the code, pass "-master" in the command line
// argument.
// Click on setting menu item, after that click on the Debug tab,
// type -master in the Program arguments: field.
/****************************************************************/
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h>
// specifies the Buffer size for the pipe.
#define PIPE_BUFFERLENGTH 19
int main(int argc, char* argv[]) {
BOOL bReturn = FALSE;
if (strcmp(argv[1],"-master") == 0) {
// This part of the code will be executed for the master process.
HANDLE hRdMaster = NULL,hWrSlave = NULL;
HANDLE hRdSlave = NULL,hWrMaster = NULL;
HANDLE hChildProcess = NULL;
HANDLE hDuplRdMaster = NULL,hDuplWrMaster = NULL;
STARTUPINFO startInfo;
PROCESS_INFORMATION prcInfo;
SECURITY_ATTRIBUTES secAttr;
char pSlaveCmdLine[256] = {'\0'};
char swMasterStr[10] = {'\0'};
char szModulePath[100] = {'\0'};
char szTempWrSlaveHandle[10] = {'\0'};
char szTempRdSlaveHandle[10] = {'\0'};
cout<<"I am a Master Process"<<endl;
// Setting the security descriptor for an object and it
// decides whether the object's handle will be inheritable
// or not.
secAttr.bInheritHandle = TRUE;
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.lpSecurityDescriptor = NULL;
GetStartupInfo(&startInfo);
// Parent process will create an anonymous pipe with its read
// handle and write handle inheritable. The parent process will pass
// the handle to its write end to the child process, so that the child process
// can write over it. The handle to the read end should only be with
// parent process as it has to read the data which is written by the
// child process and hence it should be made non-inheritable. This is
// achieved by DuplicateHandle.
// parent -> read and child -> write
// This can be considered as pipe1 for understanding the code.
bReturn = CreatePipe(&hRdMaster,&hWrSlave,&secAttr,PIPE_BUFFERLENGTH);
DuplicateHandle(GetCurrentProcess(),hRdMaster,GetCurrentProcess(),&hDuplRdMaster,DUPLICATE_SAME_ACCESS,FALSE,DUPLICATE_SAME_ACCESS);
CloseHandle(hRdMaster);
// Parent process will create an anonymous pipe with its write
// handle and read handle inheritable. The parent process passes
// the handle to the read end to the slave process. The handle
// to the write end should not be inheritable and hence DuplicateHandle
// is called to create a non-inheritable handle amd after that
// inheritable handle is closed so that it should not be
// available for the child process.
// parent -> write and child -> read
// This can be considered as pipe2 for understanding the code.
bReturn = CreatePipe(&hRdSlave,&hWrMaster,&secAttr,PIPE_BUFFERLENGTH);
DuplicateHandle(GetCurrentProcess(),hWrMaster,GetCurrentProcess(),&hDuplWrMaster,DUPLICATE_SAME_ACCESS,FALSE,DUPLICATE_SAME_ACCESS);
CloseHandle(hWrMaster);
// preparing the command line for the child process.
GetModuleFileName(NULL,&szModulePath[0],sizeof(szModulePath));
strcpy(pSlaveCmdLine,"\"");
strcat(pSlaveCmdLine,szModulePath);
strcat(pSlaveCmdLine,"\"");
strcat(pSlaveCmdLine," ");
strcat(pSlaveCmdLine, "-slave");
strcat(pSlaveCmdLine," ");
// Passing a value of the handle to the write end of the
// pipe1 as a command line argument.
wsprintf(szTempWrSlaveHandle,"%d",hWrSlave);
strcat(pSlaveCmdLine,szTempWrSlaveHandle);
// Passing a value of the handle to the read end of the
// pipe2 as a command line argument.
strcat(pSlaveCmdLine," ");
wsprintf(szTempRdSlaveHandle,"%d",hRdSlave);
strcat(pSlaveCmdLine,szTempRdSlaveHandle);
// Creating a child process and passing a master process made
// command line argument.
bReturn = CreateProcess(argv[0],pSlaveCmdLine,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&startInfo,&prcInfo);
if (bReturn) {
// Opens a handle to the child process so that it could be
// used in the wait function (WaitForSingleObject).
hChildProcess = OpenProcess(SYNCHRONIZE,FALSE,prcInfo.dwProcessId);
}
// Reading data from pipe1.
for(int i=0;i<50;i++) {
char ReadBuff[50] = {'\0'};
BOOL bRet = FALSE;
DWORD dwRead;
if((i>=0) && (i<=9)) {
bRet = ReadFile(hDuplRdMaster,&ReadBuff,18,&dwRead,NULL);
}
else {
bRet = ReadFile(hDuplRdMaster,&ReadBuff,19,&dwRead,NULL);
}
if(bRet == FALSE) {
assert(bRet != FALSE);
break;
}
cout<<"Master Reading: "<<ReadBuff<<endl;
}
CloseHandle(hWrSlave);
CloseHandle(hDuplRdMaster);
// Writing data on pipe2.
for(int j=10;j>0;j--) {
char Buff[50] = {'\0'};
int len;
DWORD dwWritten;
BOOL bRet = FALSE;
len = wsprintf(Buff,"This is line no:%i\n",j);
bRet = WriteFile((HANDLE)hDuplWrMaster,Buff,len,&dwWritten,NULL);
if (bRet == TRUE) {
cout<<"Master Writting: "<<Buff<<endl;
}
else {
cout<<"The following Data couldn't be written: "<<Buff<<endl;
}
}
cout<<"Waiting for child process to exit "<<endl;
WaitForSingleObject(hChildProcess,INFINITE);
CloseHandle(hDuplWrMaster);
CloseHandle(hRdSlave);
}
else if (strcmp(argv[1],"-slave") == 0) {
// This code is executed for child process,
HANDLE hWrSlave = NULL; // handle to write end to pipe1.
HANDLE hRdSlave = NULL; // handle to read end to pipe2.
int laddWrSlave = 0;
int laddRdSlave = 0;
DWORD dwWritten;
laddWrSlave = atoi(argv[2]);
laddRdSlave = atoi(argv[3]);
cout<<"Value of write handle to pipe1: "<<laddWrSlave<<endl;
cout<<"Value of read handle to pipe2 : "<<laddRdSlave<<endl;
hWrSlave = (void*)laddWrSlave;
hRdSlave = (void*)laddRdSlave;
// Writing data on the pipe1.
for(int i=0;i<50;i++) {
char Buff[50] = {'\0'};
int len;
BOOL bRet = FALSE;
len = wsprintf(Buff,"This is line no:%i\n",i);
bRet = WriteFile((HANDLE)hWrSlave,Buff,len,&dwWritten,NULL);
if (bRet == TRUE) {
cout<<"Slave Writing: "<<Buff<<endl;
}
else {
cout<<"The following Data couldn't be written: "<<Buff<<endl;
}
}
CloseHandle(hWrSlave);
cout<<"Slave has read the following Data:"<<endl;
// Reading data from pipe2.
for(int j=1;j<=10;j++) {
char ReadBuff[50] = {'\0'};
BOOL bRet = FALSE;
DWORD dwRead;
if(j==1) {
bRet = ReadFile((HANDLE)hRdSlave,&ReadBuff,20,&dwRead,NULL);
}
else {
bRet = ReadFile((HANDLE)hRdSlave,&ReadBuff,19,&dwRead,NULL);
}
if(bRet == FALSE) {
cout<<"Couldn't Read the Data"<<endl;
break;
}
else {
printf(ReadBuff);
}
}
CloseHandle(hRdSlave);
cout<<endl<<"Press enter to terminate the slave process!"<<endl;
cin.get();
}
return 0;
}