With the addition of the CFSTR_LINKSOURCE and CFSTR_LINKSRCDESCRIPTOR formats to Cosmo's data transfer objects, we enable containers to link to a Figure object. Cosmo registers these formats in the CCosmoDoc constructor and saves them in m_cfLinkSource and m_cfLinkSrcDescriptor. We add these formats to those stored in the transfer object in CCosmoDoc::TransferObjectCreate. This function calls CCosmoDoc::RenderMedium to render the data itself. As mentioned in Chapter 20, CFSTR_LINKSOURCE is a stream containing a serialized moniker; CFSTR_LINKSRCDESCRIPTOR is an OBJECTDESCRIPTOR structure:
BOOL CCosmoDoc::RenderMedium(UINT cf, LPSTGMEDIUM pSTM)
{
[Case for CF_EMBEDSOURCE]
/*
* CFSTR_OBJECTDESCRIPTOR and CFSTR_LINKSRCDESCRIPTOR are the
* same formats, but copy link source only if we have a moniker.
*/
if (cf==m_cfLinkSrcDescriptor && NULL==m_pMoniker)
return FALSE;
if (cf==m_cfObjectDescriptor œœ cf==m_cfLinkSrcDescriptor)
{
SIZEL szl, szlT;
POINTL ptl;
RECT rc;
LPTSTR psz=NULL;
m_pPL->SizeGet(&rc);
SETSIZEL(szlT, rc.right, rc.bottom);
XformSizeInPixelsToHimetric(NULL, &szlT, &szl);
SETPOINTL(ptl, 0, 0);
//Include moniker display name now if we have one.
if (m_pMoniker)
{
LPBC pbc;
CreateBindCtx(0, &pbc);
m_pMoniker->GetDisplayName(pbc, NULL, &psz);
pbc->Release();
}
CoTaskMemFree((void *)psz);
pSTM->hGlobal=INOLE_AllocObjectDescriptor
(CLSID_CosmoFigure, DVASPECT_CONTENT, szl, ptl
, OLEMISC_RECOMPOSEONRESIZE, PSZ(IDS_OBJECTDESCRIPTION)
, psz);
pSTM->tymed=TYMED_HGLOBAL;
return (NULL!=pSTM->hGlobal);
}
if (cf==m_cfLinkSource)
{
if (NULL!=m_pMoniker)
{
FORMATETC fe;
HRESULT hr;
pSTM->tymed=TYMED_NULL;
SETDefFormatEtc(fe, cf, TYMED_ISTREAM);
hr=INOLE_GetLinkSourceData(m_pMoniker
, (LPCLSID)&CLSID_CosmoFigure, &fe, pSTM);
return SUCCEEDED(hr);
}
}
return FALSE;
}
We don't, of course, copy either link format if we have no moniker. If we have a moniker, we include the moniker's display name in CFSTR_LINKSRCDESCRIPTOR, using our helper function INOLE_AllocObjectDescriptor to create the data. To create CFSTR_LINKSOURCE, we use the helper function INOLE_GetLinkSourceData, which creates a stream in global memory, saves the moniker to the stream with OleSaveToStream, and saves the object's CLSID with a call to WriteClassStm.
As for the placement of the linking formats on the clipboard, they should always be after other formats, even after simple formats such as CF_TEXT. The reason is that linking almost never happens by default when a container pastes. It almost always happens when the user explicitly asks the container to perform a Paste Link operation. Keep the link data at the lowest spot on the totem pole.