windows-nt/Source/XPSP1/NT/shell/lib/caggunk.cpp
2020-09-26 16:20:57 +08:00

124 lines
3.2 KiB
C++

#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)
{
if (InterlockedDecrement(&_cRef))
return _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 0;
}
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);
}