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 >
Wrap
C/C++ Source or Header
|
1997-08-05
|
15KB
|
524 lines
/*+==========================================================================
File: GUIBALL.CPP
Summary: Implementation file for the CGuiBall C++ class. A GuiBall is
a C++ object that displays a moving and bouncing ball in the
client area of a designated window. It is anchored to the
Windows GUI (Graphical User Interface) environment. This
GuiBall object continuously paints a ball image based on data
it obtains from a virtual ball object. This virtual ball
object is instantiated as a COM object (a COBall) in a
separate thread-safe In-process server, CONSERVE.
GuiBall relies on the system timer to send periodic WM_TIMER
messages to a window procedure designated in the
CGuiBall::Init call. When these messages are received, the
window procedure calls the CGuiBall::PaintBall method which
both moves and displays the ball image.
For a comprehensive tutorial code tour of GUIBALL's contents
and offerings see the tutorial CONCLIEN.HTM file. For more
specific technical details on the internal workings see the
comments dispersed throughout the GUIBALL source code.
Classes: CGuiBall.
Origin: 5-30-96: atrent - Editor inheritance from GUIBALL.CPP in the
FRECLIEN source.
----------------------------------------------------------------------------
This file is part of the Microsoft COM Tutorial Code Samples.
Copyright (C) Microsoft Corporation, 1997. All rights reserved.
This source code is intended only as a supplement to Microsoft
Development Tools and/or on-line documentation. See these other
materials for detailed information regarding Microsoft code samples.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
==========================================================================+*/
/*--------------------------------------------------------------------------
We include WINDOWS.H for all Win32 applications.
We include OLE2.H because we will be calling the COM/OLE libraries.
We include OLECTL.H because it has definitions for connectable objects.
We include APPUTIL.H because we will be building this application using
the convenient Virtual Window and Dialog classes and other
utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
We include IBALL.H and BALLGUID.H for the common Ball-related Interface
class, GUID, and CLSID specifications.
We include GUIBALL.H because it has the C++ class used for GUI display
of the moving ball.
We include CONCLIEN.H because it has class and resource definitions
specific to this CONCLIEN application.
---------------------------------------------------------------------------*/
#include <windows.h>
#include <ole2.h>
#include <olectl.h>
#include <apputil.h>
#include <iball.h>
#include <ballguid.h>
#include "guiball.h"
#include "sink.h"
#include "conclien.h"
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::CGuiBall
Summary: Constructor.
Args: void
Modifies: ...
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
CGuiBall::CGuiBall(void)
{
m_hWnd = 0;
m_pIBall = NULL;
m_crColor = RGB(0,0,0);
m_OldPos.x = 0;
m_OldPos.y = 0;
m_OldExt.x = 0;
m_OldExt.y = 0;
m_pCOBallSink = NULL;
m_dwBallSink = 0;
m_dwBounceSndDur = BOUNCE_SOUND_DURATION;
m_dwBounceBotFreq = BOUNCE_BOTTOM_FREQUENCY;
m_dwBounceSideFreq = BOUNCE_SIDE_FREQUENCY;
m_dwBounceTopFreq = BOUNCE_TOP_FREQUENCY;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::~CGuiBall
Summary: Destructor.
Args: void
Modifies: ...
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
CGuiBall::~CGuiBall(void)
{
BOOL bOk = TRUE;
// Kill the client's app timer that drives repaints. Stops the WM_TIMER
// messages to the display window.
KillTimer(m_hWnd, 1);
if (m_pIBall)
{
// Call down to the server's COBall and tell it about the shutdown.
// This sets COBall's m_bAlive to FALSE, neutralizes all
// subsequent Move calls, and thus prevents any more NotifySinks calls
// from within the Move method.
m_pIBall->Move(FALSE);
// Disconnect all Sinks--currently only one: BallSink. This officially
// stops all BallSink notifications.
DisconnectBallSink();
// Release the reference to the BallSink object.
RELEASE_INTERFACE(m_pCOBallSink);
// Release the main interface pointer copy held in CGuiBall.
RELEASE_INTERFACE(m_pIBall);
}
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::Init
Summary: Get everything related to CGuiBall started. Make any
subordinate objects, like COBall, and get it started. Starts
the system timer that keeps the virtual ball moving with GUI
painted images.
Args: HWND hWnd
Handle of the display window. Part of what makes CGuiBall
a GUI kind of thing.
Modifies: ...
Returns: BOOL
TRUE for success; FALSE for fail.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
BOOL CGuiBall::Init(
HWND hWnd)
{
BOOL bOk = FALSE;
HRESULT hr;
COBallSink* pCob = NULL;
if (hWnd)
{
m_hWnd = hWnd;
// Call COM service to create a COBall instance. We are not
// aggregating it so we ask for its IBall interface directly.
hr = CoCreateInstance(
CLSID_DllSndBall,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBall,
(PPVOID)&m_pIBall);
if (SUCCEEDED(hr))
{
// Create the COBallSink Sink object to receive COBall events.
pCob = new COBallSink(NULL, this);
if (NULL != pCob)
{
// Save a pointer to the COBall IUnknown interface. AddRef
// because of this saved copy.
m_pCOBallSink = pCob;
m_pCOBallSink->AddRef();
}
else
hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
// Set up the client process to periodically move & paint the ball
// thru WM_TIMER messages to the specified hWnd's Window proc.
SetTimer(hWnd, 1, BALL_PAINT_DELAY, NULL);
bOk = TRUE;
}
}
}
return (bOk);
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::PaintBall
Summary: Tell CGuiBall to move one increment and paint one image of the
GuiBall.
Args: void
Modifies: ...
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
void CGuiBall::PaintBall(void)
{
HDC hDC;
HBRUSH hBrush;
POINT Org, Ext;
HRGN hTmp, hOld, hNew;
if (m_pIBall)
{
// Move the ball before painting it. By placing this Move call here
// we link moving with painting in synchronized lock step.
m_pIBall->Move(TRUE);
// Ask the COBall for its current ball (location, region, and color).
m_pIBall->GetBall(&Org, &Ext, &m_crColor);
// Create the old ball image/region.
hOld = CreateEllipticRgn(m_OldPos.x, m_OldPos.y, m_OldExt.x, m_OldExt.y);
// Create the new ball image/region.
hNew = CreateEllipticRgn(Org.x, Org.y, Ext.x, Ext.y);
// Remember the new Pos and Ext as the next old set of Pos and Ext.
m_OldPos.x = Org.x;
m_OldPos.y = Org.y;
m_OldExt.x = Ext.x;
m_OldExt.y = Ext.y;
if(hDC = GetDC(m_hWnd))
{
// Erase old ball image.
hTmp = CreateRectRgn(1, 1, 2, 2);
if (NULL != hOld)
CombineRgn(hTmp, hOld, hNew, RGN_DIFF);
FillRgn(hDC, hTmp, GETCLASSBRUSH(m_hWnd));
// Make a paint brush, dip it in pixel paint, and paint the
// new Ball image. Destroy brush after use.
hBrush = CreateSolidBrush(m_crColor);
FillRgn(hDC, hNew, hBrush);
DeleteObject(hBrush);
ReleaseDC(m_hWnd, hDC);
DeleteObject(hTmp);
}
// Delete the region objects.
if (NULL != hOld)
DeleteObject(hOld);
if (NULL != hNew)
DeleteObject(hNew);
}
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::Restart
Summary: Restart the display process. Places Ball in start position
in a clean window.
Args: void.
Modifies: ...
Returns: void.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
void CGuiBall::Restart(void)
{
RECT WinRect;
HDC hDC = GetDC(m_hWnd);
if(hDC && m_pIBall)
{
// Clear the window.
// Get our window's client area rectangle.
GetClientRect(m_hWnd, &WinRect);
// Fill that rectangle with pixels of white paint.
FillRect(hDC, &WinRect, GETCLASSBRUSH(m_hWnd));
// Tell the COBall to reset itself.
m_pIBall->Reset(&WinRect, 0);
// Call our own CGuiBall method to paint an initial image of the ball.
PaintBall();
// Release the Device Context.
ReleaseDC(m_hWnd, hDC);
}
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::PaintWin
Summary: Clears window background and paints the GuiBall at its
current location.
Args: void
Modifies: ...
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
void CGuiBall::PaintWin(void)
{
HDC hDC;
PAINTSTRUCT ps;
RECT WinRect;
if(hDC = BeginPaint(m_hWnd, &ps))
EndPaint(m_hWnd, &ps);
if(hDC = GetDC(m_hWnd))
{
// Get our window's client area rectangle.
GetClientRect(m_hWnd, &WinRect);
// Fill that rectangle with pixels of white paint.
FillRect(hDC, &WinRect, GETCLASSBRUSH(m_hWnd));
// Paint a current image of the ball wherever it is.
PaintBall();
ReleaseDC(m_hWnd, hDC);
}
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::BounceBottom
Summary: Produce a sound for the ball bounce against the Bottom
boundary.
Args: void
Modifies: ...
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
void CGuiBall::BounceBottom(void)
{
// Use the Win32 Beep call.
Beep(m_dwBounceBotFreq, m_dwBounceSndDur);
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::BounceSide
Summary: Produce a sound for the ball bounce against a Side boundary.
Args: void
Modifies: ...
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
void CGuiBall::BounceSide(void)
{
// Use the Win32 Beep call.
Beep(m_dwBounceSideFreq, m_dwBounceSndDur);
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::BounceTop
Summary: Produce a sound for the ball bounce against the Top boundary.
Args: void
Modifies: ...
Returns: void
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
void CGuiBall::BounceTop(void)
{
// Use the Win32 Beep call.
Beep(m_dwBounceTopFreq, m_dwBounceSndDur);
return;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::GetConnectionPoint
Summary: Internal private method to obtain a connection point interface.
Args: REFIID riid
IID of the requested connection point Interface.
Modifies: ...
Returns: IConnectionPoint*
Requested IConnectionPoint interface pointer. NULL if none.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
IConnectionPoint* CGuiBall::GetConnectionPoint(
REFIID riid)
{
IConnectionPointContainer* pConnPointContainer = NULL;
IConnectionPoint* pConnPoint = NULL;
IConnectionPoint* pConnPt = NULL;
HRESULT hr;
// First query the object for its Connection Point Container. This
// essentially asks the object in the server if it is connectable.
hr = m_pIBall->QueryInterface(
IID_IConnectionPointContainer,
(PPVOID)&pConnPointContainer);
if SUCCEEDED(hr)
{
// Find the requested Connection Point. This AddRef's the
// returned pointer.
hr = pConnPointContainer->FindConnectionPoint(riid, &pConnPt);
if (SUCCEEDED(hr))
pConnPoint = pConnPt;
// Release the connection point container. We're done with it.
RELEASE_INTERFACE(pConnPointContainer);
}
return pConnPoint;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::ConnectBallSink
Summary: Connect the BallSink to the server COBall source.
Args: void
Modifies: ...
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
HRESULT CGuiBall::ConnectBallSink(void)
{
HRESULT hr = E_FAIL;
DWORD dwKey;
IConnectionPoint* pConnPoint = NULL;
if (!m_dwBallSink)
{
// Get the Ball Sink connection point.
pConnPoint = GetConnectionPoint(IID_IBallSink);
if (NULL != pConnPoint)
{
// Connect the object in the server to the Ball Sink in this client.
hr = pConnPoint->Advise(m_pCOBallSink, &dwKey);
if (SUCCEEDED(hr))
m_dwBallSink = dwKey;
// Release the connection point. We're done with it.
RELEASE_INTERFACE(pConnPoint);
}
}
return hr;
}
/*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
Method: CGuiBall::DisconnectBallSink
Summary: Disconnect the BallSink from the server COBall source.
Args: void.
Modifies: ...
Returns: HRESULT
Standard result code. NOERROR for success.
M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
HRESULT CGuiBall::DisconnectBallSink(void)
{
HRESULT hr = E_FAIL;
IConnectionPoint* pConnPoint;
if (m_dwBallSink)
{
// Get the Ball Sink connection point.
pConnPoint = GetConnectionPoint(IID_IBallSink);
if (NULL != pConnPoint)
{
// Disconnect the object in the server from the Ball Sink in
// this client.
hr = pConnPoint->Unadvise(m_dwBallSink);
if (SUCCEEDED(hr))
m_dwBallSink = 0;
// Release the connection point. We're done with it.
RELEASE_INTERFACE(pConnPoint);
}
}
return hr;
}