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

In series of articles on creating a COM Component using C++, in previous article, we have implemented a component using C++. The component implemented IUnknown standard interface and IHello custom interface. Custom interfaces are the interfaces defined by us. Standard interfaces are the interfaces which are defined by COM component library.

We need to package this component as either EXE component or DLL component.

EXE components required main or WinMain functions. So, if you want to pack this component as an EXE component, you need to provide main or WinMain functions in your component code.

DLL components require two helper functions, DllGetClassObject and DllCanUnloadNow. DllGetClassObject to create an instance of a requested component and return the requested interface. DllCanUnloadNow function determines whether the DLL can unload from memory or not.

Lets package our component as DLL component. So, we need to implement DllGetClassObject and DllCanUnloadNow function.

The syntax of DllGetClassObject function is:

HRESULT __stdcall DllGetClassObject(
  REFCLSID rclsid,
  REFIID riid,
  LPVOID *ppv
);

This function takes two input parameters one is CLSID of the component, another one is IID of an interface and returns the pointer to the requested interface object.

We know IID is the GUID of an interface. What about CLSID? CLSID is also a GUID. But this one is an IID of a component. So, we need to provide a GUID to our component. Generate a GUID (you can generate GUID using uToolbox’s GUID generator tool. Good thing is, this tool generates GUID in different formats.) and add it in HelloComponent.h file. Below is the CLSID for HelloComponent.

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

Add the below code into HelloComponent.cpp file.

// DllGetClassObject - Returns the requested interface object pointer
// 
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
	HRESULT hr = S_OK;

	if ( rclsid == CLSID_HelloComponent )
	{
		CHelloComponent *pObj = new CHelloComponent();
		if ( pObj )
		{
			hr = pObj->QueryInterface(riid, ppv);
			if ( FAILED(hr) )
			{
				delete pObj;
				pObj = NULL;
			}
		}
	}

	return hr;
}

Now look at DllCanUnloadNow function. This will tell whether to unload the DLL or not. How it decides whether to unload DLL or not? The answer is simple. We have to add a variable into HelloComponent to keep track number of instances created.

So, add m_cComponents static member into CHelloComponent and increments its value by 1 when an instance is created. Don’t forget to decrement the value by 1 when the component is released.

Now CHelloComponent looks like below:

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

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

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

Now implement DllCanUnloadNow function. It is simple.

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

Lets compile HelloComponent.cpp file and generate DLL file.

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

This will compile HelloComponent.cpp file and generate HelloComponent.dll.

Now DLL file is created. Next we have to register our component. We will discuss about registering the component in our next article.

**

1 comment for “COM: Creating a COM Component using C++ (Part-3)

Leave a Reply