// 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__