|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.