Making Transactions

There are two more commands that facilitate conversations through duplex pipes: TransactNamedPipe and CallNamedPipe combine read and a write operations into single transactions. Transactions are particularly efficient over networks because they minimize the number of transmissions.

To support reciprocal transactions, a pipe must have the following characteristics:

The server sets all those attributes with CreateNamedPipe. The client can adjust the attributes, if necessary, with SetNamedPipeHandleState. The blocking mode has no effect on transaction commands.

Sending a Request

The first command, TransactNamedPipe, sends a request and waits for a response. Clients and servers both may use the command, although clients tend to find it more useful.

BOOL TransactNamedPipe(
   HANDLE hNamedPipe,              // handle of named pipe
   LPVOID lpvWriteBuf,             // buffer holding information to send
   DWORD dwWriteBufSize,           // size of the write buffer in bytes
   LPVOID lpvReadBuf,              // buffer for information received
   DWORD dwReadBufSize,            // size of the read buffer in bytes
   LPDWORD lpdwBytesRead,          // bytes actually read (value returned)
   LPOVERLAPPED lpOverlapped );    // info for asynchronous I/O

In spite of its many parameters, the function is straightforward. It writes the contents of lpvWriteBuf into the pipe, waits for the next response, and copies the message it receives into the lpvReadBuf buffer.

The function fails if the pipe has the wrong attributes or if the read buffer is too small to accommodate the entire message. In that case, GetLastError returns ERROR_MORE_DATA, and you should finish reading with ReadFile or PeekNamedPipe.

TransactNamedPipe handles one exchange through a pipe. After establishing a connection, a program might call TransactNamedPipe many times before disconnecting.

Using a Pipe for a Single Transaction

Another command, CallNamedPipe, works for clients that need a pipe for only a single transaction. CallNamedPipe connects to, reads from, writes to, and closes the pipe handle.

BOOL CallNamedPipe(
   LPTSTR lpszPipeName,    // points to string naming a pipe object
   LPVOID lpvWriteBuf,     // buffer holding information to send
   DWORD dwWriteBuf,       // size of the write buffer in bytes
   LPVOID lpvReadBuf,      // buffer for information received
   DWORD dwReadBuf,        // size of the read buffer in bytes
   LPDWORD lpdwRead,       // bytes actually read (value returned)
   DWORD dwTimeout );      // maximum wait time in milliseconds

For its first parameter, CallNamedPipe expects the name of a pipe that already exists. Only clients call this function. Most of the other parameters supply the buffers needed to perform both halves of a transaction.

CallNamedPipe condenses into a single call a whole series of commands: WaitNamedPipe, CreateFile, WriteFile, ReadFile, and CloseHandle. The final parameter, dwTimeout, sets the maximum waiting period for the WaitNamedPipe part of this transaction.

If the read buffer is too small to hold an entire message, the command reads what it can and returns FALSE. GetLastError reports ERROR_MORE_DATA, but because the pipe has already been closed, the extra data is lost.

© 1998 SYBEX Inc. All rights reserved.