At any time, a client may call CreateFile to open its end of a named pipe. Two problems, however, may arise:
In short, both server and client must be able to block while waiting for conditions that permit a connection to occur. To do so, the server calls ConnectNamedPipe and the client calls WaitNamedPipe.
BOOL ConnectNamedPipe(
HANDLE hNamedPipe, // handle of an available named pipe
LPOVERLAPPED lpOverlapped ); // info for asynchronous operation
BOOL WaitNamedPipe(
LPTSTR lpszPipeName, // points to string naming pipe object
DWORD dwTimeout ); // maximum wait time in milliseconds
NOTE
These coordinating functions work only with named pipes because a client cannot create its own handle to an anonymous pipe; it must receive a handle directly from the server, and in that case, the connection is already made.
Like ReadFile and WriteFile, ConnectNamedPipe can respond asynchronously. The lpOverlapped parameter contains an event handle, and the event object signals when a client connects.
How ConnectNamedPipe behaves depends on whether the pipe was created with, or subsequently modified to include, the FILE_FLAG_OVERLAPPING flag and the PIPE_WAIT mode. Its operation is most intuitive on pipes that allow waiting.
The unintuitive use of TRUE and FALSE returns results from the fact that ConnectNamedPipe returns TRUE only if the pipe begins in a listening state and a client connects after the connect command begins and before it returns. If the pipe is already connected and the command responds asynchronously (returns without waiting) or is called for a pipe that does not allow waiting, the command generally returns FALSE.
The client’s wait command, WaitNamedPipe, does not actually create a connection. It returns TRUE when a pipe is or becomes available, but it does not return a handle to the available pipe.
It is common for a client to repeat the wait-then-create cycle until it acquires a valid handle. Normally, WaitNamedPipe considers a pipe available only when the server calls ConnectNamedPipe to wait for a link. The two commands work together to synchronize server and client. If, however, the server creates a new pipe and has never connected to any client, WaitNamedPipe returns TRUE even without a matching ConnectNamedPipe.
The purpose behind the apparent inconsistency is to guarantee that WaitNamedPipe connects only at times when the server knows its pipe is available. If a client breaks a connection, the server may not realize it right away; and if another client connected immediately, the server could not know it had a new partner. By recognizing only new pipes and pipes made available through ConnectNamedPipe, WaitNamedPipe prevents clients from sneaking in on the middle of a running conversation.
NOTE
WaitForSingleObject does not work with pipes because pipes do not have signal states.
A client breaks its connection by calling CloseHandle. A server may do the same, but sometimes it may prefer to disconnect without destroying the pipe, saving it for later reuse. By calling DisconnectNamedPipe, the server forces the conversation to end and invalidates the client’s handle.
BOOL DisconnectNamedPipe( HANDLE hNamedPipe );
If the client tries to read or write with its handle after the server disconnects, the client receives an error result. The client must still call CloseHandle.
Any data lingering unread in the pipe is lost when the connection ends. A friendly server can protect the last messages by calling FlushFileBuffers first.
BOOL FlushFileBuffers( HANDLE hFile );
When FlushFileBuffers receives a handle to a named pipe, it blocks until the pipe’s buffers are empty.
Disconnecting a pipe from its client does not destroy the pipe object. After breaking a connection, the server should call ConnectNamedPipe to await a new connection on the freed pipe or else call CloseHandle to destroy that instance. Clients blocked on WaitNamedPipe do not unblock when a client closes its pipe handle. The server must disconnect its end and call ConnectNamedPipe to listen for a new client.