Supporting linking to embeddings as an object is quite simple for a local server such as Cosmo: it needs only to implement IOleObject::SetMoniker properly because the default handler will automatically call the container's IOleContainer::LockContainer to handle proper shutdown. When the object is implemented from an in-process server such as Polyline, the object itself has to register its full moniker as running and also handle the shutdown conditions by calling LockContainer at the appropriate times. You can make these calls either in IRunnableObject::Run or in IOleObject::SetClientSite. Polyline uses the latter case (in IOLEOBJ.CPP) because it does not have any client site pointers by the time IRunnableObject::Run is called:
STDMETHODIMP CImpIOleObject::SetClientSite
(LPOLECLIENTSITE pIOleClientSite)
{
if (NULL!=m_pObj->m_pIOleClientSite)
m_pObj->m_pIOleClientSite->Release();
m_pObj->m_pIOleClientSite=pIOleClientSite;
if (NULL!=m_pObj->m_pIOleClientSite)
{
HRESULT hr;
LPMONIKER pmk;
LPOLECONTAINER pIOleCont;
m_pObj->m_pIOleClientSite->AddRef();
hr=m_pObj->m_pIOleClientSite->GetMoniker
(OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, &pmk);
if (SUCCEEDED(hr))
{
INOLE_RegisterAsRunning(this, pmk, 0
, &m_pObj->m_dwRegROT);
pmk->Release();
}
hr=m_pObj->m_pIOleClientSite->GetContainer(&pIOleCont);
if (SUCCEEDED(hr))
{
m_pObj->m_fLockContainer=TRUE;
pIOleCont->LockContainer(TRUE);
pIOleCont->Release();
}
}
return NOERROR;
}
Polyline revokes the running object table registration in its destructor, CPolyline::~CPolyline.
Now all we need to know is when to call IOleContainer::LockContainer(FALSE) to start container shutdown. We make the call when the linking container (the one linking to this embedded object) releases all of its connections to this object. To know when this happens, we must implement IExternalConnection, which Polyline does in IEXTCONN.CPP, as shown on the following page.
STDMETHODIMP_(DWORD) CImpIExternalConnection::AddConnection
(DWORD dwConn, DWORD dwReserved)
{
if (EXTCONN_STRONG & dwConn)
return ++m_cLockStrong;
return 0;
}
STDMETHODIMP_(DWORD) CImpIExternalConnection::ReleaseConnection
(DWORD dwConn, DWORD dwReserved, BOOL fLastReleaseCloses)
{
if (EXTCONN_STRONG==dwConn)
{
if (0==--m_cLockStrong && fLastReleaseCloses)
m_pObj->m_pImpIOleObject->Close(OLECLOSE_SAVEIFDIRTY);
return m_cLockStrong;
}
return 0L;
}
When the last external strong lock disappears, we call our own IOleObject::Close to handle our shutdown. In that function, we check the m_fLockContainer flag set in IOleObject::SetClientSite. If that flag is TRUE, we unlock the container to have it shut down as well:
STDMETHODIMP CImpIOleObject::Close(DWORD dwSaveOption)
{
[Other handling as usual]
if (m_pObj->m_fLockContainer)
{
//Match LockContainer call from SetClientSite.
LPOLECONTAINER pIOleCont;
if (SUCCEEDED(m_pObj->m_pIOleClientSite
->GetContainer(&pIOleCont)))
{
pIOleCont->LockContainer(FALSE);
pIOleCont->Release();
}
}
§
}