196 lines
5.6 KiB
C++
196 lines
5.6 KiB
C++
// ITUnk.h -- Base level IUnknown interface used by objects in this DLL
|
|
|
|
#ifndef __ITUNK_H__
|
|
|
|
#define __ITUNK_H__
|
|
|
|
// The CITUnknown class takes care of object reference counting for all
|
|
// the objects we create in this DLL. This means that all of our base
|
|
// level IUnknown interfaces must inherit from this class.
|
|
//
|
|
// Since we don't define an implementation for QueryInterface, this class
|
|
// cannot be used by itself.
|
|
//
|
|
// This class does nothing for standard interfaces derrived indirectly
|
|
// from IUnknown (IStorage, IStream, ...).
|
|
|
|
// The Guid_Parts define is a tool for building constant arrays of IID's.
|
|
|
|
#define Guid_Parts(guid) guid.Data1, guid.Data2, guid.Data3, \
|
|
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], \
|
|
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]
|
|
|
|
typedef IUnknown *PUnknown;
|
|
|
|
class CITUnknown : public IUnknown
|
|
{
|
|
public:
|
|
|
|
// CITUnknown();
|
|
CITUnknown(const IID *paIID, UINT cIID, IUnknown * pIFace);
|
|
CITUnknown(const IID *paIID, UINT cIID, IUnknown **papIFace);
|
|
static void CloseActiveObjects();
|
|
void MoveInFrontOf(CITUnknown *pITUnk);
|
|
void MarkSecondary();
|
|
BOOL IsSecondary();
|
|
|
|
virtual ~CITUnknown() = 0; // The destructor has to be virtual so that the
|
|
// proper destructor is called for each subclass
|
|
// of CITUnknown.
|
|
|
|
STDMETHODIMP_(ULONG) AddRef (void);
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
STDMETHODIMP QueryInterface(REFIID riid, PPVOID ppv);
|
|
|
|
#ifdef _DEBUG
|
|
static void OpenReferee(void);
|
|
static void CloseReferee(void);
|
|
#endif // _DEBUG
|
|
|
|
static HRESULT FinishSetup(HRESULT hr, CITUnknown *pUnk, REFIID riid, PPVOID ppv);
|
|
|
|
static CITCriticalSection s_csUnk;
|
|
// DEBUGDEF(static CITCriticalSection s_csUnk)
|
|
|
|
private:
|
|
|
|
void CommonInitialing();
|
|
void Uncouple();
|
|
|
|
LONG m_cRefs;
|
|
const IID *m_paIID;
|
|
UINT m_cIID;
|
|
IUnknown *m_pIFace;
|
|
IUnknown **m_papIFace;
|
|
|
|
BOOL m_fAlreadyDead;
|
|
BOOL m_fSecondary;
|
|
CITUnknown *m_pitunkPrev;
|
|
CITUnknown *m_pitunkNext;
|
|
// DEBUGDEF(CITUnknown *m_pitunkNext)
|
|
|
|
DEBUGDEF(static BOOL s_fCSInitialed)
|
|
static CITUnknown *s_pitunkActive;
|
|
// DEBUGDEF(static CITUnknown *s_pitunkActive)
|
|
};
|
|
|
|
typedef CITUnknown *PITUnknown;
|
|
|
|
inline void CITUnknown::MarkSecondary()
|
|
{
|
|
m_fSecondary = TRUE;
|
|
}
|
|
|
|
inline BOOL CITUnknown::IsSecondary()
|
|
{
|
|
return m_fSecondary;
|
|
}
|
|
|
|
// DEBUGDEF(extern PITUnknown CITUnknown::m_pitunkActive)
|
|
|
|
// The class CImpITUnknown will be used as one of the base classes defining
|
|
// the imbedded implementation which rely on CITUnknown for aggregation logic.
|
|
//
|
|
// The pattern here is that the outer class derived from CITUnknown will have
|
|
// a constructor of the form:
|
|
//
|
|
// CMyObject::CMyObject(IUnknown *punkOuter) :
|
|
// m_ImpIObject(this, punkOuter)
|
|
// {
|
|
// // Initialing code for CMyObject goes here...
|
|
// }
|
|
//
|
|
// Where m_ImpIObject is a member variable of CMyObject which has been derived
|
|
// from CImpITUnknown where CImpITUnknown has a constructor of the form:
|
|
//
|
|
// CMyObject::CImpIMyObject::CImpIMyObject(CITUnknown *pBackObj, IUnknown *punkOuter)
|
|
// : CImpITUnknown(pBackObj, punkOuter)
|
|
// {
|
|
// // Initialing code for CImpIMyObject goes here...
|
|
// }
|
|
//
|
|
// If the derrivation is indirect, you must define constructors for every class in the
|
|
// derivation chain to pass the pBackObj and punkOuter parameters down to CImpITUnknown.
|
|
|
|
class CImpITUnknown;
|
|
|
|
typedef CImpITUnknown *PCImpITUnknown;
|
|
|
|
class CImpITUnknown : public IUnknown
|
|
{
|
|
public:
|
|
|
|
CImpITUnknown(void);
|
|
|
|
CImpITUnknown(CITUnknown *pBackObj, IUnknown *punkOuter);
|
|
|
|
~CImpITUnknown();
|
|
|
|
STDMETHODIMP_(ULONG) AddRef (void);
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
STDMETHODIMP QueryInterface(REFIID riid, PPVOID ppv);
|
|
|
|
CITUnknown *Container();
|
|
BOOL HasControllingUnknown();
|
|
IUnknown * ControllingIUnknown();
|
|
BOOL ActiveMark();
|
|
|
|
void MarkActive (PCImpITUnknown &pListStart);
|
|
void MarkInactive();
|
|
|
|
static void DetachReference(PCImpITUnknown &pITUnk);
|
|
|
|
CImpITUnknown *NextObject();
|
|
|
|
private:
|
|
|
|
IUnknown *m_pUnkOuter;
|
|
CITUnknown *m_pBackObj;
|
|
BOOL m_fControlled;
|
|
CImpITUnknown *m_pImpITUnknownNext;
|
|
CImpITUnknown **m_ppImpITUnknownList;
|
|
BOOL m_fActive;
|
|
};
|
|
|
|
// The DetachRef define verifies that the target pointer variable has
|
|
// a type derived from PCImpITUnknown and then call DetachReference
|
|
// to safely disconnect the variable and decrement our reference count.
|
|
// Note that you still have to worry about multithreading cases. That
|
|
// is, you must avoid race conditions between two threads which try
|
|
// release the same pointer simultaneously. In practice the way to
|
|
// deal with that problem is to have all objects owned by a single
|
|
// thread and avoid the race condition.
|
|
|
|
#define DetachRef(p) { \
|
|
DEBUGDEF(PCImpITUnknown pUnk = p); \
|
|
CImpITUnknown::DetachReference((PCImpITUnknown) p); \
|
|
}
|
|
|
|
inline BOOL CImpITUnknown::HasControllingUnknown()
|
|
{
|
|
return m_fControlled;
|
|
}
|
|
|
|
inline CImpITUnknown::CImpITUnknown(void) { RonM_ASSERT(FALSE); }
|
|
|
|
inline IUnknown *CImpITUnknown::ControllingIUnknown()
|
|
{
|
|
return m_pUnkOuter;
|
|
}
|
|
|
|
inline BOOL CImpITUnknown::ActiveMark() { return m_fActive; }
|
|
|
|
inline CImpITUnknown *CImpITUnknown::NextObject()
|
|
{
|
|
RonM_ASSERT(m_fActive);
|
|
|
|
return m_pImpITUnknownNext;
|
|
}
|
|
|
|
inline CITUnknown *CImpITUnknown::Container()
|
|
{
|
|
return m_pBackObj;
|
|
}
|
|
|
|
#endif // __ITUNK_H__
|