In our previous article, we have identified that CoCreateFunction is requesting an instance of IClassFactory.
Why CoCreateInstance is requesting an instance of IClassFactory?
One of the goal of the COM is locate the objects easily without worrying about where they are located and where they are housed in; whether they are housed in in-process, local or in remote. in-process means, the objects are housed in the same address space of the client application. local means, the objects are housed in separate address space (they housed in separate executable files). remotely means, the objects are housed in completely different system other than the system where the client application is running and obviously they are in different address space than the client application’s address space.
CoCreateInstance should succeed in all these cases. If suppose, CoCreateInstance function is designed such a way that, it will create an instance of a component directly using new operator. Do you think the code will work? Yes, it should work. But it will work only for in-process components. But it will definitely fail to work if the component is housed in local server and remote server. Hence we used DllGetClassObject to instantiate our component. But still we were not able to create our component through CoCreateInstance.
In the design of CoCreateInstance, the component creation process pushed to IClassFactory. IClassFactory is an important COM’s interface to enable the clients to reach the objects without worrying where the objects are housed in. So, each component (not each interface) we are developing should implement IClassFactory interface. IClassFactory interface supports the following methods.
[in] IUnknown *pUnkOuter,
[in] REFIID riid,
[out] void **ppvObject
Here, pUnkOuter is the pointer to the aggregate object. In our sample we are not using any aggregate object. So, we should pass NULL through this parameter.
riid is the interface ID. Based on this ID, CreateInstance will create an instance of a class.
ppvObject is the address of an instance of a class.
Another method is LockServer. The function prototype is like below:
HRESULT LockServer([in] BOOL bLock);
bLock is the boolean parameter which indicates whether to keep the object server in memory or not. This function enables to create instances more easily. In our example, we are not going to use this function. But we should implement this in our IClassFactory implementation class.
For our component, the code for IClassFactory‘s CreateInstance function looks like below:
HRESULT CObjectFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
if ( pUnkOuter != NULL )
CHelloComponent *pComponent = new CHelloComponent();
if ( pComponent == NULL )
HRESULT hr = pComponent->QueryInterface(riid, ppv);
As I mentioned before, we are not supporting Aggregation in our HelloComponent. So, the first argument must be NULL. If you pass any other value, other than NULL, CreateInstance should return CLASS_E_NOAGGREGATION error, because our component is not supporting aggregation; hence the first “if” in CreateInstance function.
Have you notice that? Actually, IClassFactory‘s CreateInstance function is responsible for creating components. Not the DllGetClassObject function. So, we have created our HelloComponent instance and returning the result. Notice that we called Release method, after QueryInterface on our HelloComponent. This Release method call is helpful, if the QueryInterface function fails to get the requested interface’s pointer. If it succeeds also we are calling Release method; because, initially we are setting the reference count value to “1”; even though no components were referenced. So, this Release method will balance the reference count.
And the code for LockServer method is looks like below.
HRESULT CObjectFactory::LockServer(BOOL bLock)
( bLock == TRUE ) ? ( m_cServerLocks + 1 ) : ( m_cServerLocks - 1 );
To keep the server in memory, we maintain one variable, m_cServerLocks.
Next article we will add these methods into our HelloComponent code.