Annotation of mstools/samples/namepipe/npserver/server32.c, revision 1.1.1.1

1.1       root        1: /******************************************************************************\
                      2: *       This is a part of the Microsoft Source Code Samples. 
                      3: *       Copyright (C) 1993 Microsoft Corporation.
                      4: *       All rights reserved. 
                      5: *       This source code is only intended as a supplement to 
                      6: *       Microsoft Development Tools and/or WinHelp documentation.
                      7: *       See these sources for detailed information regarding the 
                      8: *       Microsoft samples programs.
                      9: \******************************************************************************/
                     10: 
                     11: /*************************************************************************\
                     12: *  PROGRAM: server32.c
                     13: *
                     14: *  PURPOSE:
                     15: *
                     16: *     To demonstrate the use of named pipes and the overlapped structure.
                     17: *     This code serves as the server side of the named pipe instances.
                     18: *     For more details on an overview of this codes designs or use, see
                     19: *     the README file.  For details on the implementation, see the comments
                     20: *     in this code.
                     21: *
                     22: *
                     23: \*************************************************************************/
                     24: 
                     25: #define  STRICT
                     26: #include <windows.h>
                     27: #include "server32.h"
                     28: 
                     29: #include <string.h>
                     30: #include <stdio.h>
                     31: #include <stdlib.h>
                     32: 
                     33:                                        // clients[] is a global array of
                     34:                                        // structures used to keep track
                     35:                                        // of the multiple instances of
                     36:                                        // the server side of the named
                     37:                                        // pipe.  As a client connects
                     38:                                        // to a given instance, a new
                     39:                                        // server thread is created and
                     40:                                        // added to the array.
                     41: WRTHANDLE clients[MAX_PIPE_INSTANCES];
                     42: DWORD     clientCount = 0;             // Global count of connected clients.
                     43: 
                     44: HWND   hWnd;
                     45: HANDLE hInst;
                     46: 
                     47: 
                     48: /*************************************************************************\
                     49: *
                     50: *  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
                     51: *
                     52: *  PURPOSE: calls initialization function, processes message loop
                     53: *
                     54: *  COMMENTS:
                     55: *
                     56: \*************************************************************************/
                     57: 
                     58: int APIENTRY WinMain (HINSTANCE hInstance,
                     59:                       HINSTANCE hPrevInstance,
                     60:                       LPSTR  lpCmdLine,
                     61:                       int    nCmdShow)
                     62: 
                     63: 
                     64: {
                     65: 
                     66:   MSG  msg;
                     67:   WNDCLASS wc;
                     68: 
                     69: 
                     70:   UNREFERENCED_PARAMETER( lpCmdLine );
                     71:   UNREFERENCED_PARAMETER( hPrevInstance );
                     72: 
                     73:   hInst = hInstance;
                     74: 
                     75:   wc.style = 0;
                     76:   wc.lpfnWndProc = (WNDPROC)MainWndProc;
                     77:   wc.cbClsExtra = 0;
                     78:   wc.cbWndExtra = 0;
                     79:   wc.hInstance = hInstance;
                     80:   wc.hIcon = LoadIcon (hInstance, "npserver");
                     81:   wc.hCursor = LoadCursor (NULL, IDC_ARROW);
                     82:   wc.hbrBackground = GetStockObject (WHITE_BRUSH);
                     83:   wc.lpszMenuName = "PipeMenu";
                     84:   wc.lpszClassName = "PipeWClass";
                     85: 
                     86:   RegisterClass(&wc);
                     87: 
                     88:   hWnd = CreateWindow ("PipeWClass",
                     89:                        "Server32 Named Pipe Sample",
                     90:                        WS_OVERLAPPEDWINDOW,
                     91:                        CW_USEDEFAULT,
                     92:                        CW_USEDEFAULT,
                     93:                        CW_USEDEFAULT,
                     94:                        CW_USEDEFAULT,
                     95:                        NULL,
                     96:                        NULL,
                     97:                        hInstance,
                     98:                        NULL);
                     99: 
                    100: 
                    101:   ShowWindow (hWnd, nCmdShow);
                    102: 
                    103:   while (GetMessage (&msg, NULL, 0, 0))
                    104:     DispatchMessage (&msg);
                    105: 
                    106:   return (msg.wParam);
                    107: 
                    108: }
                    109: 
                    110: /*************************************************************************\
                    111: *
                    112: *  FUNCTION:  MainWndProc (HWND, UINT, WPARAM, LPARAM)
                    113: *
                    114: *  PURPOSE:   To process messages.  To launch client and server threads
                    115: *
                    116: \*************************************************************************/
                    117: 
                    118: LONG CALLBACK MainWndProc (HWND   hwnd,
                    119:                            UINT   message,
                    120:                            WPARAM wParam,
                    121:                            LPARAM lParam)
                    122: {
                    123: 
                    124:   LONG        lpServerThreadID;
                    125:   PAINTSTRUCT paintStruct;
                    126:   HDC         hDC;
                    127: 
                    128:   switch (message)
                    129:       {
                    130:         case WM_PAINT:
                    131:            // DrawBranch is used to paint the spools and text to the window.
                    132:            hDC = BeginPaint (hwnd, &paintStruct);
                    133:            DrawBranch (hDC);
                    134:            EndPaint (hwnd, &paintStruct);
                    135:            return(0);
                    136: 
                    137:         case WM_CREATE :
                    138:            // Create the first instance of a server side of the pipe.
                    139:            CreateThread ((LPSECURITY_ATTRIBUTES)NULL,       // No security.
                    140:                          (DWORD)0,                          // Same stack size.
                    141:                          (LPTHREAD_START_ROUTINE)ServerProc,// Thread procedure.
                    142:                          (LPVOID)&hwnd,                     // Parameter.
                    143:                          (DWORD)0,                          // Start immediatly.
                    144:                          (LPDWORD)&lpServerThreadID);       // Thread ID.
                    145:            return (0);
                    146: 
                    147:         case WM_DESTROY :
                    148:            PostQuitMessage (0);
                    149:            return (0);
                    150:        }
                    151:     return DefWindowProc (hwnd, message, wParam, lParam);
                    152: }
                    153: 
                    154: 
                    155: 
                    156: /*************************************************************************\
                    157: *
                    158: *  PROCEDURE: ServerProc (HWND *hWnd)
                    159: *
                    160: *  PURPOSE:
                    161: *
                    162: *    A thread procedure, which creates an instance of the server side of
                    163: *    the named pipe, and then blocks waiting for a client to connect.
                    164: *    Once the client connects, a global array is updated with the specific
                    165: *    clients information, and this procedure is called again
                    166: *    to launch another waiting server thread.  After launching the new
                    167: *    thread, this thread begins to loop, reading the named pipe.  When
                    168: *    a message comes from it's client, it uses TellAll() to broadcast
                    169: *    the message to the other clients in the array.
                    170: *
                    171: *  CALLED BY:
                    172: *
                    173: *    ServerProc();
                    174: *    WinMain();
                    175: *
                    176: *  CALLS TO:
                    177: *
                    178: *    TellAll();
                    179: *    ServerProc().
                    180: *
                    181: *  COMMENTS:
                    182: *
                    183: *    Clients is a global array which hold information on each client
                    184: *    connected to the named pipe.  This procedure recieves a buffer.
                    185: *    It then steps through this global array, and for each client it
                    186: *    writes the buffer.
                    187: *
                    188: \*************************************************************************/
                    189: 
                    190: VOID ServerProc(HWND *hWnd)
                    191:  {
                    192:    HANDLE hPipe;                       // Pipe handle.
                    193:    CHAR   inBuf[IN_BUF_SIZE] = "";     // Input buffer for pipe.
                    194:    DWORD  ServerThreadID;              // Used for CreateThread().
                    195: 
                    196:    CHAR   errorBuf[LINE_LEN] = "";     // Used for error messages.
                    197:    DWORD  bytesRead;                   // Used in ReadFile().
                    198:    DWORD  retCode;                     // Used to trap return codes.
                    199:    DWORD  clientIndex;                 // Index into global array, for this
                    200:                                        // instances client.
                    201:    DWORD  lastError;                   // Traps returns from GetLastError().
                    202:    BOOL   ExitLoop = FALSE;            // Boolean Flag to exit loop.
                    203: 
                    204:    OVERLAPPED OverLapWrt;              // Overlapped structure for writing.
                    205:    HANDLE     hEventWrt;               // Event handle for overlapped write.
                    206: 
                    207:    OVERLAPPED OverLapRd;               // Overlapped structure for reading.
                    208:    HANDLE     hEventRd;                // Event handle for overlapped reads.
                    209:    DWORD        bytesTransRd;          // Bytes transferred by overlapped.
                    210:    PSECURITY_DESCRIPTOR    pSD;
                    211:    SECURITY_ATTRIBUTES     sa;
                    212: 
                    213:                                        // create a security NULL security
                    214:                                        // descriptor, one that allows anyone
                    215:                                        // to write to the pipe... WARNING
                    216:                                        // entering NULL as the last attribute
                    217:                                        // of the CreateNamedPipe() will
                    218:                                        // indicate that you wish all
                    219:                                        // clients connecting to it to have
                    220:                                        // all of the same security attributes
                    221:                                        // as the user that started the
                    222:                                        // pipe server.
                    223: 
                    224:    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
                    225:                SECURITY_DESCRIPTOR_MIN_LENGTH);
                    226: 
                    227:    if (pSD == NULL)
                    228:      {
                    229:      MessageBox (*hWnd, "Error in LocalAlloc for pSD",
                    230:                  "Debug: ServerProc()", MB_OK);
                    231:      return;
                    232:      }
                    233: 
                    234:    if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
                    235:      {
                    236:      wsprintf (errorBuf, "Error: InitializeSecurityDescriptor() %d",
                    237:                GetLastError());
                    238:      MessageBox (*hWnd, errorBuf, "Debug: ServerProc()", MB_OK);
                    239:        LocalFree((HLOCAL)pSD);
                    240:        return;
                    241:      }
                    242: 
                    243:                                        // add a NULL disc. ACL to the
                    244:                                        // security descriptor.
                    245: 
                    246:    if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE))
                    247:      {
                    248:      wsprintf (errorBuf, "Error: SetSecurityDescriptorDacl() %d",
                    249:                 GetLastError());
                    250:      MessageBox (*hWnd, errorBuf, "Debug: ServerProc()", MB_OK);
                    251:      LocalFree((HLOCAL)pSD);
                    252:      return;
                    253:      }
                    254: 
                    255:    sa.nLength = sizeof(sa);
                    256:    sa.lpSecurityDescriptor = pSD;
                    257:    sa.bInheritHandle = TRUE;
                    258: 
                    259:                                        // Create a local named pipe with
                    260:                                        // the name '\\.\PIPE\test'.  The
                    261:                                        // '.' signifies local pipe.
                    262:    hPipe = CreateNamedPipe ("\\\\.\\PIPE\\test", // Pipe name = 'test'.
                    263:                PIPE_ACCESS_DUPLEX                // 2 way pipe.
                    264:                | FILE_FLAG_OVERLAPPED,           // Use overlapped structure.
                    265:                PIPE_WAIT                         // Wait on messages.
                    266:                | PIPE_READMODE_MESSAGE           // Specify message mode pipe.
                    267:                | PIPE_TYPE_MESSAGE,
                    268:                MAX_PIPE_INSTANCES,               // Maximum instance limit.
                    269:                OUT_BUF_SIZE,                     // Buffer sizes.
                    270:                IN_BUF_SIZE,
                    271:                TIME_OUT,                         // Specify time out.
                    272:                &sa);                             // Security attributes.
                    273: 
                    274:                                        // Check Errors.
                    275:     if ((DWORD)hPipe == 0xFFFFFFFF)
                    276:      {
                    277: 
                    278:      retCode = GetLastError();         // Report any error, it should always
                    279:      wsprintf (errorBuf,               // succeed.
                    280:                "Error return code from CreateNamedPipe = %li.",
                    281:                 retCode);
                    282:      MessageBox (*hWnd, errorBuf, "Debug Window",
                    283:                  MB_ICONINFORMATION | MB_OK | MB_APPLMODAL);
                    284:      };
                    285: 
                    286:                                        // Block until a client connects.
                    287:    ConnectNamedPipe(hPipe, NULL);
                    288: 
                    289:                                        // Create and init overlap for writing.
                    290:    hEventWrt = CreateEvent (NULL, TRUE, FALSE, NULL);
                    291:    memset (&OverLapWrt, 0, sizeof(OVERLAPPED));
                    292:    OverLapWrt.hEvent = hEventWrt;
                    293: 
                    294:                                        // Set the clientIndex, then increment
                    295:                                        // the count.  Fill in the structure
                    296:                                        // for this client in the array.
                    297:    clientIndex = clientCount++;
                    298:    clients[clientIndex].hPipe   = hPipe;
                    299:    clients[clientIndex].live    = TRUE;
                    300:    clients[clientIndex].overLap = OverLapWrt;
                    301:    clients[clientIndex].hEvent  = hEventWrt;
                    302: 
                    303:                                        // Create and init overlap for reading.
                    304:    hEventRd = CreateEvent(NULL,TRUE,FALSE,NULL);
                    305:    memset (&OverLapRd, 0, sizeof(OVERLAPPED));
                    306:    OverLapRd.hEvent = hEventRd;
                    307: 
                    308:                                        // Read from the client, the first
                    309:                                        // first message should always be
                    310:                                        // the clients user name.
                    311:    retCode = ReadFile (hPipe, inBuf, PLEASE_READ, &bytesRead, &OverLapRd);
                    312: 
                    313:    if (!retCode)
                    314:     lastError = GetLastError();
                    315: 
                    316:    if (lastError == ERROR_IO_PENDING)  // Wait on read if need be.
                    317:      WaitForSingleObject (hEventRd, (DWORD)-1);
                    318: 
                    319:                                        // Put client's name in the array.
                    320:    strcpy (clients[clientIndex].Name, inBuf);
                    321: 
                    322:                                        // Create a thread which will make
                    323:                                        // another server instance of the
                    324:                                        // named pipe.
                    325:    CreateThread ((LPSECURITY_ATTRIBUTES)NULL,        // No security attributes.
                    326:                  (DWORD)0,                           // Use same stack size.
                    327:                  (LPTHREAD_START_ROUTINE)ServerProc, // Thread procedure.
                    328:                  (LPVOID)hWnd,                       // Parameter to pass.
                    329:                  (DWORD)0,                           // Run immediately.
                    330:                  (LPDWORD)&ServerThreadID);          // Thread identifier.
                    331: 
                    332:    TellAll("");                        // Forces a paint, draws a red spool
                    333:                                        // and name for this client.
                    334: 
                    335:                                        // Do loop which basically reads from
                    336:                                        // this specific client, and then
                    337:                                        // uses TellAll() to broadcast the
                    338:                                        // message to all the connected
                    339:                                        // clients.
                    340:    do{
                    341:                                        // Read the pipe.
                    342:       retCode = ReadFile (hPipe, inBuf, PLEASE_READ, &bytesRead, &OverLapRd);
                    343: 
                    344:                                        // Check for three kinds of errors:
                    345:                                        // If Error = IO_PENDING, wait til
                    346:                                        // the event handle signals success,
                    347:                                        // If BROKEN_PIPE, exit the do loop.
                    348:                                        // Any other error, flag it to the
                    349:                                        // user and exit the do loop.
                    350:       if (!retCode)
                    351:         {
                    352:         lastError = GetLastError();
                    353: 
                    354:         switch (lastError)
                    355:           {
                    356:                                        // IO_PENDING, wait on the event.
                    357:            case ERROR_IO_PENDING:
                    358:              WaitForSingleObject (hEventRd, (DWORD)-1);
                    359:              break;
                    360:                                        // Pipe is broken, exit the loop.
                    361:            case ERROR_BROKEN_PIPE:
                    362:              ExitLoop = TRUE;
                    363:              break;
                    364:                                        // Something else is wrong, exit the
                    365:                                        // the loop after telling the user.
                    366:            default:
                    367:              wsprintf (errorBuf, "ReadFile Error in ServerProc()= %d",
                    368:              lastError);
                    369:              MessageBox (*hWnd, errorBuf, "Debug Information", MB_OK);
                    370:              ExitLoop = TRUE;
                    371:              break;
                    372:           }
                    373:         }
                    374: 
                    375:       if (!ExitLoop)
                    376:         {
                    377:         GetOverlappedResult (hPipe, &OverLapRd, &bytesTransRd, FALSE);
                    378: 
                    379:                                        // Use TellAll to broadcast the message.
                    380:         if (bytesTransRd)
                    381:           TellAll(inBuf);
                    382:         else
                    383:           TellAll("");
                    384:         }
                    385: 
                    386:    }while(!ExitLoop);
                    387: 
                    388:    clients[clientIndex].live = FALSE;  // Turns spool gray.
                    389:    CloseHandle (hPipe);                // Close handles.
                    390:    CloseHandle (hEventRd);
                    391:    CloseHandle (hEventWrt);
                    392:    DisconnectNamedPipe (hPipe);        // Close pipe instance.
                    393:    ExitThread(0);                      // Clean up and die.
                    394:   }
                    395: 
                    396: 
                    397: /*************************************************************************\
                    398: *
                    399: *  PROCEDURE: TellAll (CHAR *buffer)
                    400: *
                    401: *  PURPOSE:
                    402: *
                    403: *    To write the buffer (input parameter) to all of the clients listed
                    404: *    in the global array "clients".
                    405: *
                    406: *  CALLED BY:
                    407: *
                    408: *    ServerProc();
                    409: *
                    410: *  COMMENTS:
                    411: *
                    412: *    Clients is a global array which hold information on each client
                    413: *    connected to the named pipe.  This procedure recieves a buffer.
                    414: *    It then steps through this global array, and for each client it
                    415: *    writes the buffer.
                    416: *
                    417: \*************************************************************************/
                    418: 
                    419: VOID TellAll( CHAR *buffer )
                    420:   {
                    421:     DWORD i;                           // Index through array.
                    422:     DWORD bytesWritten;                // Used in WriteFile().
                    423:     DWORD retCode;                     // Traps return codes.
                    424:     CHAR  Buf[LINE_LEN];               // Message Buffer.
                    425:     DWORD lastError;                   // Traps returns from GetLastError().
                    426: 
                    427:     for(i=0; i < clientCount; i++)     // For all clients in the array.
                    428:       {
                    429:                                        // If client isn't alive, don't waste
                    430:                                        // time writing to it.
                    431:       if (clients[i].live)
                    432:         {
                    433:         retCode = WriteFile (clients[i].hPipe, buffer, strlen(buffer),
                    434:                              &bytesWritten, &clients[i].overLap);
                    435: 
                    436:                                        // Check 3 kinds of errors: IO_PENDING,
                    437:                                        // NO_DATA, or other.  Wait on event
                    438:                                        // handle if IO_PENDING, else, if it's
                    439:                                        // anything other than NO_DATA (pipe
                    440:                                        // client disconnected), flag the user.
                    441:                                        // In any case, if it's not IO_PENDING,
                    442:                                        // clients[i].live = FALSE, spool turns
                    443:                                        // gray.
                    444:         if (!retCode)
                    445:           {
                    446:           lastError = GetLastError();
                    447: 
                    448:                                        // IO_PENDING, wait on event handle.
                    449:           if (lastError == ERROR_IO_PENDING)
                    450:             {
                    451:             WaitForSingleObject (clients[i].hEvent, (DWORD)-1);
                    452:             }
                    453:           else
                    454:             {
                    455:                                        // If not NO_DATA, flag user.
                    456:             if (lastError != ERROR_NO_DATA)
                    457:               {
                    458:               wsprintf (Buf, "%s = %d", buffer, GetLastError());
                    459:               MessageBox(hWnd, Buf, "Debug,TellAll:", MB_OK);
                    460:               }
                    461:             clients[i].live = FALSE;
                    462:             }
                    463:           }
                    464:         } //if client.live
                    465:       } // for loop
                    466:                                        // Paint window with new information.
                    467:     InvalidateRect(hWnd, NULL, TRUE);
                    468:   }
                    469: 
                    470: 
                    471: 
                    472: /*************************************************************************\
                    473: *
                    474: *  PROCEDURE: DrawBranch (HDC hDC)
                    475: *
                    476: *  PURPOSE:
                    477: *
                    478: *    To draw one of four bitmaps for each client, depending upon the clients
                    479: *    status (alive = red spool, dead or disconnected = gray), and location in
                    480: *    the array.  It also draws the clients user name beside the spool.
                    481: *    This procedure is executed when the WM_PAINT message is trapped.
                    482: *
                    483: *  CALLED BY:
                    484: *
                    485: *    WinMain();
                    486: *
                    487: *  COMMENTS:
                    488: *
                    489: \*************************************************************************/
                    490: VOID DrawBranch(HDC hDC)
                    491: {
                    492:                                        // Spool bitmaps.
                    493:   HBITMAP hEndLive, hEndDead, hMidLive, hMidDead, hBitMap;
                    494: 
                    495:   HDC hDCMem;
                    496:   int X, Y;
                    497:   BITMAP bm;
                    498:   POINT ptSize, ptOrg;
                    499:   DWORD index;
                    500: 
                    501:                                        // Load bitmaps: two red (live),
                    502:                                        // two dead (gray).  End = end
                    503:                                        // of tree (last client to connect),
                    504:                                        // mid means in the middle somewhere.
                    505:        hEndLive = LoadBitmap (hInst, "EndLive");
                    506:        hEndDead = LoadBitmap (hInst, "EndDead");
                    507: 
                    508:        hMidLive = LoadBitmap (hInst, "MidLive");
                    509:        hMidDead = LoadBitmap (hInst, "MidDead");
                    510: 
                    511:                                        // For each client, determine if
                    512:                                        // if alive or not, and position;
                    513:                                        // then blt appropriate map and
                    514:                                        // clients name.
                    515:     for (index = 0; index < clientCount; index++)
                    516:       {
                    517: 
                    518:       if (index < clientCount - 1)     // ClientCount - 1 = last (end) client.
                    519:        {
                    520:         if(clients[index].live)        // If live = red, else = gray.
                    521:          hBitMap = hMidLive;
                    522:         else
                    523:          hBitMap = hMidDead;
                    524:        }
                    525:       else
                    526:        {
                    527:         if(clients[index].live)        // If live = red, else = gray.
                    528:          hBitMap = hEndLive;
                    529:         else
                    530:          hBitMap = hEndDead;
                    531:        }
                    532:                                        // Calculate coordinates:
                    533:       X = BITMAP_X;                    // X position is constant.
                    534:       Y = index * BITMAP_Y;            // Y is based on index in the array.
                    535: 
                    536:                                        // Blt the chosen map.
                    537:       hDCMem = CreateCompatibleDC(hDC);
                    538:       SelectObject(hDCMem, hBitMap);
                    539:       SetMapMode(hDCMem, GetMapMode(hDC));
                    540: 
                    541:       GetObject(hBitMap, sizeof(BITMAP), &bm);
                    542: 
                    543:       ptSize.x = bm.bmWidth;
                    544:       ptSize.y = bm.bmHeight;
                    545:       DPtoLP (hDC, &ptSize, 1);
                    546: 
                    547:       ptOrg.x = 0;
                    548:       ptOrg.y = 0;
                    549:       DPtoLP (hDCMem, &ptOrg, 1);
                    550: 
                    551:       BitBlt(hDC, X, Y, ptSize.x, ptSize.y,
                    552:              hDCMem, ptOrg.x, ptOrg.y, SRCCOPY);
                    553: 
                    554: 
                    555:       X =  NAME_X;                     // Relocate X,Y for clients name.
                    556:       Y += NAME_Y;
                    557:                                        // Write name next to spool.
                    558:       TextOut (hDC, X, Y, clients[index].Name, strlen(clients[index].Name));
                    559:       DeleteDC(hDCMem);
                    560:       }
                    561: 
                    562: 
                    563: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.