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

When we run our test application, we were getting a message “No such interface supported”. It seems, CreateInstance was failed to return the instance of the component. Before looking into the way CreateInstance creates an instance of our component; let us test our DLL by calling exported functions directly without the help of COM library.

To do this:

  • We need to first load our component into memory.
  • Find the addresses of exported functions.
  • Call the exported functions by using their addresses.

First, we can use LoadLibrary function to load our component into memory. The syntax of the function is:

HMODULE WINAPI LoadLibrary(
  _In_  LPCTSTR lpFileName
);

Here lpFileName is the name of the module, either EXE or DLL file. If the function succeeds it will return a handle to the loaded module. The code looks like below:

HMODULE hModule = LoadLibrary("HelloComponent.dll");

Then, we need to get the exported function’s address. We know that, we have exported two functions from our component. One is DllGetClassObject and another one is DllCanUnloadNow. In our component, DllGetClassObject is responsible for creating an instance of a class that is defined in our component. So, lets get the pointer to DllGetClassObject function.

We can use GetProcAddress function to retrieve the address of an exported function from the given module. The syntax of this function is:

FARPROC WINAPI GetProcAddress(
  _In_  HMODULE hModule,
  _In_  LPCSTR lpProcName
);

Here hModule is the handle to the loaded module. In our case, we already have this handle from LoadLibrary function.

lpProcName is the name of the function or variable we want to get the address.

If this function succeeds, it will return an address to the exported function which is mentioned through lpProcName parameter. The code looks like below:

HRESULT (__stdcall *pfnDllGetClassObject)(IN REFCLSID rclsid, IN REFIID riid, OUT LPVOID FAR* ppv);

pfnDllGetClassObject pfn = (pfnDllGetClassObject)::GetProcAddress(hModule, "DllGetClassObject");

Now we have the address of the exported function. Now we can call the exported function by passing right arguments. In our case we need an instance of the class whose IID is IID_IHello.

All together, here is the code. Save this code into “TestDll.cpp”.

// TestDll.cpp
// 
#include "TestApp.h"

using namespace std;

void main()
{
	// Initialize COM Library
	// 
	HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
	if ( FAILED(hr) )
	{
		cout << _com_error(hr).ErrorMessage() << endl;
		exit(0);
	}

	// Create instance
	// 
	CHelloComponent *pHello = NULL;

	HMODULE hModule = ::LoadLibrary("C:\\Visual Studio Projects 2012\\COM\\HelloComponent\\HelloComponent.dll");
	if ( hModule != NULL )
	{
		cout << "LoadLibrary Success." << endl;
 		typedef HRESULT (__stdcall *pfnDllGetClassObject)(IN REFCLSID rclsid, IN REFIID riid, OUT LPVOID FAR* ppv);
 		pfnDllGetClassObject pfn = (pfnDllGetClassObject)::GetProcAddress(hModule, "DllGetClassObject");
 		if ( pfn != NULL )
 		{
 			hr = pfn(CLSID_HelloComponent, IID_IHello, (LPVOID *)&pHello);
 			if ( SUCCEEDED(hr) )
 			{
 				if ( pHello != NULL )
 				{
 					pHello->SayHello(L"CodeSteps");
					pHello->Release();
				}					
			}
		}
		else
			cout << "DllGetClassObject failed." << endl;

		::FreeLibrary(hModule);
	}
	else
		cout << "LoadLibrary Failed." << endl;		

	// Uninitialize COM Library
	// 
	CoUninitialize();
}

Now compile the code and run it. You will see “Hello, CodeSteps” message on the screen. It seems, the DLL is working fine.

Why it is not working when we use CreateInstance function? Lets look at how CreateInstance loads and calls DLL’s exported function DllGetClassObject in our next upcoming articles.

**

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

Leave a Reply