|
|
1.1.1.3 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: 1.1 root 12: /**************************************************************************** 13: 14: PROGRAM: Server.c 15: 16: PURPOSE: Server template for Windows applications 17: 18: FUNCTIONS: 19: 20: WinMain() - calls initialization function, processes message loop 21: InitApplication() - initializes window data and registers window 22: InitInstance() - saves instance handle and creates main window 23: MainWndProc() - processes messages 24: About() - processes messages for "About" dialog box 25: 26: COMMENTS: 27: 28: Windows can have several copies of your application running at the 29: same time. The variable hInst keeps track of which instance this 30: application is so that processing will be to the correct window. 31: 32: ****************************************************************************/ 33: 34: #include <stdio.h> 35: #include <stdlib.h> 36: #include <string.h> 37: #include "server.h" /* specific to this program */ 38: #include "huge.h" 39: 40: DWORD idInst = 0; 1.1.1.3 ! root 41: CONVCONTEXT CCFilter = { sizeof(CONVCONTEXT), 0, 0, 0, 0L, 0L, ! 42: { ! 43: sizeof(SECURITY_QUALITY_OF_SERVICE), ! 44: SecurityImpersonation, ! 45: SECURITY_STATIC_TRACKING, ! 46: TRUE ! 47: } ! 48: }; 1.1 root 49: HANDLE hInst; /* current instance */ 50: HWND hwndServer; 51: RECT rcRand; 52: RECT rcCount; 53: RECT rcComment; 54: RECT rcExec; 55: RECT rcConnCount; 56: RECT rcRndrDelay; 57: RECT rcRunaway; 58: RECT rcAllBlock; 59: RECT rcNextAction; 60: RECT rcHugeSize; 61: RECT rcAppowned; 62: BOOL fAllBlocked = FALSE; 63: BOOL fAllEnabled = TRUE; 64: BOOL fEnableOneCB = FALSE; 65: BOOL fBlockNextCB = FALSE; 66: BOOL fTermNextCB = FALSE; 67: BOOL fAppowned = FALSE; 68: WORD cRunaway = 0; 69: WORD RenderDelay = 0; 70: DWORD count = 0; 71: WORD seed = 0; 72: HSZ hszAppName = 0; 73: CHAR szClass[] = "ServerWClass"; 74: CHAR szTopic[MAX_TOPIC] = "Test"; 75: CHAR szServer[MAX_TOPIC] = "Server"; 76: CHAR szComment[MAX_COMMENT] = ""; 77: CHAR szExec[MAX_EXEC] = ""; 78: CHAR *pszComment = szComment; 79: WORD cyText; 80: WORD cServers = 0; 81: HDDEDATA hDataHelp[CFORMATS] = {0}; 82: HDDEDATA hDataCount[CFORMATS] = {0}; 83: HDDEDATA hDataRand[CFORMATS] = {0}; 84: HDDEDATA hDataHuge[CFORMATS] = {0}; 85: DWORD cbHuge = 0; 86: 87: char szDdeHelp[] = "DDEML test server help:\r\n\n"\ 88: "The 'Server'(service) and 'Test'(topic) names may change.\r\n\n"\ 89: "Items supported under the 'Test' topic are:\r\n"\ 90: "\tCount:\tThis value increments on each data change.\r\n"\ 91: "\tRand:\tThis value is randomly generated each data change.\r\n"\ 92: "\tHuge:\tThis is randomlly generated text data >64k that the\r\n"\ 93: "\t\tDDEML test client can verify.\r\n"\ 94: "The above items change after any request if in Runaway mode and \r\n"\ 95: "can bo POKEed in order to change their values. POKEed Huge data \r\n"\ 96: "must be in a special format to verify the correctness of the data \r\n"\ 97: "or it will not be accepted.\r\n"\ 98: "If the server is set to use app owned data handles, all data sent \r\n"\ 99: "uses HDATA_APPOWNED data handles."\ 100: ; 101: 102: FORMATINFO aFormats[CFORMATS] = { 103: { 0, "CF_TEXT" }, // exception! predefined format 104: { 0, "Dummy1" }, 105: { 0, "Dummy2" }, 106: }; 107: 108: 109: /* 110: * Topic and Item tables supported by this application. 111: */ 112: 113: /* HSZ PROCEDURE PSZ */ 114: 115: ITEMLIST SystemTopicItemList[CSYSTEMITEMS] = { 116: 117: { 0, TopicListXfer, SZDDESYS_ITEM_TOPICS }, 118: { 0, ItemListXfer, SZDDESYS_ITEM_SYSITEMS }, 119: { 0, sysFormatsXfer, SZDDESYS_ITEM_FORMATS }, 120: { 0, HelpXfer, SZDDESYS_ITEM_HELP}, 121: }; 122: 123: 124: ITEMLIST TestTopicItemList[CTESTITEMS] = { 125: 126: { 0, TestRandomXfer, "Rand" }, // 0 index 127: { 0, TestCountXfer, "Count"}, // 1 index 128: { 0, TestHugeXfer, "Huge" }, // 2 index 129: { 0, ItemListXfer, SZDDESYS_ITEM_SYSITEMS }, // 3 index 130: }; 131: 132: 133: /* The system topic is always assumed to be first. */ 134: /* HSZ PROCEDURE #ofITEMS PSZ */ 135: TOPICLIST topicList[CTOPICS] = { 136: 137: { 0, SystemTopicItemList, CSYSTEMITEMS, SZDDESYS_TOPIC}, // 0 index 138: { 0, TestTopicItemList, CTESTITEMS, szTopic}, // 1 index 139: }; 140: 141: 142: 143: 144: 145: 146: /**************************************************************************** 147: 148: FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) 149: 150: PURPOSE: calls initialization function, processes message loop 151: 152: COMMENTS: 153: 154: Windows recognizes this function by name as the initial entry point 155: for the program. This function calls the application initialization 156: routine, if no other instance of the program is running, and always 157: calls the instance initialization routine. It then executes a message 158: retrieval and dispatch loop that is the top-level control structure 159: for the remainder of execution. The loop is terminated when a WM_QUIT 160: message is received, at which time this function exits the application 161: instance by returning the value passed by PostQuitMessage(). 162: 163: If this function must abort before entering the message loop, it 164: returns the conventional value NULL. 165: 166: ****************************************************************************/ 167: 1.1.1.2 root 168: INT WINAPI WinMain( 1.1.1.3 ! root 169: HINSTANCE hInstance, ! 170: HINSTANCE hPrevInstance, 1.1.1.2 root 171: LPSTR lpCmdLine, 172: INT nCmdShow) 1.1 root 173: { 174: MSG msg; /* message */ 175: 176: if (!hPrevInstance) /* Other instances of app running? */ 177: if (!InitApplication(hInstance)) /* Initialize shared things */ 178: return (FALSE); /* Exits if unable to initialize */ 179: 180: /* Perform initializations that apply to a specific instance */ 181: 182: if (!InitInstance(hInstance, nCmdShow)) 183: return (FALSE); 184: 185: /* Acquire and dispatch messages until a WM_QUIT message is received. */ 186: 187: while (GetMessage(&msg, /* message structure */ 188: 0, /* handle of window receiving the message */ 189: 0, /* lowest message to examine */ 190: 0)) /* highest message to examine */ 191: { 192: TranslateMessage(&msg); /* Translates virtual key codes */ 193: DispatchMessage(&msg); /* Dispatches message to window */ 194: } 195: 196: UnregisterClass(szClass, hInstance); 197: return (msg.wParam); /* Returns the value from PostQuitMessage */ 198: } 199: 200: 201: /**************************************************************************** 202: 203: FUNCTION: InitApplication(HANDLE) 204: 205: PURPOSE: Initializes window data and registers window class 206: 207: COMMENTS: 208: 209: This function is called at initialization time only if no other 210: instances of the application are running. This function performs 211: initialization tasks that can be done once for any number of running 212: instances. 213: 214: In this case, we initialize a window class by filling out a data 215: structure of type WNDCLASS and calling the Windows RegisterClass() 216: function. Since all instances of this application use the same window 217: class, we only need to do this when the first instance is initialized. 218: 219: 220: ****************************************************************************/ 221: 222: BOOL InitApplication(hInstance) 223: HANDLE hInstance; /* current instance */ 224: { 225: WNDCLASS wc; 226: 227: /* Fill in window class structure with parameters that describe the */ 228: /* main window. */ 229: 230: wc.style = 0; /* Class style(s). */ 231: wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for */ 232: /* windows of this class. */ 233: wc.cbClsExtra = 0; /* No per-class extra data. */ 234: wc.cbWndExtra = 0; /* No per-window extra data. */ 235: wc.hInstance = hInstance; /* Application that owns the class. */ 236: wc.hIcon = LoadIcon(hInstance, "server"); 237: wc.hCursor = LoadCursor(NULL, IDC_ARROW); 238: wc.hbrBackground = (HANDLE)(COLOR_APPWORKSPACE+1); 239: wc.lpszMenuName = "ServerMenu"; /* Name of menu resource in .RC file. */ 240: wc.lpszClassName = "ServerWClass"; /* Name used in call to CreateWindow. */ 241: 242: /* Register the window class and return success/failure code. */ 243: 244: return (RegisterClass(&wc)); 245: 246: } 247: 248: 249: /**************************************************************************** 250: 251: FUNCTION: InitInstance(HANDLE, int) 252: 253: PURPOSE: Saves instance handle and creates main window 254: 255: COMMENTS: 256: 257: This function is called at initialization time for every instance of 258: this application. This function performs initialization tasks that 259: cannot be shared by multiple instances. 260: 261: In this case, we save the instance handle in a static variable and 262: create and display the main program window. 263: 264: ****************************************************************************/ 265: 266: BOOL InitInstance(hInstance, nCmdShow) 267: HANDLE hInstance; /* Current instance identifier. */ 268: INT nCmdShow; /* Param for first ShowWindow() call. */ 269: { 270: INT i; 271: RECT Rect; 272: TEXTMETRIC metrics; 273: HDC hdc; 274: 275: /* Save the instance handle in static variable, which will be used in */ 276: /* many subsequence calls from this application to Windows. */ 277: 278: hInst = hInstance; 279: 280: 281: /* Create a main window for this application instance. */ 282: 283: hwndServer = CreateWindow( 284: "ServerWClass", /* See RegisterClass() call. */ 285: "Server|Test", 286: WS_OVERLAPPEDWINDOW, /* Window style. */ 287: CW_USEDEFAULT, /* Default horizontal position. */ 288: CW_USEDEFAULT, /* Default vertical position. */ 289: 400, 290: 200, 291: NULL, /* Overlapped windows have no parent. */ 292: NULL, /* Use the window class menu. */ 293: hInstance, /* This instance owns this window. */ 294: NULL /* Pointer not needed. */ 295: ); 296: 297: GetClientRect(hwndServer, (LPRECT) &Rect); 298: 299: /* If window could not be created, return "failure" */ 300: 301: if (!hwndServer) 302: return (FALSE); 303: 304: hdc = GetDC(hwndServer); 305: GetTextMetrics(hdc, &metrics); 306: cyText = (WORD)(metrics.tmHeight + metrics.tmExternalLeading); 307: ReleaseDC(hwndServer, hdc); 308: 309: aFormats[0].atom = CF_TEXT; // exception - predefined. 310: for (i = 1; i < CFORMATS; i++) { 311: aFormats[i].atom = RegisterClipboardFormat(aFormats[i].sz); 312: } 313: 314: /* Make the window visible; update its client area; and return "success" */ 315: 316: ShowWindow(hwndServer, nCmdShow); /* Show the window */ 317: UpdateWindow(hwndServer); /* Sends WM_PAINT message */ 318: seed = 1; 319: srand(1); 320: CCFilter.iCodePage = CP_WINANSI; // initial default codepage 321: if (!DdeInitialize(&idInst, (PFNCALLBACK)MakeProcInstance((FARPROC)DdeCallback, 322: hInstance), APPCMD_FILTERINITS, 0)) { 323: Hszize(); 324: DdeNameService(idInst, hszAppName, 0, DNS_REGISTER); 325: return(TRUE); 326: } 327: return (FALSE); 328: 329: } 330: 331: /**************************************************************************** 332: 333: FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) 334: 335: PURPOSE: Processes messages 336: 337: MESSAGES: 338: 339: WM_COMMAND - application menu (About dialog box) 340: WM_DESTROY - destroy window 341: 342: COMMENTS: 343: 344: To process the IDM_ABOUT message, call MakeProcInstance() to get the 345: current instance address of the About() function. Then call Dialog 346: box which will create the box according to the information in your 347: server.rc file and turn control over to the About() function. When 348: it returns, free the intance address. 349: 350: ****************************************************************************/ 351: 352: LONG APIENTRY MainWndProc(hWnd, message, wParam, lParam) 353: HWND hWnd; /* window handle */ 354: UINT message; /* type of message */ 355: WPARAM wParam; /* additional information */ 1.1.1.2 root 356: LPARAM lParam; /* additional information */ 1.1 root 357: { 358: switch (message) { 359: case WM_INITMENU: 360: if (GetMenu(hWnd) != (HMENU)wParam) 361: break; 362: 363: CheckMenuItem((HMENU)wParam, IDM_BLOCKALLCBS, 364: fAllBlocked ? MF_CHECKED : MF_UNCHECKED); 365: CheckMenuItem((HMENU)wParam, IDM_UNBLOCKALLCBS, 366: fAllEnabled ? MF_CHECKED : MF_UNCHECKED); 367: CheckMenuItem((HMENU)wParam, IDM_BLOCKNEXTCB, 368: fBlockNextCB ? MF_CHECKED : MF_UNCHECKED); 369: CheckMenuItem((HMENU)wParam, IDM_TERMNEXTCB, 370: fTermNextCB ? MF_CHECKED : MF_UNCHECKED); 371: CheckMenuItem((HMENU)wParam, IDM_RUNAWAY, 372: cRunaway ? MF_CHECKED : MF_UNCHECKED); 373: CheckMenuItem((HMENU)wParam, IDM_APPOWNED, 374: fAppowned ? MF_CHECKED : MF_UNCHECKED); 375: break; 376: 377: case WM_COMMAND: /* message: command from application menu */ 1.1.1.2 root 378: switch (LOWORD(wParam)) { 1.1 root 379: case IDM_ENABLEONECB: 380: DdeEnableCallback(idInst, 0, EC_ENABLEONE); 381: fAllBlocked = FALSE; 382: fAllEnabled = FALSE; 383: InvalidateRect(hwndServer, &rcAllBlock, TRUE); 384: break; 385: 386: case IDM_TERMNEXTCB: 387: fTermNextCB = !fTermNextCB; 388: InvalidateRect(hwndServer, &rcNextAction, TRUE); 389: break; 390: 391: case IDM_BLOCKNEXTCB: 392: fBlockNextCB = !fBlockNextCB; 393: InvalidateRect(hwndServer, &rcNextAction, TRUE); 394: break; 395: 396: case IDM_BLOCKALLCBS: 397: DdeEnableCallback(idInst, 0, EC_DISABLE); 398: fAllBlocked = TRUE; 399: fAllEnabled = FALSE; 400: InvalidateRect(hwndServer, &rcAllBlock, TRUE); 401: break; 402: 403: case IDM_UNBLOCKALLCBS: 404: DdeEnableCallback(idInst, 0, EC_ENABLEALL); 405: fAllEnabled = TRUE; 406: fAllBlocked = FALSE; 407: InvalidateRect(hwndServer, &rcAllBlock, TRUE); 408: break; 409: 410: case IDM_APPOWNED: 411: fAppowned = !fAppowned; 412: if (!fAppowned) { 413: WORD iFmt; 414: for (iFmt = 0; iFmt < CFORMATS; iFmt++) { 415: if (hDataHuge[iFmt]) { 416: DdeFreeDataHandle(hDataHuge[iFmt]); 417: hDataHuge[iFmt] = 0; 418: InvalidateRect(hwndServer, &rcHugeSize, TRUE); 419: } 420: if (hDataCount[iFmt]) { 421: DdeFreeDataHandle(hDataCount[iFmt]); 422: hDataCount[iFmt] = 0; 423: } 424: if (hDataRand[iFmt]) { 425: DdeFreeDataHandle(hDataRand[iFmt]); 426: hDataRand[iFmt] = 0; 427: } 428: if (hDataHelp[iFmt]) { 429: DdeFreeDataHandle(hDataHelp[iFmt]); 430: hDataHelp[iFmt] = 0; 431: } 432: } 433: } 434: InvalidateRect(hwndServer, &rcAppowned, TRUE); 435: break; 436: 437: case IDM_RUNAWAY: 438: cRunaway = !cRunaway; 439: InvalidateRect(hwndServer, &rcRunaway, TRUE); 440: if (!cRunaway) { 441: break; 442: } 443: // fall through 444: 445: case IDM_CHANGEDATA: 446: PostMessage(hwndServer, UM_CHGDATA, 1, 0); // rand 447: PostMessage(hwndServer, UM_CHGDATA, 1, 1); // count 448: break; 449: 450: case IDM_RENDERDELAY: 1.1.1.3 ! root 451: DoDialog(MAKEINTRESOURCE(DID_VALUEENTRY), (DLGPROC)RenderDelayDlgProc, 0, TRUE); 1.1 root 452: InvalidateRect(hwndServer, &rcRndrDelay, TRUE); 453: break; 454: 455: case IDM_SETSERVER: 1.1.1.3 ! root 456: DoDialog(MAKEINTRESOURCE(DID_VALUEENTRY), (DLGPROC)SetServerDlgProc, 0, TRUE); 1.1 root 457: break; 458: 459: case IDM_SETTOPIC: 1.1.1.3 ! root 460: DoDialog(MAKEINTRESOURCE(DID_VALUEENTRY), (DLGPROC)SetTopicDlgProc, 0, TRUE); 1.1 root 461: break; 462: 463: case IDM_CONTEXT: 1.1.1.3 ! root 464: DoDialog(MAKEINTRESOURCE(DID_CONTEXT), (DLGPROC)ContextDlgProc, 0, TRUE); 1.1 root 465: break; 466: 467: case IDM_ABOUT: 1.1.1.3 ! root 468: DoDialog(MAKEINTRESOURCE(DID_ABOUT), (DLGPROC)About, 0, TRUE); 1.1 root 469: break; 470: 471: case IDM_HELP: 472: break; 473: 474: default: 475: return (DefWindowProc(hWnd, message, wParam, lParam)); 476: } 477: break; 478: 479: case WM_PAINT: 480: PaintServer(hWnd); 481: break; 482: 483: case UM_CHGDATA: 484: { 485: WORD iFmt; 486: 487: // wParam = TopicIndex, 488: // LOWORD(lParam) = ItemIndex 489: // We asynchronously do DdePostAdvise() calls to prevent infinite 490: // loops when in runaway mode. 491: if (wParam == 1) { // test topic 492: if (lParam == 0) { // rand item 493: seed = rand(); 494: for (iFmt = 0; iFmt < CFORMATS ; iFmt++) { 495: if (hDataRand[iFmt]) { 496: DdeFreeDataHandle(hDataRand[iFmt]); 497: hDataRand[iFmt] = 0; 498: } 499: } 500: InvalidateRect(hwndServer, &rcRand, TRUE); 501: DdePostAdvise(idInst, topicList[wParam].hszTopic, 502: (HSZ)topicList[wParam].pItemList[lParam].hszItem); 503: } 504: if (lParam == 1) { // count item 505: count++; 506: for (iFmt = 0; iFmt < CFORMATS ; iFmt++) { 507: if (hDataCount[iFmt]) { 508: DdeFreeDataHandle(hDataCount[iFmt]); 509: hDataCount[iFmt] = 0; 510: } 511: } 512: InvalidateRect(hwndServer, &rcCount, TRUE); 513: DdePostAdvise(idInst, topicList[wParam].hszTopic, 514: (HSZ)topicList[wParam].pItemList[lParam].hszItem); 515: } 516: // Huge item does not runaway - too slow. 517: } 518: if (cRunaway) { 519: Delay(50, TRUE); 520: // This gives enough time for the system to remain 521: // useable in runaway mode. 522: PostMessage(hwndServer, UM_CHGDATA, wParam, lParam); 523: } 524: } 525: break; 526: 527: case WM_DESTROY: /* message: window being destroyed */ 528: if (fAppowned) 1.1.1.2 root 529: SendMessage(hwndServer, WM_COMMAND, (WPARAM)MAKELONG(IDM_APPOWNED, 0), (LONG)(0)); 1.1 root 530: DdeNameService(idInst, 0, 0, DNS_UNREGISTER); // unregister all services 531: UnHszize(); 532: DdeUninitialize(idInst); 533: PostQuitMessage(0); 534: break; 535: 536: default: 537: return (DefWindowProc(hWnd, message, wParam, lParam)); 538: } 539: return(0); 540: } 541: 542: 543: 544: 545: 546: VOID Delay( 547: DWORD delay, 548: BOOL fModal) 549: { 550: MSG msg; 551: delay = GetCurrentTime() + delay; 552: while (GetCurrentTime() < delay) { 553: if (fModal && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { 554: TranslateMessage(&msg); 555: DispatchMessage(&msg); 556: } 557: } 558: } 559: 560: 561: 562: /* 563: * This function not only paints the server client area with current info, 564: * it also has the side effect of setting the global RECTs that bound each 565: * info area. This way flashing is reduced. 566: */ 567: VOID PaintServer( 568: HWND hwnd) 569: { 570: PAINTSTRUCT ps; 571: RECT rc; 572: CHAR szT[MAX_COMMENT]; 573: 574: BeginPaint(hwnd, &ps); 575: SetBkMode(ps.hdc, TRANSPARENT); 576: GetClientRect(hwnd, &rc); 577: rc.bottom = rc.top + cyText; // all rects are cyText in height. 578: 579: rcComment = rc; 580: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, pszComment); 581: 582: wsprintf(szT, "# of connections:%d", cServers); 583: rcConnCount = rc; 584: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT); 585: 586: szT[0] = '\0'; 587: rcAllBlock = rc; 588: if (fAllEnabled) 589: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "All Conversations are Enabled."); 590: else if (fAllBlocked) 591: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "All Conversations are Blocked."); 592: else 593: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT); 594: 595: rcNextAction = rc; 596: if (fBlockNextCB) 597: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "Next callback will block."); 598: else if (fTermNextCB) 599: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "Next callback will terminate."); 600: else 601: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT); 602: 603: wsprintf(szT, "Count item = %ld", count); 604: rcCount = rc; 605: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT); 606: 607: wsprintf(szT, "Rand item = %d", seed); 608: rcRand = rc; 609: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT); 610: 611: wsprintf(szT, "Huge item size = %ld", cbHuge); 612: rcHugeSize = rc; 613: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT); 614: 615: wsprintf(szT, "Render delay is %d milliseconds.", RenderDelay); 616: rcRndrDelay = rc; 617: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT); 618: 619: rcExec = rc; 620: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szExec); 621: 622: rcRunaway = rc; 623: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, cRunaway ? "Runaway active." : ""); 624: 625: rcAppowned = rc; 626: DrawTextLine(ps.hdc, &ps.rcPaint, &rc, fAppowned ? "Using AppOwned Data Handles." : ""); 627: 628: EndPaint(hwnd, &ps); 629: } 630: 631: 632: VOID DrawTextLine( 633: HDC hdc, 634: RECT *prcClip, 635: RECT *prcText, 636: PSTR psz) 637: { 638: RECT rc; 639: 640: if (IntersectRect(&rc, prcText, prcClip)) { 641: DrawText(hdc, psz, -1, prcText, 642: DT_LEFT | DT_EXTERNALLEADING | DT_SINGLELINE | DT_EXPANDTABS | 643: DT_NOCLIP | DT_NOPREFIX); 644: } 645: OffsetRect(prcText, 0, cyText); 646: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.