Annotation of mstools/samples/npserver/server32.c, revision 1.1.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.