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 Replies to “Emulating CoCreateInstance()”

  1. Hi Lallous,

    Great stuff, I only wonder now how I can catch the events that are fired from a COM object.

    Regards,
    Martin

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.