windows-nt/Source/XPSP1/NT/admin/activec/inc/tiedobj.h
2020-09-26 16:20:57 +08:00

321 lines
9 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1999 - 1999
//
// File: tiedobj.h
//
// History: 08/28/1999 VivekJ Created
//--------------------------------------------------------------------------
#ifndef TIEDOBJ_H
#define TIEDOBJ_H
#pragma once
#include "conuistr.h" // for MMC_E_OBJECT_IS_GONE
/************************************************************************
* This file provides base and template class support to encapsulate the
* relationship between an object and a COM tearoff object that holds a pointer
* to that object.
* The object is referred to as the Tied object, since the COM object is
* "tied" to it, and cannot do anything useful apart from it.
* The COM object disables itself when the tied object is deleted. This
* allows for automatic detection of dead states. An object can also "orphan"
* all COM objects tied to it by calling the UnadviseAll method.
*
* An example of a tied object relationship is that of CAMCDoc and CMMCDocument.
* CMMCDocument is derived from CTiedComObject<CAMCDoc>, and CAMCDoc derives
* from CTiedObject. CAMCDoc thus keeps a list of all COM object that are tied
* to it, and notifies them when it is destroyed. Similarly, the COM objects notify
* the tied object when they are destroyed, so that they are removed from the list.
*
* NOTE: the tied object does NOT addref the COM objects, it just keeps a list of them.
* If it was to addref them, there would be all sorts of circular lifetime problems.
* By ensuring that the tied object and the COM objects notify each other of their
* own destruction, lifetime management is correctly handled.
*
* Use CTiedComObjectCreator::ScCreateAndConnect to create an instance of the
* COM object and tie it to the tied object.
*
************************************************************************/
class CTiedObject;
class CTiedComObjectRoot;
/*+-------------------------------------------------------------------------*
* class CTiedComObjectRoot
*
*
* PURPOSE: Base class for CTiedComObject
*
*+-------------------------------------------------------------------------*/
class CTiedComObjectRoot
{
public:
virtual void Unadvise() = 0; // so that the tied object can inform that it is being deleted.
};
/*+-------------------------------------------------------------------------*
* class CTiedObject
*
*
* PURPOSE: The base class that any object which has COM objects tied to
* it should derive from. Provides methods to add a new COM object
* to its list of tied objects, to remove a COM object from its
* list, and to
*
*+-------------------------------------------------------------------------*/
class CTiedObject
{
typedef CTiedComObjectRoot * PTIEDCOMOBJECTROOT;
typedef std::list<PTIEDCOMOBJECTROOT> CTiedComObjects;
CTiedComObjects m_TiedComObjects;
public:
SC ScAddToList(CTiedComObjectRoot *p);
void RemoveFromList(CTiedComObjectRoot *p);
virtual ~CTiedObject();
protected:
void UnadviseAll();
};
/*+-------------------------------------------------------------------------*
*
* CTiedObject::ScAddToList
*
* PURPOSE: Adds the COM object to the list of objects. Usually called soon
* after constructing the COM object.
*
* PARAMETERS:
* CTiedComObjectRoot * p :
*
* RETURNS:
* inline SC
*
*+-------------------------------------------------------------------------*/
inline
SC CTiedObject::ScAddToList(CTiedComObjectRoot *p)
{
DECLARE_SC (sc, _T("CTiedObject::ScAddToList"));
if(!p)
return (sc = E_INVALIDARG);
m_TiedComObjects.push_back(p);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CTiedObject::RemoveFromList
*
* PURPOSE: Removes the specfied COM object from the list of COM objects.
* Usually called from the destructor of the COM object.
*
* PARAMETERS:
* CTiedComObjectRoot * p : The COM object.
*
* RETURNS:
* inline void
*
*+-------------------------------------------------------------------------*/
inline
void CTiedObject::RemoveFromList(CTiedComObjectRoot *p)
{
CTiedComObjects::iterator iter;
iter = std::find (m_TiedComObjects.begin(), m_TiedComObjects.end(), p);
ASSERT(iter != m_TiedComObjects.end());
if(iter != m_TiedComObjects.end())
m_TiedComObjects.erase(iter);
}
inline
void CTiedObject::UnadviseAll()
{
CTiedComObjects::iterator iter;
for(iter = m_TiedComObjects.begin(); iter != m_TiedComObjects.end(); iter++)
{
(*iter)->Unadvise();
}
}
inline
CTiedObject::~CTiedObject()
{
UnadviseAll();
}
/*+-------------------------------------------------------------------------*
* template class CTiedComObject
*
*
* PURPOSE: The base class for COM objects that are tied to non-COM objects
* for instance, CMMCDocument is tied to CAMCDoc - it delegates
* all its methods to the tied object.
*
*+-------------------------------------------------------------------------*/
template <class TiedObjectClass>
class CTiedComObject : public CTiedComObjectRoot
{
friend class TiedObjectClass;
public:
CTiedComObject() : m_pT(NULL) {}
virtual ~CTiedComObject();
void SetTiedObject(TiedObjectClass *pT);
protected:
// called by the COM methods to make sure that the tied object exists.
SC ScGetTiedObject(TiedObjectClass*&pT);
bool IsTied() { return m_pT != NULL; }
void Unadvise();
private:
TiedObjectClass *m_pT;
};
/*+-------------------------------------------------------------------------*
*
* ~CTiedComObject
*
* PURPOSE: Destructor. Tells the tied object to remove this one from
* its list of tied COM objects.
*
*+-------------------------------------------------------------------------*/
template<class TiedObjectClass>
CTiedComObject<TiedObjectClass>::~CTiedComObject()
{
if(m_pT != NULL)
{
m_pT->RemoveFromList(this);
}
}
template<class TiedObjectClass>
void
CTiedComObject<TiedObjectClass>::SetTiedObject(TiedObjectClass *pT)
{
ASSERT(pT != NULL);
m_pT = pT;
}
template<class TiedObjectClass>
inline void
CTiedComObject<TiedObjectClass>::Unadvise()
{
m_pT = NULL;
}
/*+-------------------------------------------------------------------------*
*
* CTiedComObject::ScGetTiedObject
*
* PURPOSE: Checks that a valid tied object pointer exists, and returns it.
*
* PARAMETERS:
* TiedObjectClass** ppT : [OUT]: The object pointer
*
* RETURNS:
* SC: MMC_E_OBJECT_IS_GONE if no valid pointer exists.
*+-------------------------------------------------------------------------*/
template<class TiedObjectClass>
inline SC
CTiedComObject<TiedObjectClass>::ScGetTiedObject(TiedObjectClass*&pT)
{
DECLARE_SC (sc, _T("CTiedComObject::ScGetTiedObject"));
pT = m_pT;
if(NULL == m_pT)
return (sc = ScFromMMC(MMC_E_OBJECT_IS_GONE));
return (sc);
}
/*+-------------------------------------------------------------------------*
*
* ScCreateConnection
*
* PURPOSE: Creates a two-way connection between a COM object and its tied
* object.
*
* PARAMETERS:
* TiedComObjClass comObj :
* TiedObjClass obj :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
template<class TiedComObjClass, class TiedObjClass>
SC ScCreateConnection(TiedComObjClass &comObj, TiedObjClass &obj)
{
DECLARE_SC (sc, _T("ScCreateConnection"));
sc = obj.ScAddToList(&comObj);
if(sc)
return (sc);
comObj.SetTiedObject(&obj);
return (sc);
}
/*+-------------------------------------------------------------------------*
* CTiedComObjectCreator
*
*
* PURPOSE: has a single static function, ScCreateAndConnect, which creates
* an instance of the COM object (if the smart pointer supplied is
* NULL) and connects it to the Tied object supplied.
*
*+-------------------------------------------------------------------------*/
template <class TiedComObjectClass>
class CTiedComObjectCreator
{
public:
template<class TiedObjClass, class SmartPointerClass>
static SC ScCreateAndConnect(TiedObjClass &obj, SmartPointerClass &smartPointer)
{
DECLARE_SC(sc, TEXT("CTiedComObjectCreator::ScCreateAndConnect") );
// if the object has not yet been created, create it.
if(smartPointer == NULL)
{
CComObject<TiedComObjectClass> *pTiedComObject = NULL;
sc = CComObject<TiedComObjectClass>::CreateInstance(&pTiedComObject);
if (sc)
return (sc);
if(!pTiedComObject)
return (sc = E_UNEXPECTED);
sc = ScCreateConnection(*pTiedComObject, obj); // create a link between the tied obj and tied com obj.
if(sc)
return sc;
smartPointer = pTiedComObject; // This AddRef's it once. need to addref it for the client as well.
}
return sc;
}
};
#endif // TIEDOBJ_H