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 / conserve / ball.cpp next >
C/C++ Source or Header  |  1997-08-05  |  44KB  |  1,375 lines

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