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