BALL.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:43k
源码类别:

Windows编程

开发平台:

Visual C++

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