Interprocess communication through Named pipes

shabbir's Avatar author of Interprocess communication through Named pipes
This is an article on Interprocess communication through Named pipes in MFC.
Threads and processes are very similar but they differ in the way they share resources. Processes are normally independent and have its own address space. Now the question comes when 2 independent processes want to communicate how do they do that. There are quite a few options for them to establish a good amount of communication protocol. Some of them are listed below.

1. Message passing.
2. Through Socket communication.
3. Named piped communication.

I will be mainly focusing on Named piped Communication.

We start a server in a low priority thread.
Code: CPP
CPipeSampleDlg *pPipeDlg = (CPipeSampleDlg*)lpData;

while(TRUE)
{
    BOOL fConnected,fSuccess;
    CHAR chRequest[MAX_PATH];
    DWORD cbBytesRead;
   
    // If Pipe server is stopped break from the loop.
    if(pPipeDlg->m_PipeHandle == NULL)
        break;

    fConnected = ConnectNamedPipe(pPipeDlg->m_PipeHandle, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
   
    if (fConnected)
    {
        fSuccess = ReadFile (pPipeDlg->m_PipeHandle, // handle to pipe
            chRequest, // buffer to receive data
            MAX_PATH, // size of buffer
            &cbBytesRead, // number of bytes read
            NULL); // not overlapped I/O
       
        chRequest[cbBytesRead] = '\0';
        CString msg;
        msg.Format("Received string : %s\r\n",chRequest);
        pPipeDlg->ShowLastError(msg);

        FlushFileBuffers(pPipeDlg->m_PipeHandle);
        DisconnectNamedPipe(pPipeDlg->m_PipeHandle);
    }
}
return 0;
The thread waits for a client to connect to it as passes some data to the server.

Code: CPP
CString szPipeName;
szPipeName = _T("\\\\.\\pipe\\PipeTest");

BOOL bret = FALSE;

//first we will try to connect to the exising PIPE
bret = ::WaitNamedPipe((LPCSTR)szPipeName,PROVIDER_WAIT_TIME);
//the named
if(bret == FALSE)
{
    ShowLastError();
    return;
}
else
{
    //the PIPE is available so we will do the rest of the work in a thread
    ShowLastError("PIPE is available for connection");
    BOOL flg;
    DWORD dwWrite;

    CString szPipeUpdate;
   
    HANDLE hPipeHandle = ::CreateFile((LPCSTR)szPipeName,GENERIC_WRITE,0,NULL,
        OPEN_EXISTING,0,NULL);
   
    szPipeUpdate = _T("WM_USER_MESSAGE");
   
    flg = WriteFile(hPipeHandle, szPipeUpdate, strlen(szPipeUpdate), &dwWrite, NULL);

    if (FALSE == flg)
        ShowLastError("Sending string : " + szPipeUpdate + " Failed");
    else
        ShowLastError("Sending string : " + szPipeUpdate);

    CloseHandle(hPipeHandle);
}
The client connects to the pipe creates a file to be wriiten. Writes the file and returns. It does not wait for the server to complete the process with the data. This is asynchronous mode of tranfer.

I have used the name of the pipe as "\\\\.\\pipe\\PipeTest" which connects to the server on the local machine but it can be used to specify some other name of the server or even the ip address where the server is running like "\\\\127.0.0.1\\pipe\\PipeTest"

I have similar code in VB with same API's for you to see.
Server code
Code: VB
Dim ovl As OVERLAPPED
Dim fConnected, fSuccess As Boolean
Dim iConnectionStatus As Long
Dim chRequest As String
Dim cbBytesRead As Long

Do
    DoEvents
   
    If PipeHandle = 0 Then
        Exit Do
    End If
   
    iConnectionStatus = ConnectNamedPipe(PipeHandle, ovl)
   
    If iConnectionStatus <> 0 Then
        fConnected = True
    Else
        If Err.LastDllError = ERROR_PIPE_CONNECTED Then
            fConnected = True
        Else
            fConnected = False
        End If
    End If
   
    If fConnected = True Then
        chRequest = Space(MAX_PATH)
        fSuccess = ReadFile(PipeHandle, chRequest, MAX_PATH, cbBytesRead, ovl)
    
        If Not fSuccess Or cbBytesRead = 0 Then
           Exit Do
        End If
   
        ShowLastStatus "Recieved : " + chRequest
        FlushFileBuffers ByVal PipeHandle
        DisconnectNamedPipe ByVal PipeHandle
    End If
Loop
Client code
Code: VB
Dim bret As Boolean
bret = False
   
bret = WaitNamedPipe(szPipeName, PROVIDER_WAIT_TIME)
If bret = False Then
    ShowLastStatus
Else
    ShowLastStatus "PIPE is available for connection"
    Dim flg As Boolean
    Dim dwWrite As Long
    Dim szPipeUpdate As String
    Dim hPipeHandle As Long
    Dim sa As SECURITY_ATTRIBUTES
    Dim ovl As OVERLAPPED
           
    hPipeHandle = CreateFile(szPipeName, GENERIC_WRITE, 0, sa, OPEN_EXISTING, 0, 0)
   
    szPipeUpdate = "HI FROM CLIENT"
   
    flg = WriteFile(hPipeHandle, szPipeUpdate, Len(szPipeUpdate), dwWrite, ovl)

    If False = flg Then
        ShowLastStatus "Sending string : " + szPipeUpdate + " Failed"
    Else
        ShowLastStatus "Sending string : " + szPipeUpdate
    End If
End If
API's
Code: VB
'Constants
Public Const PROVIDER_WAIT_TIME = 30
Public Const PIPE_ACCESS_DUPLEX = &H3
Public Const FILE_FLAG_OVERLAPPED = &H40000000
Public Const PIPE_TYPE_MESSAGE = &H4
Public Const PIPE_WAIT = &H0
Public Const MAX_PATH = 260
Public Const INVALID_HANDLE_VALUE = -1
Public Const FORMAT_MESSAGE_ALLOCATE_BUFFER = &H100
Public Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
Public Const FORMAT_MESSAGE_IGNORE_INSERTS = &H200
Public Const LANG_NEUTRAL = &H0
Public Const GENERIC_WRITE = &H40000000
Public Const OPEN_EXISTING = 3
Public Const ERROR_PIPE_CONNECTED = 535&

'Types
Public Type SECURITY_ATTRIBUTES
        nLength As Long
        lpSecurityDescriptor As Long
        bInheritHandle As Long
End Type
Public Type OVERLAPPED
        Internal As Long
        InternalHigh As Long
        offset As Long
        OffsetHigh As Long
        hEvent As Long
End Type

'Functions
Public Declare Function CreateNamedPipe Lib "kernel32" Alias "CreateNamedPipeA" (ByVal lpName As String, ByVal dwOpenMode As Long, ByVal dwPipeMode As Long, ByVal nMaxInstances As Long, ByVal nOutBufferSize As Long, ByVal nInBufferSize As Long, ByVal nDefaultTimeOut As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES) As Long
Public Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Long) As Long
Public Declare Function ConnectNamedPipe Lib "kernel32" (ByVal hNamedPipe As Long, lpOverlapped As OVERLAPPED) As Long
Public Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As OVERLAPPED) As Long
Public Declare Function FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As Long
Public Declare Function DisconnectNamedPipe Lib "kernel32" (ByVal hNamedPipe As Long) As Long
Public Declare Function WaitNamedPipe Lib "kernel32" Alias "WaitNamedPipeA" (ByVal lpNamedPipeName As String, ByVal nTimeOut As Long) As Long
Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Public Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As OVERLAPPED) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
I am not a VB expert and if I you have any suggestion feel free to post a comment.

