|
|
1.1.1.3 ! root 1: /****************************** Module Header ******************************\ ! 2: * Module Name: demo.c ! 3: * ! 4: * Copyright (c) 1991, Microsoft Corporation ! 5: * ! 6: * Yet another User test program. ! 7: * ! 8: * History: ! 9: * 04-17-90 ??????? Created. ! 10: ! 11: * 09-09-91 PetrusW Rewrote. ! 12: * create as many threads (windows) as we wish ! 13: * change the UI to MDI ! 14: \***************************************************************************/ ! 15: ! 16: ! 17: /* ******MULTI-THREADED GUIDE******** ! 18: ! 19: ! 20: There are aspects to a multi-threaded app, that need be explained, ! 21: so that a programmer understand the pitfalls of a multi-threaded app, ! 22: and avoid future problems in a multi-threaded application. ! 23: ! 24: The primary pifalls involve the usage of GDI objects. (DC's, regions, etc). ! 25: GDI is the only subsytem in NT win32, that does NOT serialize access ! 26: to its objects. This is for speed/throughput reasons. The premise ! 27: of GDI objects, is that an object is per process owned, per thread locked. ! 28: ! 29: This means if you have multiple threads, accessing the same GDI object, ! 30: you will have MAJOR headaches, because while one thread deletes an object, ! 31: the other may be using it. The model we put forward towards developers, is ! 32: the following model. ! 33: ! 34: Seperate threads for ! 35: ! 36: > Input ! 37: > File IO ! 38: > Printing ! 39: > Graphics * Note its ok to have graphics/Printing threads, because ! 40: The use a different device. ! 41: ! 42: ! 43: Note that you can be single threaded, and have no GDI object serialization ! 44: problems. What types of problems occur, is when seperate threads attempt ! 45: to delete/use a GDI object, or share an object between multiple threads. ! 46: Since an object is per thread locked, means you will get an unexpected ! 47: error within the other thread. Many windows programmers, do not expect ! 48: certain calls to ever fail, but a poorly constructed multi-threaded app ! 49: under win32 (given the above scenerios) may fail, and if not checked, ! 50: will cause subsequent GDI calls to fail, ultimately causing the GDI client ! 51: side server to die, taking the app with it. ! 52: ! 53: Thus its most important to realize that while multi-threaded apps are cool, ! 54: they must be programmed with respect to the above guidelines. ! 55: ! 56: */ ! 57: ! 58: 1.1 root 59: #include <stdlib.h> 60: 61: #include "mltithrd.h" 62: #include <stdarg.h> 63: 64: #define CCOLORS 16 65: #define CPOINTS 20 66: #define COBJS 1 67: 68: 69: /* 70: * Some handy globals. 71: */ 72: HANDLE ghModule; 73: HWND ghwndMain = NULL; 74: HBRUSH ghbrWhite, ghbrBlack; 75: HBRUSH gahbrColor[CCOLORS]; 76: int cmdDemo = 0; 77: BOOL bKillMe = FALSE; 78: 79: HMENU hMenu, hMenuWindow; 80: 81: DWORD aclr[CCOLORS] = { 82: 0x00000000, // black 83: 0x007F0000, // red 84: 0x00007F00, // green 85: 0x007F7F00, // mustard/brown 86: 0x0000007F, // blue 87: 0x007F007F, // magenta 88: 0x00007F7F, // cyan 89: 0x00BFBFBF, // light gray 90: 0x007F7F7F, // dark gray 91: 0x00FF0000, // bright red 92: 0x0000FF00, // bright green 93: 0x00FFFF00, // bright yellow 94: 0x000000FF, // bright blue 95: 0x00FF00FF, // bright magenta 96: 0x0000FFFF, // bright cyan 97: 0x00FFFFFF // bright white 98: }; 99: 100: 101: typedef struct _b { 102: POINT apt[CPOINTS]; 103: int dx; 104: int dy; 105: int vx; 106: int vy; 107: int ax; 108: int ay; 109: int iColor; 110: } B; 111: 112: 113: typedef struct _ThreadBlockInfo { 114: HANDLE hThread; 115: BOOL bKillThrd; 116: HWND hwndClient; 117: HWND hwndThreadWindow; 118: LONG lThreadId; 119: char CaptionBarText[SIZEOFCAPTIONTEXT]; 120: B gab[COBJS]; 121: RECT rcClient; 122: HDC hdcThreadWindow; 123: } THREADBLOCKINFO, *PTHREADBLOCKINFO; 124: 125: 126: typedef struct _node { 127: THREADBLOCKINFO ThreadWindow; 128: HANDLE hNext; 129: } NODE, *PNODE; 130: 131: 132: /* 133: * Forward declarations. 134: */ 135: BOOL InitializeApp (void); 1.1.1.3 ! root 136: int WINAPI MainWndProc (HWND, UINT, DWORD, LONG); ! 137: int WINAPI ThreadWndProc (HWND, UINT, DWORD, LONG); ! 138: int WINAPI About (HWND, UINT, DWORD, LONG); 1.1 root 139: 140: LONG StartBounce (PTHREADBLOCKINFO); 141: void DrawBox (int, int, HBRUSH, PTHREADBLOCKINFO); 142: void MoveBox (int *px, int *py, int *pdx, int *pdy, int *pvx, int *pvy, int ax, int ay, PTHREADBLOCKINFO pThreadBlockInfo); 143: void BounceProc (PTHREADBLOCKINFO); 144: BOOL StartDemo (int, PTHREADBLOCKINFO); 145: int GetRandomVector (); 146: void InitializeBoxes (BOOL, PTHREADBLOCKINFO); 147: 148: /***************************************************************************\ 149: * main 150: * 151: * 152: * History: 153: * 04-17-91 ??????? Created. 154: 155: \***************************************************************************/ 156: 1.1.1.3 ! root 157: int WINAPI WinMain( 1.1 root 158: HANDLE hInstance, 159: HANDLE hPrevInstance, 160: LPSTR lpCmdLine, 161: int nShowCmd) 162: { 163: MSG msg; 164: 165: // this will change to something more reasonable 166: 167: ghModule = GetModuleHandle(NULL); 168: 169: if (!InitializeApp()) { 170: MessageBox(ghwndMain, "MLTITHRD: InitializeApp failure!", "Error", MB_OK); 171: return 0; 172: } 173: 174: while (GetMessage(&msg, NULL, 0, 0)) { 175: TranslateMessage(&msg); 176: DispatchMessage(&msg); 177: } 178: 179: return 1; 180: 181: hInstance; 182: hPrevInstance; 183: lpCmdLine; 184: nShowCmd; 185: } 186: 187: 188: /***************************************************************************\ 189: * InitializeApp 190: * 191: * History: 192: * 04-17-91 ??????? Created. 193: 194: * 09-09-91 PetrusW Rewrote. 195: \***************************************************************************/ 196: 197: BOOL InitializeApp(void) 198: { 199: WNDCLASS wc; 200: int i; 201: 202: srand(51537); 203: 204: for (i = 0; i < CCOLORS; i++) { 205: gahbrColor[i] = CreateSolidBrush(aclr[i]); 206: } 207: 208: ghbrWhite = CreateSolidBrush(0x00FFFFFF); 209: ghbrBlack = CreateSolidBrush(0x00000000); 210: 211: wc.style = CS_OWNDC; 1.1.1.3 ! root 212: wc.lpfnWndProc = (WNDPROC) MainWndProc; 1.1 root 213: wc.cbClsExtra = 0; 214: wc.cbWndExtra = sizeof(LONG); 215: wc.hInstance = ghModule; 216: wc.hIcon = LoadIcon(ghModule,MAKEINTRESOURCE(APPICON)); 217: wc.hCursor = LoadCursor(NULL, IDC_ARROW); 218: wc.hbrBackground = ghbrWhite; 219: wc.lpszMenuName = "MainMenu"; 220: wc.lpszClassName = "MltithrdClass"; 221: 222: if (!RegisterClass(&wc)) 223: return FALSE; 224: 225: wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; 1.1.1.3 ! root 226: wc.lpfnWndProc = (WNDPROC) ThreadWndProc; 1.1 root 227: wc.cbClsExtra = 0; 228: wc.cbWndExtra = 0; 229: wc.hInstance = ghModule; 230: wc.hIcon = LoadIcon(ghModule,MAKEINTRESOURCE(APPICON)); 231: wc.hCursor = LoadCursor(NULL, IDC_ARROW); 232: wc.hbrBackground = ghbrWhite; 233: wc.lpszMenuName = NULL; 234: wc.lpszClassName = "ThreadClass"; 235: 236: if (!RegisterClass(&wc)) 237: return FALSE; 238: 239: hMenu = LoadMenu(ghModule, "MainMenu"); 240: hMenuWindow = GetSubMenu(hMenu, 1); 241: 242: ghwndMain = CreateWindowEx(0L, "MltithrdClass", "Mltithrd", 243: WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME | 244: WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN | 245: WS_VISIBLE | WS_SYSMENU, 246: 80, 70, 400, 300, 247: NULL, hMenu, ghModule, NULL); 248: 249: if (ghwndMain == NULL) 250: return FALSE; 251: 252: SetWindowLong(ghwndMain, GWL_USERDATA, 0L); 253: 254: SetFocus(ghwndMain); /* set initial focus */ 255: 256: return TRUE; 257: } 258: 259: 260: /***************************************************************************\ 261: * MainWndProc 262: * 263: * History: 264: * 04-17-91 ??????? Created. 265: 266: * 09-09-91 PetrusW Rewrote. 267: \***************************************************************************/ 268: 1.1.1.3 ! root 269: int WINAPI MainWndProc( 1.1 root 270: HWND hwnd, 271: UINT message, 272: DWORD wParam, 273: LONG lParam) 274: { 275: static int iCount=1; 276: static HWND hwndClient; 277: CLIENTCREATESTRUCT clientcreate; 278: HWND hwndChildWindow; 279: 280: 281: switch (message) { 282: 283: 284: case WM_CREATE: 285: SetWindowLong(hwnd, 0, (LONG)NULL); 286: 287: clientcreate.hWindowMenu = hMenuWindow; 288: clientcreate.idFirstChild = 1; 289: 290: hwndClient = CreateWindow("MDICLIENT", NULL, 291: WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, 292: 0,0,0,0, 293: hwnd, NULL, ghModule, (LPVOID)&clientcreate); 294: return 0L; 295: 296: case WM_DESTROY: { 297: HANDLE hHead, hTmp; 298: PNODE pHead; 299: 300: bKillMe = TRUE; 301: 302: hHead = (HANDLE) GetWindowLong(hwnd, 0); 303: if (hHead) { 304: if ((pHead = (PNODE) LocalLock(hHead))==NULL) 305: MessageBox(ghwndMain, "Failed in LocalLock!", "Error", MB_OK); 306: while (pHead->hNext != NULL) { 307: 308: hTmp = hHead; 309: hHead = pHead->hNext; 310: LocalUnlock(hTmp); 311: 312: if (LocalFree(hTmp)!=NULL) 313: MessageBox(ghwndMain, "Failed in LocalFree!", "Error", MB_OK); 314: if ((pHead = (PNODE) LocalLock(hHead))==NULL) 315: MessageBox(ghwndMain, "Failed in LocalLock, hHead!", "Error", MB_OK); 316: } 317: LocalUnlock(hHead); 318: 319: if (LocalFree(hHead)!=NULL) 320: MessageBox(ghwndMain, "LocalFree failed to free hHead!", "Error", MB_OK); 321: } 322: PostQuitMessage(0); 323: return 0L; 324: } 325: 326: #ifdef LATER 327: case WM_LBUTTONDOWN: 328: InitializeBoxes(TRUE, &ThreadWindow); 329: break; 330: #endif 331: 332: case WM_COMMAND: 333: 334: switch (LOWORD(wParam)) { 335: case IDM_TILE: 336: SendMessage(hwndClient, WM_MDITILE, 0L, 0L); 337: return 0L; 338: case IDM_CASCADE: 339: SendMessage(hwndClient, WM_MDICASCADE, 0L, 0L); 340: return 0L; 341: case IDM_ARRANGE: 342: SendMessage(hwndClient, WM_MDIICONARRANGE, 0L, 0L); 343: return 0L; 344: case MM_BOUNCE: { 345: HANDLE hNode, hHead; 346: HANDLE hThrd; 347: PNODE pNode; 348: MDICREATESTRUCT mdicreate; 349: 350: hNode = LocalAlloc(LHND, (WORD) sizeof(NODE)); 351: if (hNode) { 352: if ((pNode = (PNODE)LocalLock(hNode))==NULL) 353: MessageBox(ghwndMain, "Failed in LocalLock, hNode!", "Error", MB_OK); 354: 355: wsprintf((LPSTR)&(pNode->ThreadWindow.CaptionBarText), "Thread Window %d", iCount); 356: 357: mdicreate.szClass = "ThreadClass"; 358: mdicreate.szTitle = (LPSTR)&(pNode->ThreadWindow.CaptionBarText); 359: mdicreate.hOwner = ghModule; 360: mdicreate.x = 361: mdicreate.y = 362: mdicreate.cx = 363: mdicreate.cy = CW_USEDEFAULT; 364: mdicreate.style = 0l; 365: mdicreate.lParam = 0L; 366: 367: /*Create Child Window*/ 368: hwndChildWindow = (HANDLE) SendMessage(hwndClient, WM_MDICREATE, 369: 0L, 370: (LONG)(LPMDICREATESTRUCT)&mdicreate); 371: 372: if (hwndChildWindow == NULL) { 373: MessageBox(ghwndMain, "Failed in Creating Thread Window!", "Error", MB_OK); 374: return 0L; 375: } 376: 377: // This stuff is here for simplicity. Initialization should 378: // be done in StartDemo 379: pNode->ThreadWindow.hwndClient = hwndClient; 380: pNode->ThreadWindow.hwndThreadWindow = hwndChildWindow; 381: hHead = (HANDLE)GetWindowLong(hwnd, 0); 382: pNode->hNext = hHead; 383: SetWindowLong(hwnd, 0, (LONG) hNode); 384: 385: // Create the thread suspended so we can alter its priority 386: 387: // before it begins to run. 388: 389: 390: 391: hThrd = CreateThread(NULL, 0, 392: (LPTHREAD_START_ROUTINE)StartBounce, 393: &pNode->ThreadWindow, 1.1.1.3 ! root 394: CREATE_SUSPENDED, 1.1 root 395: 396: (LPDWORD) &pNode->ThreadWindow.lThreadId ); 397: if (hThrd) { 398: 399: // I really don't need this info, it won't even be 400: // updated right the way for this thread will be 401: // preempted. 402: pNode->ThreadWindow.hThread = hThrd; 403: iCount++; 404: 405: 406: // This way the primary (input) thread will be higher priority 407: 408: // than the bouncers, thus keeping MLTITHRD responsive to user 409: 410: // input. 411: 412: 413: 414: SetThreadPriority(hThrd, THREAD_PRIORITY_BELOW_NORMAL); 415: 416: 417: 418: // Everything's set, let it go. 419: 420: 421: 422: ResumeThread(hThrd); 423: 424: 425: } else { 426: MessageBox(ghwndMain, "Create Thread Failed!", "Error", MB_OK); 427: } 428: LocalUnlock(hNode); 429: 430: } else { 431: MessageBox(ghwndMain, "Failed to Allocate Node!", "Error", MB_OK); 432: } 433: return 0L; 434: } 435: 436: case MM_ABOUT: 1.1.1.3 ! root 437: if (DialogBox(ghModule, "AboutBox", ghwndMain, About) == -1) 1.1 root 438: MessageBox(ghwndMain, "Mltithrd: About Dialog Creation Error!", "Error", MB_OK); 439: return 0L; 440: 441: default: 442: return DefFrameProc(hwnd, hwndClient, message, wParam, lParam); 443: } 444: 445: default: 446: 447: return DefFrameProc(hwnd, hwndClient, message, wParam, lParam); 448: } 449: } 450: 451: /********************************************************************\ 452: * ThreadWndProc 453: * 454: * History: 455: * 04-17-91 ??????? Created. 456: 457: * 09-09-91 PetrusW Rewrote. 458: \***************************************************************************/ 459: 1.1.1.3 ! root 460: int WINAPI ThreadWndProc( 1.1 root 461: HWND hwnd, 462: UINT message, 463: DWORD wParam, 464: LONG lParam) 465: { 466: switch (message) { 467: case WM_SIZE: 468: 469: case WM_CREATE: { 470: PTHREADBLOCKINFO pThreadBlockInfo; 471: PNODE pHead; 472: HANDLE hHead, hTmp; 473: 474: 475: 476: // now find match 477: hHead = (HANDLE) GetWindowLong(ghwndMain, 0); 478: if (hHead) { 479: if ((pHead = (PNODE)LocalLock(hHead))==NULL) 480: MessageBox(ghwndMain, "Failed in LocalLock!", "Error", MB_OK); 481: 482: while ((pHead->ThreadWindow.hwndThreadWindow != hwnd) && 483: (pHead->hNext != NULL)) { 484: hTmp = hHead; 485: hHead = pHead->hNext; 486: LocalUnlock(hTmp); 487: 488: if ((pHead = (PNODE) LocalLock(hHead))==NULL) 489: MessageBox(ghwndMain, "Failed in LocalLock!", "Error", MB_OK); 490: } 491: if (pHead->ThreadWindow.hwndThreadWindow == hwnd) { 492: pThreadBlockInfo = &pHead->ThreadWindow; 493: goto Thread_Found; 494: } else { 495: //MessageBox(ghwndMain, "Trouble - Can't find the thread node!", "Error", MB_OK); 496: goto Thread_Out; 497: } 498: 499: Thread_Found: 500: if (!GetClientRect(pThreadBlockInfo->hwndThreadWindow, 501: &pThreadBlockInfo->rcClient)) 502: MessageBox(ghwndMain, "Failed in GetClientRect!", "Error", MB_OK); 503: Thread_Out: 504: LocalUnlock(hHead); 505: 506: return DefMDIChildProc(hwnd, message, wParam, lParam); 507: } else { 508: //MessageBox(ghwndMain, "Can't GetWindowLong(ghwndMain,0) !", "Error", MB_OK); 509: } return DefMDIChildProc(hwnd, message, wParam, lParam); 510: } 511: 512: case WM_CLOSE: { 513: PTHREADBLOCKINFO pThreadBlockInfo; 514: PNODE pHead; 515: HANDLE hHead, hTmp; 516: 517: 518: 519: // now find match 520: hHead = (HANDLE) GetWindowLong(ghwndMain, 0); 521: if (hHead) { 522: if ((pHead = (PNODE)LocalLock(hHead))==NULL) 523: MessageBox(ghwndMain, "Failed in LocalLock!", "Error", MB_OK); 524: 525: while ((pHead->ThreadWindow.hwndThreadWindow != hwnd) && 526: (pHead->hNext != NULL)) { 527: hTmp = hHead; 528: hHead = pHead->hNext; 529: LocalUnlock(hTmp); 530: 531: if ((pHead = (PNODE) LocalLock(hHead))==NULL) 532: MessageBox(ghwndMain, "Failed in LocalLock!", "Error", MB_OK); 533: } 534: if (pHead->ThreadWindow.hwndThreadWindow == hwnd) { 535: pThreadBlockInfo = &pHead->ThreadWindow; 536: goto Thread_Found1; 537: } else { 538: //MessageBox(ghwndMain, "Trouble - Can't find the thread node!", "Error", MB_OK); 539: goto Thread_Out1; 540: } 541: 542: Thread_Found1: 543: pThreadBlockInfo->bKillThrd = TRUE; 544: 545: Thread_Out1: 546: LocalUnlock(hHead); 547: 548: } else { 549: //MessageBox(ghwndMain, "Can't GetWindowLong(ghwndMain,0) !", "Error", MB_OK); 550: } 551: return DefMDIChildProc(hwnd, message, wParam, lParam); 552: } 553: 554: case WM_DESTROY: 555: 556: 557: return 0L; 558: 559: default: 560: return DefMDIChildProc(hwnd, message, wParam, lParam); 561: } 562: 563: } 564: 565: 566: /***************************************************************************\ 567: * About 568: * 569: * About dialog proc. 570: * 571: * History: 572: * 04-13-91 ??????? Created. 573: 574: * 09-09-91 PetrusW Rewrote. 575: \***************************************************************************/ 576: 1.1.1.3 ! root 577: int WINAPI About( 1.1 root 578: HWND hDlg, 579: UINT message, 580: DWORD wParam, 581: LONG lParam) 582: { 583: switch (message) { 584: case WM_INITDIALOG: 585: return TRUE; 586: 587: case WM_COMMAND: 588: if (wParam == IDOK) 589: EndDialog(hDlg, wParam); 590: break; 591: } 592: 593: return FALSE; 594: 595: lParam; 596: hDlg; 597: } 598: 599: long StartBounce(PTHREADBLOCKINFO pThreadBlockInfo) 600: { 601: if (!StartDemo(MM_BOUNCE, pThreadBlockInfo)) 602: return(0); 603: 604: cmdDemo = MM_BOUNCE; 605: /* Here everythings been initialized, ThreadBlockINfo, etc*/ 606: /* Now loop and call BounceProc to draw and move boxes*/ 607: 608: /* NOTE NOTE, each thread MUST have its own message loop!*/ 609: 610: while (TRUE) { 611: 612: if (!bKillMe && !pThreadBlockInfo->bKillThrd) { 613: BounceProc(pThreadBlockInfo); 614: } else { 615: break; 616: } 617: } 618: 619: 620: ExitThread(0); 621: if (!CloseHandle(pThreadBlockInfo->hThread)) 622: MessageBox(ghwndMain, "Failed in CloseHandle!", "Error", MB_OK); 623: } 624: 625: 626: BOOL StartDemo( 627: int cmd, 628: PTHREADBLOCKINFO pThreadBlockInfo) 629: { 630: 631: // Initializing the rcClient for the bouncing box 632: // Better be initializing here for once CreateThread is called, this 633: // thread got the time slice; parent thread is preempted. 634: if (!GetClientRect(pThreadBlockInfo->hwndThreadWindow, 635: &pThreadBlockInfo->rcClient)) 636: MessageBox(ghwndMain, "Failed in GetClientRect!", "Error", MB_OK); 637: pThreadBlockInfo->bKillThrd = FALSE; 638: 639: InitializeBoxes(FALSE, pThreadBlockInfo); 640: 641: return TRUE; 642: UNREFERENCED_PARAMETER(cmd); 643: } 644: 645: 646: void InitializeBoxes( 647: BOOL fVectorsOnly, 648: PTHREADBLOCKINFO pThreadBlockInfo) 649: { 650: int j; 651: int i; 652: 653: /* 654: * Initialize bounce arrays... 655: */ 656: for (i = 0; i < COBJS; i++) { 657: 658: if (!fVectorsOnly) { 659: for (j = 0; j < CPOINTS; j++) { 660: pThreadBlockInfo->gab[i].apt[j].x = 0; 661: pThreadBlockInfo->gab[i].apt[j].y = 0; 662: } 663: pThreadBlockInfo->gab[i].iColor = 0; 664: } 665: 666: if (GetRandomVector() <= 3) { 667: if (GetRandomVector() >= 4) { 668: pThreadBlockInfo->gab[i].vx = 4; 669: } else { 670: pThreadBlockInfo->gab[i].vx = 1; 671: } 672: 673: pThreadBlockInfo->gab[i].vy = GetRandomVector(); 674: } else { 675: if (GetRandomVector() >= 4) { 676: pThreadBlockInfo->gab[i].vy = 4; 677: } else { 678: pThreadBlockInfo->gab[i].vy = 1; 679: } 680: 681: pThreadBlockInfo->gab[i].vx = GetRandomVector(); 682: } 683: 684: pThreadBlockInfo->gab[i].dx = pThreadBlockInfo->gab[i].vx; 685: pThreadBlockInfo->gab[i].dy = pThreadBlockInfo->gab[i].vy; 686: 687: pThreadBlockInfo->gab[i].ax = GetRandomVector() + 3; 688: pThreadBlockInfo->gab[i].ay = GetRandomVector() + 3; 689: } 690: } 691: 692: int GetRandomVector() 693: { 694: /* 695: * Returns a number between 1 and 6. 696: */ 697: return (rand() % 6) + 1; 698: } 699: 700: void BounceProc( PTHREADBLOCKINFO pThreadBlockInfo) 701: { 702: int i; 703: LONG lCurrentThreadId; 704: 705: #ifdef LATER 706: // not erasing looks cool 707: /* 708: * Erase... 709: */ 710: for (i = 0; i < COBJS; i++) 711: DrawBox(gab[i].apt[0].x, gab[i].apt[0].y, ghbrWhite); 712: #endif 713: 714: 715: /* 716: * Move, and bounce on wall 717: */ 718: for (i = 0; i < COBJS; i++) 719: MoveBox((int *)&pThreadBlockInfo->gab[i].apt[0].x, (int *)&pThreadBlockInfo->gab[i].apt[0].y, 720: (int *)&pThreadBlockInfo->gab[i].dx, (int *)&pThreadBlockInfo->gab[i].dy, 721: (int *)&pThreadBlockInfo->gab[i].vx, (int *)&pThreadBlockInfo->gab[i].vy, 722: (int)pThreadBlockInfo->gab[i].ax, (int)pThreadBlockInfo->gab[i].ay, pThreadBlockInfo); 723: 724: /* 725: * Draw new... 726: */ 727: for (i = 0; i < COBJS; i++) { 728: DrawBox(pThreadBlockInfo->gab[i].apt[0].x, pThreadBlockInfo->gab[i].apt[0].y, 729: gahbrColor[pThreadBlockInfo->gab[i].iColor++ % CCOLORS], pThreadBlockInfo); 730: } 731: 732: UNREFERENCED_PARAMETER(lCurrentThreadId); 733: } 734: 735: void DrawBox( 736: int x, 737: int y, 738: HBRUSH hbr, 739: PTHREADBLOCKINFO pThreadBlockInfo) 740: { 741: HBRUSH hbrOld; 742: 743: pThreadBlockInfo->hdcThreadWindow = 744: GetDC(pThreadBlockInfo->hwndThreadWindow); 745: if (pThreadBlockInfo->hdcThreadWindow) { 746: if ((hbrOld = SelectObject(pThreadBlockInfo->hdcThreadWindow, hbr))==0) 747: MessageBox(ghwndMain, "Failed in SelectObject!", "Error", MB_OK); 748: if (!BitBlt(pThreadBlockInfo->hdcThreadWindow, x, y, 20, 20, NULL, 0, 0, PATCOPY)) 749: MessageBox(ghwndMain, "Failed in BitBlt!", "Error", MB_OK); 750: if (SelectObject(pThreadBlockInfo->hdcThreadWindow, hbrOld)==0) 751: MessageBox(ghwndMain, "Failed in SelectObject!", "Error", MB_OK); 752: if (ReleaseDC(pThreadBlockInfo->hwndThreadWindow, pThreadBlockInfo->hdcThreadWindow)==0) 753: MessageBox(ghwndMain, "Failed in ReleaseDC!", "Error", MB_OK); 754: } else { 755: MessageBox(ghwndMain, "Failed in GetDC!", "Error", MB_OK); 756: } 757: } 758: 759: void MoveBox( 760: int *px, 761: int *py, 762: int *pdx, 763: int *pdy, 764: int *pvx, 765: int *pvy, 766: int ax, 767: int ay, 768: PTHREADBLOCKINFO pThreadBlockInfo) 769: { 770: 771: (*pdx)--; 772: if (*pdx == 0) { 773: *px -= ax; 774: *pdx = *pvx; 775: } else if (*pdx == 3) { 776: *px += ax; 777: *pdx = *pvx; 778: } 779: 780: (*pdy)--; 781: if (*pdy == 0) { 782: *py -= ay; 783: *pdy = *pvy; 784: } else if (*pdy == 3) { 785: *py += ay; 786: *pdy = *pvy; 787: } 788: 789: if (*px < pThreadBlockInfo->rcClient.left) { 790: *px = pThreadBlockInfo->rcClient.left; 791: 792: if (*pvx >= 4) 793: *pvx -= 3; 794: else 795: *pvx += 3; 796: 797: *pdx = *pvx; 798: } 799: 800: if (*px > (pThreadBlockInfo->rcClient.right - 20)) { 801: *px = pThreadBlockInfo->rcClient.right - 20; 802: 803: if (*pvx >= 4) 804: *pvx -= 3; 805: else 806: *pvx += 3; 807: 808: *pdx = *pvx; 809: } 810: 811: if (*py < pThreadBlockInfo->rcClient.top) { 812: *py = pThreadBlockInfo->rcClient.top; 813: 814: if (*pvy >= 4) 815: *pvy -= 3; 816: else 817: *pvy += 3; 818: 819: *pdy = *pvy; 820: } 821: 822: if (*py > (pThreadBlockInfo->rcClient.bottom - 20)) { 823: *py = pThreadBlockInfo->rcClient.bottom - 20; 824: 825: if (*pvy >= 4) 826: *pvy -= 3; 827: else 828: *pvy += 3; 829: 830: *pdy = *pvy; 831: } 832: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.