CodeSteps

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

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

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

Let’s include IClassFactory‘s implementation into our HelloComponent.

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

After we have added the 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 the CreateInstance of CObjectFactory class. This is an important change we made; compare to the 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 the “Hello, CodeSteps” message on the console window. It seems, our component is working fine. Finally, we were able to create our component instance through CoCreateInstance.

Let’s summarize how we have created our COM component in our next article.

**

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

Leave a Reply

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

Scroll to top