Tuesday, January 26, 2010

BEGIN_OBJECT_MAP Removal Update

I recently run into a bug in where my dll was supposed to support multiple objects. In my previous post, I was just supporting one. When com was calling DllGetClassObject, it was always just getting one object, which was incorrect. So this is how I went about fixing it.
Imagine you ATL code had something like this:

BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_Obj1, CObj1)
OBJECT_ENTRY(CLSID_Obj2, CObj2)
OBJECT_ENTRY(CLSID_Obj3, CObj3)
END_OBJECT_MAP()

In your class factory, you need to be able to create the correct object. First I fixed my class factory object.
I added a new member variable:
REFCLSID m_clsid;
And got is set in the constructor:

CClassFactory::CClassFactory(
REFCLSID clsid) : m_cRef(1), m_clsid(clsid)
{
IncModuleCount();
} // CClassFactory::CClassFactory

Next I fixed my CreateInstance method

STDMETHODIMP CClassFactory::CreateInstance(
__in_opt IUnknown *pUnkownOuter,
REFIID riid,
__deref_out_opt void **ppv)
{
HRESULT hr = S_OK;
IUnknown *pUnknown = NULL;

if (ppv)
{
*ppv = NULL;
}
else
{
hr = E_INVALIDARG;
}

if (S_OK == hr)
{
if (pUnkownOuter)
{
hr = CLASS_E_NOAGGREGATION;
}
}

if (S_OK == hr)
{
if (CLSID_Obj1 == m_clsid)
{
pUnknown = new CObj1();
}
else if (CLSID_Obj2 == m_clsid)
{
pUnknown = new CObj2();
}
else if (CLSID_Obj3 == m_clsid)
{
pUnknown = new CObj3();
}
else
{
hr = E_NOINTERFACE;
}

if (S_OK == hr && !pUnknown)
{
hr = E_OUTOFMEMORY;
}
}

if (S_OK == hr)
{
hr = pUnknown->QueryInterface(riid, ppv);
}

if (pUnknown)
{
pUnknown->Release();
}

return hr;
} // CClassFactory::CreateInstance


And then fixed my DllGetClassObject

STDAPI DllGetClassObject(
__in REFCLSID rclsid,
__in REFIID riid,
__deref_out LPVOID FAR *ppv)
{
HRESULT hr = S_OK;
CClassFactory *pClassFactory = NULL;

if (ppv)
{
*ppv = NULL;
}
else
{
hr = E_INVALIDARG;
}

if (S_OK == hr)
{
pClassFactory = new CClassFactory(rclsid);

if (!pClassFactory)
{
hr = E_OUTOFMEMORY;
}
}

if (S_OK == hr)
{
hr = pClassFactory->QueryInterface(riid, ppv);
}

if (pClassFactory)
{
pClassFactory->Release();
}

return hr;
}