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