Platform SDK: Interprocess Communications

Transactions on Named Pipes

A named pipe transaction is a client-server communication that combines a write operation and a read operation into a single network operation. A transaction can be used only on a duplex, message-type pipe. Transactions improve the performance of network communications between a client and a remote server. Processes can use the TransactNamedPipe and CallNamedPipe functions to perform named pipe transactions.

The TransactNamedPipe function is most commonly used by a pipe client to write a request message to the named pipe server and read the server's response message. The pipe client must specify GENERIC_READ | GENERIC_WRITE access when it opens its pipe handle by calling the CreateFile function. Then, the pipe client sets the pipe handle to message-read mode by calling the SetNamedPipeHandleState function. If the read buffer specified in the call to TransactNamedPipe is not large enough to hold the entire message written by the server, the function returns zero and GetLastError returns ERROR_MORE_DATA. The client can read the remainder of the message by calling either the ReadFile, ReadFileEx, or PeekNamedPipe function.

TransactNamedPipe is typically called by pipe clients, but can also be used by a pipe server.

The following example shows a pipe client using TransactNamedPipe. The example assumes that the pipe client has used CreateFile to connect to the pipe and SetNamedPipeHandleState to set the pipe handle's read mode, as shown in the pipe client example in the preceding topic.

fSuccess = TransactNamedPipe( 
   hPipe,               // pipe handle 
   lpszWrite,           // message to server 
   strlen(lpszWrite)+1, // message length 
   chReadBuf,           // buffer to receive reply 
   512,                 // size of read buffer 
   &cbRead,             // number of bytes read 
   NULL);               // not overlapped 
 
// Exit if an error occurs, unless the error indicates there is more 
// data in the message. 
 
if (!fSuccess && (GetLastError() != ERROR_MORE_DATA)) 
{
   MyErrExit("TransactNamedPipe"); 
}
 
while(1) 
{ 
// Data from the pipe is written to STDOUT. 
 
   if (! WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), 
      chReadBuf, cbRead, &cbWritten, NULL) ) 
      break; 
 
// Break if TransactNamedPipe or ReadFile is successful. 
 
   if (fSuccess) 
      break; 
 
// Read from the pipe if there is more data in the message.
 
   fSuccess = ReadFile( 
      hPipe,      // pipe handle 
      chReadBuf,  // buffer to receive reply 
      512,        // size of buffer 
      &cbRead,    // number of bytes read 
      NULL);      // not overlapped 
 
// Exit if an error other than ERROR_MORE_DATA occurs. 
 
   if (! fSuccess && (GetLastError() != ERROR_MORE_DATA)) 
      break; 
} 

A pipe client uses CallNamedPipe to combine the CreateFile, WaitNamedPipe (if necessary), TransactNamedPipe, and CloseHandle function calls into a single call. Because the pipe handle is closed before the function returns, any additional bytes in the message are lost if the message is larger than the specified size of the read buffer. The following example shows the use of CallNamedPipe.

// Combines connect, wait, write, read, and close operations. 
 
fSuccess = CallNamedPipe( 
    lpszPipename,        // pipe name 
    lpszWrite,           // message to server 
    strlen(lpszWrite)+1, // message length 
    chReadBuf,           // buffer to receive reply 
    512,                 // size of read buffer 
    &cbRead,             // number of bytes read 
    20000);              // waits for 20 seconds 
 
if (fSuccess || GetLastError() == ERROR_MORE_DATA) 
{ 
 
// Data from the pipe is written to STDOUT. 
 
   WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), 
      chReadBuf, cbRead, &cbWritten, NULL); 
 
// The pipe is closed, so no more bytes can be read from the 
// message. 
 
   if (! fSuccess) 
      printf("\n...extra data in message was lost\n"); 
}