Annotation of mstools/samples/npserver/server32.c, revision 1.1

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

unix.superglobalmegacorp.com

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