Lesson 4 | How IClassFactory creates objects |
Objective | Discover how IClassFactory creates objects. |
How IClassFactory Creates Objects
Recall that there is a one-to-one association between a class object/factory and a COM object.
If we implement two COM objects, namely
O1
and
O2
we must implement two class factories, one for each type of COM object.
Assume
CF01
is the class factory for
O1
and
CF02
is the class factory for
O2
.
A call to
CF01::CreateInstance
does the following:
- Creates an instance of COM object
O1
.
- Within
CreateInstance
, after object O1
is created, calls O1::QueryInterface
to have O1
return the requested interface pointer to the client.
A call to
CF02::CreateInstance
does the following:
- Creates an instance of
O2
.
- Calls
O2::QueryInterface
to have O2
return the requested interface pointer to the client.
We will revisit class factories in a follow-up lesson.
IClassFactory shows C++-style logic that demonstrates how to implement a class factory (See code below, Implementing IClassFactory).
One question that still needs to be addressed is how does a client get a pointer into a class factory to create instances of COM object?
We will discuss this in the next set of lessons when we examine COM servers and clients.
Implementing IClassFactory
ULONG g_lock = 0;
//Assume COM object MyComObject is implemented
//by class CMyComObject using the multiple inheritance technique.
class CMyComObject : public IMyComInterface,
public IYourComInterface { ... }
struct CFMyComObject : public IClassFactory
{
ULONG m_refcnt;
HRESULT QueryInterface
(const IID& riid, VOID **ppv) {
//class factories normally only respond to
//IID_IUnknown and IClassFactory
if (IID_IUnknown == riid ||
IID_IClassFactory == riid) {
*ppv = this;
((IUnknown *) *ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
ULONG AddRef() { return ++m_refcnt; }
ULONG Release() {
//When the reference count goes to zero we
//normally delete the class factory
if (--m_refcnt == 0) {
delete this;
return 0;
}
return m_refcnt;
}
HRESULT CreateInstance(IUnknown *pOuter,
const IID& riid, void **ppv) {
CMyComObject *pc;
//if pOuter is not NULL, return an ERROR
if (pOuter != NULL)
return E_NOAGGREGATION;
//Create a new instance of the C++ class that
//implements our COM object and call
pc = new CMyComObject();
//QueryInterface in it to see
//if the object supports the interface
//requested by the client.
HRESULT hr = pc->QueryInterface(riid, ppv);
//If the client has asked for an interface not
//supported by the newly created COM object
//delete the COM object and
//return the error code
//from the QueryInterface call. This
//will usually be E_NOINTERFACE.
if (FAILED(hr)) {
delete pc;
return hr;
}
return S_OK;
}
HRESULT LockServer(BOOL fLock) {
if (fLock) ++g_lock;
else --g_lock;
}
CFMyComObject() : m_refcnt(0) { }
};
Debug Class Factory - Exercise