Have you ever found the need to
pass a back pointer of the container class(or any other back pointer) from acontainer
class to the contained class
and if the the contained class is a CComObject<> (internal COM objects only), we
dont have a way to pass the initilization parmeter from the container class. Let me
explain this:)
If you have the container and contained class like :
class CContainer
{
Startup()
{
m_spObj->CreateInstance(&m_spObj);
m_spObj->Init(this);
}
public:
CComObject<CContained> *m_spObj;
};
class ATL_NO_VTABLE CContained : public CComObjectRoot ...
{
Init(CContainer* p)
{
m_pBackPointer = p ;
}
CContainer *m_pBackPointer;
};
The need to have the Init() function above is because we dont have a way from
CComObject<> variants
to pass the container class(or any other data) as a ctor argument
It would be nice if we could do something like :
class CContainer
{
HRESULT Initialization()
{
//with this the CContained has now the back
pointer to the CContainer object
return
m_spComObject->CreateInstanceWithData(&m_spComObject,this);
}
...
...
RescueMe() { //Do Something
}
public:
CInternalComObjectWithData<CContained, CContainer>
*m_spComObject;
...
};
And the corresponding Contained class looks like :
class ATL_NO_VTABLE CContained :
public DataHolder<CContainer>, public CComObjectRoot...
{
...
...
...
SaveMe()
{
m_pData->RescueMe();
}
public:
...
};
The following classes allows you do the same magic for your internal(Non-CoCretable) COM objects in an ATLish way.
//-------------------------------------------------------------------------
template <typename InitData>
struct DataHolder
{
DataHolder():m_pData(0){}
InitData *m_pData;
};
template <typename Base, typename InitData>
class CInternalComObjectWithData : public Base
{
protected:
CInternalComObjectWithData(InitData* p)
{
ATLASSERT(p != NULL);
m_pData = p ;
_Module.Lock();
}
public:
typedef Base _BaseClass;
typedef InitData _InitDataClass;
// Set refcount to 1 to protect destruction
~CInternalComObjectWithData()
{
m_dwRef = 1L;
FinalRelease();
#ifdef _ATL_DEBUG_INTERFACES
_Module.DeleteNonAddRefThunk(_GetRawUnknown());
#endif
_Module.Unlock();
}
//If InternalAddRef or InternalRelease is undefined then your class
//doesn't derive from CInternalComObjectWithDataRoot
STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
STDMETHOD_(ULONG, Release)()
{
ULONG l = InternalRelease();
if (l == 0)
delete this;
return l;
}
//if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{return _InternalQueryInterface(iid, ppvObject);}
template <class Q>
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
{
return QueryInterface(__uuidof(Q), (void**)pp);
}
static HRESULT WINAPI
CreateInstanceWithData(CInternalComObjectWithData<Base,InitData>** pp, InitData
*pData)
{
if(!pp || !pData){ return E_POINTER; }
HRESULT hRes = E_OUTOFMEMORY;
CInternalComObjectWithData<Base,InitData>* p = NULL;
p = new
CInternalComObjectWithData<Base,InitData>(pData);
if (p != NULL)
{
p->SetVoid(NULL);
p->InternalFinalConstructAddRef();
hRes =
p->FinalConstruct();
p->InternalFinalConstructRelease();
if (hRes != S_OK)
{
delete p;
p = NULL;
}
}
*pp = p;
return hRes;
}
};
//------------------------------------------------------------------------