#include "stock.h" #pragma hdrstop #include "caggunk.h" ULONG CAggregatedUnknown::AddRef() { return _punkAgg->AddRef(); } ULONG CAggregatedUnknown::Release() { return _punkAgg->Release(); } HRESULT CAggregatedUnknown::QueryInterface(REFIID riid, void **ppvObj) { return _punkAgg->QueryInterface(riid, ppvObj); } HRESULT CAggregatedUnknown::CUnkInner::QueryInterface(REFIID riid, void **ppvObj) { if (IsEqualIID(riid, IID_IUnknown)) { *ppvObj = SAFECAST(this, IUnknown*); InterlockedIncrement(&_cRef); return S_OK; } CAggregatedUnknown* pparent = IToClass(CAggregatedUnknown, _unkInner, this); return pparent->v_InternalQueryInterface(riid, ppvObj); } ULONG CAggregatedUnknown::CUnkInner::AddRef(void) { return InterlockedIncrement(&_cRef); } ULONG CAggregatedUnknown::CUnkInner::Release(void) { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { CAggregatedUnknown* pparent = IToClass(CAggregatedUnknown, _unkInner, this); if (!pparent->v_HandleDelete(&_cRef)) { _cRef = 1000; // protect against cached pointers bumping us up then down delete pparent; } } return cRef; } CAggregatedUnknown::CAggregatedUnknown(IUnknown* punkAgg) { _punkAgg = punkAgg ? punkAgg : &_unkInner; } CAggregatedUnknown::~CAggregatedUnknown() { } // // Convert our controlling unknown to its canonical IUnknown *without* // altering the reference count on the outer object. // // This is critical in order for QueryOuterInterface to work properly. // // Returns NULL if something horrible went wrong. // // OLE Magic: Since objects are required also to return the canonical // IUnknown in response to any QI(IUnknown), it follows that the canonical // IUnknown remains valid so long as there are any outstanding references // to the object. In other words, you can Release() the canonical IUnknown // and the pointer remains valid so long as you keep the object alive by // other means. // // Believe it or not, this is a feature. It's in the book! // IUnknown *CAggregatedUnknown::_GetCanonicalOuter(void) { IUnknown *punkAggCanon; HRESULT hres = _punkAgg->QueryInterface(IID_IUnknown, (void **)&punkAggCanon); if (SUCCEEDED(hres)) { punkAggCanon->Release(); // see "OLE Magic" comment above return punkAggCanon; } else { // The outer object is most likely some other shell component, // so let's ASSERT so whoever owns the outer component will fix it. ASSERT(!"The outer object's implementation of QI(IUnknown) is broken."); return NULL; } } void CAggregatedUnknown::_ReleaseOuterInterface(IUnknown** ppunk) { ASSERT(IS_VALID_CODE_PTR(_punkAgg, IUnknown)); IUnknown *punkAggCanon = _GetCanonicalOuter(); // non-refcounted pointer // // SHReleaseOuterInterface can handle punkAggCanon == NULL // SHReleaseOuterInterface(punkAggCanon, ppunk); } HRESULT CAggregatedUnknown::_QueryOuterInterface(REFIID riid, void ** ppvOut) { IUnknown *punkAggCanon = _GetCanonicalOuter(); // non-refcounted pointer // // SHQueryOuterInterface can handle punkAggCanon == NULL. // return SHQueryOuterInterface(punkAggCanon, riid, ppvOut); }