[ 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;
}
![]()
