Windows NT Systems Programming: Spring 2000

[ Home | Syllabus | Course Notes | Assignments | Search]


Exercise 24a: simulated COM object

Description of desired object:

Source Code Here


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

Client Program

#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); hptrd_left.gif (955 bytes)

    pClf->CreateInstance(IID_IUnknown, (void**) &pUnk); hptrd_left.gif (955 bytes)
    pUnk->QueryInterface(IID_IMotion, (void**) &pMot);  hptrd_left.gif (955 bytes)
    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;
}
rainbow.gif (2243 bytes)

Implementation Class Definition

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

Tracing the Client Program (GetClassObject)

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);hptrd_left.gif (955 bytes)
    ASSERT((nIid == IID_IUnknown) || (nIid == IID_IClassFactory));hptrd_left.gif (955 bytes)
    return g_factory.ExternalQueryInterface(nIid, ppvObj);hptrd_left.gif (955 bytes)
    // 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; hptrd_left.gif (955 bytes)
      break;
    default:
      *ppvObj = NULL;
      return FALSE;
    }
    ExternalAddRef( );hptrd_left.gif (955 bytes)
    return TRUE;
}                      

 

rainbow.gif (2243 bytes)

 


CreateInstance

Purpose: to create an instance of the space ship object using the class factory object

BOOL CSpaceshipFactory::XClassFactory::hptrd_left.gif (955 bytes)CreateInstance(int nIid,
                                                      void** ppvObj) {
    CSpaceship* pObj = new CSpaceship(); hptrd_left.gif (955 bytes)
    if (pObj->ExternalQueryInterface(nIid, ppvObj)) {hptrd_left.gif (955 bytes)
        pObj->ExternalRelease(); // balance reference count
        return TRUE;
    }
    return FALSE;
}
BOOL CSpaceship::ExternalQueryInterface(int nIid, void** ppvObj) {
    switch (nIid) {
    case IID_IUnknown:hptrd_left.gif (955 bytes)
    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;
}                               

 

rainbow.gif (2243 bytes)

 


Releasing Components

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

Copyright chris wild 1999/2000.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: March 14, 2000.