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 / npclient / client32.c next >
C/C++ Source or Header  |  1997-10-05  |  15KB  |  404 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. /*************************************************************************\
  13. *  PROGRAM: client32.c
  14. *
  15. *  PURPOSE:
  16. *
  17. *     To demonstrate the use of named pipes and the overlapped structure.
  18. *     This code serves as the client side of the named pipe instances.
  19. *     For more details on an overview of this codes designs or use, see
  20. *     the README file.  For details on the implementation, see the comments
  21. *     in this code.
  22. *
  23. *
  24. \*************************************************************************/
  25.  
  26. #define  STRICT
  27. #include <windows.h>
  28. #include "client32.h"
  29.  
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33.  
  34. HANDLE hInst;
  35. HWND   hWndClient;
  36.  
  37. CHAR ShrName[LINE_LEN];                 // Global: net share name.
  38. CHAR ClntName[NAME_SIZE];               // Global: user or pipe client name.
  39. CHAR lpBuffer[255];                     // Global: buffer for string resources                                                 
  40.  
  41. /*************************************************************************\
  42. *
  43. *  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  44. *
  45. *  PURPOSE: Launches the Client's dialog box.
  46. *
  47. *  COMMENTS:
  48. *
  49. \*************************************************************************/
  50.  
  51. int APIENTRY WinMain (HINSTANCE hInstance,
  52.                       HINSTANCE hPrevInstance,
  53.                       LPSTR     lpCmdLine,
  54.                       int       nCmdShow)
  55.  
  56.  
  57. {
  58.   DWORD retCode;
  59.  
  60.   UNREFERENCED_PARAMETER( nCmdShow );
  61.   UNREFERENCED_PARAMETER( lpCmdLine );
  62.   UNREFERENCED_PARAMETER( hPrevInstance );
  63.  
  64.   hInst   = hInstance;
  65.   retCode = DialogBox ((HANDLE)hInst, (LPCTSTR)"ClientDialog",
  66.                        NULL, (DLGPROC)ClientDlgProc);
  67.   return  (retCode);
  68.  
  69. }
  70.  
  71.  
  72. /*************************************************************************\
  73. *
  74. *  PROCEDURE: InitDlgProc (HWND hDlg, WORD wMsg, LONG wParam, LONG lParam)
  75. *
  76. *  PURPOSE:  This dialog box prompts the user for a net share name and
  77. *            a client or user name.  These values are placed into global
  78. *            strings ShrName and ClntName.
  79. *
  80. *  CALLED BY:
  81. *
  82. *    ClientDlgProc();
  83. *
  84. \*************************************************************************/
  85.  
  86. LONG CALLBACK InitDlgProc (HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  87.   {
  88.  
  89.   UNREFERENCED_PARAMETER(lParam);
  90.  
  91.   switch (wMsg)
  92.     {
  93.     case WM_INITDIALOG:
  94.       PostMessage (GetDlgItem (hDlg, IDD_SVREDIT),
  95.                    EM_LIMITTEXT, LINE_LEN, 0);
  96.  
  97.       PostMessage (GetDlgItem (hDlg, IDD_CLNTEDIT),
  98.                    EM_LIMITTEXT, NAME_SIZE, 0);
  99.     case WM_COMMAND:
  100.       switch (LOWORD(wParam))
  101.         {                            // When the user clicks okay, get the
  102.         case IDB_INITOK:             // share name and user name from the
  103.                                      // edit fields.
  104.           GetWindowText (GetDlgItem (hDlg, IDD_SVREDIT), ShrName, LINE_LEN);
  105.           GetWindowText (GetDlgItem (hDlg, IDD_CLNTEDIT), ClntName, NAME_SIZE);
  106.           EndDialog(hDlg, 0);
  107.           return (0);
  108.  
  109.         default:
  110.           return (0);
  111.         }
  112.     default:
  113.       return (0);
  114.     }
  115.   return (0);
  116.   }
  117.  
  118.  
  119. /*************************************************************************\
  120. *
  121. *  PROCEDURE: ClientDlgProc (HWND hDlg, WORD wMsg, LONG wParam, LONG lParam)
  122. *
  123. *  PURPOSE:  This procedure services the dialog box that serves as an interface
  124. *            to the named pipe server instance.  The larger edit field is used
  125. *            to read messages from the server instance.  The smaller edit field
  126. *            is used to type messages to the server instance.  This procedure
  127. *            is responsible for connecting to the named pipe, creating a
  128. *            seperate thread to read the pipe, and sending to the pipe.
  129. *
  130. *  CALLED BY:
  131. *
  132. *    WinMain();
  133. *
  134. *  CALLS TO:
  135. *
  136. *    InitDlgProc();
  137. *    ReadPipe();
  138. *
  139. \**************************************************************************/
  140.  
  141. LONG CALLBACK ClientDlgProc (HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  142.   {
  143.   DWORD  retCode;                      // Return code.
  144.   CHAR   errorBuf[LINE_LEN] = "";      // Error message buffer.
  145.   CHAR   outBuf[OUT_BUF_SIZE]  = "";   // Buffer trapping message to send.
  146.   CHAR   sendBuf[OUT_BUF_SIZE] = "";   // Buffer used to modify message.
  147.   DWORD  bytesWritten;                 // Used for WriteFile().
  148.   DWORD  threadID;                     // Used for CreateThread().
  149.   CHAR   fileName[LINE_LEN+NAME_SIZE+2]; // Used to modify pipe/file name.
  150.   DWORD  lastError;                    // Used to get returns from GetLastError.
  151.  
  152.   static HANDLE hPipe;                 // File or Pipe handle.
  153.   static OVERLAPPED OverLapWrt;        // Overlapped structure
  154.   static HANDLE     hEventWrt;         // Event handle for overlapped writes.
  155.  
  156.   UNREFERENCED_PARAMETER( lParam );
  157.  
  158.   hWndClient = hDlg;
  159.  
  160.   switch (wMsg)
  161.     {
  162.  
  163.     case WM_COMMAND:
  164.       switch (LOWORD(wParam))
  165.         {
  166.  
  167.         // When the user presses Send: capture the string from the edit
  168.         // field, prepend it with the user name, and overlap write it to
  169.         // the server instance of the named pipe.
  170.  
  171.         case IDB_SEND:                 // Get the text from the edit field.
  172.           GetWindowText (GetDlgItem(hDlg,IDD_EDITWRITE),
  173.                          outBuf, PLEASE_WRITE);
  174.  
  175.                                        // Prepend it with the user name, and
  176.                                        // terminate it with a new line
  177.                                        // character.
  178.  
  179.           wsprintf (sendBuf, "%s%s %s\n", ClntName, ":", outBuf);
  180.  
  181.                                        // Do the overlapped write.
  182.           retCode = WriteFile (hPipe, sendBuf, PLEASE_WRITE,
  183.                      &bytesWritten, &OverLapWrt);
  184.           if (!retCode)
  185.             {
  186.             lastError = GetLastError();
  187.                                        // If Error = IO_PENDING, wait til
  188.                                        // the event signals success.
  189.             if (lastError == ERROR_IO_PENDING)
  190.               WaitForSingleObject (hEventWrt, (DWORD)-1);
  191.             }
  192.  
  193.           return (0);
  194.  
  195.         default:
  196.           return (0);
  197.  
  198.         }
  199.  
  200.  
  201.     case WM_INITCLIENT:
  202.  
  203.        // On initialization, use the Init dialog box prompt the user for a
  204.        // net share name and a client or user name.  A share name of "."
  205.        // means that the named pipe is local to this machine.  Named pipe
  206.        // names should have the form '\\.\PIPE\<pipename>', for a local machine
  207.        // or '\\<machinename>\PIPE\<pipename>' for remote machines.
  208.        // Once the share name is captured from the Init dialog box,
  209.        // convert the name into the proper form; then do a CreateFile()
  210.        // to connect to the pipe.  Handle any error from the CreateFile().
  211.        // Then write the user name to the server instance of the named
  212.        // pipe.  Finally, create a thread to read the named pipe.
  213.  
  214.                                        // Launch Init dialog box to capture
  215.                                        // share name and user name.
  216.        DialogBox ((HANDLE)GetModuleHandle(NULL),
  217.                   (LPCTSTR)"InitDialog",
  218.                   (HWND)hDlg,
  219.                   (DLGPROC)InitDlgProc);
  220.  
  221.                                        // Put captured user name in window
  222.                                        // caption.
  223.        SetWindowText (hDlg, ClntName);
  224.  
  225.                                        // Construct file/pipe name.
  226.        wsprintf (fileName, "%s%s%s", "\\\\", ShrName, "\\PIPE\\test");
  227.  
  228.                                        // Do CreateFile() to connect to the
  229.                                        // named pipe.
  230.        hPipe = CreateFile (fileName,              // Pipe name.
  231.                            GENERIC_WRITE          // Generic access, read/write.
  232.                            | GENERIC_READ,
  233.                            FILE_SHARE_READ        // Share both read and write.
  234.                            | FILE_SHARE_WRITE ,
  235.                            NULL,                  // No security.
  236.                            OPEN_EXISTING,         // Fail if not existing.
  237.                            FILE_FLAG_OVERLAPPED,  // Use overlap.
  238.                            NULL);                 // No template.
  239.  
  240.                                        // Do some error checking.
  241.        if ((DWORD)hPipe == 0xFFFFFFFF)
  242.          {
  243.          retCode = GetLastError();
  244.  
  245.                                        // This error means pipe wasn't found.
  246.          if ((retCode == ERROR_SEEK_ON_DEVICE) ||
  247.              (retCode == ERROR_FILE_NOT_FOUND)) {
  248.              LoadString(hInst, IDS_CANTFINDPIPE, lpBuffer, sizeof(lpBuffer));
  249.              MessageBox (hDlg, lpBuffer, "", MB_OK);
  250.          }
  251.          else
  252.            {                           // Flagging unknown errors.
  253.              LoadString(hInst, IDS_GENERALERROR, lpBuffer, sizeof(lpBuffer));
  254.              wsprintf (errorBuf, lpBuffer, retCode);
  255.              LoadString(hInst, IDS_DEBUGTITLE, lpBuffer, sizeof(lpBuffer));
  256.              MessageBox (hDlg, errorBuf, lpBuffer,
  257.                        MB_ICONINFORMATION | MB_OK | MB_APPLMODAL);
  258.            }
  259.  
  260.          EndDialog (hDlg, 0);          // Kill app if pipe didn't connect.
  261.          };
  262.  
  263.                                        // Create and init overlapped structure
  264.                                        // for writes.
  265.        hEventWrt = CreateEvent (NULL, TRUE, FALSE, NULL);
  266.        OverLapWrt.hEvent = hEventWrt;
  267.  
  268.                                        // Write the client name to server.
  269.        retCode = WriteFile (hPipe, ClntName, PLEASE_WRITE,
  270.                             &bytesWritten, &OverLapWrt);
  271.  
  272.        if (!retCode)                   // Wait on overlapped if need be.
  273.          {
  274.          lastError = GetLastError();
  275.          if (lastError == ERROR_IO_PENDING)
  276.            WaitForSingleObject (hEventWrt, (DWORD)-1);
  277.          }
  278.                                        // Create a thread to read the pipe.
  279.        CreateThread (NULL,
  280.                      0,
  281.                      (LPTHREAD_START_ROUTINE)ReadPipe,
  282.                      (LPVOID)&hPipe,
  283.                      0,
  284.                      &threadID);
  285.        return (0);
  286.  
  287.  
  288.  
  289.      case WM_INITDIALOG:
  290.                                        // PostMessage() give time for the
  291.                                        // dialog box to be created.
  292.        PostMessage (hDlg, WM_INITCLIENT, 0, 0);
  293.        return (0);
  294.  
  295.  
  296.  
  297.      case WM_GO_AWAY:
  298.        CloseHandle (hPipe);
  299.        CloseHandle (hEventWrt);
  300.        EndDialog (hDlg, TRUE);
  301.        return TRUE;
  302.  
  303.  
  304.  
  305.      case WM_SYSCOMMAND:
  306.        if (wParam == SC_CLOSE)
  307.          {
  308.          CloseHandle (hPipe);
  309.          CloseHandle (hEventWrt);
  310.          EndDialog(hDlg, TRUE);
  311.          return TRUE;
  312.          }
  313.        break;
  314.      }
  315.     return (FALSE);
  316.  
  317.   }
  318.  
  319. /*************************************************************************\
  320. *
  321. *  PROCEDURE: ReadPipe (HANDLE *hRead)
  322. *
  323. *  PURPOSE:  This is a thread function which loops and reads the named pipe.
  324. *
  325. *  CALLED BY:
  326. *
  327. *    ClientDlgProc.
  328. *
  329. *
  330. \*************************************************************************/
  331.  
  332. VOID ReadPipe (HANDLE *hPipe)
  333.   {
  334.     CHAR       inBuf[IN_BUF_SIZE] = "";// Input buffer.
  335.     DWORD      bytesRead;              // Used for ReadFile()
  336.     DWORD      retCode;                // Used to trap return codes.
  337.     CHAR       Buf[80];                // Message box buffer.
  338.     DWORD      lastError;              // Used to trap returns from GetLastError.
  339.  
  340.     HANDLE     hEventRd;               // Event handle for overlapped reads.
  341.     OVERLAPPED OverLapRd;              // Overlapped structure.
  342.     DWORD      bytesTrans;             // Bytes transferred in read.
  343.  
  344.                                        // Create and init overlap structure.
  345.     hEventRd = CreateEvent (NULL, TRUE, FALSE, NULL);
  346.     memset (&OverLapRd, 0, sizeof(OVERLAPPED));
  347.     OverLapRd.hEvent = hEventRd;
  348.  
  349.     // Loop, reading the named pipe until it is broken.  The ReadFile() uses
  350.     // an overlapped structure.  When the event handle signals a completed
  351.     // read, this loop writes the message to the larger edit field.
  352.  
  353.     do{
  354.                                        // Read the pipe handle.
  355.       retCode = ReadFile (*hPipe, inBuf, IN_BUF_SIZE, &bytesRead, &OverLapRd);
  356.  
  357.       if (!retCode) {                  // Do some error checking.
  358.    
  359.         lastError = GetLastError();
  360.                                        // Check for 3 kinds of errors:
  361.                                        // IO_PENDING, BROKEN_PIPE, or
  362.                                        // other.
  363.                                        // If Error = IO_PENDING, wait for
  364.                                        // event handle to signal success.
  365.         if (lastError == ERROR_IO_PENDING)
  366.           {
  367.           WaitForSingleObject (hEventRd, (DWORD)-1);
  368.  
  369.           }
  370.         else {                         // If pipe is broken, tell user and break.
  371.  
  372.           if (lastError == (DWORD)ERROR_BROKEN_PIPE) {
  373.             LoadString(hInst, IDS_CONNECTBROKEN, lpBuffer, sizeof(lpBuffer));
  374.             MessageBox (hWndClient, lpBuffer, "", MB_OK);
  375.           }
  376.           else {                       // Or flag unknown errors, and break.
  377.              LoadString(hInst, IDS_READFAILED, lpBuffer, sizeof(lpBuffer));
  378.              wsprintf (Buf, lpBuffer, GetLastError());
  379.              LoadString(hInst, IDS_CLIENTDBG, lpBuffer, sizeof(lpBuffer));
  380.              MessageBox (hWndClient, Buf, lpBuffer, MB_OK);
  381.           }
  382.           break;
  383.         }
  384.       }
  385.                                        // NULL terminate string.
  386.       GetOverlappedResult (*hPipe, &OverLapRd, &bytesTrans, FALSE);
  387.       inBuf[bytesTrans] = '\0';
  388.  
  389.                                        // Write message to larger edit field.
  390.       SendMessage (GetDlgItem (hWndClient, IDD_EDITREAD),
  391.                    EM_REPLACESEL,
  392.                    0, (LONG)inBuf);
  393.                                        // Add a new line.
  394.       SendMessage (GetDlgItem (hWndClient, IDD_EDITREAD),
  395.                    EM_REPLACESEL,
  396.                    0, (LONG)"\r\n");
  397.       }while(1);
  398.  
  399.                                        // When pipe is broken, send quit
  400.                                        // messages to Client dialog box.
  401.     PostMessage (hWndClient, WM_GO_AWAY, 0,0);
  402.     ExitThread(0);
  403.   }
  404.