[ 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; }