CInternalComObjectWithData class

 

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;
    }
};
//------------------------------------------------------------------------