[ Home | Syllabus | Course Notes | Assignments | Search]
Implementing the Component ISum
Could use any language - Let's use C++ first
Remember that the ISum interface object is an abstract class because its four functions are pure virtual.
(What are the four functions?)
Therefore we need to derive a implementation class from it.
class CInsideDCOM : public ISum { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID iid, void** ppv); // ISum HRESULT __stdcall Sum(int x, int y, int* retval); CInsideDCOM() : m_cRef(1) { g_cComponents++; } ~CInsideDCOM() { cout << "Component: CInsideDCOM::~CInsideDCOM()" << endl, g_cComponents--; } private: ULONG m_cRef; };
Implementing IUnknown Functions
ULONG CInsideDCOM::AddRef() { return ++m_cRef; } ULONG CInsideDCOM::Release() { if(--m_cRef != 0) // test if last reference return m_cRef; delete this; // "calls" destructor return 0; } HRESULT CInsideDCOM::QueryInterface(REFIID iid, void** ppv) { if(iid == IID_IUnknown) { *ppv = (IUnknown*)this; } else if(iid == IID_ISum) { *ppv = (ISum*)this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; }
QueryInterface Rules
QueryInterface on any interface of a component, must produce
the same results.
You can query ISum for IUnknown for instance.
Symmetric: Calls for the same interface must
return the same pointer value.
If a call fails one time, it must fail everytime.
Reflexive: If queries on one interface for a for a second succeed, then queries on the second for the first must also succeed.
Transitive: If a query on interface one gives interface two and a query on interface two gives interface three, then a query for interface three on interface one must succeed.
SUM implementation
HRESULT CInsideDCOM::Sum(int x, int y, int* retval) { *retval = x + y; return S_OK; }
Creating a "Location Transparent" to IUnknown
Used by CoCreateInstance, calls CreateInstance.
class CFactory : public IClassFactory { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID iid, void** ppv); // IClassFactory HRESULT __stdcall CreateInstance(IUnknown *pUnknownOuter, REFIID iid, void** ppv); HRESULT __stdcall LockServer(BOOL bLock); CFactory() : m_cRef(1) { } ~CFactory() { } private: ULONG m_cRef; };
HRESULT CFactory::CreateInstance(IUnknown *pUnknownOuter, REFIID iid, void** ppv) { if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION; CInsideDCOM *pInsideDCOM = new CInsideDCOM; cout << "Component: CFactory::CreateInstance() " << pInsideDCOM << endl; if(pInsideDCOM == NULL) return E_OUTOFMEMORY; // QueryInterface probably for IID_IUNKNOWN HRESULT hr = pInsideDCOM->QueryInterface(iid, ppv); pInsideDCOM->Release(); return hr; }
HRESULT CFactory::LockServer(BOOL bLock) { if(bLock) g_cServerLocks++; else g_cServerLocks--; return S_OK; } HRESULT __stdcall DllCanUnloadNow() { cout << "Component: DllCanUnloadNow() " << (g_cServerLocks == 0 && g_cComponents == 0 ? "Yes" : "No") << endl; if(g_cServerLocks == 0 && g_cComponents == 0) return S_OK; else return S_FALSE; } HRESULT __stdcall DllGetClassObject(REFCLSID clsid, REFIID iid, void** ppv) { cout << "Component: DllGetClassObject" << endl; if(clsid != CLSID_InsideDCOM) return CLASS_E_CLASSNOTAVAILABLE; CFactory* pFactory = new CFactory; if(pFactory == NULL) return E_OUTOFMEMORY; // QueryInterface probably for IClassFactory HRESULT hr = pFactory->QueryInterface(iid, ppv); pFactory->Release(); return hr; }