If You Already Have a Data Object...Component Cosmo

If a source is about to copy an object that is already a data object, it's not necessary to use an entirely different class as does DataTran. For example, the Polyline object used by CoCosmo implements IDataObject, so CoCosmo can make another Polyline and copy data directly into it. Any data object works as well as any other. The copying is necessary to create a snapshot of the current, visible Polyline so changes to it will not cause problems with delayed rendering. End users will expect that the data they paste is exactly the same data they copied. If CoCosmo places the visible Polyline on the clipboard, the data is live, so any change made to the Polyline object will show up when the data is pasted later. What the end user copied and what that user pasted is not the same. Not good.

Instead, CoCosmo instantiates an extra hidden Polyline with the same dimensions as the visible one and copies the visible object's data into it. A perfect snapshot. CoCosmo then tosses the hidden Polyline onto the clipboard, as shown in the following code (taken from CHAP12\COCOSMO\DOCUMENT.CPP, which continues to use the Polyline implementation from Chapter 10):


BOOL CCosmoDoc::Clip(HWND hWndFrame, BOOL fCut)
{
PPOLYLINE pPL;
LPDATAOBJECT pDataSrc, pIDataObject;
FORMATETC fe;
STGMEDIUM stm;
BOOL fRet=TRUE;
HRESULT hr;
RECT rc;

hr=CoCreateInstance(CLSID_Polyline10, NULL, CLSCTX_INPROC_SERVER
, IID_IPolyline10, (PPVOID)&pPL);

if (FAILED(hr))
return FALSE;

m_pPL->RectGet(&rc);

if (FAILED(pPL->Init(m_hWnd, &rc, WS_CHILD, ID_POLYLINE)))
{
pPL->Release();
return FALSE;
}

m_pPL->QueryInterface(IID_IDataObject, (PPVOID)&pDataSrc);

SETDefFormatEtc(fe, m_cf, TYMED_HGLOBAL);
fRet=SUCCEEDED(pDataSrc->GetData(&fe, &stm));
pDataSrc->Release();

if (!fRet)
{
pPL->Release();
return FALSE;
}

pPL->QueryInterface(IID_IDataObject, (PPVOID)&pIDataObject);
pPL->Release();

pIDataObject->SetData(&fe, &stm, TRUE);

fRet=SUCCEEDED(OleSetClipboard(pIDataObject));

if (NULL!=m_pIDataClip)
m_pIDataClip->Release();

m_pIDataClip=pIDataObject;

//Delete our current data if "cut" succeeded.
if (fRet && fCut)
{
m_pPL->New();
FDirtySet(TRUE);
}

return fRet;
}

The preceding code handles both Cut and Copy operations with identical vigor, but Cut removes the affected data from the document. Keep in mind, however, that you still need to create a snapshot of the data regardless of whether you are cutting it or copying it.