Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

422 lines
13 KiB

// RefCnt.h -- Class definition for reference counted objects
#ifndef __REFCNT_H__
#define __REFCNT_H__
class CPersist;
class CRCObject;
#ifdef _DEBUG
// The WithType define is used in the debugging build to record the type name
// for a class object. It also records the file name and line number where the
// object was created.Use the WithType define in the header of each constructor
// for the object type you wish to tag.
// #define RECORD_TYPE(typename) CRCObject(typename) // , THIS_FILE, __LINE__)
#define WithType(TypeName) (TypeName)
// Beware! The #defines below are careful to mention pObject only once. We
// follow that discipline to allow pObject to be a creation expression
// (i.e., new CObjectType(...) ). If you change the defines, maintain
// that discipline.
//
// We also assume varpObject is a pointer variable with the same type
// as pObject.
// The AttachRef, ChangeRef, and DetachRef defines are used to keep track of the
// member variables which point to reference counted objects. In the retail
// environment they simply implement reference counting so that objects are
// automatically deleted when the reference counts go from one to zero. In the
// debug environment we actually keep lists of the member variables which refer
// to each object. To use these defines you must derive your class directly or
// indirectly from CRCObject, and you must invoke the DECLARE_REF_COUNTERS define
// in the public section of your class definition.
//
// You can also use these defines to keep track of references stored in local
// variables and global variables. However you should be avoid their use when
// you're returning a reference as the explicit result of a function. Consider
// the pattern:
//
// AttachRef(pMyObject, new CMyObject(...));
//
// ... Processing which changes *pMyObject ...
//
// DetachRef(pMyObject); // Should use ForgetRef(pMyObject) instead...
//
// return pMyObject;
//
// This code will fail because the call to DetachRef will deallocate the object
// and set pMyObject to NULL. In cases like this use the ForgetRef define instead.
// It will decrement the reference count without setting the pointer variable to
// NULL, and it won't delete the object if it's ref count goes to zero. This is
// the only case where you should use ForgetRef.
// Use these defines to adjust the reference counts
// for member variables in the current class.
// You can also use the defines to reference count
// local stack frame variables.
#define AttachRefAndOwner(varpObject, pObject, pOwner) (( pObject)->AttachReference(&(varpObject), pOwner))
#define ChangeRefAndOwner(varpObject, pObject, pOwner) (( pObject)->ChangeReference(&(varpObject), pOwner))
#define DetachRefAndOwner(varpObject, pOwner) ((varpObject)->DetachReference(&(varpObject), TRUE , pOwner))
#define ForgetRefAndOwner(varpObject, pOwner) ((varpObject)->DetachReference(&(varpObject), FALSE, pOwner))
#define AttachRef(varpObject, pObject) AttachRefAndOwner(varpObject, pObject, this)
#define ChangeRef(varpObject, pObject) ChangeRefAndOwner(varpObject, pObject, this)
#define DetachRef(varpObject) DetachRefAndOwner(varpObject, this)
#define ForgetRef(varpObject) ForgetRefAndOwner(varpObject, this)
// Use the ClsXXX defines when you want to adjust the
// reference count for member variable in another class.
#define ClsAttachRef(pClass, varpObject, pObject) (( pObject)->AttachReference(&(pClass->varpObject), pClass))
#define ClsChangeRef(pClass, varpObject, pObject) (( pObject)->ChangeReference(&(pClass->varpObject), pClass))
#define ClsDetachRef(pClass, varpObject) ((pClass->varpObject)->DetachReference(&(pClass->varpObject), TRUE , pClass))
#define ClsForgetRef(pClass, varpObject) ((pClass->varpObject)->DetachReference(&(pClass->varpObject), FALSE, pClass))
// Use the PAttachRef, PChangeRef, PDetachRef, and PForgetRef when you have a pointer
// to pointer variable instead of the variable itself.
#define PAttachRef(ppObject, pObject) (( pObject)->AttachReference((ppObject), this))
#define PChangeRef(ppObject, pObject) (( pObject)->ChangeReference((ppObject), this))
#define PDetachRef(ppObject) ((*ppObject)->DetachReference((ppObject), TRUE , this))
#define PForgetRef(ppObject) ((*ppObject)->DetachReference((ppObject), FALSE, this))
#define ATTACH_PARMS CRCObject **ppObject, PVOID pvClass
#define DETACH_PARMS CRCObject **ppObject, BOOL fAutoDelete, PVOID pvClass
// The DECLARE_REF_COUNTERS define will define a set of reference counting functions
// for your class. Their function is to force type validation on the pointer variable
// and the address expression.
#define DECLARE_REF_COUNTERS(class_type) inline void AttachReference(class_type **ppObject, PVOID pvClass) \
{ CRCObject::RawAttachReference((CRCObject **) ppObject, pvClass); } \
inline void ChangeReference(class_type **ppObject, PVOID pvClass) \
{ CRCObject::RawChangeReference((CRCObject **) ppObject, pvClass); } \
inline void DetachReference(class_type **ppObject, BOOL fAutoDelete, PVOID pvClass) \
{ CRCObject::RawDetachReference((CRCObject **) ppObject, fAutoDelete, pvClass); }
#else
#define WithType(TypeName) ()
#define AttachRefAndOwner(varpObject, pObject, pOwner) (( pObject)->AttachReference(&(varpObject) ))
#define ChangeRefAndOwner(varpObject, pObject, pOwner) (( pObject)->ChangeReference(&(varpObject) ))
#define DetachRefAndOwner(varpObject, pOwner) ((varpObject)->DetachReference(&(varpObject), TRUE ))
#define ForgetRefAndOwner(varpObject, pOwner) ((varpObject)->DetachReference(&(varpObject), FALSE))
#define AttachRef(varpObject, pObject) (pObject)->AttachReference(&(varpObject))
#define ChangeRef(varpObject, pObject) (pObject)->ChangeReference(&(varpObject))
#define DetachRef(varpObject) ((varpObject)->DetachReference(&(varpObject), TRUE ))
#define ForgetRef(varpObject) ((varpObject)->DetachReference(&(varpObject), FALSE))
#define ClsAttachRef(pClass, varpObject, pObject) (( pObject)->AttachReference(&(pClass->varpObject) ))
#define ClsChangeRef(pClass, varpObject, pObject) (( pObject)->ChangeReference(&(pClass->varpObject) ))
#define ClsDetachRef(pClass, varpObject) ((pClass->varpObject)->DetachReference(&(pClass->varpObject), TRUE ))
#define ClsForgetRef(pClass, varpObject) ((pClass->varpObject)->DetachReference(&(pClass->varpObject), FALSE))
#define PAttachRef(ppObject, pObject) (( pObject)->AttachReference((ppObject)))
#define PChangeRef(ppObject, pObject) (( pObject)->ChangeReference((ppObject)))
#define PDetachRef(ppObject) ((*ppObject)->DetachReference((ppObject), TRUE ))
#define PForgetRef(ppObject) ((*ppObject)->DetachReference((ppObject), FALSE))
#define ATTACH_PARMS CRCObject **ppObject
#define DETACH_PARMS CRCObject **ppObject, BOOL fAutoDelete
#define DECLARE_REF_COUNTERS(class_type) inline void AttachReference(class_type **ppObject) \
{ CRCObject::RawAttachReference((CRCObject **) ppObject); } \
inline void ChangeReference(class_type **ppObject) \
{ CRCObject::RawChangeReference((CRCObject **) ppObject); } \
inline void DetachReference(class_type **ppObject, BOOL fAutoDelete) \
{ CRCObject::RawDetachReference((CRCObject **) ppObject, fAutoDelete); }
#endif
typedef struct _OwnerLink
{
struct _OwnerLink *polNext;
PVOID pvClass;
CRCObject **pprcObj;
CRCObject *prcObj;
} OwnerLink;
typedef OwnerLink *POwnerLink;
#ifdef _DEBUG
class CObjectAccountant;
class CObjectCounter
{
friend class CRCObject;
friend class CObjectAccountant;
public:
// Constructor --
CObjectCounter();
// Destructor --
~CObjectCounter();
private:
// Counting routines --
void ObjectBirth (CRCObject *prcObj);
void ObjectDeath (CRCObject *prcObj);
void AddReference(CRCObject *prcObj);
void SubReference(CRCObject *prcObj);
// Existence Tests --
BOOL ObjectRecorded(CRCObject *prcObj);
CRCObject *m_prcObjectFirst;
UINT m_crcObject;
UINT m_crcObjRef;
};
extern CObjectCounter ObjectCounter;
class CObjectAccountant
{
public:
// Constructor --
CObjectAccountant(int cObjDelta, int cRefDelta);
// Destructor --
~CObjectAccountant();
private:
int m_cObjStarting;
int m_cRefStarting;
int m_cObjDelta;
int m_cRefDelta;
};
#define PredictObjects(Name, cObjDelta, cRefDelta) CObjectAccountant Name(cObjDelta, cRefDelta)
#define ReportBirth() ObjectCounter.ObjectBirth(this)
#define ReportDeath() ObjectCounter.ObjectDeath(this)
#define AddRef() ObjectCounter.AddReference(this)
#define SubRef() ObjectCounter.SubReference(this)
#else // _DEBUG
#define PredictObjects(Name, cObjDelta, cRefDelta)
#define ReportBirth()
#define ReportDeath()
#define AddRef()
#define SubRef()
#endif // _DEBUG
class CRCObject
{
#ifdef _DEBUG
friend class CObjectCounter;
#endif // _DEBUG
public:
// Destructor --
virtual ~CRCObject();
#ifdef _DEBUG
virtual void StoreImage(CPersist *pDiskImage);
#else
virtual void StoreImage(CPersist *pDiskImage) {};
#endif
#ifdef _DEBUG
static void SkipImage(CPersist *pDiskImage);
#else
static void SkipImage(CPersist *pDiskImage) {};
#endif
protected:
// Constructor --
#ifdef _DEBUG
CRCObject(PSZ pszTypeName); // , PSZ pszFile, UINT iLine);
#else
CRCObject();
#endif
#ifdef _DEBUG
virtual void ConnectImage(CPersist *pDiskImage);
#else
virtual void ConnectImage(CPersist *pDiskImage) {};
#endif
// Reference Count Routines --
void RawAttachReference(ATTACH_PARMS);
void RawDetachReference(DETACH_PARMS);
void RawChangeReference(ATTACH_PARMS);
private:
int m_cReferences;
#ifdef _DEBUG
PSZ m_pszTypeName;
// PSZ m_pszFile;
// UINT m_iFile;
POwnerLink m_pol;
CRCObject *m_prcObjNext;
CRCObject **m_pprcObjLast;
#endif // _DEBUG
};
typedef CRCObject *PCRCObject;
#ifdef _DEBUG
inline CRCObject::CRCObject(PSZ pszTypeName) // , PSZ pszFile, UINT iLine)
#else // _DEBUG
inline CRCObject::CRCObject()
#endif
{
m_cReferences= 0;
#ifdef _DEBUG
ASSERT(pszTypeName);
m_pszTypeName = pszTypeName;
// m_pszFile = pszFile;
// m_iLine = iLine;
m_pol = NULL;
m_prcObjNext = NULL;
m_pprcObjLast = NULL;
ReportBirth();
#endif // _DEBUG
}
inline CRCObject::~CRCObject()
{
ASSERT(m_cReferences == 0 );
ASSERT(m_pol == NULL);
ReportDeath();
}
inline void CRCObject::RawAttachReference(ATTACH_PARMS)
{
ASSERT(ppObject && pvClass);
ASSERT(*ppObject == NULL);
#ifdef _DEBUG
POwnerLink pol;
for (pol= m_pol; pol; pol= pol->polNext)
{
ASSERT(pol->prcObj == this);
ASSERT(pol->pprcObj != ppObject || pol->pvClass != pvClass);
}
// Note: We don't use __try/__finally code around the
// polNew allocation below because it only exists
// in Debug code.
POwnerLink polNew= New OwnerLink;
polNew->polNext= m_pol;
polNew->pprcObj= ppObject;
polNew->pvClass= pvClass;
polNew->prcObj = this;
m_pol= polNew;
#endif // _DEBUG
*ppObject= this;
++m_cReferences;
AddRef();
}
inline void CRCObject::RawDetachReference(DETACH_PARMS)
{
ASSERT(ppObject && pvClass);
ASSERT(*ppObject != NULL);
#ifdef _DEBUG
ASSERT(m_cReferences > 0);
ASSERT(m_pol != NULL);
BOOL fFound;
POwnerLink pol, *ppolLast;
for (fFound= FALSE, ppolLast= &m_pol, pol= *ppolLast;
pol;
ppolLast= &(pol->polNext), pol= *ppolLast
)
{
ASSERT(pol->prcObj == this);
if (pol->pprcObj == ppObject && pol->pvClass == pvClass)
{
*ppolLast= pol->polNext;
delete pol;
fFound= TRUE;
break;
}
}
ASSERT(fFound);
#endif // _DEBUG
if (fAutoDelete) *ppObject= NULL;
SubRef();
if (!--m_cReferences && fAutoDelete) delete this;
}
inline void CRCObject::RawChangeReference(ATTACH_PARMS)
{
ASSERT(ppObject && pvClass);
if (*ppObject)
#ifdef _DEBUG
(*ppObject)->RawDetachReference(ppObject, TRUE, pvClass);
#else // _DEBUG
(*ppObject)->RawDetachReference(ppObject, TRUE);
#endif // _DEBUG
#ifdef _DEBUG
RawAttachReference(ppObject, pvClass);
#else // _DEBUG
RawAttachReference(ppObject);
#endif
}
#endif // __REFCNT_H__