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

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

unix.superglobalmegacorp.com

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