CodeSteps

Python, C, C++, C#, PowerShell, Android, Visual C++, Java ...

COM – Creating a COM Component using C++ – IClassFactory

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 goals of the COM is to locate the objects easily without worrying about where they are located and where they are housed; whether they are housed in in-processlocal, or 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 are housed in separate executable files)remotely means, the objects are housed in a completely different system other than the system where the client application is running and obviously they are in a 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 a 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 a 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 was pushed to IClassFactory. IClassFactory is an important COM’s interface to enable the clients to reach the objects without worrying about where the objects are housed in. So, each component (not each interface) we are developing should implement the IClassFactory interface. IClassFactory interface supports the following methods.

HRESULT CreateInstance(
  [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 that indicates whether to keep the object server in memory or not. This function enables to creation of instances more easily. In our example, we are not going to use this function. But we should implement this in our IClassFactory implementation class.

IClassFactory’s CreateInstance code

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 )
		return CLASS_E_NOAGGREGATION;

	CHelloComponent *pComponent = new CHelloComponent();
	if ( pComponent == NULL )
		return E_OUTOFMEMORY;

	HRESULT hr = pComponent->QueryInterface(riid, ppv);
	pComponent->Release();

	return hr;
}

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 noticed that? Actually, IClassFactory‘s CreateInstance function is responsible for creating components. Not the DllGetClassObject function. So, we have created our HelloComponent instance and returned the result. Notice that we called the 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 the 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.

LockServer method

And the code for the LockServer method looks like below.

HRESULT CObjectFactory::LockServer(BOOL bLock)
{
	m_cServerLocks = 
( bLock == TRUE ) ? ( m_cServerLocks + 1 ) : ( m_cServerLocks - 1 );

	return S_OK;
}

To keep the server in memory, we maintain one variable, m_cServerLocks.

Next article we will add these methods into our HelloComponent code.

**

COM – Creating a COM Component using C++ – IClassFactory

One thought on “COM – Creating a COM Component using C++ – IClassFactory

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top