[ Home | Syllabus | Course Notes | Assignments | Search]
Description of desired object:
Interfaces to spaceship component.
We will build this one by hand - as simulated COM object
Here is interface.h (relevant parts)
// here is the stuff that we really want
struct IMotion : public IUnknown
{
IMotion() { }
virtual void Fly() = 0; // pure
virtual int& GetPosition() = 0;
};
struct IVisual : public IUnknown
{
IVisual() { }
virtual void Display() = 0;
};
// here is the stuff needed for creating and managing components
struct IUnknown
// manages component - returns interface vtables and controls lifetime
{
IUnknown() { }
virtual BOOL QueryInterface(int nIid, void** ppvObj) = 0;
virtual DWORD Release() = 0;
virtual DWORD AddRef() = 0;
};
struct IClassFactory : public IUnknown
// used to create components
{
IClassFactory( ) { }
virtual BOOL CreateInstance(int nIid, void** ppvObj) = 0;
};
#include "interface.h"
int main( ) // simulates OLE client program
{
IUnknown* pUnk; // If you declare these void*, you lose type-safety
IMotion* pMot;
IVisual* pVis;
IClassFactory* pClf;
GetClassObject(CLSID_CSpaceship, IID_IClassFactory,
(void**) &pClf);
pClf->CreateInstance(IID_IUnknown, (void**) &pUnk);
pUnk->QueryInterface(IID_IMotion, (void**) &pMot);
pMot->QueryInterface(IID_IVisual, (void**) &pVis);
// next three lines are the "real" program
pMot->Fly(); // fly to next position
int nPos = pMot->GetPosition();
pVis->Display(); // and display spaceship
pClf->Release(); // clean up
pUnk->Release();
pMot->Release();
pVis->Release();
return 0;
}
class CSpaceship
{
private:
int m_nPosition;
int m_nAcceleration;
int m_nColor;
public:
CSpaceship() { m_nPosition = 100; m_nAcceleration = 101; m_nColor = 102; }
~CSpaceship( ) { }
class XMotion : public IMotion // inherits interface class
// nested classes
{
public:
XMotion( ) { }
virtual void Fly();
virtual int& GetPosition();
} m_xMotion;
class XVisual : public IVisual
{
public:
XVisual( ) { }
virtual void Display();
} m_xVisual;
friend class XVisual; // These must be at the bottom!
friend class XMotion;
};
Purpose: generate a classfactory object for creating
Spaceship objects.
See previous notes on com servers and com registry
CSpaceshipFactory g_factory;
//----------simulates COM component ----------------------------------
// In real COM, this would be DllGetClassObject, which would be called
// whenever a client called CoGetClassObject
BOOL GetClassObject(int nClsid, int nIid, void** ppvObj)
{
ASSERT(nClsid == CLSID_CSpaceship);
ASSERT((nIid == IID_IUnknown) || (nIid == IID_IClassFactory));
return g_factory.ExternalQueryInterface(nIid, ppvObj);
// refcount is 2, which prevents accidental deletion
}
BOOL CSpaceshipFactory::ExternalQueryInterface(int nIid,
void** ppvObj) {
switch (nIid) {
case IID_IUnknown:
case IID_IClassFactory:
*ppvObj = &m_xClassFactory;
break;
default:
*ppvObj = NULL;
return FALSE;
}
ExternalAddRef( );
return TRUE;
}
Purpose: to create an instance of the space ship object using the class factory object
BOOL CSpaceshipFactory::XClassFactory::CreateInstance(int nIid, void** ppvObj) { CSpaceship* pObj = new CSpaceship();
if (pObj->ExternalQueryInterface(nIid, ppvObj)) {
pObj->ExternalRelease(); // balance reference count return TRUE; } return FALSE; }
BOOL CSpaceship::ExternalQueryInterface(int nIid, void** ppvObj) {
switch (nIid) {
case IID_IUnknown:
case IID_IMotion:
*ppvObj = &m_xMotion; // Both IMotion and IVisual are derived
break; // from IUnknown, so either pointer will do
case IID_IVisual:
*ppvObj = &m_xVisual;
break;
default:
*ppvObj = NULL;
return FALSE;
}
ExternalAddRef();
return TRUE;
}
DWORD ExternalRelease() {
if (m_dwRef == 0)
return 0;
if(--m_dwRef == 0L) {
delete this; // delete when reference count become 0
return 0;
}
return m_dwRef;
}