home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / THREAD.PAK / THREADS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  22.9 KB  |  820 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   threads.c
  9. //
  10. //  PURPOSE:  Window and thread procedures for the 4 threads. 
  11. //
  12. //  FUNCTIONS:
  13. //    WndProc            - Processes messages for the main window.
  14. //    MsgCommand         - Handle the WM_COMMAND messages for the main window.
  15. //    MsgCreate          - Handle the WM_CREATE message
  16. //    MsgSize            - Handle the WM_SIZE message for the main window
  17. //    MsgDestroy         - Handle the WM_DESTROY message by calling 
  18. //                         PostQuitMessage().
  19. //    CmdExit            - Handles the file exit command by calling destory 
  20. //                         window on the main window.
  21. //    ThreadChildWndProc - Window procedure for the child thread windows
  22. //    MsgSizeThread      - Process the WM_SIZE message for the child windows.
  23. //    CountThread        - Thread for counting 
  24. //    GCDThread          - Thread for computing the Greatest Common 
  25. //                         Demoniator for two numbers
  26. //    PrimeThread        - Thread for computing prime numbers.
  27. //    RectThread         - Thread for displaying random rectangles.
  28. //
  29. //  COMMENTS:
  30. //
  31.  
  32. #include <windows.h>            // required for all Windows applications
  33. #include <windowsx.h>
  34. #include "globals.h"            // prototypes specific to this application
  35. #include "resource.h"
  36.  
  37. #include <limits.h>             // for the max value stuff
  38. #include <math.h>               // for sqrt function
  39. #include <stdlib.h>             // for rand function
  40.  
  41.  
  42. // Main window message table definition.
  43. MSD rgmsd[] =
  44. {
  45.     {WM_COMMAND, MsgCommand},
  46.     {WM_DESTROY, MsgDestroy},
  47.     {WM_CREATE, MsgCreate},
  48.     {WM_CLOSE, MsgClose},
  49.     {WM_SIZE, MsgSize}
  50. };
  51.  
  52. MSDI msdiMain =
  53. {
  54.     sizeof(rgmsd) / sizeof(MSD),
  55.     rgmsd,
  56.     edwpWindow
  57. };
  58.  
  59.  
  60. // Main window command table definition.
  61. CMD rgcmd[] =
  62. {
  63.     //
  64.     // We'll go to the same function for all the thread
  65.     // state functions.  Inside CmdThreadState, we'll use 
  66.     // IDM_ to figure out which thread state we're actually
  67.     // going to set.
  68.     //
  69.     {IDM_COUNT,     CmdThreadState},
  70.     {IDM_GCD,       CmdThreadState},
  71.     {IDM_PRIME,     CmdThreadState},
  72.     {IDM_RECT,      CmdThreadState},
  73.     {IDM_EXIT,      CmdExit},
  74.     {IDM_ABOUT,     CmdAbout}
  75. };
  76.  
  77. CMDI cmdiMain =
  78. {
  79.     sizeof(rgcmd) / sizeof(CMD),
  80.     rgcmd,
  81.     edwpWindow
  82. };
  83.  
  84.  
  85. // Child window message table definition.
  86. MSD rgmsdThreadChild[] =
  87. {
  88.    {WM_SIZE, MsgSizeThread}
  89. };
  90.  
  91. MSDI msdiThreadChild =
  92. {
  93.     sizeof(rgmsdThreadChild) / sizeof(MSD),
  94.     rgmsdThreadChild,
  95.     edwpWindow
  96. };
  97.  
  98. // Array of structures for the 4 threads.  See globals.h for more 
  99. // information on this structure.
  100. // 
  101. THREADINFO ThreadInfo[4];
  102. LONG       cyChar;                    // Character height
  103. LONG       cxChar;                    // Character height
  104.  
  105. //
  106. //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
  107. //
  108. //  PURPOSE:  Processes messages for the main window.
  109. //
  110. //  PARAMETERS:
  111. //    hwnd     - window handle
  112. //    uMessage - message number
  113. //    wparam   - additional information (dependant on message number)
  114. //    lparam   - additional information (dependant on message number)
  115. //
  116. //  RETURN VALUE:
  117. //    The return value depends on the message number.  If the message
  118. //    is implemented in the message dispatch table, the return value is
  119. //    the value returned by the message handling function.  Otherwise,
  120. //    the return value is the value returned by the default window procedure.
  121. //
  122. //  COMMENTS:
  123. //    Call the DispMessage() function with the main window's message dispatch
  124. //    information (msdiMain) and the message specific information.
  125. //
  126.  
  127. LRESULT CALLBACK WndProc(HWND   hwnd, 
  128.                          UINT   uMessage, 
  129.                          WPARAM wparam, 
  130.                          LPARAM lparam)
  131. {
  132.     return DispMessage(&msdiMain, hwnd, uMessage, wparam, lparam);
  133. }
  134.  
  135. //
  136. //  FUNCTION: MsgCommand(HWND, UINT, WPARAM, LPARAM)
  137. //
  138. //  PURPOSE: Handle the WM_COMMAND messages for the main window.
  139. //
  140. //  PARAMETERS:
  141. //    hwnd     - window handle
  142. //    uMessage - WM_COMMAND (Unused)
  143. //    GET_WM_COMMAND_ID(wparam, lparam)   - Command identifier
  144. //    GET_WM_COMMAND_HWND(wparam, lparam) - Control handle
  145. //
  146. //  RETURN VALUE:
  147. //    The return value depends on the message number.  If the message
  148. //    is implemented in the message dispatch table, the return value is
  149. //    the value returned by the message handling function.  Otherwise,
  150. //    the return value is the value returned by the default window procedure.
  151. //
  152. //  COMMENTS:
  153. //    Call the DispCommand() function with the main window's command dispatch
  154. //    information (cmdiMain) and the command specific information.
  155. //
  156.  
  157. #pragma argsused
  158. LRESULT MsgCommand(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  159. {
  160.     return DispCommand(&cmdiMain, hwnd, wparam, lparam);
  161. }
  162.  
  163.  
  164. //
  165. //  FUNCTION: MsgCreate
  166. //
  167. //  PURPOSE: Handle the WM_CREATE message
  168. //
  169. //  PARAMETERS:
  170. //    hwnd     - window handle
  171. //    uMessage - WM_COMMAND (Unused)
  172. //    GET_WM_COMMAND_ID(wparam, lparam)   - Command identifier
  173. //    GET_WM_COMMAND_HWND(wparam, lparam) - Control handle
  174. //
  175. //  RETURN VALUE:
  176. //    The return value depends on the message number.  If the message
  177. //    is implemented in the message dispatch table, the return value is
  178. //    the value returned by the message handling function.  Otherwise,
  179. //    the return value is the value returned by the default window procedure.
  180. //
  181. //  COMMENTS:
  182. //    Call the DispCommand() function with the main window's command dispatch
  183. //    information (cmdiMain) and the command specific information.
  184. //
  185.  
  186. #pragma argsused
  187. LRESULT MsgCreate(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  188. {
  189.      DWORD      dwThreadID;
  190.      WNDCLASS   wc;
  191.     int        i;
  192.     char       szChildClass[9];
  193.     HDC        hdc;
  194.     TEXTMETRIC tm;
  195.     LPTHREAD_START_ROUTINE lpfnThread[4] = 
  196.                    {CountThread, GCDThread, PrimeThread, RectThread};
  197.     
  198.     // Get and store information as globals which will be used later.
  199.     hdc = GetDC(hwnd);
  200.     GetTextMetrics(hdc, &tm);
  201.     cyChar = tm.tmHeight;
  202.      cxChar = tm.tmAveCharWidth;
  203.     ReleaseDC(hwnd, hdc);
  204.  
  205.  
  206.     // Build the template for the child window class
  207.     // Get the child window class from the resource string table
  208.     LoadString(hInst, IDS_THREADCHILD, szChildClass, sizeof(szChildClass));
  209.  
  210.     // Set the class name and the window proc
  211.     wc.lpszClassName = szChildClass;
  212.     wc.style         = CS_HREDRAW | CS_VREDRAW; // Class style(s).
  213.     wc.cbClsExtra    = 0;                       // No per-class extra data.
  214.      wc.cbWndExtra    = 0;                       // No per-window extra data.
  215.     wc.hInstance     = hInst;                   // Global instance
  216.     wc.hIcon         = NULL;                    // No icon for child windows
  217.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW); // Cursor
  218.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // Default color
  219.     wc.lpszMenuName  = NULL;                    // No menu
  220.     wc.lpfnWndProc   = ThreadChildWndProc;
  221.  
  222.     // Register the child windows
  223.     RegisterClass(&wc);
  224.  
  225.     // Create the child windows
  226.      for (i = IDC_COUNT; i <= IDC_RECT ; i++)
  227.     {
  228.         // Create the window and keep track of the window
  229.         // handle in our global ThreadInfo structure.
  230.         ThreadInfo[i].hwnd = 
  231.               CreateWindow(szChildClass, 
  232.                            NULL,
  233.                            WS_CHILDWINDOW | WS_BORDER | WS_VISIBLE,
  234.                            0, 0, 0, 0,
  235.                            hwnd,
  236.                            (HMENU) i,
  237.                            hInst,
  238.                                     NULL);
  239.  
  240.         ThreadInfo[i].bThreadState  = TRUE;
  241.         ThreadInfo[i].hThread = CreateThread (NULL,
  242.                                               0,
  243.                                               lpfnThread[i],
  244.                                               NULL,
  245.                                               CREATE_SUSPENDED,
  246.                                               &dwThreadID);
  247.         SetThreadPriority(ThreadInfo[i].hThread, THREAD_PRIORITY_BELOW_NORMAL);
  248.     }
  249.     
  250.      return 0;
  251. }
  252.  
  253.  
  254. //  FUNCTION: MsgSize
  255. //
  256. //  PURPOSE: Handle the WM_SIZE message for the main window
  257. //
  258. //  PARAMETERS:
  259. //    hwnd     - window handle
  260. //    uMessage - WM_SIZE
  261. //    wparam - not used
  262. //    lparam - loword is the width, hiword the height
  263. //
  264. //  RETURN VALUE:
  265. //
  266. //  COMMENTS:
  267. //    Call the DispCommand() function with the main window's command dispatch
  268. //    information (cmdiMain) and the command specific information.
  269. //
  270. #pragma argsused
  271. LRESULT MsgSize(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  272. {
  273.     // Count window at upper left of main window's client area
  274.     MoveWindow(ThreadInfo[IDC_COUNT].hwnd,
  275.                0, 
  276.                0, 
  277.                LOWORD(lparam) / 2, 
  278.                HIWORD(lparam) / 2, 
  279.                TRUE);
  280.  
  281.     // GCD window at upper right quadrant
  282.     MoveWindow(ThreadInfo[IDC_GCD].hwnd,
  283.                LOWORD(lparam) / 2, 
  284.                0,
  285.                LOWORD(lparam) / 2, 
  286.                HIWORD(lparam) / 2,
  287.                TRUE);
  288.  
  289.     // Prime window in lower left
  290.     MoveWindow(ThreadInfo[IDC_PRIME].hwnd,
  291.                0,
  292.                     HIWORD(lparam) / 2,
  293.                LOWORD(lparam) / 2, 
  294.                HIWORD(lparam) / 2,
  295.                TRUE);
  296.  
  297.     // Put Rect window in lower left quandrant
  298.     MoveWindow(ThreadInfo[IDC_RECT].hwnd,
  299.                LOWORD(lparam) / 2, 
  300.                HIWORD(lparam) / 2,
  301.                LOWORD(lparam) / 2, 
  302.                HIWORD(lparam) / 2,
  303.                TRUE);
  304.  
  305.     return 0;
  306. }
  307.  
  308.  
  309. //  FUNCTION: MsgClose
  310. //
  311. //  PURPOSE: Handle the WM_CLOSE
  312. //
  313. //  PARAMETERS:
  314. //    hwnd     - window handle
  315. //    uMessage - WM_CLOSE
  316. //    wparam - not used
  317. //    lparam - not used
  318. //
  319. //  RETURN VALUE:
  320. //
  321. //  COMMENTS:
  322. //    This is our chance to do some clean-up before we exit.
  323. //
  324. #pragma argsused
  325. LRESULT MsgClose(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  326. {
  327.     HANDLE lpThreadHandles[4];
  328.     DWORD  fWaitResult;
  329.  
  330.     // 
  331.     // On the close of the window we need to let the threads
  332.     // stop processing. We can do that by setting the booleans
  333.     // in the ThreadInfo structures to FALSE indicating that they
  334.     // can be exited.
  335.     // 
  336.         
  337.     ThreadInfo[IDC_COUNT].bThreadState = FALSE;
  338.      ThreadInfo[IDC_GCD].bThreadState   = FALSE;
  339.     ThreadInfo[IDC_PRIME].bThreadState = FALSE;
  340.     ThreadInfo[IDC_RECT].bThreadState  = FALSE;
  341.  
  342.     // Make sure all threads are active before waiting on them!
  343.     ResumeThread(ThreadInfo[IDC_COUNT].hThread);
  344.     ResumeThread(ThreadInfo[IDC_GCD].hThread);
  345.     ResumeThread(ThreadInfo[IDC_PRIME].hThread);
  346.     ResumeThread(ThreadInfo[IDC_RECT].hThread);
  347.  
  348.     // Store all thread handles in an array that will be passed to
  349.     // WaitForMultipleObjects so that we can wait until all threads
  350.      // exit before destroying the window.
  351.     lpThreadHandles[0] = ThreadInfo[IDC_COUNT].hThread;
  352.     lpThreadHandles[1] = ThreadInfo[IDC_GCD].hThread;
  353.     lpThreadHandles[2] = ThreadInfo[IDC_PRIME].hThread;
  354.     lpThreadHandles[3] = ThreadInfo[IDC_RECT].hThread;
  355.  
  356.     // Wait until all the threads die before destroying the window.
  357.     // This is important because these threads write to children of
  358.     // this window. Note that we must wait without blocking forever
  359.     // because the threads call UpdateWindow, which sends a WM_PAINT
  360.     // to this thread's window procedure. If we wait INFINITE here,
  361.     // we won't process the WM_PAINT and we'll deadlock.  So, we'll
  362.      // sit in a nice little loop until the other threads have had
  363.     // a chance to finish.
  364.  
  365.     do
  366.     {
  367.         MSG msg;
  368.  
  369.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  370.         {
  371.             TranslateMessage(&msg);
  372.             DispatchMessage(&msg);
  373.         }
  374.  
  375.         fWaitResult = WaitForMultipleObjects (4, lpThreadHandles, TRUE, 0);
  376.     }
  377.     while (fWaitResult != WAIT_OBJECT_0);
  378.  
  379.  
  380.     DestroyWindow(hwnd);  // All children are destroyed too.
  381.  
  382.     // Don't forget to destroy all thread handles!
  383.     CloseHandle(ThreadInfo[IDC_COUNT].hThread);
  384.     CloseHandle(ThreadInfo[IDC_GCD].hThread);
  385.     CloseHandle(ThreadInfo[IDC_PRIME].hThread);
  386.      CloseHandle(ThreadInfo[IDC_RECT].hThread);
  387.    
  388.     return 0;
  389. }
  390.  
  391.  
  392. //
  393. //  FUNCTION: MsgDestroy(HWND, UINT, WPARAM, LPARAM)
  394. //
  395. //  PURPOSE: Handles the WM_DESTROY message
  396. //
  397. //  PARAMETERS:
  398. //
  399. //    hwnd      - Window handle  (Unused)
  400. //    uMessage  - WM_DESTROY
  401. //    wparam    - Extra data     (Unused)
  402. //    lparam    - Extra data     (Unused)
  403. //
  404. //  RETURN VALUE:
  405. //
  406. //    Always returns 0 - Message handled
  407. //
  408. //  COMMENTS:
  409. //
  410. //
  411.  
  412. #pragma argsused
  413. LRESULT MsgDestroy(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  414. {
  415.     PostQuitMessage(0);
  416.     return 0;
  417. }
  418.  
  419.  
  420. //
  421. //  FUNCTION: CmdThreadState(HWND, WORD, WORD, HWND)
  422. //
  423. //  PURPOSE: Start or end the count thread
  424. //
  425. //  PARAMETERS:
  426. //    hwnd     - The window.
  427. //    wCommand - One of IDM_COUNT, IDM_GCD, IDM_PRIME, IDM_RECT.
  428. //    wNotify  - Notification number (unused)
  429. //    hwndCtrl - NULL (unused)
  430. //
  431. //  RETURN VALUE:
  432. //    Always returns 0 - command handled.
  433. //
  434. //  COMMENTS:
  435. //
  436. //
  437. #pragma argsused
  438. LRESULT CmdThreadState(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  439. {
  440.      UINT mfMenuCheck;
  441.      int  nThread;
  442.  
  443.      //
  444.     // Get the correct array index by subtracting the base menu command 
  445.     // (IDM_COUNT) from wCommand.  Set mfMenuCheck to the old state of 
  446.     // the thread state indicator.  That is, if bThread state is active
  447.     // we're going to make it inactive so we need to uncheck the menu
  448.     // item.  If the thread state is inactive, we're going to change it
  449.     // to active so check to menu item.
  450.     //
  451.  
  452.     nThread = wCommand - IDM_COUNT;
  453.  
  454.     // If the menu is already checked, then the thread should be running.  We
  455.      // should then stop the thread and uncheck the menu.  However, if the menu
  456.     // is unchecked, then the thread is suspended.  We should then resume the
  457.     // thread and check the menu.
  458.     if (GetMenuState(GetMenu(hwnd), wCommand, MF_BYCOMMAND) & MF_CHECKED)
  459.     {   
  460.         SuspendThread (ThreadInfo[nThread].hThread);
  461.         mfMenuCheck = MF_UNCHECKED;
  462.     }
  463.     else
  464.     {
  465.         mfMenuCheck = MF_CHECKED;
  466.         ResumeThread (ThreadInfo[nThread].hThread);
  467.      }
  468.     
  469.     CheckMenuItem(GetMenu(hwnd), wCommand, MF_BYCOMMAND|mfMenuCheck);
  470.     
  471.     return 0;
  472. }
  473.  
  474.  
  475. //
  476. //  FUNCTION: CmdExit(HWND, WORD, WORD, HWND)
  477. //
  478. //  PURPOSE: Exit the application.
  479. //
  480. //  PARAMETERS:
  481. //    hwnd     - The window.
  482. //    wCommand - IDM_EXIT (unused)
  483. //    wNotify  - Notification number (unused)
  484. //    hwndCtrl - NULL (unused)
  485. //
  486. //  RETURN VALUE:
  487. //    Always returns 0 - command handled.
  488. //
  489. //  COMMENTS:
  490. //
  491. //
  492.  
  493. #pragma argsused
  494. LRESULT CmdExit(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  495. {
  496.     // Close the main window, and let it clean up.
  497.     SendMessage(hwnd, WM_CLOSE, 0, 0);
  498.     return 0;
  499. }
  500.  
  501.  
  502. //
  503. //  FUNCTION: ThreadChildWndProc(HWND, UINT, WPARAM, LPARAM)
  504. //
  505. //  PURPOSE:  Processes messages for child thread proc
  506. //
  507. //  PARAMETERS:
  508. //    hwnd     - window handle
  509. //    uMessage - message number
  510. //    wparam   - additional information (dependant on message number)
  511. //    lparam   - additional information (dependant on message number)
  512. //
  513. //  RETURN VALUE:
  514. //
  515. //  COMMENTS:
  516. //    Call the DispMessage() function with the main window's message dispatch
  517. //    information (msdiMain) and the message specific information.
  518. //
  519. LRESULT CALLBACK ThreadChildWndProc(HWND   hwnd, 
  520.                                     UINT   uMessage, 
  521.                                     WPARAM wparam, 
  522.                                     LPARAM lparam)
  523. {
  524.     return DispMessage(&msdiThreadChild, hwnd, uMessage, wparam, lparam);
  525. }
  526.  
  527.  
  528. //
  529. //  FUNCTION: MsgSizeThread(HWND, UINT, WPARAM, LPARAM)
  530. //
  531. //  PURPOSE:  Process the WM_SIZE message for the child windows.
  532. //
  533. //  PARAMETERS:
  534. //    hwnd     - window handle
  535. //    uMessage - WM_SIZE
  536. //    wparam   - additional information (dependant on message number)
  537. //    lparam   - additional information (dependant on message number)
  538. //
  539. //  RETURN VALUE:
  540. //
  541. //  COMMENTS:
  542. //    Call the DispMessage() function with the main window's message dispatch
  543. //    information (msdiMain) and the message specific information.
  544. //
  545. #pragma argsused
  546. LRESULT MsgSizeThread(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  547. {
  548.     int i; 
  549.  
  550.     // Find the ThreadInfo structure that corresponds to this window and
  551.     // then update its size.
  552.     for (i = IDC_COUNT; i <= IDC_RECT ; i++)
  553.     {
  554.         if (ThreadInfo[i].hwnd == hwnd)
  555.           {
  556.             ThreadInfo[i].cy = HIWORD(lparam);
  557.             ThreadInfo[i].cx = LOWORD(lparam);
  558.         }
  559.     }
  560.     
  561.     return 0;
  562. }
  563.  
  564.  
  565. //
  566. //  FUNCTION: CountThread()
  567. //
  568. //  PURPOSE:  Thread for counting 
  569. //
  570. //  PARAMETERS:
  571. //      void
  572. //
  573. //  RETURN VALUE:
  574. //
  575. //  COMMENTS:
  576. //      Nothing real fancy, just incrementing through some numbers.
  577. //
  578. //
  579. #pragma argsused
  580. DWORD WINAPI CountThread(LPVOID arg)
  581. {
  582.      int nLine = 0;
  583.     int nCount = 0;
  584.     char szCount[12];
  585.     HDC hdc;
  586.  
  587.     while (ThreadInfo[IDC_COUNT].bThreadState)
  588.     {
  589.         wsprintf(szCount, "%ld", nCount++);
  590.         hdc = GetDC(ThreadInfo[IDC_COUNT].hwnd);
  591.         TextOut(hdc, cxChar, nLine * cyChar, szCount, strlen(szCount));
  592.         ReleaseDC(ThreadInfo[IDC_COUNT].hwnd, hdc);
  593.  
  594.           if (++nLine * cyChar > (ThreadInfo[IDC_COUNT].cy))
  595.         {
  596.             nLine = 0;
  597.         }
  598.         if (nCount < 0)
  599.             nCount = 0;
  600.     }
  601.     return 0;
  602. }
  603.  
  604. //
  605. //  FUNCTION: GCDThread()
  606. //
  607. //  PURPOSE:  Thread for computing the Greatest Common Demoniator
  608. //            for two numbers
  609. //
  610. //  PARAMETERS:
  611. //      void
  612. //
  613. //  RETURN VALUE:
  614. //
  615. //  COMMENTS:
  616. //      Nothing real fancy
  617. //
  618. //
  619. #pragma argsused
  620. DWORD WINAPI GCDThread(LPVOID arg)
  621. {
  622.     int x = INT_MAX;
  623.     int y = 1;
  624.     int nMod;
  625.     int nTempx;
  626.     int nTempy;
  627.     int nLine = 0;
  628.     char szGCD[31];
  629.     HDC hdc;
  630.     RECT rc;
  631.  
  632.     GetClientRect(ThreadInfo[IDC_GCD].hwnd, &rc);
  633.  
  634.     while (ThreadInfo[IDC_GCD].bThreadState)
  635.     {
  636.         // Remember what the start values are
  637.         nTempx = x;
  638.         nTempy = y;
  639.         
  640.         //
  641.         // Iterative loop to find GCD based on Euclid's
  642.         // algorithm
  643.         //
  644.         while (nTempy)
  645.           {
  646.             nMod = nTempx % nTempy;
  647.             nTempx = nTempy;
  648.             nTempy = nMod;
  649.         }
  650.         
  651.         // Show the results
  652.         wsprintf(szGCD, "%10ld %10ld %6ld", x, y, nTempx);
  653.         hdc = GetDC(ThreadInfo[IDC_GCD].hwnd);
  654.  
  655.         rc.top = nLine * cyChar;
  656.         rc.bottom = rc.top + cyChar;
  657.  
  658.         ExtTextOut(hdc, cxChar, nLine * cyChar, ETO_OPAQUE, &rc, szGCD, strlen(szGCD), NULL);
  659.         ReleaseDC(ThreadInfo[IDC_GCD].hwnd, hdc);
  660.         // If we've reached the bottom of the display start over at the top.
  661.         if (++nLine * cyChar> (ThreadInfo[IDC_GCD].cy))
  662.         {
  663.                 nLine = 0;
  664.         }
  665.         // Decrement x and reset if we go below 1
  666.         if (--x < 1)
  667.         {
  668.             x = 1;
  669.           }
  670.  
  671.           // Increment y and reset if we go past INT_MAX
  672.           if (y == INT_MAX)
  673.           {
  674.                 y = 1;
  675.           }
  676.           else
  677.           y++;
  678.      }
  679.     return 0;
  680. }
  681.  
  682.  
  683. //
  684. //  FUNCTION: PrimeThread(void *arg)
  685. //
  686. //  PURPOSE:  Thread for computing prime numbers.
  687. //
  688. //  PARAMETERS:
  689. //      void
  690. //
  691. //  RETURN VALUE:
  692. //
  693. //  COMMENTS:
  694. //      Nothing real fancy
  695. //
  696. //
  697. #pragma argsused
  698. DWORD WINAPI PrimeThread(LPVOID arg)
  699. {
  700.      int nLine = 0;          // Line number
  701.      int nPrime = 1;         // Prime number
  702.     int nSqrtPrime;         // The square root of the prime number
  703.     int nDiv;
  704.     BOOL bPrime;            // Prime flag
  705.     char szPrime[20];       // String to hold prime number
  706.     HDC hdc;                // HDC for TextOut
  707.  
  708.     while (ThreadInfo[IDC_PRIME].bThreadState)
  709.     {
  710.         // Set the sqrt root of the number as the max div we care about. 
  711.         nSqrtPrime = (int) sqrt(nPrime);
  712.  
  713.           // Now assume that it the number is a prime number
  714.         bPrime = TRUE;
  715.  
  716.         // Now look for possible divisors
  717.         for (nDiv = 2; nDiv <= nSqrtPrime; nDiv++)
  718.         {
  719.             // If nPrime is evenly divisible then it's not a prime
  720.             if (!(nPrime % nDiv))
  721.             {
  722.                 bPrime = FALSE;
  723.                 break;
  724.             }
  725.           }
  726.  
  727.         if (bPrime)
  728.         {
  729.             wsprintf(szPrime, "%ld", nPrime);
  730.             hdc = GetDC(ThreadInfo[IDC_PRIME].hwnd);
  731.             TextOut(hdc, cxChar, nLine * cyChar, szPrime, strlen(szPrime));
  732.             ReleaseDC(ThreadInfo[IDC_PRIME].hwnd, hdc);
  733.  
  734.             if (++nLine * cyChar> (ThreadInfo[IDC_PRIME].cy))
  735.             {
  736.                 nLine = 0;
  737.                 }
  738.         }
  739.         
  740.         // Increment the prime number. Reset to 1 if it's negative
  741.         if (++nPrime < 0)
  742.         {
  743.             nPrime = 1;
  744.         }
  745.     }
  746.     return 0;
  747. }
  748.  
  749.  
  750. //
  751. //  FUNCTION: RectThread(void *arg)
  752. //
  753. //  PURPOSE:  Thread for displaying random rectangles.
  754. //
  755. //  PARAMETERS:
  756. //      void
  757. //
  758. //  RETURN VALUE:
  759. //
  760. //  COMMENTS:
  761. //      Nothing real fancy
  762. //
  763. //
  764. #pragma argsused
  765. DWORD WINAPI RectThread(LPVOID arg)
  766. {
  767.     HDC hdc;
  768.     HBRUSH hBrush, hOldBrush;
  769.     int nLeft;
  770.     int nRight;
  771.      int nTop;
  772.     int nBottom;
  773.     BYTE nRed;
  774.     BYTE nGreen = 0;
  775.     BYTE nBlue  = 0;
  776.     
  777.  
  778.     hdc = GetDC(ThreadInfo[IDC_RECT].hwnd);
  779.  
  780.     while (ThreadInfo[IDC_RECT].bThreadState)
  781.     {
  782.         //
  783.           // Make sure the coordinates of the child
  784.         // window are valid - we could be minimized.
  785.         // and we don't want to do a divide if the 
  786.         // coordinates are 0.
  787.         //
  788.         if (ThreadInfo[IDC_RECT].cx > 0 && ThreadInfo[IDC_RECT].cy > 0)
  789.         {
  790.             // Seed the coordinates for the rectangle
  791.             nLeft   = rand() % ThreadInfo[IDC_RECT].cx;
  792.             nRight  = rand() % ThreadInfo[IDC_RECT].cx;
  793.             nTop    = rand() % ThreadInfo[IDC_RECT].cy;
  794.             nBottom = rand() % ThreadInfo[IDC_RECT].cy;
  795.  
  796.             // Seed the colors for the rectangle
  797.                 nRed    = nBlue;
  798.                 nBlue   = nGreen;
  799.                 nGreen  = (BYTE) (rand() % 255);
  800.  
  801.             // Set the brush color, draw the rectangle
  802.  
  803.             hBrush = CreateSolidBrush(RGB(nRed, nGreen, nBlue));
  804.             hOldBrush = SelectObject(hdc, hBrush);
  805.             Rectangle(hdc, 
  806.                       min(nLeft, nRight),
  807.                              min(nTop, nBottom),
  808.                       max(nLeft, nRight),
  809.                       max(nTop, nBottom));
  810.  
  811.             SelectObject(hdc, hOldBrush);
  812.             DeleteObject(hBrush);
  813.         }
  814.     }
  815.  
  816.     ReleaseDC(ThreadInfo[IDC_RECT].hwnd, hdc);
  817.     return 0;
  818. }
  819.  
  820.