COM: Creating a COM Component using C++ (Part-10)

CoCreateInstance is depends on IClassFactory to create class instances. We have looked into IClassFactory‘s methods and we have implemented these methods in our previous article.

Lets include IClassFactory‘s implementation into our HelloComponent.

We already have HelloComponent‘s declaration in “HelloComponent.h” file and its implementation in “HelloComponent.cpp” file. The same way, we will add IClassFactory interface declaration into “HelloComponent.h” file. And we will add IClassFactory interface implementation into
“HelloComponent.cpp” file.

After we have added IClassFactory interface declaration; the file “HelloComponent.h” looks like below:

#pragma once

#include "Hello.h"
#include "Hello_i.c"

#include <iostream>

// {23893EE4-8514-4BD6-8830-A7EBDDF5C944}
static const GUID CLSID_HelloComponent = { 0x23893ee4, 0x8514, 0x4bd6, { 0x88, 0x30, 0xa7, 0xeb, 0xdd, 0xf5, 0xc9, 0x44 } };

// CHelloComponent class
//
class CHelloComponent : public IHello
{
public:
	CHelloComponent() : m_cRef (1)
	{
		m_cComponents++;
	}
	~CHelloComponent()
	{
		m_cComponents--;
	}

	// -- IUnknown Methods
	ULONG STDMETHODCALLTYPE AddRef();
	ULONG STDMETHODCALLTYPE Release();
	HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv);

	// -- IHello Method
	HRESULT STDMETHODCALLTYPE SayHello(BSTR message);

public:
	static int m_cComponents;

private:
	ULONG m_cRef;
};

// CObjectFactory class
//
class CObjectFactory : public IClassFactory
{
public:
	CObjectFactory() : m_cRef (1)
	{
	}
	~CObjectFactory()
	{
	}

	// -- IUnknown Methods
	ULONG STDMETHODCALLTYPE AddRef();
	ULONG STDMETHODCALLTYPE Release();
	HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv);

	// -- IClassFactory Methods
	HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv);
	HRESULT STDMETHODCALLTYPE LockServer(BOOL bLock);

public:
	static int m_cServerLocks;

private:
	ULONG m_cRef;
};

// -- Initialize static members of a class here.
int CHelloComponent::m_cComponents = 0;
int CObjectFactory::m_cServerLocks = 0;

Now we need to add IClassFactory interface implementation. After we have added IClassFactory interface implementation; the file “HelloComponent.cpp” looks like below:

#include "HelloComponent.h"

#include <Objbase.h>
#include <comutil.h>

using namespace std;

HRESULT CHelloComponent::SayHello(BSTR message)
{
	_bstr_t bstrMessage = message;

	cout << "Hello, " << bstrMessage << endl;
 	return S_OK;
}

ULONG CHelloComponent::AddRef()
{
 	return (++m_cRef);
}

ULONG CHelloComponent::Release()
{
 	if ( --m_cRef != 0 )
  		return m_cRef;  	 

	delete this;
 	return 0;
}

HRESULT CHelloComponent::QueryInterface(REFIID riid, LPVOID *ppv) 
{ 
	if ( ( riid == IID_IHello ) || ( riid == IID_IUnknown ) )
 	{ 
		*ppv = (void *) this; 
		AddRef();
 	} 
	else 
		*ppv = NULL;

 	return (*ppv == NULL) ? E_NOINTERFACE : S_OK;
}

// CObjectFactory class - Implementation
// 
ULONG CObjectFactory::AddRef() 
{ 
	return (++m_cRef); 
} 

ULONG CObjectFactory::Release() 
{ 
	if ( --m_cRef != 0 )  
		return m_cRef;  	

 	delete this;
 	return 0;
} 

HRESULT CObjectFactory::QueryInterface(REFIID riid, LPVOID *ppv) 
{ 
	if ( ( riid == IID_IClassFactory ) || ( riid == IID_IUnknown ) ) 
	{ 
		*ppv = (void *) this; 
		AddRef();
 	}
 	else
 		*ppv = NULL;

 	return (*ppv == NULL) ? E_NOINTERFACE : S_OK;
} 

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;
}

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

	return S_OK;
}

// DllGetClassObject - This is the entry point to the DLL
// 
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
	if ( rclsid != CLSID_HelloComponent )
		return CLASS_E_CLASSNOTAVAILABLE;

	CObjectFactory *pFactory = new CObjectFactory();
	if ( pFactory == NULL )
		return E_OUTOFMEMORY;

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

	return hr;
}

// DllCanUnloadNow
// 
STDAPI DllCanUnloadNow()
{
	return (CHelloComponent::m_cComponents == 0) ? S_OK : S_FALSE;
}

Observe that, we have created an instance of CObjectFactory in DllGetClassObject to return the IClassFactory interface pointer. This is what CoCreateInstance expected. So, we have removed our CHelloComponent creation from DllGetClassObject and added this instance creation into CreateInstance of CObjectFactory class. This is an important change we made; compare to previous HelloComponent code.

Now we need to re-generate our “HelloComponent.dll” file. Below is the command:

cl /EHsc /LD HelloComponent.cpp /link /def:HelloComponent.def comsuppw.lib

The file “HelloComponent.dll” will be generated. Now we will run our “TestApp.exe” file.

After we run it, it displays “Hello, CodeSteps” message on console window. It seems, our component is working fine. Finally we were able to create our component instance through CoCreateInstance.

Lets summarize how we have created our COM component in our next article.

**

Leave a Reply