home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / ipc / namepipe / console / nmpipe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  9.3 KB  |  276 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. #include <stdio.h>
  13. #include <windows.h>
  14. #include <stdlib.h>
  15. #include <process.h>
  16.  
  17. /* Error checking macro. If bSuccess == TRUE, print error info */
  18. #define PERR(bSuccess, szApi) {if (!(bSuccess)) printf("%s: Error %d from %s \
  19.     on line %d\n", __FILE__, GetLastError(), szApi, __LINE__);}
  20.  
  21. #define DEFNAME "\\\\.\\pipe\\nmpipe" /* Default pipe name */
  22. /* Define OVERLAPPED_IO to TRUE to use Overlapped IO. Otherwise define as
  23.    FALSE */
  24. //#define OVERLAPPED_IO TRUE
  25. #define OVERLAPPED_IO FALSE
  26.  
  27. /* structure to pass into the writer thread */
  28. typedef struct {
  29.   HANDLE hPipe;     /* pipe write handle */
  30.   char *szData;     /* data to repeatedly write */
  31.   int iDataSize;    /* size of buffer pointed to by szData */
  32. } WRITER_PARAMS;
  33.  
  34. /*
  35.  ** BOOL pipeCheck(HANDLE h)
  36.  *
  37.  *  PARAMETERS: HANDLE hPipe: pipe handle to close if an error condition exists
  38.  *
  39.  *  DESCRIPTION: if GetLastError() returns a common error generated by a
  40.  *               broken pipe, close the pipe handle. Call this right after a
  41.  *               pipe operation.
  42.  *
  43.  *  RETURNS: FALSE if the pipe is broken, TRUE if not.
  44.  *
  45.  */
  46. BOOL pipeCheck(HANDLE hPipe)
  47. {
  48.   DWORD dwLastError = GetLastError();
  49.  
  50.   if (dwLastError == ERROR_BROKEN_PIPE || dwLastError == ERROR_NO_DATA)
  51.     {
  52.     puts("\n* pipe broken, closing...");
  53.     CloseHandle(hPipe);
  54.     return(FALSE);
  55.     }
  56.   if (dwLastError == ERROR_INVALID_HANDLE) /* is handle already closed? */
  57.     return(FALSE);
  58.   return(TRUE);
  59. } /* pipeCheck() */
  60.  
  61. /*
  62.  ** void reader(HANDLE hPipe)
  63.  *
  64.  *  PARAMETERS: HANDLE hPipe: pipe handle to read from
  65.  *
  66.  *  DESCRIPTION: read from the handle and dump data to the console.
  67.  *
  68.  *  RETURNS: none
  69.  *
  70.  */
  71. void reader(HANDLE hPipe)
  72. {
  73.   char buf[64];
  74.   DWORD dwRead;
  75.   BOOL bSuccess;
  76.   OVERLAPPED ol;
  77.  
  78.   if (OVERLAPPED_IO) /* if overlapped, prepare OVERLAPPED structure */
  79.   {
  80.     memset(&ol, 0, sizeof(ol));
  81.     ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  82.     PERR(ol.hEvent, "CreateEvent");
  83.   }
  84.   while (1) 
  85.     {
  86.     bSuccess = ReadFile(hPipe, buf, sizeof(buf), &dwRead,
  87.         OVERLAPPED_IO ? &ol : NULL);
  88.     if (!bSuccess && GetLastError() == ERROR_IO_PENDING)
  89.       bSuccess = GetOverlappedResult(hPipe, &ol, &dwRead, TRUE);
  90.     /* If ReadFile or GetOverlappedResult fails, check pipe. If pipe is
  91.        broken, fall out of loop */
  92.     if (!bSuccess && !pipeCheck(hPipe))
  93.       break;
  94.     /* else check for any other kinds of errors that may have occurred */
  95.     PERR(bSuccess, "ReadFile");
  96.     printf("%.*s", dwRead, buf); /* print only number of chars read */
  97.     } /* while */
  98.   CloseHandle(ol.hEvent);
  99.   _endthread();
  100. } /* reader() */
  101.  
  102. /*
  103.  ** void writer(WRITER_PARAMS *writer_params)
  104.  *
  105.  *  PARAMETERS: WRITER_PARAMS *writer_params: misc info needed for writing to
  106.  *              the pipe
  107.  *
  108.  *  DESCRIPTION: write data from WRITER_PARAMS to the pipe
  109.  *
  110.  *  RETURNS: none
  111.  *
  112.  */
  113. void writer(WRITER_PARAMS *writer_params)
  114. {
  115.   DWORD dwWritten;
  116.   BOOL bSuccess;
  117.   OVERLAPPED ol;
  118.  
  119.   if (OVERLAPPED_IO)
  120.   {
  121.     memset(&ol, 0, sizeof(ol));
  122.     ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  123.     PERR(ol.hEvent, "CreateEvent");
  124.   }
  125.   while(1) 
  126.   {
  127.     bSuccess = WriteFile(writer_params->hPipe, writer_params->szData,
  128.         writer_params->iDataSize, &dwWritten, OVERLAPPED_IO ? &ol : NULL);
  129.     if (!bSuccess && GetLastError() == ERROR_IO_PENDING)
  130.       bSuccess = GetOverlappedResult(writer_params->hPipe, &ol, &dwWritten,
  131.           TRUE);
  132.     /* If ReadFile or GetOverlappedResult fails, check pipe. If pipe is
  133.        broken, fall out of loop */
  134.     if (!bSuccess && !pipeCheck(writer_params->hPipe))
  135.       break;
  136.     /* else check for any other kinds of errors that may have occurred */
  137.     PERR(bSuccess, "WriteFile");
  138.     } /* while */
  139.   free(writer_params);
  140.   CloseHandle(ol.hEvent);
  141.   _endthread();
  142. } /* writer() */
  143.  
  144. /*
  145.  ** main()
  146.  *
  147.  *  DESCRIPTION: Connect pipe instances to clients. Start a reader thread for
  148.  *               each client. If OVERLAPPED_IO is defined, also start a
  149.  *               writer thread for full duplex pipe I/O testing. If this is
  150.  *               a client, connect to the server pipe and start a writer
  151.  *               thread. If OVERLAPPED_IO, also start a reader thread.
  152.  *
  153.  */
  154.  
  155. void main(int argc, char *argv[])
  156. {
  157.   HANDLE hPipe;
  158.   BOOL bSuccess;
  159.   BOOL bNotConnected;
  160.   char *szPname;
  161.   WRITER_PARAMS *writer_params;
  162.   DWORD dwClients;
  163.   SECURITY_ATTRIBUTES saPipe;
  164.   OVERLAPPED ol;
  165.   DWORD dwRead;
  166.  
  167.   if (argc < 3)
  168.     {
  169.     puts("nmpipe [/s|/c] <string> <pipename>");
  170.     puts("'/s' to start as server, '/c' to start as client");
  171.     puts("<string>: string to write to the pipe");
  172.     puts("<pipename>: full UNC name of pipe (optional)");
  173.     puts("example: nmpipe /s \"hello from server \" \\\\.\\pipe\\pipetst");
  174.     return;
  175.     }
  176.   szPname = (argc > 3) ? argv[3] : DEFNAME;
  177.   if (tolower(argv[1][1]) == 's')
  178.     {
  179.     if (OVERLAPPED_IO)
  180.     {
  181.       memset(&ol, 0, sizeof(ol));
  182.       ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  183.       PERR(ol.hEvent, "CreateEvent");
  184.     }
  185.     SetConsoleTitle("SERVER: nmpipe sample");
  186.     /* set up a NULL DACL in our pipe security descriptor to allow anyone to
  187.        connect to the pipe server */
  188.     saPipe.lpSecurityDescriptor =
  189.         (PSECURITY_DESCRIPTOR) malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
  190.     InitializeSecurityDescriptor(saPipe.lpSecurityDescriptor,
  191.         SECURITY_DESCRIPTOR_REVISION);
  192.     SetSecurityDescriptorDacl(saPipe.lpSecurityDescriptor, TRUE, (PACL) NULL,
  193.         FALSE);
  194.     saPipe.nLength = sizeof(saPipe);
  195.     saPipe.bInheritHandle = TRUE;
  196.     while(1)
  197.       {
  198.       /* Create a named pipe: duplex, type byte, readmode byte, unlimited
  199.          instances, default timeout of 60s */
  200.       hPipe = CreateNamedPipe(szPname, PIPE_ACCESS_DUPLEX |
  201.           (OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0), PIPE_TYPE_BYTE |
  202.           PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0,
  203.           60000, &saPipe);
  204.       PERR(hPipe != INVALID_HANDLE_VALUE, "CreateNamedPipe");
  205.       puts("\n* pipe created, waiting for connection...");
  206.       bSuccess = ConnectNamedPipe(hPipe, OVERLAPPED_IO ? &ol : NULL);
  207.       if (!bSuccess && GetLastError() == ERROR_IO_PENDING)
  208.         bSuccess = GetOverlappedResult(hPipe, &ol, &dwRead, TRUE);
  209.       /* check return from either ConnectNamedPipe or GetOverlappedResult.
  210.          If a client managed to connect between the CreateNamedPipe and
  211.          ConnectNamedPipe calls, ERROR_PIPE_CONNECTED will result */
  212.       if (!bSuccess && GetLastError() != ERROR_PIPE_CONNECTED)
  213.         {
  214.         /* something went wrong, report error, close instance and try again */
  215.         PERR(bSuccess, "ConnectNamedPipe");
  216.         CloseHandle(hPipe);
  217.         continue;
  218.         }
  219.       /* find out how many pipe instances there currently are */
  220.       bSuccess = GetNamedPipeHandleState(hPipe, NULL, &dwClients, NULL, NULL,
  221.           NULL, 0);
  222.       PERR(bSuccess, "GetNamedPipeHandleState"); 
  223.       printf("\n* %d clients connected", dwClients);
  224.       _beginthread(reader, 0, hPipe);
  225.       writer_params = malloc(sizeof(WRITER_PARAMS));
  226.       writer_params->hPipe = hPipe;
  227.       writer_params->szData = argv[2];
  228.       writer_params->iDataSize = strlen(argv[2]);
  229.       /* WARNING! reading and writing at the same time to a non-overlapped
  230.          pipe is a no-no! If not overlapped, server only reads and client
  231.          only writes */
  232.       if (OVERLAPPED_IO)
  233.         _beginthread(writer, 0, writer_params);
  234.       } /* while */
  235.     CloseHandle(ol.hEvent);
  236.     CloseHandle(hPipe);
  237.     }
  238.   else /* no '/s', assume it's a client */
  239.     {
  240.     char szTemp[64];
  241.  
  242.     sprintf(szTemp, "Client %s", argv[2]);
  243.     SetConsoleTitle(szTemp);
  244.     bNotConnected = TRUE;
  245.     while (bNotConnected)
  246.       {
  247.       /* attempt to connect to pipe instance */
  248.       hPipe = CreateFile(szPname, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  249.           OPEN_EXISTING, OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0, NULL);
  250.       if (GetLastError() == ERROR_PIPE_BUSY)
  251.         {
  252.         puts("Pipe busy, waiting for a pipe instance...");
  253.         bSuccess = WaitNamedPipe(szPname, NMPWAIT_USE_DEFAULT_WAIT);
  254.         PERR(bSuccess, "WaitNamedPipe");
  255.         }
  256.       else
  257.         {
  258.         PERR(hPipe != INVALID_HANDLE_VALUE, "CreateFile");
  259.         bNotConnected = (hPipe == INVALID_HANDLE_VALUE);
  260.         }
  261.       } /* while */
  262.     puts("Connected to pipe...");
  263.     if (OVERLAPPED_IO) /* if overlapped, start reader thread */
  264.       _beginthread(reader, 0, hPipe);
  265.     writer_params = malloc(sizeof(WRITER_PARAMS));
  266.     writer_params->hPipe = hPipe;
  267.     writer_params->szData = argv[2];
  268.     writer_params->iDataSize = strlen(argv[2]);
  269.     writer(writer_params);
  270.     } /* else */
  271.   free(saPipe.lpSecurityDescriptor);
  272.   CloseHandle(hPipe);
  273.   CloseHandle(ol.hEvent);
  274.   return;
  275. }
  276.