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 / conclien / guiball.cpp < prev    next >
C/C++ Source or Header  |  1997-08-05  |  15KB  |  524 lines

  1. /*+==========================================================================
  2.   File:      GUIBALL.CPP
  3.  
  4.   Summary:   Implementation file for the CGuiBall C++ class. A GuiBall is
  5.              a C++ object that displays a moving and bouncing ball in the
  6.              client area of a designated window.  It is anchored to the
  7.              Windows GUI (Graphical User Interface) environment. This
  8.              GuiBall object continuously paints a ball image based on data
  9.              it obtains from a virtual ball object. This virtual ball
  10.              object is instantiated as a COM object (a COBall) in a
  11.              separate thread-safe In-process server, CONSERVE.
  12.  
  13.              GuiBall relies on the system timer to send periodic WM_TIMER
  14.              messages to a window procedure designated in the
  15.              CGuiBall::Init call. When these messages are received, the
  16.              window procedure calls the CGuiBall::PaintBall method which
  17.              both moves and displays the ball image.
  18.  
  19.              For a comprehensive tutorial code tour of GUIBALL's contents
  20.              and offerings see the tutorial CONCLIEN.HTM file. For more
  21.              specific technical details on the internal workings see the
  22.              comments dispersed throughout the GUIBALL source code.
  23.  
  24.   Classes:   CGuiBall.
  25.  
  26.   Origin:    5-30-96: atrent - Editor inheritance from GUIBALL.CPP in the
  27.              FRECLIEN source.
  28.  
  29. ----------------------------------------------------------------------------
  30.   This file is part of the Microsoft COM Tutorial Code Samples.
  31.  
  32.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  33.  
  34.   This source code is intended only as a supplement to Microsoft
  35.   Development Tools and/or on-line documentation.  See these other
  36.   materials for detailed information regarding Microsoft code samples.
  37.  
  38.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  39.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  40.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  41.   PARTICULAR PURPOSE.
  42. ==========================================================================+*/
  43.  
  44. /*--------------------------------------------------------------------------
  45.   We include WINDOWS.H for all Win32 applications.
  46.   We include OLE2.H because we will be calling the COM/OLE libraries.
  47.   We include OLECTL.H because it has definitions for connectable objects.
  48.   We include APPUTIL.H because we will be building this application using
  49.     the convenient Virtual Window and Dialog classes and other
  50.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  51.   We include IBALL.H and BALLGUID.H for the common Ball-related Interface
  52.     class, GUID, and CLSID specifications.
  53.   We include GUIBALL.H because it has the C++ class used for GUI display
  54.     of the moving ball.
  55.   We include CONCLIEN.H because it has class and resource definitions
  56.     specific to this CONCLIEN application.
  57. ---------------------------------------------------------------------------*/
  58. #include <windows.h>
  59. #include <ole2.h>
  60. #include <olectl.h>
  61. #include <apputil.h>
  62. #include <iball.h>
  63. #include <ballguid.h>
  64. #include "guiball.h"
  65. #include "sink.h"
  66. #include "conclien.h"
  67.  
  68.  
  69. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  70.   Method:   CGuiBall::CGuiBall
  71.  
  72.   Summary:  Constructor.
  73.  
  74.   Args:     void
  75.  
  76.   Modifies: ...
  77.  
  78.   Returns:  void
  79. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  80. CGuiBall::CGuiBall(void)
  81. {
  82.   m_hWnd       = 0;
  83.   m_pIBall     = NULL;
  84.   m_crColor    = RGB(0,0,0);
  85.   m_OldPos.x   = 0;
  86.   m_OldPos.y   = 0;
  87.   m_OldExt.x   = 0;
  88.   m_OldExt.y   = 0;
  89.   m_pCOBallSink = NULL;
  90.   m_dwBallSink = 0;
  91.   m_dwBounceSndDur = BOUNCE_SOUND_DURATION;
  92.   m_dwBounceBotFreq = BOUNCE_BOTTOM_FREQUENCY;
  93.   m_dwBounceSideFreq = BOUNCE_SIDE_FREQUENCY;
  94.   m_dwBounceTopFreq = BOUNCE_TOP_FREQUENCY;
  95. }
  96.  
  97.  
  98. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  99.   Method:   CGuiBall::~CGuiBall
  100.  
  101.   Summary:  Destructor.
  102.  
  103.   Args:     void
  104.  
  105.   Modifies: ...
  106.  
  107.   Returns:  void
  108. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  109. CGuiBall::~CGuiBall(void)
  110. {
  111.   BOOL bOk = TRUE;
  112.  
  113.   // Kill the client's app timer that drives repaints. Stops the WM_TIMER
  114.   // messages to the display window.
  115.   KillTimer(m_hWnd, 1);
  116.  
  117.   if (m_pIBall)
  118.   {
  119.     // Call down to the server's COBall and tell it about the shutdown.
  120.     // This sets COBall's m_bAlive to FALSE, neutralizes all
  121.     // subsequent Move calls, and thus prevents any more NotifySinks calls
  122.     // from within the Move method.
  123.     m_pIBall->Move(FALSE);
  124.  
  125.     // Disconnect all Sinks--currently only one: BallSink. This officially
  126.     // stops all BallSink notifications.
  127.     DisconnectBallSink();
  128.  
  129.     // Release the reference to the BallSink object.
  130.     RELEASE_INTERFACE(m_pCOBallSink);
  131.  
  132.     // Release the main interface pointer copy held in CGuiBall.
  133.     RELEASE_INTERFACE(m_pIBall);
  134.   }
  135. }
  136.  
  137.  
  138. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  139.   Method:   CGuiBall::Init
  140.  
  141.   Summary:  Get everything related to CGuiBall started. Make any
  142.             subordinate objects, like COBall, and get it started. Starts
  143.             the system timer that keeps the virtual ball moving with GUI
  144.             painted images.
  145.  
  146.   Args:     HWND hWnd
  147.               Handle of the display window. Part of what makes CGuiBall
  148.               a GUI kind of thing.
  149.  
  150.   Modifies: ...
  151.  
  152.   Returns:  BOOL
  153.               TRUE for success; FALSE for fail.
  154. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  155. BOOL CGuiBall::Init(
  156.        HWND hWnd)
  157. {
  158.   BOOL bOk = FALSE;
  159.   HRESULT hr;
  160.   COBallSink* pCob = NULL;
  161.  
  162.   if (hWnd)
  163.   {
  164.     m_hWnd = hWnd;
  165.  
  166.     // Call COM service to create a COBall instance. We are not
  167.     // aggregating it so we ask for its IBall interface directly.
  168.     hr = CoCreateInstance(
  169.            CLSID_DllSndBall,
  170.            NULL,
  171.            CLSCTX_INPROC_SERVER,
  172.            IID_IBall,
  173.            (PPVOID)&m_pIBall);
  174.     if (SUCCEEDED(hr))
  175.     {
  176.       // Create the COBallSink Sink object to receive COBall events.
  177.       pCob = new COBallSink(NULL, this);
  178.       if (NULL != pCob)
  179.       {
  180.         // Save a pointer to the COBall IUnknown interface. AddRef
  181.         // because of this saved copy.
  182.         m_pCOBallSink = pCob;
  183.         m_pCOBallSink->AddRef();
  184.       }
  185.       else
  186.         hr = E_OUTOFMEMORY;
  187.  
  188.       if (SUCCEEDED(hr))
  189.       {
  190.         // Set up the client process to periodically move & paint the ball
  191.         // thru WM_TIMER messages to the specified hWnd's Window proc.
  192.         SetTimer(hWnd, 1, BALL_PAINT_DELAY, NULL);
  193.         bOk = TRUE;
  194.       }
  195.     }
  196.   }
  197.  
  198.   return (bOk);
  199. }
  200.  
  201.  
  202. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  203.   Method:   CGuiBall::PaintBall
  204.  
  205.   Summary:  Tell CGuiBall to move one increment and paint one image of the
  206.             GuiBall.
  207.  
  208.   Args:     void
  209.  
  210.   Modifies: ...
  211.  
  212.   Returns:  void
  213. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  214. void CGuiBall::PaintBall(void)
  215. {
  216.   HDC       hDC;
  217.   HBRUSH    hBrush;
  218.   POINT     Org, Ext;
  219.   HRGN      hTmp, hOld, hNew;
  220.  
  221.   if (m_pIBall)
  222.   {
  223.     // Move the ball before painting it. By placing this Move call here
  224.     // we link moving with painting in synchronized lock step.
  225.     m_pIBall->Move(TRUE);
  226.  
  227.     // Ask the COBall for its current ball (location, region, and color).
  228.     m_pIBall->GetBall(&Org, &Ext, &m_crColor);
  229.  
  230.     // Create the old ball image/region.
  231.     hOld = CreateEllipticRgn(m_OldPos.x, m_OldPos.y, m_OldExt.x, m_OldExt.y);
  232.  
  233.     // Create the new ball image/region.
  234.     hNew = CreateEllipticRgn(Org.x, Org.y, Ext.x, Ext.y);
  235.  
  236.     // Remember the new Pos and Ext as the next old set of Pos and Ext.
  237.     m_OldPos.x = Org.x;
  238.     m_OldPos.y = Org.y;
  239.     m_OldExt.x = Ext.x;
  240.     m_OldExt.y = Ext.y;
  241.  
  242.     if(hDC = GetDC(m_hWnd))
  243.     {
  244.       // Erase old ball image.
  245.       hTmp = CreateRectRgn(1, 1, 2, 2);
  246.       if (NULL != hOld)
  247.       CombineRgn(hTmp, hOld, hNew, RGN_DIFF);
  248.       FillRgn(hDC, hTmp, GETCLASSBRUSH(m_hWnd));
  249.  
  250.       // Make a paint brush, dip it in pixel paint, and paint the
  251.       // new Ball image. Destroy brush after use.
  252.       hBrush = CreateSolidBrush(m_crColor);
  253.       FillRgn(hDC, hNew, hBrush);
  254.       DeleteObject(hBrush);
  255.       ReleaseDC(m_hWnd, hDC);
  256.       DeleteObject(hTmp);
  257.     }
  258.  
  259.     // Delete the region objects.
  260.     if (NULL != hOld)
  261.       DeleteObject(hOld);
  262.   if (NULL != hNew)
  263.       DeleteObject(hNew);
  264.   }
  265.  
  266.   return;
  267. }
  268.  
  269.  
  270. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  271.   Method:   CGuiBall::Restart
  272.  
  273.   Summary:  Restart the display process. Places Ball in start position
  274.             in a clean window.
  275.  
  276.   Args:     void.
  277.  
  278.   Modifies: ...
  279.  
  280.   Returns:  void.
  281. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  282. void CGuiBall::Restart(void)
  283. {
  284.   RECT  WinRect;
  285.   HDC   hDC = GetDC(m_hWnd);
  286.  
  287.   if(hDC && m_pIBall)
  288.   {
  289.     // Clear the window.
  290.     // Get our window's client area rectangle.
  291.     GetClientRect(m_hWnd, &WinRect);
  292.     // Fill that rectangle with pixels of white paint.
  293.     FillRect(hDC, &WinRect, GETCLASSBRUSH(m_hWnd));
  294.  
  295.     // Tell the COBall to reset itself.
  296.     m_pIBall->Reset(&WinRect, 0);
  297.  
  298.     // Call our own CGuiBall method to paint an initial image of the ball.
  299.     PaintBall();
  300.  
  301.     // Release the Device Context.
  302.     ReleaseDC(m_hWnd, hDC);
  303.   }
  304.  
  305.   return;
  306. }
  307.  
  308.  
  309. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  310.   Method:   CGuiBall::PaintWin
  311.  
  312.   Summary:  Clears window background and paints the GuiBall at its
  313.             current location.
  314.  
  315.   Args:     void
  316.  
  317.   Modifies: ...
  318.  
  319.   Returns:  void
  320. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  321. void CGuiBall::PaintWin(void)
  322. {
  323.   HDC         hDC;
  324.   PAINTSTRUCT ps;
  325.   RECT        WinRect;
  326.  
  327.   if(hDC = BeginPaint(m_hWnd, &ps))
  328.     EndPaint(m_hWnd, &ps);
  329.  
  330.   if(hDC = GetDC(m_hWnd))
  331.   {
  332.     // Get our window's client area rectangle.
  333.     GetClientRect(m_hWnd, &WinRect);
  334.     // Fill that rectangle with pixels of white paint.
  335.     FillRect(hDC, &WinRect, GETCLASSBRUSH(m_hWnd));
  336.  
  337.     // Paint a current image of the ball wherever it is.
  338.     PaintBall();
  339.  
  340.     ReleaseDC(m_hWnd, hDC);
  341.   }
  342.  
  343.   return;
  344. }
  345.  
  346.  
  347. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  348.   Method:   CGuiBall::BounceBottom
  349.  
  350.   Summary:  Produce a sound for the ball bounce against the Bottom
  351.             boundary.
  352.  
  353.   Args:     void
  354.  
  355.   Modifies: ...
  356.  
  357.   Returns:  void
  358. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  359. void CGuiBall::BounceBottom(void)
  360. {
  361.   // Use the Win32 Beep call.
  362.   Beep(m_dwBounceBotFreq, m_dwBounceSndDur);
  363.  
  364.   return;
  365. }
  366.  
  367.  
  368. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  369.   Method:   CGuiBall::BounceSide
  370.  
  371.   Summary:  Produce a sound for the ball bounce against a Side boundary.
  372.  
  373.   Args:     void
  374.  
  375.   Modifies: ...
  376.  
  377.   Returns:  void
  378. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  379. void CGuiBall::BounceSide(void)
  380. {
  381.   // Use the Win32 Beep call.
  382.   Beep(m_dwBounceSideFreq, m_dwBounceSndDur);
  383.  
  384.   return;
  385. }
  386.  
  387.  
  388. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  389.   Method:   CGuiBall::BounceTop
  390.  
  391.   Summary:  Produce a sound for the ball bounce against the Top boundary.
  392.  
  393.   Args:     void
  394.  
  395.   Modifies: ...
  396.  
  397.   Returns:  void
  398. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  399. void CGuiBall::BounceTop(void)
  400. {
  401.   // Use the Win32 Beep call.
  402.   Beep(m_dwBounceTopFreq, m_dwBounceSndDur);
  403.  
  404.   return;
  405. }
  406.  
  407.  
  408. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  409.   Method:   CGuiBall::GetConnectionPoint
  410.  
  411.   Summary:  Internal private method to obtain a connection point interface.
  412.  
  413.   Args:     REFIID riid
  414.               IID of the requested connection point Interface.
  415.  
  416.   Modifies: ...
  417.  
  418.   Returns:  IConnectionPoint*
  419.               Requested IConnectionPoint interface pointer. NULL if none.
  420. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  421. IConnectionPoint* CGuiBall::GetConnectionPoint(
  422.                     REFIID riid)
  423. {
  424.   IConnectionPointContainer* pConnPointContainer = NULL;
  425.   IConnectionPoint* pConnPoint = NULL;
  426.   IConnectionPoint* pConnPt = NULL;
  427.   HRESULT hr;
  428.  
  429.   // First query the object for its Connection Point Container. This
  430.   // essentially asks the object in the server if it is connectable.
  431.   hr = m_pIBall->QueryInterface(
  432.          IID_IConnectionPointContainer,
  433.          (PPVOID)&pConnPointContainer);
  434.   if SUCCEEDED(hr)
  435.   {
  436.     // Find the requested Connection Point. This AddRef's the
  437.     // returned pointer.
  438.     hr = pConnPointContainer->FindConnectionPoint(riid, &pConnPt);
  439.     if (SUCCEEDED(hr))
  440.       pConnPoint = pConnPt;
  441.  
  442.     // Release the connection point container. We're done with it.
  443.     RELEASE_INTERFACE(pConnPointContainer);
  444.   }
  445.  
  446.   return pConnPoint;
  447. }
  448.  
  449.  
  450. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  451.   Method:   CGuiBall::ConnectBallSink
  452.  
  453.   Summary:  Connect the BallSink to the server COBall source.
  454.  
  455.   Args:     void
  456.  
  457.   Modifies: ...
  458.  
  459.   Returns:  HRESULT
  460.               Standard result code. NOERROR for success.
  461. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  462. HRESULT CGuiBall::ConnectBallSink(void)
  463. {
  464.   HRESULT hr = E_FAIL;
  465.   DWORD dwKey;
  466.   IConnectionPoint* pConnPoint = NULL;
  467.  
  468.   if (!m_dwBallSink)
  469.   {
  470.     // Get the Ball Sink connection point.
  471.     pConnPoint = GetConnectionPoint(IID_IBallSink);
  472.     if (NULL != pConnPoint)
  473.     {
  474.       // Connect the object in the server to the Ball Sink in this client.
  475.       hr = pConnPoint->Advise(m_pCOBallSink, &dwKey);
  476.       if (SUCCEEDED(hr))
  477.         m_dwBallSink = dwKey;
  478.  
  479.       // Release the connection point. We're done with it.
  480.       RELEASE_INTERFACE(pConnPoint);
  481.     }
  482.   }
  483.  
  484.   return hr;
  485. }
  486.  
  487.  
  488. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  489.   Method:   CGuiBall::DisconnectBallSink
  490.  
  491.   Summary:  Disconnect the BallSink from the server COBall source.
  492.  
  493.   Args:     void.
  494.  
  495.   Modifies: ...
  496.  
  497.   Returns:  HRESULT
  498.               Standard result code. NOERROR for success.
  499. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  500. HRESULT CGuiBall::DisconnectBallSink(void)
  501. {
  502.   HRESULT hr = E_FAIL;
  503.   IConnectionPoint* pConnPoint;
  504.  
  505.   if (m_dwBallSink)
  506.   {
  507.     // Get the Ball Sink connection point.
  508.     pConnPoint = GetConnectionPoint(IID_IBallSink);
  509.     if (NULL != pConnPoint)
  510.     {
  511.       // Disconnect the object in the server from the Ball Sink in
  512.       // this client.
  513.       hr = pConnPoint->Unadvise(m_dwBallSink);
  514.       if (SUCCEEDED(hr))
  515.         m_dwBallSink = 0;
  516.  
  517.       // Release the connection point. We're done with it.
  518.       RELEASE_INTERFACE(pConnPoint);
  519.     }
  520.   }
  521.  
  522.   return hr;
  523. }
  524.