Article ID: 201321
Article Last Modified on 5/3/2005
/********** Start of singleton code **********/
template <class Base>
class CMyComObject: public CComObject<Base>
{
public:
// Variable that lets class factory know COM object is deleted.
CMyComObject** m_ppObj;
STDMETHOD_(ULONG, Release)()
{
ULONG l = InternalRelease();
if (l == 0)
{
// Set to NULL so class factory knows to recreate us.
*m_ppObj = NULL;
delete this;
}
return l;
}
static HRESULT WINAPI CreateInstance(CMyComObject<Base>** pp)
{
ATLASSERT(pp != NULL);
HRESULT hRes = E_OUTOFMEMORY;
CMyComObject<Base>* p = NULL;
ATLTRY(p = new CMyComObject<Base>())
if (p != NULL)
{
p->SetVoid(NULL);
p->InternalFinalConstructAddRef();
hRes = p->FinalConstruct();
p->InternalFinalConstructRelease();
if (hRes != S_OK)
{
delete p;
p = NULL;
}
}
*pp = p;
// Initialize m_ppObj to CComObject<> pointer in class factory.
p->m_ppObj = pp;
return hRes;
}
};
template <class T>
class CMyComClassFactorySingleton : public CComClassFactory
{
public:
CMyComObject<T>* m_pObj; // actual COM object
CComAutoCriticalSection m_sec; // A critical section is needed
// because class factory is stored in CComObjectCached. All clients
// get the same raw pointer to the class factory. Any instance
// data in this class factory must be synchronized.
// IClassFactory
STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid,
void** ppvObj)
{
if (NULL == ppvObj)
return E_POINTER;
*ppvObj = NULL;
// Aggregation is not supported in Singletons.
ATLASSERT(pUnkOuter == NULL);
if (pUnkOuter != NULL)
return CLASS_E_NOAGGREGATION;
HRESULT hRes = E_FAIL;
// Lock critical section.
m_sec.Lock();
// Create COM object.
if (NULL == m_pObj)
{
hRes = CMyComObject<T>::CreateInstance(&m_pObj);
if (SUCCEEDED(hRes))
{
// Free marshaled interface and release stream.
if (m_pStream)
{
AtlFreeMarshalStream(m_pStream);
m_pStream = NULL;
}
// Marshal interface into a stream.
// Can't use AtlMarshalPtrInProc since we need to use
// MSHLFLAGS_TABLEWEAK.
hRes = CreateStreamOnHGlobal(NULL, TRUE, &m_pStream);
if (SUCCEEDED(hRes))
{
hRes = CoMarshalInterface(m_pStream, IID_IUnknown,
m_pObj, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
if (FAILED(hRes))
{
m_pStream->Release();
m_pStream = NULL;
}
}
}
if (FAILED(hRes))
{
// Unlock critical section.
m_sec.Unlock();
return hRes;
}
}
CComPtr<IUnknown> spUnk;
// Unmarshal interface from stream.
hRes = AtlUnmarshalPtr(m_pStream, IID_IUnknown, &spUnk);
// unlock critical section
m_sec.Unlock();
if (FAILED (hRes))
return hRes;
// Call QI on unmarshaled interface.
hRes = spUnk->QueryInterface(riid, ppvObj);
return hRes;
}
LPSTREAM m_pStream; // IStream* used for storing marshaled interface.
void FinalRelease()
{
// Free marshaled interface and release stream.
if (m_pStream)
AtlFreeMarshalStream (m_pStream);
}
CMyComClassFactorySingleton() : m_pObj(NULL), m_pStream(NULL)
{
}
};
#define DECLARE_CLASSFACTORY_MYSINGLETON(obj)
DECLARE_CLASSFACTORY_EX(CMyComClassFactorySingleton<obj>)
/********** End of singleton code **********/
class CMyComponent : public CComCoClass<...>, ...
{
DECLARE_CLASSFACTORY_MYSINGLETON(CMyComponent)
...
}
Additional query words: kbDSupport CComObjectGlobal CComObjectNoLock CComObject single instance CComClassFactorySingleton
Keywords: kbhowto kbinfo kbarchitecture KB201321