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 / freserve / ball.cpp next >
Encoding:
C/C++ Source or Header  |  1997-08-05  |  28.6 KB  |  960 lines

  1. /*+==========================================================================
  2.   File:      BALL.CPP
  3.  
  4.   Summary:   Implementation file for the COBall COM Object Class (for
  5.              aggregatable COBall COM Objects). This module provides a free
  6.              threaded virtual ball object. The ball has internal
  7.              algorithms that determine its position within a bounded two
  8.              dimensional area. No display or other GUI behavior is done in
  9.              this ball.  It is a mathematical entity. Clients of this ball
  10.              can command it to reset, move, and reveal its current
  11.              position, size, and color. These last are used by a client
  12.              that displays images of this ball. The color in particular is
  13.              an internal property maintained by the ball that indicates
  14.              the thread of execution that last moved this ball.
  15.  
  16.              COBall offers a main standard IUnknown interface (basic COM
  17.              object features) and the custom IBall interface (Moving Ball
  18.              related features).  This multiple interface COM Object Class
  19.              is achieved via the technique of nested classes.  The
  20.              implementation of the IBall interface is nested inside the
  21.              COBall Class.
  22.  
  23.              This file also implements some internal C++ classes (CXForm
  24.              and CBallThread) that provide internal support for the custom
  25.              IBall interface.
  26.  
  27.              For a comprehensive tutorial code tour of this module's
  28.              contents and offerings see the tutorial FRESERVE.HTM
  29.              file. For more specific technical details on the internal
  30.              workings see the comments dispersed throughout the module's
  31.              source code.
  32.  
  33.   Classes:   CXForm, CBallThread, COBall.
  34.  
  35.   Functions: none.
  36.  
  37.   Origin:    4-5-96: atrent - Editor-inheritance from CAR.CPP in
  38.              the DLLSERVE Tutorial Code Sample. Also borrows from
  39.              the GDIDEMO sample in the Win32 samples of the Win32 SDK.
  40.  
  41. ----------------------------------------------------------------------------
  42.   This file is part of the Microsoft COM Tutorial Code Samples.
  43.  
  44.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  45.  
  46.   This source code is intended only as a supplement to Microsoft
  47.   Development Tools and/or on-line documentation.  See these other
  48.   materials for detailed information regarding Microsoft code samples.
  49.  
  50.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  51.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  52.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  53.   PARTICULAR PURPOSE.
  54. ==========================================================================+*/
  55.  
  56.  
  57. /*---------------------------------------------------------------------------
  58.   We include WINDOWS.H for all Win32 applications.
  59.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  60.   We include APPUTIL.H because we will be building this application using
  61.     the convenient Virtual Window and Dialog classes and other
  62.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  63.   We include IBALL.H and BALLGUID.H for the common Ball-related Interface
  64.     class, GUID, and CLSID specifications.
  65.   We include SERVER.H because it has internal class declarations and
  66.     resource ID definitions specific for this DLL.
  67.   We include BALL.H because it has the class COBall declarations.
  68. ---------------------------------------------------------------------------*/
  69. #include <windows.h>
  70. #include <ole2.h>
  71. #include <apputil.h>
  72. #include <iball.h>
  73. #include <ballguid.h>
  74. #include "server.h"
  75. #include "ball.h"
  76.  
  77.  
  78. /*---------------------------------------------------------------------------
  79.   COBall's implementation of its internal utility class CXForm.
  80. ---------------------------------------------------------------------------*/
  81.  
  82.  
  83. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  84.   Method:   CXForm::Clear
  85.  
  86.   Summary:  Clears and initializes the transformation matrix.
  87.  
  88.   Args:     void
  89.  
  90.   Modifies: ...
  91.  
  92.   Returns:  void
  93. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  94. void CXForm::Clear(void)
  95. {
  96.   int Row,Col;
  97.  
  98.   for(Row=0; Row < 3; Row++)
  99.     for(Col=0; Col < 3; Col++)
  100.       if(Row == Col)
  101.         XForm[Row][Col] = 1;
  102.       else
  103.         XForm[Row][Col] = 0;
  104.  
  105.   return;
  106. }
  107.  
  108.  
  109. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  110.   Method:   CXForm::Scale
  111.  
  112.   Summary:  Method to allow setting the transformation to multiply
  113.             by a scale factor.
  114.  
  115.   Args:     int xScale
  116.               x Scale factor.
  117.             int yScale
  118.               y Scale factor.
  119.  
  120.   Modifies: ...
  121.  
  122.   Returns:  void
  123. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  124. void CXForm::Scale(int xScale, int yScale)
  125. {
  126.   int idx;
  127.  
  128.   for(idx=0; idx < 3; idx++)
  129.   {
  130.     XForm[idx][0] = XForm[idx][0] * xScale;
  131.     XForm[idx][1] = XForm[idx][1] * yScale;
  132.   }
  133.  
  134.   return;
  135. }
  136.  
  137.  
  138. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  139.   Method:   CXForm::Trans
  140.  
  141.   Summary:  Perform the transform using the internal matrix.
  142.  
  143.   Args:     int xTrans
  144.               x coordinate.
  145.             int yTrans
  146.               y coordinate.
  147.  
  148.   Modifies: ...
  149.  
  150.   Returns:  void
  151. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  152. void CXForm::Trans(int xTrans, int yTrans)
  153. {
  154.   XForm[2][0] = XForm[2][0] + xTrans;
  155.   XForm[2][1] = XForm[2][1] + yTrans;
  156.  
  157.   return;
  158. }
  159.  
  160.  
  161. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  162.   Method:   CXForm::Point
  163.  
  164.   Summary:  Transform a point.
  165.  
  166.   Args:     POINT* pPoint
  167.               Pointer to the point.
  168.  
  169.   Modifies: ...
  170.  
  171.   Returns:  void
  172. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  173. void CXForm::Point(POINT* pPoint)
  174. {
  175.   int x,y;
  176.  
  177.   x = (XForm[0][0] * pPoint->x) + (XForm[1][0] * pPoint->y) + XForm[2][0];
  178.   y = (XForm[0][1] * pPoint->x) + (XForm[1][1] * pPoint->y) + XForm[2][1];
  179.  
  180.   pPoint->x = x;
  181.   pPoint->y = y;
  182.  
  183.   return;
  184. }
  185.  
  186.  
  187. /*---------------------------------------------------------------------------
  188.   COBall's implementation of its main COM object class including
  189.   Constructor, Destructor, QueryInterface, AddRef, and Release.
  190. ---------------------------------------------------------------------------*/
  191.  
  192. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  193.   Method:   COBall::COBall
  194.  
  195.   Summary:  COBall Constructor. Note the member initializer:
  196.             "m_ImpIBall(this, pUnkOuter)" which is used to pass the 'this'
  197.             and pUnkOuter pointers of this constructor function to the
  198.             constructor in the instantiation of the implementation of the
  199.             CImpIBall interface (which is nested inside this present
  200.             COBall Object Class).
  201.  
  202.   Args:     IUnknown* pUnkOuter,
  203.               Pointer to the the outer Unknown.  NULL means this COM Object
  204.               is not being Aggregated.  Non NULL means it is being created
  205.               on behalf of an outside COM object that is reusing it via
  206.               aggregation.
  207.             CServer* pServer)
  208.               Pointer to the server's control object.
  209.  
  210.   Modifies: m_cRefs, m_pUnkOuter, m_pServer.
  211.  
  212.   Returns:  void
  213. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  214. COBall::COBall(
  215.   IUnknown* pUnkOuter,
  216.   CServer* pServer) :
  217.   m_ImpIBall(this, pUnkOuter)
  218. {
  219.   // Zero the COM object's reference count.
  220.   m_cRefs = 0;
  221.  
  222.   // No AddRef necessary if non-NULL, as we're nested.
  223.   m_pUnkOuter = pUnkOuter;
  224.  
  225.   // Assign the pointer to the server control object.
  226.   m_pServer = pServer;
  227.  
  228.   return;
  229. }
  230.  
  231.  
  232. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  233.   Method:   COBall::~COBall
  234.  
  235.   Summary:  COBall Destructor.
  236.  
  237.   Args:     void
  238.  
  239.   Modifies: .
  240.  
  241.   Returns:  void
  242. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  243. COBall::~COBall(void)
  244. {
  245.   return;
  246. }
  247.  
  248.  
  249. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  250.   Method:   COBall::QueryInterface
  251.  
  252.   Summary:  QueryInterface of the COBall non-delegating
  253.             IUnknown implementation.
  254.  
  255.   Args:     REFIID riid,
  256.               [in] GUID of the Interface being requested.
  257.             PPVOID ppv)
  258.               [out] Address of the caller's pointer variable that will
  259.               receive the requested interface pointer.
  260.  
  261.   Modifies: .
  262.  
  263.   Returns:  HRESULT
  264. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  265. STDMETHODIMP COBall::QueryInterface(
  266.                REFIID riid,
  267.                PPVOID ppv)
  268. {
  269.   HRESULT hr = E_NOINTERFACE;
  270.  
  271.   if (OwnThis())
  272.   {
  273.     *ppv = NULL;
  274.  
  275.     if (IID_IUnknown == riid)
  276.       *ppv = this;
  277.     else if (IID_IBall == riid)
  278.       *ppv = &m_ImpIBall;
  279.  
  280.     if (NULL != *ppv)
  281.     {
  282.       // We've handed out a pointer to the interface so obey the COM rules
  283.       // and AddRef the reference count.
  284.       ((LPUNKNOWN)*ppv)->AddRef();
  285.       hr = NOERROR;
  286.     }
  287.  
  288.     UnOwnThis();
  289.   }
  290.  
  291.   return (hr);
  292. }
  293.  
  294.  
  295. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  296.   Method:   COBall::AddRef
  297.  
  298.   Summary:  AddRef of the COBall non-delegating IUnknown implementation.
  299.  
  300.   Args:     void
  301.  
  302.   Modifies: m_cRefs.
  303.  
  304.   Returns:  ULONG
  305.               New value of m_cRefs (COM object's reference count).
  306. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  307. STDMETHODIMP_(ULONG) COBall::AddRef(void)
  308. {
  309.   ULONG cRefs;
  310.  
  311.   if (OwnThis())
  312.   {
  313.     cRefs = ++m_cRefs;
  314.  
  315.     UnOwnThis();
  316.   }
  317.  
  318.   return cRefs;
  319. }
  320.  
  321.  
  322. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  323.   Method:   COBall::Release
  324.  
  325.   Summary:  Release of the COBall non-delegating IUnknown implementation.
  326.  
  327.   Args:     void
  328.  
  329.   Modifies: m_cRefs.
  330.  
  331.   Returns:  ULONG
  332.               New value of m_cRefs (COM object's reference count).
  333. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  334. STDMETHODIMP_(ULONG) COBall::Release(void)
  335. {
  336.   ULONG cRefs;
  337.   CServer* pServer;
  338.  
  339.   if (OwnThis())
  340.   {
  341.     cRefs = --m_cRefs;
  342.  
  343.     if (0 == cRefs)
  344.     {
  345.       // Save a local copy of the pointer to the server control object.
  346.       pServer = m_pServer;
  347.  
  348.       // We artificially bump the main ref count to prevent reentrancy
  349.       // via the main object destructor.  Not really needed in this
  350.       // COBall but a good practice because we are aggregatable and
  351.       // may at some point in the future add something entertaining like
  352.       // some Releases to the COBall destructor. We relinquish thread
  353.       // ownership of this object before deleting it--a good practice.
  354.       m_cRefs++;
  355.       UnOwnThis();
  356.       delete this;
  357.  
  358.       // We've reached a zero reference count for this COM object and
  359.       // we have deleted the COM object. So we tell the server housing
  360.       // to decrement its global object count so that the server will
  361.       // be unloaded if appropriate.
  362.       if (NULL != pServer)
  363.         pServer->ObjectsDown();
  364.     }
  365.     else
  366.       UnOwnThis();
  367.   }
  368.  
  369.   return cRefs;
  370. }
  371.  
  372.  
  373. /*---------------------------------------------------------------------------
  374.   COBall's nested implementation of the IBall interface including
  375.   Constructor, Destructor, QueryInterface, AddRef, Release, Reset, Move,
  376.   and GetBall. This interface implementation also has internal methods
  377.   that are not particulary intended for outside clients: GetDimensions,
  378.   SetDimensions, GetDirection, SetDirection, GetPosition, SetPostion,
  379.   CheckBounce, and FindThread. The IBall interface only provides client
  380.   access to the IUnknown methods and the Reset, Move, and GetBall methods.
  381. ---------------------------------------------------------------------------*/
  382.  
  383. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  384.   Method:   COBall::CImpIBall::CImpIBall
  385.  
  386.   Summary:  Constructor for the CImpIBall interface instantiation.
  387.  
  388.   Args:     COBall* pBackObj,
  389.               Back pointer to the parent outer object.
  390.             IUnknown* pUnkOuter
  391.               Pointer to the outer Unknown.  For delegation.
  392.  
  393.   Modifies: m_pBackObj, m_pUnkOuter.
  394.  
  395.   Returns:  void
  396. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  397. COBall::CImpIBall::CImpIBall(
  398.   COBall* pBackObj,
  399.   IUnknown* pUnkOuter)
  400. {
  401.   size_t i;
  402.   BYTE r=128, g=128, b=128;
  403.  
  404.   // Init the Back Object Pointer to point to the parent object.
  405.   m_pBackObj = pBackObj;
  406.  
  407.   // Init the CImpIBall interface's delegating Unknown pointer.  We use
  408.   // the Back Object pointer for IUnknown delegation here if we are not
  409.   // being aggregated.  If we are being aggregated we use the supplied
  410.   // pUnkOuter for IUnknown delegation.  In either case the pointer
  411.   // assignment requires no AddRef because the CImpIBall lifetime is
  412.   // quaranteed by the lifetime of the parent object in which
  413.   // CImpIBall is nested.
  414.   if (NULL == pUnkOuter)
  415.     m_pUnkOuter = pBackObj;
  416.   else
  417.     m_pUnkOuter = pUnkOuter;
  418.  
  419.   // Now initialize the Ball application entity data.
  420.   m_bAlive       = TRUE;
  421.   m_xDirection   = 0;
  422.   m_yDirection   = 0;
  423.   m_bNewPosition = FALSE;
  424.   m_xPosition    = 0;
  425.   m_yPosition    = 0;
  426.   m_nWidth       = 30;
  427.   m_nHeight      = 30;
  428.   m_xSkew        = BALL_MOVE_SKEW;
  429.   m_ySkew        = BALL_MOVE_SKEW;
  430.   m_crColor      = RGB(0,0,0);
  431.  
  432.   // Clear point transformation array.
  433.   m_XForm.Clear();
  434.  
  435.   // Init BallThread array--init colors and clear thread Ids.
  436.   // The BallThreads are the threads that contend to move and/or
  437.   // paint the ball object.
  438.   for (i = 0; i < MAX_BALLTHREADS; i++)
  439.     m_aBallThreads[i].Id = 0;
  440.   m_aBallThreads[0].Color = RGB(0  ,  0,  0);  // Black
  441.   m_aBallThreads[1].Color = RGB(255,  0,  0);  // Red
  442.   m_aBallThreads[2].Color = RGB(0  ,255,  0);  // Green
  443.   m_aBallThreads[3].Color = RGB(0  ,  0,255);  // Blue
  444.   m_aBallThreads[4].Color = RGB(255,  0,255);  // Purple
  445.   m_aBallThreads[5].Color = RGB(0  ,255,255);  // Aqua
  446.   m_aBallThreads[6].Color = RGB(255,255,  0);  // Brown
  447.   if (MAX_BALLTHREADS > 8)
  448.     for (i=7; i<MAX_BALLTHREADS; i++)
  449.     {
  450.       // Fill the remainder with some random colors.
  451.       m_aBallThreads[i].Color = RGB(r,g,b);
  452.       r = (BYTE) lRandom() % 255;
  453.       g = (BYTE) lRandom() % 255;
  454.       b = (BYTE) lRandom() % 255;
  455.     }
  456.  
  457.   return;
  458. }
  459.  
  460.  
  461. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  462.   Method:   COBall::CImpIBall::~CImpIBall
  463.  
  464.   Summary:  Destructor for the CImpIBall interface instantiation.
  465.  
  466.   Args:     void
  467.  
  468.   Modifies: .
  469.  
  470.   Returns:  void
  471. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  472. COBall::CImpIBall::~CImpIBall(void)
  473. {
  474.   return;
  475. }
  476.  
  477.  
  478. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  479.   Method:   COBall::CImpIBall::GetDimensions
  480.  
  481.   Summary:  Internal utility method to get the ball x,y dimensions.
  482.  
  483.   Args:     POINT* pDimension
  484.               Pointer to the point that will contain the dimensions.
  485.  
  486.   Modifies: *pDimension.
  487.  
  488.   Returns:  void
  489. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  490. void COBall::CImpIBall::GetDimensions(POINT* pDimension)
  491. {
  492.   pDimension->x = m_nWidth;
  493.   pDimension->y = m_nHeight;
  494.  
  495.   return;
  496. }
  497.  
  498.  
  499. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  500.   Method:   COBall::CImpIBall::SetDimensions
  501.  
  502.   Summary:  Internal utility method to set the ball x,y dimensions.
  503.  
  504.   Args:     int nWidth
  505.               New Ball width.
  506.             int nHeight
  507.               New Ball Height.
  508.  
  509.   Modifies: .
  510.  
  511.   Returns:  void
  512. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  513. void COBall::CImpIBall::SetDimensions(int nWidth, int nHeight)
  514. {
  515.   m_nWidth  = nWidth;
  516.   m_nHeight = nHeight;
  517.  
  518.   return;
  519. }
  520.  
  521.  
  522. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  523.   Method:   COBall::CImpIBall::GetDirection
  524.  
  525.   Summary:  Internal utility method to get the ball direction.
  526.  
  527.   Args:     POINT* pDirection
  528.               Pointer to the Point that will contain the x,y direction
  529.               data.
  530.  
  531.   Modifies: ...
  532.  
  533.   Returns:  void
  534. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  535. void COBall::CImpIBall::GetDirection(POINT* pDirection)
  536. {
  537.   pDirection->x = m_xDirection;
  538.   pDirection->y = m_yDirection;
  539.  
  540.   return;
  541. }
  542.  
  543.  
  544. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  545.   Method:   COBall::CImpIBall::SetDirection
  546.  
  547.   Summary:  Internal utility method to set the ball direction.
  548.  
  549.   Args:     int xDirection
  550.               x coordinate of the new direction.
  551.             int yDirection
  552.               y coordinate of the new direction.
  553.  
  554.   Modifies: ...
  555.  
  556.   Returns:  void
  557. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  558. void COBall::CImpIBall::SetDirection(int xDirection, int yDirection)
  559. {
  560.   m_xDirection = xDirection;
  561.   m_yDirection = yDirection;
  562.  
  563.   return;
  564. }
  565.  
  566.  
  567. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  568.   Method:   COBall::CImpIBall::GetPosition
  569.  
  570.   Summary:  Internal utility method to get current the ball position.
  571.  
  572.   Args:     POINT* pPosition
  573.               Pointer to the Point that is the position.
  574.  
  575.   Modifies: *pPostion.
  576.  
  577.   Returns:  void
  578. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  579. void COBall::CImpIBall::GetPosition(POINT* pPosition)
  580. {
  581.   POINT Org;
  582.  
  583.   Org.x = 0;
  584.   Org.y = 0;
  585.   m_XForm.Point(&Org);
  586.  
  587.   pPosition->x = Org.x;
  588.   pPosition->y = Org.y;
  589.  
  590.   return;
  591. }
  592.  
  593.  
  594. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  595.   Method:   COBall::CImpIBall::SetPosition
  596.  
  597.   Summary:  Internal utility method to set current the ball position.
  598.  
  599.   Args:     int x
  600.               x-coordinate of new position.
  601.             int y
  602.               y-coordinate of new position.
  603.  
  604.   Modifies: ...
  605.  
  606.   Returns:  void
  607. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  608. void COBall::CImpIBall::SetPosition(int x, int y)
  609. {
  610.   m_bNewPosition = TRUE;
  611.   m_xPosition    = x;
  612.   m_yPosition    = y;
  613.  
  614.   return;
  615. }
  616.  
  617.  
  618. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  619.   Method:   COBall::CImpIBall::CheckBounce
  620.  
  621.   Summary:  Internal utility method to check the current ball position,
  622.             dimension, and direction data and determine if the ball has
  623.             hit the internal WinRect bounding rectangle. If it has then
  624.             the ball data is recalculated to achieve a "bounce" effect
  625.             for the ball as it moves.
  626.  
  627.   Args:     void
  628.  
  629.   Modifies: ...
  630.  
  631.   Returns:  void
  632. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  633. void COBall::CImpIBall::CheckBounce(void)
  634. {
  635.   POINT Pos, Dir, Dim;
  636.   int   xNewPos, yNewPos, xNewDir, yNewDir;
  637.  
  638.   GetPosition(&Pos);
  639.   GetDirection(&Dir);
  640.   GetDimensions(&Dim);
  641.  
  642.   // Check each edge of the client rectangle.  If the ball goes past the
  643.   // boundries, reset its position and direction to give it a "bounce"
  644.   // effect the next time it is displayed.
  645.   xNewDir = Dir.x;
  646.   yNewDir = Dir.y;
  647.   xNewPos = Pos.x + Dir.x;
  648.   yNewPos = Pos.y + Dir.y;
  649.  
  650.   if(xNewPos < m_WinRect.left)
  651.   {
  652.     xNewDir = ((lRandom() % m_xSkew) + m_xSkew);
  653.     SetPosition(m_WinRect.left, Pos.y);
  654.   }
  655.   if((xNewPos + Dim.x) > m_WinRect.right)
  656.   {
  657.     xNewDir = -(((int)lRandom() % m_xSkew) + m_xSkew);
  658.     SetPosition(m_WinRect.right - Dim.x, Pos.y);
  659.   }
  660.   if(yNewPos < m_WinRect.top)
  661.   {
  662.     yNewDir = ((lRandom() % m_ySkew) + m_ySkew);
  663.     SetPosition(Pos.x, m_WinRect.top);
  664.   }
  665.   if((yNewPos + Dim.y) > m_WinRect.bottom)
  666.   {
  667.     yNewDir = -(((int)lRandom() % m_ySkew) + m_ySkew);
  668.     SetPosition(Pos.x, m_WinRect.bottom - Dim.y);
  669.   }
  670.  
  671.   SetDirection(xNewDir, yNewDir);
  672.  
  673.   return;
  674. }
  675.  
  676.  
  677. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  678.   Method:   COBall::CImpIBall::FindThread
  679.  
  680.   Summary:  Internal utility method to Find the thread that is now
  681.             executing this code. If the executing thread is not already in
  682.             the Thread array remember the new Thread's Id and add it to the
  683.             array. This in effect assigns the thread a color that can be
  684.             used for tutorial display of which thread is executing on the
  685.             ball object.
  686.  
  687.   Args:     void
  688.  
  689.   Modifies: ...
  690.  
  691.   Returns:  void
  692. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  693. void COBall::CImpIBall::FindThread(void)
  694. {
  695.   BOOL bFound = FALSE;
  696.   DWORD dwTId = GetCurrentThreadId();
  697.   size_t i = 0;
  698.  
  699.   while(!bFound && i<MAX_BALLTHREADS)
  700.   {
  701.     if (m_aBallThreads[i].Id == 0)
  702.     {
  703.       // Found empty slot. This simple array logic allows no empty holes.
  704.       m_aBallThreads[i].Id = dwTId;
  705.       bFound = TRUE;
  706.     }
  707.     else
  708.     {
  709.       if (m_aBallThreads[i].Id == dwTId)
  710.       {
  711.         // Found previous visiting thread--use its assigned color.
  712.         m_crColor = m_aBallThreads[i].Color;
  713.         bFound = TRUE;
  714.       }
  715.       else
  716.       {
  717.         i++;
  718.         if (i >= MAX_BALLTHREADS)
  719.         {
  720.           // Thread array is full--use a gray color for all other
  721.           // excess visiting threads.
  722.           m_crColor = RGB(127,127,127);
  723.           bFound = TRUE;
  724.         }
  725.       }
  726.     }
  727.   }
  728.  
  729.   return;
  730. }
  731.  
  732.  
  733. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  734.   Method:   COBall::CImpIBall::QueryInterface
  735.  
  736.   Summary:  The QueryInterface IUnknown member of this IBall interface
  737.             implementation that delegates to m_pUnkOuter, whatever it is.
  738.  
  739.   Args:     REFIID riid,
  740.               [in] GUID of the Interface being requested.
  741.             PPVOID ppv)
  742.               [out] Address of the caller's pointer variable that will
  743.               receive the requested interface pointer.
  744.  
  745.   Modifies: .
  746.  
  747.   Returns:  HRESULT
  748.               Returned by the delegated outer QueryInterface call.
  749. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  750. STDMETHODIMP COBall::CImpIBall::QueryInterface(
  751.                REFIID riid,
  752.                PPVOID ppv)
  753. {
  754.   // Delegate this call to the outer object's QueryInterface.
  755.   return m_pUnkOuter->QueryInterface(riid, ppv);
  756. }
  757.  
  758.  
  759. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  760.   Method:   COBall::CImpIBall::AddRef
  761.  
  762.   Summary:  The AddRef IUnknown member of this IBall interface
  763.             implementation that delegates to m_pUnkOuter, whatever it is.
  764.  
  765.   Args:     void
  766.  
  767.   Modifies: .
  768.  
  769.   Returns:  ULONG
  770.               Returned by the delegated outer AddRef call.
  771. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  772. STDMETHODIMP_(ULONG) COBall::CImpIBall::AddRef(void)
  773. {
  774.   // Delegate this call to the outer object's AddRef.
  775.   return m_pUnkOuter->AddRef();
  776. }
  777.  
  778.  
  779. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  780.   Method:   COBall::CImpIBall::Release
  781.  
  782.   Summary:  The Release IUnknown member of this IBall interface
  783.             implementation that delegates to m_pUnkOuter, whatever it is.
  784.  
  785.   Args:     void
  786.  
  787.   Modifies: .
  788.  
  789.   Returns:  ULONG
  790.               Returned by the delegated outer Release call.
  791. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  792. STDMETHODIMP_(ULONG) COBall::CImpIBall::Release(void)
  793. {
  794.   // Delegate this call to the outer object's Release.
  795.   return m_pUnkOuter->Release();
  796. }
  797.  
  798.  
  799. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  800.   Method:   COBall::CImpIBall::Reset
  801.  
  802.   Summary:  The Reset member method of the IBall interface implementation.
  803.             Called by outside clients of a COBall object to reset the
  804.             virtual ball. It is restored to the upper left corner.
  805.  
  806.   Args:     RECT* pNewRect,
  807.               Pointer to a RECT structure. Tells the COBall the bounding
  808.               rectangle within which the ball can move.
  809.             short nBallSize,
  810.               The size of the ball in pixels. nBallSize == Width == Height
  811.               meaning that a circle is assumed.
  812.  
  813.   Modifies: ...
  814.  
  815.   Returns:  HRESULT
  816.               Standard result code. NOERROR for success.
  817. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  818. STDMETHODIMP COBall::CImpIBall::Reset(
  819.                RECT* pNewRect,
  820.                short nBallSize)
  821. {
  822.   HRESULT hr = E_FAIL;
  823.   int nDim, xDirection, yDirection;
  824.  
  825.   if (OwnThis())
  826.   {
  827.     // Find the thread who is executing this and remember its color.
  828.     FindThread();
  829.  
  830.     m_xSkew = m_ySkew = BALL_MOVE_SKEW;
  831.     m_WinRect.left = pNewRect->left;
  832.     m_WinRect.top = pNewRect->top;
  833.     m_WinRect.right = pNewRect->right;
  834.     m_WinRect.bottom = pNewRect->bottom;
  835.     nDim = nBallSize ? nBallSize : max(5, m_WinRect.right / 13);
  836.     SetDimensions(nDim, nDim);
  837.     SetPosition(0, 0);
  838.     xDirection = ((lRandom() % m_xSkew) + m_xSkew);
  839.     yDirection = ((lRandom() % m_ySkew) + m_ySkew);
  840.     SetDirection(xDirection, yDirection);
  841.  
  842.     hr = NOERROR;
  843.  
  844.     UnOwnThis();
  845.   }
  846.  
  847.   return hr;
  848. }
  849.  
  850.  
  851. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  852.   Method:   COBall::CImpIBall::Move
  853.  
  854.   Summary:  The Move member method of this IBall interface implementation.
  855.             Called by outside clients of a COBall object to advance the
  856.             "motion" of this COBall virtual ball entity.
  857.  
  858.   Args:     BOOL bAlive
  859.               TRUE means stay alive; FALSE means don't move and die.
  860.  
  861.   Modifies: m_bAlive.
  862.  
  863.   Returns:  HRESULT
  864.               Standard result code. NOERROR for success and means the move
  865.               was done and the ball is still alive. E_FAIL means the move
  866.               was not done and the ball has been killed.
  867. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  868. STDMETHODIMP COBall::CImpIBall::Move(
  869.                BOOL bAlive)
  870. {
  871.   HRESULT hr = E_FAIL;
  872.  
  873.   if (OwnThis())
  874.   {
  875.     if (bAlive && m_bAlive)
  876.     {
  877.       // Find thread that is now executing this code. Remember its Id and
  878.       // assign it a color. If this thread previously visited here then
  879.       // use its remembered values. In any case, set a color value in
  880.       // m_crColor of its existing or newly assigned color.
  881.       FindThread();
  882.  
  883.       // Ask the Ball if it has hit any of the edges of the current window
  884.       // rectangle. If so, it will recalculate its position and direction to
  885.       // achieve a "bounce" effect in its motion the next time it is painted.
  886.       CheckBounce();
  887.  
  888.       // Calculate and set new ball position.
  889.       if(m_bNewPosition)
  890.       {
  891.         m_bNewPosition = FALSE;
  892.         m_XForm.Clear();
  893.         m_XForm.Trans(m_xPosition, m_yPosition);
  894.       }
  895.       else
  896.         m_XForm.Trans(m_xDirection, m_yDirection);
  897.     }
  898.     else
  899.       m_bAlive = FALSE;
  900.  
  901.     hr = m_bAlive ? NOERROR : E_FAIL;
  902.  
  903.     UnOwnThis();
  904.   }
  905.  
  906.   return hr;
  907. }
  908.  
  909.  
  910. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  911.   Method:   COBall::CImpIBall::GetBall
  912.  
  913.   Summary:  The GetBall member method of this IBall interface
  914.             implementation. Called by outside clients of a COBall object
  915.             to get the necessary data on the moving ball to enable GUI
  916.             display of an actual image of this virtual ball. This COBall
  917.             is a data entity only that is kept alive by client threads
  918.             that call Move. A GUI client can independently call GetBall
  919.             to allow it to display some visual representation of the Ball.
  920.  
  921.   Args:     POINT* pOrg,
  922.               Pointer to a point that will contain the current origin
  923.               position of the ball.
  924.             POINT* pExt,
  925.               Pointer to a point that will contain the current extent
  926.               size of the ball.
  927.             COLORREF* pcrColor)
  928.               Pointer to a COLORREF that will contain the current color
  929.               of the ball. This color is determined by the last thread
  930.               that was executing in the ball before this call is made.
  931.  
  932.   Returns:  HRESULT
  933.               Standard result code. NOERROR for success.
  934. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  935. STDMETHODIMP COBall::CImpIBall::GetBall(
  936.        POINT* pOrg,
  937.        POINT* pExt,
  938.        COLORREF* pcrColor)
  939. {
  940.   HRESULT hr = E_FAIL;
  941.  
  942.   if (OwnThis())
  943.   {
  944.     *pcrColor = m_crColor;
  945.  
  946.     pOrg->x = 0;
  947.     pOrg->y = 0;
  948.     m_XForm.Point(pOrg);
  949.     pExt->x = m_nWidth;
  950.     pExt->y = m_nHeight;
  951.     m_XForm.Point(pExt);
  952.  
  953.     hr = NOERROR;
  954.  
  955.     UnOwnThis();
  956.   }
  957.  
  958.   return hr;
  959. }
  960.