home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / advanced / mtgdi / mtgdivw.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  8.0 KB  |  346 lines

  1. // mtgdivw.cpp : implementation of the CThreadView class
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "mtgdi.h"
  15.  
  16. #include "mtgdidoc.h"
  17. #include "mtgdivw.h"
  18.  
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char BASED_CODE THIS_FILE[] = __FILE__;
  22. #endif
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CThreadView
  26.  
  27. IMPLEMENT_DYNCREATE(CThreadView, CView)
  28.  
  29. BEGIN_MESSAGE_MAP(CThreadView, CView)
  30.     //{{AFX_MSG_MAP(CThreadView)
  31.     ON_COMMAND(ID_THREAD_NEWBALL, OnNewball)
  32.     ON_COMMAND(ID_THREAD_KILLTHREADS, OnKillThreads)
  33.     ON_WM_DESTROY()
  34.     ON_COMMAND(ID_THREAD_NEWLINE, OnNewline)
  35.     ON_COMMAND(ID_THREAD_NEWRECTANGLE, OnNewrectangle)
  36.     ON_COMMAND(ID_THREAD_10NEWBALLS, On10newballs)
  37.     ON_COMMAND(ID_THREAD_10NEWLINES, On10newlines)
  38.     ON_COMMAND(ID_THREAD_10NEWRECTANGLES, On10newrectangles)
  39.     ON_WM_CREATE()
  40.     ON_WM_SIZE()
  41.     ON_COMMAND(ID_THREAD_25NEWBALLS, On25newballs)
  42.     ON_COMMAND(ID_THREAD_25NEWLINES, On25newlines)
  43.     ON_COMMAND(ID_THREAD_25NEWRECTANGLES, On25newrectangles)
  44.     ON_COMMAND(ID_THREAD_KILLTHREADSSLOW, OnThreadKillThreadsSlow)
  45.     //}}AFX_MSG_MAP
  46. END_MESSAGE_MAP()
  47.  
  48. /////////////////////////////////////////////////////////////////////////////
  49. // CThreadView construction/destruction
  50.  
  51. CThreadView::CThreadView()
  52. {
  53.     m_pDC = NULL;
  54. }
  55.  
  56. CThreadView::~CThreadView()
  57. {
  58. }
  59.  
  60. void CThreadView::UpdateTitle(int nThreads)
  61. {
  62.     if (nThreads == -1)
  63.         nThreads = m_threadList.GetCount();
  64.  
  65.     CString strCaption;
  66.     if (nThreads != 0)
  67.     {
  68.         CString strFormat; strFormat.LoadString(IDS_CAPTION_FORMAT);
  69.         strCaption.Format(strFormat, nThreads);
  70.     }
  71.     else
  72.         strCaption.LoadString(IDS_CAPTION_NOTHREADS);
  73.  
  74.     GetParentFrame()->SetWindowText(strCaption);
  75. }
  76.  
  77. void CThreadView::StartThread(int ThreadID)
  78. {
  79.     CGDIThread* pThread;
  80.     CPoint Pos(rand()%100,rand()%100);
  81.     CPoint Vel1((rand()%10)+2,(rand()%10)+2);
  82.     CPoint Vel2((rand()%5)+2,(rand()%5)+2);
  83.     CSize Size(((rand()%60)+20),((rand()%60)+20));
  84.     COLORREF Color;
  85.  
  86.     //BLOCK: calculate random color
  87.     {
  88.         int r,g,b;
  89.  
  90.         do
  91.         {
  92.             r = (rand()%3);
  93.             r = (r!=0) ? (r==2) ? 255 : 127 : 0;
  94.  
  95.             g = (rand()%3);
  96.             g = (g!=0) ? (g==2) ? 255 : 127 : 0;
  97.  
  98.             b = (rand()%3);
  99.             b = (b!=0) ? (b==2) ? 255 : 127 : 0;
  100.         }
  101.         while ((r==g) && (g==b));
  102.         // No white(255,255,255), gray(127,127,127), or black(0,0,0) allowed
  103.  
  104.         Color = RGB(r,g,b);
  105.     }
  106.  
  107.     if (rand()%1) Vel1.x*=-1;
  108.     if (rand()%1) Vel1.y*=-1;
  109.     if (rand()%1) Vel2.x*=-1;
  110.     if (rand()%1) Vel2.y*=-1;
  111.  
  112.     switch(ThreadID)
  113.     {
  114.     case 1:
  115.         pThread = new CBallThread(this,
  116.             m_pDC->GetSafeHdc(), Pos, Vel1, Size, Color);
  117.         break;
  118.     case 2:
  119.         pThread = new CRectThread(this,
  120.             m_pDC->GetSafeHdc(), Pos, Vel1, Size, Color);
  121.         break;
  122.     case 3:
  123.         pThread = new CLineThread(this,
  124.             m_pDC->GetSafeHdc(), Pos, Vel1, Vel2, Size, Color);
  125.         break;
  126.     }
  127.  
  128.     if (pThread == NULL)
  129.         return;
  130.  
  131.     ASSERT_VALID(pThread);
  132.     pThread->m_pThreadParams = NULL;
  133.  
  134.     // Create Thread in a suspended state so we can set the Priority
  135.     // before it starts getting away from us
  136.     if (!pThread->CreateThread(CREATE_SUSPENDED))
  137.     {
  138.         delete pThread;
  139.         return;
  140.     }
  141.  
  142.     // since everything is successful, add the thread to our list
  143.     m_threadList.AddTail(pThread);
  144.  
  145.     // If you want to make the sample more sprightly, set the thread priority here
  146.     // a little higher. It has been set at idle priority to keep from bogging down
  147.     // other apps that may also be running.
  148.     VERIFY(pThread->SetThreadPriority(THREAD_PRIORITY_IDLE));
  149.     // Now the thread can run wild
  150.     pThread->ResumeThread();
  151. }
  152.  
  153. void CThreadView::OnDraw(CDC*)
  154. {
  155. }
  156.  
  157. /////////////////////////////////////////////////////////////////////////////
  158. // CThreadView diagnostics
  159.  
  160. #ifdef _DEBUG
  161. void CThreadView::AssertValid() const
  162. {
  163.     CView::AssertValid();
  164. }
  165.  
  166. void CThreadView::Dump(CDumpContext& dc) const
  167. {
  168.     CView::Dump(dc);
  169. }
  170.  
  171. CThreadDoc* CThreadView::GetDocument() // non-debug version is inline
  172. {
  173.     return STATIC_DOWNCAST(CThreadDoc, m_pDocument);
  174. }
  175. #endif //_DEBUG
  176.  
  177. /////////////////////////////////////////////////////////////////////////////
  178. // CThreadView message handlers
  179.  
  180. void CThreadView::OnNewball()
  181. {
  182.     StartThread(1);
  183.     UpdateTitle();
  184. }
  185.  
  186. void CThreadView::On10newballs()
  187. {
  188.     for (int i = 0; i < 10; i++)
  189.     {
  190.         StartThread(1);
  191.         UpdateTitle();
  192.     }
  193. }
  194.  
  195. void CThreadView::On25newballs()
  196. {
  197.     for (int i = 0; i < 25; i++)
  198.     {
  199.         StartThread(1);
  200.         UpdateTitle();
  201.     }
  202. }
  203.  
  204. void CThreadView::OnNewrectangle()
  205. {
  206.     StartThread(2);
  207.     UpdateTitle();
  208. }
  209.  
  210. void CThreadView::On10newrectangles()
  211. {
  212.     for (int i = 0; i < 10; i++)
  213.     {
  214.         StartThread(2);
  215.         UpdateTitle();
  216.     }
  217. }
  218.  
  219. void CThreadView::On25newrectangles()
  220. {
  221.     for (int i = 0; i < 25; i++)
  222.     {
  223.         StartThread(2);
  224.         UpdateTitle();
  225.     }
  226. }
  227.  
  228. void CThreadView::OnNewline()
  229. {
  230.     StartThread(3);
  231.     UpdateTitle();
  232. }
  233.  
  234. void CThreadView::On10newlines()
  235. {
  236.     for (int i = 0 ;i < 10; i++)
  237.     {
  238.         StartThread(3);
  239.         UpdateTitle();
  240.     }
  241. }
  242.  
  243. void CThreadView::On25newlines()
  244. {
  245.     for (int i = 0; i < 25; i++)
  246.     {
  247.         StartThread(3);
  248.         UpdateTitle();
  249.     }
  250. }
  251.  
  252. // A preferred method for killing many threads.  Tell them to go away all
  253. // at once, then wait for them all to be scheduled and to terminate
  254. // themselves.  This is much, much faster than the more straight forward
  255. // way of asking just one to terminate, then waiting for it to do so.
  256. // It is also a little bit more complex.
  257.  
  258. void CThreadView::OnKillThreads()
  259. {
  260.     // tell all threads to shutdown
  261.     for (POSITION pos = m_threadList.GetHeadPosition(); pos != NULL; )
  262.     {
  263.         CGDIThread* pThread = m_threadList.GetNext(pos);
  264.         VERIFY(SetEvent(pThread->m_hEventKill));
  265.     }
  266.  
  267.     // wait for all threads to finish shutdown
  268.     for (int nThreadsLeft = m_threadList.GetCount(); nThreadsLeft != 0; )
  269.     {
  270.         WaitForSingleObject(CGDIThread::m_hAnotherDead, INFINITE);
  271.         Sleep(nThreadsLeft*2);// 200ms for every 100 threads
  272.         nThreadsLeft = 0;
  273.         for (pos = m_threadList.GetHeadPosition(); pos != NULL; )
  274.         {
  275.             CGDIThread* pThread = m_threadList.GetNext(pos);
  276.             if (WaitForSingleObject(pThread->m_hEventDead, 0) == WAIT_TIMEOUT)
  277.                 ++nThreadsLeft;
  278.         }
  279.         UpdateTitle(nThreadsLeft);
  280.     }
  281.  
  282.     // delete all thread objects
  283.     while (!m_threadList.IsEmpty())
  284.     {
  285.         CGDIThread* pThread = m_threadList.RemoveHead();
  286.         VERIFY(WaitForSingleObject(pThread->m_hThread, INFINITE) == WAIT_OBJECT_0);
  287.         delete pThread;
  288.     }
  289.     UpdateTitle();
  290.  
  291.     // invalidate the window since all threads are now gone
  292.     Invalidate();
  293. }
  294.  
  295. // KillThreadsSlow is much easier to understand since the process of
  296. // killing a thread is encapsulated in KillThread.  If you get more
  297. // than 50 threads running, however, you'll notice quite a difference
  298. // between this method and the one above.
  299.  
  300. void CThreadView::OnThreadKillThreadsSlow()
  301. {
  302.     // Iterate through the threads killing each
  303.     // KillThread doesn't return until the Thread is dead
  304.     while (!m_threadList.IsEmpty())
  305.     {
  306.         m_threadList.RemoveHead()->KillThread();
  307.         UpdateTitle();
  308.     }
  309.  
  310.     // Invalidate the window so it blanks the window
  311.     Invalidate();
  312. }
  313.  
  314. void CThreadView::OnDestroy()
  315. {
  316.     OnKillThreads();
  317.  
  318.     delete m_pDC;
  319.     m_pDC = NULL;
  320.  
  321.     CView::OnDestroy();
  322. }
  323.  
  324. int CThreadView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  325. {
  326.     if (CView::OnCreate(lpCreateStruct) == -1)
  327.         return -1;
  328.  
  329.     // m_pDC must be initialized here instead of the constructor
  330.     // because the HWND isn't created until Create is called.
  331.     m_pDC = new CClientDC(this);
  332.     UpdateTitle();
  333.  
  334.     return 0;
  335. }
  336.  
  337. void CThreadView::OnSize(UINT nType, int cx, int cy)
  338. {
  339.     CView::OnSize(nType, cx, cy);
  340.  
  341.     // Instead of getting the client rect every time we draw, we only
  342.     // update it when it changes.
  343.     for (POSITION pos = m_threadList.GetHeadPosition(); pos != NULL; )
  344.         m_threadList.GetNext(pos)->UpdateBorder();
  345. }
  346.