home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / tutsamp / freclien / guiball.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-05  |  13.0 KB  |  427 lines

  1. /*+==========================================================================
  2.   File:      GUIBALL.CPP
  3.  
  4.   Summary:   Implementation file for the CGuiBall C++ class. A GuiBall is
  5.              a C++ object that uses three independent worker threads to
  6.              display a moving and bouncing ball in the client area of a
  7.              designated window.  It is anchored to the Windows GUI
  8.              (Graphical User Interface) environment. This GuiBall object
  9.              continuously paints a ball image based on data it obtains
  10.              from a virtual ball object. This virtual ball object is
  11.              instantiated as a COM object (a COBall) in a separate
  12.              thread-safe In-process server.
  13.  
  14.              GuiBall launches three threads which all continuously and
  15.              asynchronously command the ball to move. GuiBall itself
  16.              provides methods to initialize the GuiBall, paint the ball
  17.              image, and restart the motion. The cool thing about this
  18.              arrangement between client and server is that the ball
  19.              changes color as it moves. The ball color indicates the
  20.              thread that last moved the ball. This gives a visual
  21.              impact to multi-threading.
  22.  
  23.              For a comprehensive tutorial code tour of GUIBALL's contents
  24.              and offerings see the tutorial FRECLIEN.HTM file. For more
  25.              specific technical details on the internal workings see the
  26.              comments dispersed throughout the GUIBALL source code.
  27.  
  28.   Classes:   CThreadInitData, CGuiBall
  29.  
  30.   Origin:    4-5-96: atrent - Created for COM Tutorial Code Samples.
  31.              Also benefits from the GDIDEMO sample in the Win32 samples of
  32.              the Win32 SDK.
  33.  
  34. ----------------------------------------------------------------------------
  35.   This file is part of the Microsoft COM Tutorial Code Samples.
  36.  
  37.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  38.  
  39.   This source code is intended only as a supplement to Microsoft
  40.   Development Tools and/or on-line documentation.  See these other
  41.   materials for detailed information regarding Microsoft code samples.
  42.  
  43.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  44.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  45.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  46.   PARTICULAR PURPOSE.
  47. ==========================================================================+*/
  48.  
  49. /*--------------------------------------------------------------------------
  50.   We include WINDOWS.H for all Win32 applications.
  51.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  52.   We include APPUTIL.H because we will be building this application using
  53.     the convenient Virtual Window and Dialog classes and other
  54.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  55.   We include IBALL.H and BALLGUID.H for the common Ball-related Interface
  56.     class, GUID, and CLSID specifications.
  57.   We include GUIBALL.H because it has the C++ class used for GUI display
  58.     of the moving ball.
  59. ---------------------------------------------------------------------------*/
  60. #include <windows.h>
  61. #include <ole2.h>
  62. #include <apputil.h>
  63. #include <iball.h>
  64. #include <ballguid.h>
  65. #include "guiball.h"
  66. #include "freclien.h"
  67.  
  68.  
  69. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  70.   Method:   CGuiBall::CGuiBall
  71.  
  72.   Summary:  Constructor.
  73.  
  74.   Args:     void
  75.  
  76.   Modifies: ...
  77.  
  78.   Returns:  void
  79. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  80. CGuiBall::CGuiBall(void)
  81. {
  82.   m_hWnd    = 0;
  83.   m_pIBall  = NULL;
  84.   m_crColor = RGB(0,0,0);
  85.   m_dwBallThread1 = 0;
  86.   m_dwBallThread2 = 0;
  87.   m_dwBallThread3 = 0;
  88.   m_hBallThreads[0] = 0;
  89.   m_hBallThreads[1] = 0;
  90.   m_hBallThreads[2] = 0;
  91. }
  92.  
  93.  
  94. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  95.   Method:   CGuiBall::~CGuiBall
  96.  
  97.   Summary:  Destructor.
  98.  
  99.   Args:     void
  100.  
  101.   Modifies: ...
  102.  
  103.   Returns:  void
  104. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  105. CGuiBall::~CGuiBall(void)
  106. {
  107.   BOOL bOk = TRUE;
  108.  
  109.   if (m_pIBall)
  110.   {
  111.     // Kill the client's app timer for its repaints.
  112.     KillTimer(m_hWnd, 1);
  113.  
  114.     // Call down to the server's COBall and tell it to shutdown.
  115.     m_pIBall->Move(FALSE);
  116.  
  117.     // Wait for the threads to terminate before closing their thread handles.
  118.     WaitForMultipleObjects(3, m_hBallThreads, TRUE, INFINITE);
  119.     for (size_t i = 0; i<3; i++)
  120.       CloseHandle(m_hBallThreads[i]);
  121.  
  122.     // Release for each of the thread copies handed out.
  123.     m_pIBall->Release();
  124.     m_pIBall->Release();
  125.     m_pIBall->Release();
  126.     // Do final Release for the main copy held in CGuiBall.
  127.     RELEASE_INTERFACE(m_pIBall);
  128.   }
  129. }
  130.  
  131.  
  132. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  133.   Function: BallThreadProc
  134.  
  135.   Summary:  The common thread procedure for all Ball-moving free threads.
  136.  
  137.   Args:     LPARAM lparam
  138.               Standard Window Proc parameter.
  139.  
  140.   Modifies: .
  141.  
  142.   Returns:  DWORD
  143.               Thread procedure return (usually msg.wParam).
  144. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  145. DWORD WINAPI BallThreadProc(
  146.                LPARAM lparam)
  147. {
  148.   CThreadInitData* pInitData = (CThreadInitData*) lparam;
  149.   DWORD nEndCount = 0;
  150.   HRESULT hr;
  151.   BOOL bAlive;
  152.  
  153.   // Initialize COM for use by this thread. Tell COM this new thread
  154.   // is another free-threaded thread in the multi-threaded apartment.
  155.   hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  156.   bAlive = SUCCEEDED(hr);
  157.  
  158.   if (bAlive)
  159.   {
  160.     // Continuously move the ball while it is still alive.
  161.     while (bAlive)
  162.     {
  163.       // Use system timer to slow down the ball motion to the range
  164.       // of the humanly perceptible.
  165.       if (GetTickCount() > nEndCount)
  166.       {
  167.         // After the delay, call from this thread thru IBall interface
  168.         // to move the ball that lives in the single COBall COM object.
  169.         // Set bAlive flag FALSE if the COBall can no longer move.
  170.         hr = pInitData->m_pIBall->Move(TRUE);
  171.         bAlive = (NOERROR == hr);
  172.  
  173.         // Set new timer end count.
  174.         nEndCount = GetTickCount() + pInitData->m_nDelay;
  175.       }
  176.     }
  177.  
  178.     // UnInitialize COM for use by this thread.
  179.     CoUninitialize();
  180.   }
  181.  
  182.   return 0;
  183. }
  184.  
  185.  
  186. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  187.   Method:   CGuiBall::Init
  188.  
  189.   Summary:  Get everything related to CGuiBall started. Make any
  190.             subordinate objects, like COBall, and get it started. Starts
  191.             the worker move-threads that breathe life into the COBall COM
  192.             object.
  193.  
  194.   Args:     HWND hWnd
  195.               Handle of the main window. Part of what makes CGuiBall
  196.               a GUI kind of thing.
  197.  
  198.   Modifies: ...
  199.  
  200.   Returns:  BOOL
  201.               TRUE for success; FALSE for fail.
  202. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  203. BOOL CGuiBall::Init(
  204.        HWND hWnd)
  205. {
  206.   BOOL bOk = FALSE;
  207.   HRESULT hr;
  208.  
  209.   if (hWnd)
  210.   {
  211.     m_hWnd = hWnd;
  212.  
  213.     // Call COM service to create the single COBall instance.
  214.     // We are not aggregating it so we ask for its IBall interface
  215.     // directly.
  216.     hr = CoCreateInstance(
  217.            CLSID_DllBall,
  218.            NULL,
  219.            CLSCTX_INPROC_SERVER,
  220.            IID_IBall,
  221.            (PPVOID)&m_pIBall);
  222.     if (SUCCEEDED(hr))
  223.     {
  224.       // Now start up 3 client BallThreads that will all try to move the
  225.       // Ball concurrently. They will bring independent asynchronous life
  226.       // to the ball. The separate main process thread displays the ball.
  227.       // These threads (including the main display thread) will all
  228.       // comprise the multi-threaded apartment of the main process.
  229.  
  230.       // Create Structures for thread initialization.
  231.       m_BallThreadData1.m_hWnd = hWnd;
  232.       m_BallThreadData1.m_nDelay = BALL_MOVE_DELAY;
  233.       m_BallThreadData1.m_pIBall = m_pIBall;
  234.       m_BallThreadData2.m_hWnd = hWnd;
  235.       m_BallThreadData2.m_nDelay = BALL_MOVE_DELAY;
  236.       m_BallThreadData2.m_pIBall = m_pIBall;
  237.       m_BallThreadData3.m_hWnd = hWnd;
  238.       m_BallThreadData3.m_nDelay = BALL_MOVE_DELAY;
  239.       m_BallThreadData3.m_pIBall = m_pIBall;
  240.  
  241.       // Create the ball-moving thread #1.
  242.       m_hBallThreads[0] = CreateThread(
  243.                             0,
  244.                             0,
  245.                             (LPTHREAD_START_ROUTINE) BallThreadProc,
  246.                             (LPVOID) &m_BallThreadData1,
  247.                             0,
  248.                             &m_dwBallThread1);
  249.  
  250.       bOk = (NULL != m_hBallThreads[0]);
  251.       if (bOk)
  252.       {
  253.         // AddRef for the copy handed out to free-thread1.
  254.         m_pIBall->AddRef();
  255.  
  256.         // Create the Ball Moving Thread #2.
  257.         m_hBallThreads[1] = CreateThread(
  258.                               0,
  259.                               0,
  260.                               (LPTHREAD_START_ROUTINE) BallThreadProc,
  261.                               (LPVOID) &m_BallThreadData2,
  262.                               0,
  263.                               &m_dwBallThread2);
  264.  
  265.         bOk = (NULL != m_hBallThreads[1]);
  266.         if (bOk)
  267.         {
  268.           // AddRef for the copy handed out to free-thread2.
  269.           m_pIBall->AddRef();
  270.  
  271.           // Create the Ball Moving Thread #3.
  272.           m_hBallThreads[2] = CreateThread(
  273.                                 0,
  274.                                 0,
  275.                                 (LPTHREAD_START_ROUTINE) BallThreadProc,
  276.                                 (LPVOID) &m_BallThreadData3,
  277.                                 0,
  278.                                 &m_dwBallThread3);
  279.  
  280.           bOk = (NULL != m_hBallThreads[2]);
  281.           if (bOk)
  282.           {
  283.             // AddRef for the copy handed out to free-thread3.
  284.             m_pIBall->AddRef();
  285.           }
  286.         }
  287.       }
  288.     }
  289.     else
  290.       HrMsg(hWnd, TEXT(NOCOMOBJ_ERROR_STR), hr);
  291.  
  292.     if (!bOk)
  293.     {
  294.       hr = GetLastError();
  295.       if (FAILED(hr))
  296.         HrMsg(hWnd, TEXT(NOTHREAD_ERROR_STR), hr);
  297.     }
  298.   }
  299.  
  300.   if (bOk)
  301.   {
  302.     // Set up the client process to periodically paint the ball
  303.     // thru WM_TIMER messages to the main Window proc.
  304.     SetTimer(hWnd, 1, BALL_PAINT_DELAY, NULL);
  305.   }
  306.  
  307.   return (bOk);
  308. }
  309.  
  310.  
  311. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  312.   Method:   CGuiBall::PaintBall
  313.  
  314.   Summary:  Tell CGuiBall to paint one image of the GuiBall.
  315.  
  316.   Args:     void
  317.  
  318.   Modifies: ...
  319.  
  320.   Returns:  void
  321. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  322. void CGuiBall::PaintBall(void)
  323. {
  324.   HDC       hDC;
  325.   HBRUSH    hBrush;
  326.   POINT     Org, Ext;
  327.   HRGN      hNew;
  328.  
  329.   if (m_pIBall)
  330.   {
  331.     // Ask the COBall for its current ball (location, region, and color).
  332.     m_pIBall->GetBall(&Org, &Ext, &m_crColor);
  333.  
  334.     // Create the new ball image/region.
  335.     hNew = CreateEllipticRgn(Org.x, Org.y, Ext.x, Ext.y);
  336.  
  337.     if(hDC = GetDC(m_hWnd))
  338.     {
  339.       // Make a paint brush, dip it in pixel paint, and paint the
  340.       // ball image.
  341.       hBrush = CreateSolidBrush(m_crColor);
  342.       FillRgn(hDC, hNew, hBrush);
  343.       DeleteObject(hBrush);
  344.       ReleaseDC(m_hWnd, hDC);
  345.     }
  346.  
  347.     // Delete the region object.
  348.     DeleteObject(hNew);
  349.   }
  350.  
  351.   return;
  352. }
  353.  
  354.  
  355. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  356.   Method:   CGuiBall::Restart
  357.  
  358.   Summary:  Restart the display process. Places ball in start position
  359.             in a clean window.
  360.  
  361.   Args:     void.
  362.  
  363.   Modifies: ...
  364.  
  365.   Returns:  void.
  366. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  367. void CGuiBall::Restart(void)
  368. {
  369.   RECT  WinRect;
  370.   HDC   hDC = GetDC(m_hWnd);
  371.  
  372.   if(hDC && m_pIBall)
  373.   {
  374.     GetClientRect(m_hWnd, &WinRect);
  375.     FillRect(hDC, &WinRect, GETCLASSBRUSH(m_hWnd));
  376.  
  377.     // Tell the COBall to reset itself.
  378.     m_pIBall->Reset(&WinRect, 0);
  379.  
  380.     // Call our own CGuiBall method to paint an initial image of the ball.
  381.     PaintBall();
  382.  
  383.     // Release the Device Context.
  384.     ReleaseDC(m_hWnd, hDC);
  385.   }
  386.  
  387.   return;
  388. }
  389.  
  390.  
  391. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  392.   Method:   CGuiBall::PaintWin
  393.  
  394.   Summary:  Clears window background and paints the GuiBall at its
  395.             current location.
  396.  
  397.   Args:     void
  398.  
  399.   Modifies: ...
  400.  
  401.   Returns:  void
  402. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  403. void CGuiBall::PaintWin(void)
  404. {
  405.   HDC         hDC;
  406.   PAINTSTRUCT ps;
  407.   RECT        WinRect;
  408.  
  409.   if(hDC = BeginPaint(m_hWnd, &ps))
  410.     EndPaint(m_hWnd, &ps);
  411.  
  412.   if(hDC = GetDC(m_hWnd))
  413.   {
  414.     // Get our window's client area rectangle.
  415.     GetClientRect(m_hWnd, &WinRect);
  416.     // Fill that rectangle with pixels of white paint.
  417.     FillRect(hDC, &WinRect, GETCLASSBRUSH(m_hWnd));
  418.  
  419.     // Paint a current  image of the ball wherever it is.
  420.     PaintBall();
  421.  
  422.     ReleaseDC(m_hWnd, hDC);
  423.   }
  424.  
  425.   return;
  426. }
  427.