/******************************************************************************/<br />* This is a part of the Microsoft Source Code Samples.<br />* Copyright (C) 1993-1997 Microsoft Corporation.<br />* All rights reserved.<br />* This source code is only intended as a supplement to<br />* Microsoft Development Tools and/or WinHelp documentation.<br />* See these sources for detailed information regarding the<br />* Microsoft samples programs.<br />/******************************************************************************/</p><p>#include <stdio.h><br />#include <windows.h><br />#include <stdlib.h><br />#include <process.h></p><p>/* Error checking macro. If bSuccess != TRUE, print error info */<br />#define PERR(bSuccess, szApi) {if (!(bSuccess)) printf("%s: Error %d from %s /<br /> on line %d/n", __FILE__, GetLastError(), szApi, __LINE__);}</p><p>#define DEFNAME "////.//pipe//nmpipe" /* Default pipe name */<br />/* Define OVERLAPPED_IO to TRUE to use Overlapped IO. Otherwise define as<br /> FALSE */<br />//#define OVERLAPPED_IO TRUE<br />#define OVERLAPPED_IO FALSE</p><p>/* structure to pass into the writer thread */<br />typedef struct _WRITER_PARAMS<br />{<br /> HANDLE hPipe; /* pipe write handle */<br /> char *szData; /* data to repeatedly write */<br /> int iDataSize; /* size of buffer pointed to by szData */<br />} WRITER_PARAMS;</p><p>/*<br /> * BOOL pipeCheck(HANDLE h)<br /> * PARAMETERS: HANDLE hPipe: pipe handle to close if an error condition exists<br /> * DESCRIPTION: if GetLastError() returns a common error generated by a<br /> * broken pipe, close the pipe handle. Call this right after a<br /> * pipe operation.<br /> * RETURNS: FALSE if the pipe is broken, TRUE if not.<br />*/<br />BOOL pipeCheck(HANDLE hPipe)<br />{<br /> DWORD dwLastError = GetLastError();</p><p> if (dwLastError == ERROR_BROKEN_PIPE || dwLastError == ERROR_NO_DATA)<br /> {<br /> puts("/n* pipe broken, closing...");<br /> CloseHandle(hPipe);<br /> return(FALSE);<br /> }<br /> if (dwLastError == ERROR_INVALID_HANDLE) /* is handle already closed? */<br /> return(FALSE);<br /> return(TRUE);<br />} /* pipeCheck() */</p><p>/*<br /> * void reader(HANDLE hPipe)<br /> * PARAMETERS: HANDLE hPipe: pipe handle to read from<br /> * DESCRIPTION: read from the handle and dump data to the console.<br /> * RETURNS: none<br />*/<br />void reader(HANDLE hPipe)<br />{<br /> char buf[64];<br /> DWORD dwRead;<br /> BOOL bSuccess;<br /> OVERLAPPED ol;</p><p> if (OVERLAPPED_IO) /* if overlapped, prepare OVERLAPPED structure */<br /> {<br /> memset(&ol, 0, sizeof(ol));<br /> ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);<br /> PERR(ol.hEvent, "CreateEvent");<br /> }<br /> while (1)<br /> {<br /> bSuccess = ReadFile(hPipe, buf, sizeof(buf), &dwRead,<br /> OVERLAPPED_IO ? &ol : NULL);<br /> if (!bSuccess && GetLastError() == ERROR_IO_PENDING)<br /> bSuccess = GetOverlappedResult(hPipe, &ol, &dwRead, TRUE);<br /> /* If ReadFile or GetOverlappedResult fails, check pipe. If pipe is<br /> broken, fall out of loop */<br /> if (!bSuccess && !pipeCheck(hPipe))<br /> break;<br /> /* else check for any other kinds of errors that may have occurred */<br /> PERR(bSuccess, "ReadFile");<br /> printf("%.*s", dwRead, buf); /* print only number of chars read */<br /> } /* while */<br /> CloseHandle(ol.hEvent);<br /> _endthread();<br />} /* reader() */</p><p>/*<br /> ** void writer(WRITER_PARAMS *writer_params)<br /> * PARAMETERS: WRITER_PARAMS *writer_params: misc info needed for writing to<br /> * the pipe<br /> * DESCRIPTION: write data from WRITER_PARAMS to the pipe<br /> * RETURNS: none<br />*/<br />void writer(WRITER_PARAMS *writer_params)<br />{<br /> DWORD dwWritten;<br /> BOOL bSuccess;<br /> OVERLAPPED ol;</p><p> if (OVERLAPPED_IO)<br /> {<br /> memset(&ol, 0, sizeof(ol));<br /> ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);<br /> PERR(ol.hEvent, "CreateEvent");<br /> }<br /> while(1)<br /> {<br /> bSuccess = WriteFile(writer_params->hPipe, writer_params->szData,<br /> writer_params->iDataSize, &dwWritten, OVERLAPPED_IO ? &ol : NULL);<br /> if (!bSuccess && GetLastError() == ERROR_IO_PENDING)<br /> bSuccess = GetOverlappedResult(writer_params->hPipe, &ol, &dwWritten,<br /> TRUE);<br /> /* If ReadFile or GetOverlappedResult fails, check pipe. If pipe is<br /> broken, fall out of loop */<br /> if (!bSuccess && !pipeCheck(writer_params->hPipe))<br /> break;<br /> /* else check for any other kinds of errors that may have occurred */<br /> PERR(bSuccess, "WriteFile");<br /> } /* while */<br /> free(writer_params);<br /> CloseHandle(ol.hEvent);<br /> _endthread();<br />} /* writer() */</p><p>/*<br /> ** main()<br /> * DESCRIPTION: Connect pipe instances to clients. Start a reader thread for<br /> * each client. If OVERLAPPED_IO is defined, also start a<br /> * writer thread for full duplex pipe I/O testing. If this is<br /> * a client, connect to the server pipe and start a writer<br /> * thread. If OVERLAPPED_IO, also start a reader thread.<br />*/<br />void main(int argc, char *argv[])<br />{<br /> HANDLE hPipe;<br /> BOOL bSuccess;<br /> BOOL bNotConnected;<br /> char *szPname;<br /> WRITER_PARAMS *writer_params;<br /> DWORD dwClients;<br /> SECURITY_ATTRIBUTES saPipe;<br /> OVERLAPPED ol;<br /> DWORD dwRead;</p><p> if (argc < 3)<br /> {<br /> puts("nmpipe [/s|/c] <string> <pipename>");<br /> puts("'/s' to start as server, '/c' to start as client");<br /> puts("<string>: string to write to the pipe");<br /> puts("<pipename>: full UNC name of pipe (optional)");<br /> puts("example: nmpipe /s /"hello from server /" ////.//pipe//pipetst");<br /> return;<br /> }<br /> szPname = (argc > 3) ? argv[3] : DEFNAME;<br /> if (tolower(argv[1][1]) == 's')<br /> {<br /> if (OVERLAPPED_IO)<br /> {<br /> memset(&ol, 0, sizeof(ol));<br /> ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);<br /> PERR(ol.hEvent, "CreateEvent");<br /> }<br /> SetConsoleTitle("SERVER: nmpipe sample");<br /> /* set up a NULL DACL in our pipe security descriptor to allow anyone to<br /> connect to the pipe server */<br /> saPipe.lpSecurityDescriptor =<br /> (PSECURITY_DESCRIPTOR) malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);<br /> InitializeSecurityDescriptor(saPipe.lpSecurityDescriptor,<br /> SECURITY_DESCRIPTOR_REVISION);<br /> SetSecurityDescriptorDacl(saPipe.lpSecurityDescriptor, TRUE, (PACL) NULL,<br /> FALSE);<br /> saPipe.nLength = sizeof(saPipe);<br /> saPipe.bInheritHandle = TRUE;<br /> while(1)<br /> {<br /> /* Create a named pipe: duplex, type byte, readmode byte, unlimited<br /> instances, default timeout of 60s */<br /> hPipe = CreateNamedPipe(szPname, PIPE_ACCESS_DUPLEX |<br /> (OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0), PIPE_TYPE_BYTE |<br /> PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0,<br /> 60000, &saPipe);<br /> PERR(hPipe != INVALID_HANDLE_VALUE, "CreateNamedPipe");<br /> puts("/n* pipe created, waiting for connection...");<br /> bSuccess = ConnectNamedPipe(hPipe, OVERLAPPED_IO ? &ol : NULL);<br /> if (!bSuccess && GetLastError() == ERROR_IO_PENDING)<br /> bSuccess = GetOverlappedResult(hPipe, &ol, &dwRead, TRUE);<br /> /* check return from either ConnectNamedPipe or GetOverlappedResult.<br /> If a client managed to connect between the CreateNamedPipe and<br /> ConnectNamedPipe calls, ERROR_PIPE_CONNECTED will result */<br /> if (!bSuccess && GetLastError() != ERROR_PIPE_CONNECTED)<br /> {<br /> /* something went wrong, report error, close instance and try again */<br /> PERR(bSuccess, "ConnectNamedPipe");<br /> CloseHandle(hPipe);<br /> continue;<br /> }<br /> /* find out how many pipe instances there currently are */<br /> bSuccess = GetNamedPipeHandleState(hPipe, NULL, &dwClients, NULL, NULL,<br /> NULL, 0);<br /> PERR(bSuccess, "GetNamedPipeHandleState");<br /> printf("/n* %d clients connected", dwClients);<br /> _beginthread(reader, 0, hPipe);<br /> writer_params = malloc(sizeof(WRITER_PARAMS));<br /> writer_params->hPipe = hPipe;<br /> writer_params->szData = argv[2];<br /> writer_params->iDataSize = strlen(argv[2]);<br /> /* WARNING! reading and writing at the same time to a non-overlapped<br /> pipe is a no-no! If not overlapped, server only reads and client<br /> only writes */<br /> if (OVERLAPPED_IO)<br /> _beginthread(writer, 0, writer_params);<br /> } /* while */<br /> CloseHandle(ol.hEvent);<br /> CloseHandle(hPipe);<br /> }<br /> else /* no '/s', assume it's a client */<br /> {<br /> char szTemp[64];</p><p> sprintf(szTemp, "Client %s", argv[2]);<br /> SetConsoleTitle(szTemp);<br /> bNotConnected = TRUE;<br /> while (bNotConnected)<br /> {<br /> /* attempt to connect to pipe instance */<br /> hPipe = CreateFile(szPname, GENERIC_READ | GENERIC_WRITE, 0, NULL,<br /> OPEN_EXISTING, OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0, NULL);<br /> if (GetLastError() == ERROR_PIPE_BUSY)<br /> {<br /> puts("Pipe busy, waiting for a pipe instance...");<br /> bSuccess = WaitNamedPipe(szPname, NMPWAIT_USE_DEFAULT_WAIT);<br /> PERR(bSuccess, "WaitNamedPipe");<br /> }<br /> else<br /> {<br /> PERR(hPipe != INVALID_HANDLE_VALUE, "CreateFile");<br /> bNotConnected = (hPipe == INVALID_HANDLE_VALUE);<br /> }<br /> } /* while */<br /> puts("Connected to pipe...");<br /> if (OVERLAPPED_IO) /* if overlapped, start reader thread */<br /> _beginthread(reader, 0, hPipe);<br /> writer_params = malloc(sizeof(WRITER_PARAMS));<br /> writer_params->hPipe = hPipe;<br /> writer_params->szData = argv[2];<br /> writer_params->iDataSize = strlen(argv[2]);<br /> writer(writer_params);<br /> } /* else */<br /> free(saPipe.lpSecurityDescriptor);<br /> CloseHandle(hPipe);<br /> CloseHandle(ol.hEvent);<br /> return;<br />}<br />