No need to copy and paste the code as I have attached the VB and VC Source codes for you to download.
Attached Files
File Type: zip IPC_Pipe_VB_Src.zip (3.6 KB, 289 views)
File Type: zip IPC_Pipe_VC_Src.zip (13.7 KB, 265 views)
0
lplover2k's Avatar, Join Date: Feb 2007
Go4Expert Member
hi, can u give an example to send a .jpg file plz?
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Quote:
Originally Posted by lplover2k
hi, can u give an example to send a .jpg file plz?
The data can be anything and not necessarily be string.
0
lplover2k's Avatar, Join Date: Feb 2007
Go4Expert Member
should i serialize the file before sending it?

i replace "szPipeUpdate = _T("WM_USER_MESSAGE");" by what plz?
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Quote:
Originally Posted by lplover2k
should i serialize the file before sending it?

i replace "szPipeUpdate = _T("WM_USER_MESSAGE");" by what plz?
Read the file in the binary mode into a buffer and send the buffer.
0
lplover2k's Avatar, Join Date: Feb 2007
Go4Expert Member
how do i do that??
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Quote:
Originally Posted by lplover2k
how do i do that??
Refer to the following articles for that.

File read write in plain C.
File Handling in C - File Pointers.
File Splitter and Merger.
0
lplover2k's Avatar, Join Date: Feb 2007
Go4Expert Member
hmm..thx but can u can u write an example how to send a file with your code to ease things up?
0
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Quote:
Originally Posted by lplover2k
hmm..thx but can u can u write an example how to send a file with your code to ease things up?
If I have the time I can try but you can assume it may take ages as well.
0
lplover2k's Avatar, Join Date: Feb 2007
Go4Expert Member
oh ok...so it's that complicated?..