Copy/Cut

A Copy or a Cut operation entails gaining access to the clipboard, copying the data renderings, and releasing the clipboard. (Cut deletes the data from the source afterward.) The OLE version of this process is a bit different because there are no analogs to opening or closing the clipboard. Instead, there's just OleSetClipboard:

Create a data object (such as DataTran), and store the appropriate data in it. This is similar to calling OpenClipboard followed by SetClipboardData as many times as needed. Calling EmptyClipboard is unnecessary here: OLE does it within OleSetClipboard.

Pass the data object to OleSetClipboard. This calls the object's AddRef followed by IDataObject::EnumFormatEtc to place each format on the Windows clipboard.

The source is now finished with its own data object and can release it if desired. The object remains alive until OLE calls its Release. This step is much like calling CloseClipboard.

For a Cut operation only, remove the affected data from the source.

Cosmo performs these steps in CCosmoDoc::Clip (DOCUMENT.CPP). At least half of the code and the structure of the function are unaffected by the changes. These deal primarily with creating a data object, stuffing it with data, and placing it on the clipboard. CCosmoDoc::RenderFormat creates the renderings to give to DataTran:


BOOL CCosmoDoc::Clip(HWND hWndFrame, BOOL fCut)
{
BOOL fRet=TRUE;
HGLOBAL hMem;
UINT i;
static UINT rgcf[3]={0, CF_METAFILEPICT, CF_BITMAP};
const UINT cFormats=3;
static DWORD rgtm[3]={TYMED_HGLOBAL, TYMED_MFPICT, TYMED_GDI};
LPDATAOBJECT pIDataObject;
HRESULT hr;
STGMEDIUM stm;
FORMATETC fe;

hr=CoCreateInstance(CLSID_DataTransferObject
, NULL, CLSCTX_INPROC_SERVER
, IID_IDataObject, (PPVOID)&pIDataObject);

if (FAILED(hr))
return NULL;

rgcf[0]=m_cf;

for (i=0; i < cFormats; i++)
{
//Copy private data first.
hMem=RenderFormat(rgcf[i]);

if (NULL!=hMem)
{
stm.hGlobal=hMem;
stm.tymed=rgtm[i];
stm.pUnkForRelease=NULL;

SETDefFormatEtc(fe, rgcf[i], rgtm[i]);
pIDataObject->SetData(&fe, &stm, TRUE);
}
}

fRet=SUCCEEDED(OleSetClipboard(pIDataObject));
pIDataObject->Release();

if (fRet && fCut)
{
m_pPL->New();
FDirtySet(TRUE);
}

return fRet;
}

The order in which we store formats in a DataTran object is the same order in which it will enumerate those formats. This means we stuff formats with the highest integrity first.