To invoke the Paste Special dialog box, you first fill an OLEUIPASTESPECIAL structure (shown in the code on the following page) and call the function OleUIPasteSpecial. On return, the dialog box will indicate the index of the format the end user chose from the list. Patron uses this format to determine whether to create a data cache for CLSID_Picture_Dib or CLSID_Picture_Metafile. The real trick, however, is filling the OLEUIPASTESPECIAL structure.
typedef struct tagOLEUIPASTESPECIAL
{
[Standard header common to all OLE UI dialogs]
//Specifics for OLEUIPASTESPECIAL
//IN fields
LPDATAOBJECT lpSrcDataObj; //Source IDataObject* (on
//clipboard) for data to paste
LPOLEUIPASTEENTRY arrPasteEntries; //Array of OLEUIPASTEENTRYs
//of acceptable formats
int cPasteEntries; //Number of OLEUIPASTEENTRYs
[These are not important for this chapter.]
UINT FAR *arrLinkTypes;
int cLinkTypes;
//OUT fields
int nSelectedIndex; //User-selected arrPasteEntries
BOOL fLink; //Paste or Paste Link selected?
HGLOBAL hMetaPict; //Icon and icon title
} OLEUIPASTESPECIAL, *POLEUIPASTESPECIAL, FAR *LPOLEUIPASTESPECIAL;
The Paste Special dialog box needs to present the end user with a list box containing text descriptions of all the available formats. This lets the application control which formats are allowed at all. First the dialog box needs to know the data object that exists on the clipboard. You store that object in the lpSrcDataObj field of OLEUIPASTESPECIAL, as shown in the code in CPatronDoc::PasteSpecial (DOCUMENT.CPP):
OLEUIPASTESPECIAL ps;
_memset(&ps, 0, sizeof(ps));
if (FAILED(OleGetClipboard(&ps.lpSrcDataObj)))
return FALSE;
You must also fill the cbStruct field with the size of the structure (used to verify versions) and identify the window that owns it:
ps.cbStruct=sizeof(ps);
ps.hWndOwner=hWndFrame;
In the dwFlags field, you can specify any of these flags: PSF_SHOWHELP, PSF_SELECTPASTE, PSF_SELECTPASTELINK, and PSF_CHECKDISPLAYASICON. We'll use the latter two in the chapters about OLE Documents. To use the dialog box for simple pasting, specify the PSF_SELECTPASTE flag (including PSF_SHOWHELP if you want):
ps.dwFlags=PSF_SELECTPASTE;
Now you need only to describe the allowable formats and provide text descriptions for those formats by filling the cPasteEntries and arrPasteEntries fields:
OLEUIPASTEENTRY rgPaste[4];
ps.arrPasteEntries=rgPaste;
ps.cPasteEntries=4;
The arrPasteEntries field is a pointer to an array of OLEUIPASTEENTRY structures. Each structure describes the format and holds the description string:
typedef struct tagOLEUIPASTEENTRY
{
FORMATETC fmtetc;
LPCSTR lpstrFormatName;
LPCSTR lpstrResultText;
DWORD dwFlags;
DWORD dwScratchSpace;
} OLEUIPASTEENTRY, *POLEUIPASTEENTRY, FAR *LPOLEUIPASTEENTRY;
The following table lists the meanings of these fields:
Field | Description |
fmtetc | The FORMATETC for this entry. |
lpstrFormatName | A text description of the FORMATETC. For example, a string for a CF_DIB-based format (regardless of the aspect, storage medium, or other FORMATETC values) is "Device-Independent Bitmap". |
lpszResultText | A string that describes the data resulting from a Paste Special operation. Typically this is "a" or "an" prepended to the format description, as in "a Device-Independent Bitmap". |
dwFlags | Flags indicating what operations are allowed on this particular format. The only one of relevance for now is OLEUIPASTE_PASTEONLY, indicating that Paste is allowed. Other options enable the Paste Link and Display As Icon options. |
dwScratchSpace | Reserved for internal dialog use. |
Patron can paste any of four formats. The preferred format is a structure named PATRONOBJECT (see PAGES.H). This describes a tenant in a way that a Copy or Paste operation between Patron documents places the object in the same location as it had in the source document if possible. PATRONOBJECT is followed in preference by CF_METAFILEPICT, CF_DIB, and CF_BITMAP. Therefore, Patron fills an array of four OLEUIPASTEENTRY structures (rgPaste), as is shown in the following for its private format:
SETDefFormatEtc(rgPaste[0].fmtetc, m_cf, TYMED_HGLOBAL);
rgPaste[0].lpstrFormatName="Patron Object";
rgPaste[0].lpstrResultText="a Patron Object";
rgPaste[0].dwFlags=OLEUIPASTE_PASTEONLY;
[Similar code for other formats]
After Patron has filled these structures, it can call OleUIPasteSpecial:
uTemp=OleUIPasteSpecial(&ps);
if (OLEUI_OK==uTemp)
{
fRet=PasteFromData(ps.lpSrcDataObj
, &rgPaste[ps.nSelectedIndex].fmtetc
, TENANTTYPE_STATIC, NULL, 0L);
}
ps.lpSrcDataObj->Release();
return fRet;
If OleUIPasteSpecial returns OLEUI_OK, the end user has pressed the OK button, and we execute a Paste with the selected format, in which the nSelectedIndex field of OLEUIPASTESPECIAL matches the index of OLEUIPASTEENTRY. Patron calls its "paste from data" function before releasing the data object it obtained from OleGetClipboard.