As with any aggregation relationship, we need to expose select interfaces from the inner object through our own QueryInterface, along with those interfaces we implement ourselves. To do this, CFigure::QueryInterface delegates to the default handler's IUnknown for the caching interfaces and IRunnableObject, returning other object pointers for the remaining interfaces:
STDMETHODIMP CFigure::QueryInterface(REFIID riid, PPVOID ppv)
{
*ppv=NULL;
if (IID_IUnknown==riid)
*ppv=this;
if (IID_IPersist==riid œœ IID_IPersistStorage==riid)
*ppv=m_pImpIPersistStorage;
if (IID_IOleObject==riid)
*ppv=m_pImpIOleObject;
if (IID_IViewObject==riid œœ IID_IViewObject2==riid)
*ppv=m_pImpIViewObject2;
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
if (IID_IDataObject==riid œœ IID_IOleCache==riid
œœ IID_IOleCache2==riid œœ IID_IOleCacheControl==riid
œœ IRunnableObject==riid)
return m_pDefIUnknown->QueryInterface(riid, ppv);
return ResultFromScode(E_NOINTERFACE);
}
As we discussed earlier about aggregation, you do not want to blindly delegate requests for unrecognized interfaces to the inner object's QueryInterface unless you specifically have a reason to do so.
Whatever the case may be, you can see here that the figure object in HCosmo exposes all of those interfaces that a container will expect: some from the default handler, others from the figure object itself. In addition, CFigure::Release will destroy the object when the reference count is 0, decrementing the global object count so DllCanUnloadNow works properly.