4.5.1 Cutting and Copying Data to the Clipboard

To cut or copy data to the clipboard so that a client application can then use the data to create an embedded or linked object, the server application should:

Open the clipboard by calling the OpenClipboard function.

Empty the clipboard of any existing data by calling the EmptyClipboard function.

Get a handle for each of the data formats and then call SetClipboardData to put the data formats on the clipboard.

Close the clipboard by calling the CloseClipboard function.

If the server application cuts data to the clipboard, it typically does not offer the ObjectLink format because the source for the data has been removed from the document. (If the server application copies data to the clipboard from an untitled document, it does not offer the ObjectLink format).

The order in which various data formats are put on the clipboard depends on the type of data being copied to the clipboard and the capabilities of the server application. For more information on the clipboard data formats to be used and their order of placement, see Chapter 2, "Considerations for OLE Applications."

Typically, a server application puts server-specific formats, Native format, OwnerLink format, and presentation formats on the clipboard. If it can support links, the server application also puts the ObjectLink format on the clipboard. The server application must provide a presentation format (CF_METAFILE, CF_BITMAP, or CF_DIB) if it does not have an object handler (CF_METAFILE is typically used). Native data can be used as a presentation format only if the server application has an object handler that can use the Native data (for more information about object handlers, see Chapter 6, "Implementing Object Handlers").

If a server application uses a metafile as the presentation format for an object, the mapping mode for that metafile must be MM_ANISOTROPIC; otherwise, the metafile will not scale properly in the clipboard viewer and in OLE client applications. If a server application uses fonts in these metafiles, it can improve performance by using TrueType fonts. Metafiles scale better when they use TrueType fonts. In addition, TrueType fonts are device-independent, relieving your application from dealing with device-specific fonts depending on the printer in use. To use TrueType fonts exclusively, the server application should set bit 2 (04h) of the lpPitchandFamily member of the LOGFONT structure.

The following code example shows how SRVRDEMO.EXE copies and cuts data to the clipboard:

case IDM_COPY:

CutOrCopyObj (TRUE);

break;

.

.

.

/* CutOrCopyObj

*

* Put data onto clipboard in all the formats supported. If the

* fOpIsCopy is TRUE, the operation is COPY, otherwise it is CUT.

* This is important, because we cannot put the Object Link format

* onto the clipboard if the object was cut from the document (there

* is no longer anything to link to).

*

* BOOL fOpIsCopy - TRUE if the operation is COPY; FALSE if CUT

*/

void CutOrCopyObj (BOOL fOpIsCopy)

{

LPOBJ lpobj;

HANDLE hData;

if (OpenClipboard (hwndMain))

{

EmptyClipboard ();

lpobj = SelectedObject();

if ((hData = GetNative (lpobj)) != NULL)

SetClipboardData(cfNative, hData);

if ((hData = GetLink(lpobj)) != NULL)

SetClipboardData(cfOwnerLink, hData);

if (fOpIsCopy && docMain.doctype == doctypeFromFile)

{

// Create a link if object exists in a file.

if ((hData = GetLink(lpobj)) != NULL)

SetClipboardData(cfObjectLink, hData);

}

if ((hData = GetMetafilePict(lpobj)) != NULL)

{

SetClipboardData(CF_METAFILEPICT, hData);

}

if ((hData = GetBitmap(lpobj)) != NULL)

{

SetClipboardData(CF_BIÔAP, hData);

}

CloseClipboard ();

}

}

To cut an object to the clipboard, SRVRDEMO.EXE calls CutOrCopyObj before calling RevokeObj to revoke the object. After revoking the object, the child window is destroyed (SRVRDEMO gives each object it creates its own window), and then the menus are updated.

case IDM_CUT:

CutOrCopyObj (FALSE);

// Fall through.

case IDM_DELETE:

RevokeObj (SelectedObject());

DestroyWindow (SelectedObjectWindow());

UpdateObjMenus();

break;

.

.

.

/* RevokeObj

*

* Call OleRevokeObject because the user has destroyed the object.

*

* LPOBJ lpobj - The object which has been destroyed

*/

void RevokeObj (LPOBJ lpobj)

{

int i;

for (i=0; i< clpoleclient; i++)

{

if (lpobj->lpoleclient[i]) OleRevokeObject

(lpobj->lpoleclient[i]);

else

// if lpobj->lpoleclient[i]==NULL then there are no more

// non-NULLs in the array.

break;

}

}

/* UpdateObjMenus

*

* Grey or Ungrey menu items depending on the existence of at least

* one object in the document.

*/

static void UpdateObjMenus (void)

{

static BOOL fObjMenusEnabled = TRUE;

BOOL fOneObjExists; // Does at least one object exist?

WORD wEnable;

HMENU hMenu;

fOneObjExists = (SelectedObjectWindow() != NULL);

if (fOneObjExists == fObjMenusEnabled)

{

// Nothing has changed.

return;

}

wEnable = (fOneObjExists ? MF_ENABLED : MF_GRAYED);

hMenu = GetMenu(hwndMain);

EnableMenuItem(hMenu, menuposColor, MF_BYPOSITION | wEnable);

hMenu = GetSubMenu(GetMenu(hwndMain), menuposFile);

EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | wEnable);

EnableMenuItem(hMenu, IDM_SAVEAS, MF_BYCOMMAND | wEnable);

hMenu = GetSubMenu(GetMenu(hwndMain), menuposEdit);

EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | wEnable);

EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | wEnable);

EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | wEnable);

hMenu = GetSubMenu(GetMenu(hwndMain), menuposObject);

EnableMenuItem(hMenu, IDM_NEXTOBJ, MF_BYCOMMAND | wEnable);

DrawMenuBar (hwndMain);

fObjMenusEnabled = fOneObjExists;

}