|
|
1.1 ! 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: ! 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); ! 136: LONG MainWndProc (HWND, UINT, DWORD, LONG); ! 137: LONG ThreadWndProc (HWND, UINT, DWORD, LONG); ! 138: LONG About (HWND, UINT, DWORD, LONG); ! 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: ! 157: int WinMain( ! 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; ! 212: wc.lpfnWndProc = MainWndProc; ! 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; ! 226: wc.lpfnWndProc = ThreadWndProc; ! 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: ! 269: long MainWndProc( ! 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, ! 394: CREATE_SUSPENDED | STANDARD_RIGHTS_REQUIRED, ! 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: ! 437: if (DialogBox(ghModule, "AboutBox", ghwndMain, About) == -1) ! 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: ! 460: long ThreadWndProc( ! 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: ! 577: long About( ! 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.