Obtain a Default Handler IUnknown

When initializing the handler object, you should create a default handler instance using OleCreateDefaultHandler, passing your CLSID and a pointer to your object's controlling IUnknown because you must aggregate on the handler in this situation. You get back an IUnknown pointer to this default object according to the aggregation rules. You need to pass your own CLSID so that the default handler can implement various functions using your registry entries.

After you have this default handler's IUnknown, you should query for IOleObject, IPersistStorage, and IViewObject2 (and also perhaps IDataObject). You can later delegate to these interfaces, calling the controlling unknown's Release after each query according to the aggregation rules we saw in earlier chapters. This is much more efficient than calling QueryInterface, delegating the function, and calling Release every time you need to delegate. HCosmo does all this in CFigure::Init (called from IClassFactory::CreateInstance) after allocating its own interface implementations:


BOOL CFigure::Init(void)
{
LPUNKNOWN pIUnknown=(LPUNKNOWN)this;
HRESULT hr;
DWORD dwConn;
FORMATETC fe;

if (NULL!=m_pUnkOuter)
pIUnknown=m_pUnkOuter;

[Create interface implementations.]

m_cRef++;

hr=OleCreateDefaultHandler(CLSID_CosmoFigure, pIUnknown
, IID_IUnknown, (PPVOID)&m_pDefIUnknown);

if (FAILED(hr))
return FALSE;

//Now try to get other interfaces to which we delegate.
hr=m_pDefIUnknown->QueryInterface(IID_IOleObject
, (PPVOID)&m_pDefIOleObject);

if (FAILED(hr))
return FALSE;

pIUnknown->Release();

hr=m_pDefIUnknown->QueryInterface(IID_IViewObject2
, (PPVOID)&m_pDefIViewObject2);

if (FAILED(hr))
return FALSE;

pIUnknown->Release();

hr=m_pDefIUnknown->QueryInterface(IID_IDataObject
, (PPVOID)&m_pDefIDataObject);

if (FAILED(hr))
return FALSE;

pIUnknown->Release();

hr=m_pDefIUnknown->QueryInterface(IID_IPersistStorage
, (PPVOID)&m_pDefIPersistStorage);

if (FAILED(hr))
return FALSE;

pIUnknown->Release();
m_cRef--;

//Set up an advise on native data so we can keep in sync.
SETDefFormatEtc(fe, m_cf, TYMED_HGLOBAL);
m_pDefIDataObject->DAdvise(&fe, 0, m_pIAdviseSink, &dwConn);

return TRUE;
}

When we want to free this default handler object, we need to call the controlling unknown's AddRef and then call Release through each m_pDefI* that we obtained earlier, again according to aggregation rules. This is done in CFigure::~CFigure.

Otherwise, everything about this code should look familiar by now, except for the part at the end, which sets up a data change advise connection. The default handler will connect our IAdviseSink here to the local object when the latter becomes a running object. We use this connection to synchronize with the local object as described in "Synchronizing with a Local Server" in Chapter 11 on page 551 and "Synchronized Swimming with Your Local Server" later in this chapter. Note that I don't save the connection key from DAdvise because I won't need to call DUnadvise until I release m_pDefIDataObject, which will terminate the connection for me.