Named Pipe Client Server
A pair of minimal C console programs — a named-pipe server built with CreateNamedPipe and a client that opens it and writes a message.
The smallest complete named-pipe exchange on Windows. The server creates \\.\pipe\SamplePipe as a duplex, message-mode, blocking pipe with unlimited instances, then loops: wait for a client with ConnectNamedPipe, read one message, print it, flush, and disconnect. The client just opens the same path with CreateFile (yes, really - pipes open through the file API) and writes a single string. Message-mode pipes are the nice part: each WriteFile arrives as an intact unit, so you do not have to frame your own protocol. Use this as the skeleton for simple local IPC between two of your own programs.
// PipeServer/Entry.Cpp
#include <windows.h>
#include <stdio.h>
#define BUFSIZE 1024
#define PIPE_TIMEOUT 5000
int main()
{
BOOL fConnected;
LPTSTR lpszPipename = "\\\\.\\pipe\\SamplePipe";
CHAR chRequest[BUFSIZE];
DWORD cbBytesRead;
BOOL fSuccess;
HANDLE hPipe;
hPipe = CreateNamedPipe ( lpszPipename,
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
PIPE_TIMEOUT, // client time-out
NULL); // no security attribute
if (hPipe == INVALID_HANDLE_VALUE)
return true;
for (;;)
{
// Trying connectnamedpipe in sample for CreateNamedPipe
// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function returns
// zero, GetLastError returns ERROR_PIPE_CONNECTED.
fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
fSuccess = ReadFile (hPipe, // handle to pipe
chRequest, // buffer to receive data
BUFSIZE, // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
chRequest[cbBytesRead] = '\0';
printf("Data Received: %s\n",chRequest);
if (! fSuccess || cbBytesRead == 0)
break;
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
}
else
// The client could not connect in the CreateNamedPipe sample, so close the pipe.
CloseHandle(hPipe);
}
CloseHandle(hPipe);
return 1;
}
// PipeClient/Entry.Cpp
#include <windows.h>
#include <stdio.h>
#define BUFSIZE 1024
#define PIPE_TIMEOUT 5000
int main()
{
HANDLE hFile;
BOOL flg;
DWORD dwWrite;
char szPipeUpdate[200];
hFile = CreateFile("\\\\.\\pipe\\SamplePipe", GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
0, NULL);
strcpy(szPipeUpdate,"Data from Named Pipe client for createnamedpipe");
if(hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed for Named Pipe client\n" );
}
else
{
flg = WriteFile(hFile, szPipeUpdate, strlen(szPipeUpdate), &dwWrite, NULL);
if (FALSE == flg)
{
printf("WriteFile failed for Named Pipe client\n");
}
else
{
printf("WriteFile succeeded for Named Pipe client\n");
}
CloseHandle(hFile);
}
}
Two details worth keeping: the server's ConnectNamedPipe check treats ERROR_PIPE_CONNECTED as success (that is what comes back when a client was already waiting), and the server source carries a commented block showing the same pipe being registered as a SQL Server dump device (sp_addumpdevice ... @devtype = 'pipe') - a neat historical use of exactly this pattern for offloading backups over the network.