Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / C++

Unleashing anonymous pipes – Part 1

Rate me:
Please Sign up or sign in to vote.
4.08/5 (17 votes)
19 Aug 20037 min read 101.5K   4.1K   39  
Using anonymous pipes for interprocess communication
// 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;

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions