Emulating CoCreateInstance()

Introduction

A while ago I wrote a small utility that converts DOT syntax into an image using
the WinGraphViz.DLL COM component.

However it is not very usual to have the user register this component before
running the tool, thus I started looking around for a way to use COM component
as if they were normal DLL.
The research yielded that there are many techniques to accomplish that:

  1. Registration-Free COM (for XP and above)
  2. Emulating the CoCreateInstance()

To learn more about the Registration-Free COM please check the references at
the end of this article.

Emulating CoCreateInstance()

Normally, to create an instance you would do something like:

  hr = CoCreateInstance(CLSID_DOT, NULL, CLSCTX_ALL,
  IID_IDOT, (LPVOID *)&pIDOT);

This will cause OLE to fetch the associated DLL from the registry and call its
DllGetClassObject() method to get a class factory then from the class factory
an instance of your required IID will be created.

For that reason we may emulate the CoCreateInstance() by the following code:

HRESULT __stdcall MyCoCreateInstance(
  LPCTSTR szDllName,
  IN REFCLSID rclsid,
  IUnknown* pUnkOuter,
  IN REFIID riid,
  OUT LPVOID FAR* ppv)
{
  HRESULT hr = REGDB_E_KEYMISSING;

  HMODULE hDll = ::LoadLibrary(szDllName);
  if (hDll == 0)
    return hr;

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

  pDllGetClassObject GetClassObject = (pDllGetClassObject)::GetProcAddress(hDll, "DllGetClassObject");
  if (GetClassObject == 0)
  {
    ::FreeLibrary(hDll);
    return hr;
  }

  IClassFactory *pIFactory;

  hr = GetClassObject(rclsid, IID_IClassFactory, (LPVOID *)&pIFactory);

  if (!SUCCEEDED(hr))
    return hr;

  hr = pIFactory->CreateInstance(pUnkOuter, riid, ppv);
  pIFactory->Release();

  return hr;
}

Notice that how this function takes a parameter holding the DLL’s name.

Using the code

You need your application to run first if the COM is registered, if not you
would resort to emulating the CoCreateInstance(). Your code could look like
this:

hr = CoCreateInstance(CLSID_DOT, NULL, CLSCTX_ALL,
  IID_IDOT, (LPVOID *)&pIDOT);

if (hr == REGDB_E_CLASSNOTREG)
{
  hr = MyCoCreateInstance(_T("WinGraphViz.dll"), CLSID_DOT, NULL, IID_IDOT, (LPVOID *)&pIDOT);
}

if (FAILED(hr))
{
  cout << "CoCreateInstance Failed: " << hr << "nn";
  return -1;
}

Reference

The following links were helpful during the building of this simple snippet:

3 thoughts on “Emulating CoCreateInstance()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s