A transfer protocol in the OLE sense is a mechanism for communicating an IDataObject pointer from a source to a consumer. The OLE Clipboard is one such protocol, supported through four OLE API functions:
OLE API Function | Description |
OleSetClipboard | Places a data object on the clipboard; that data object wraps all the data to copy or cut. OLE calls AddRef on this object and asks it to enumerate its formats. OLE makes these formats available to potential consumers. |
OleGetClipboard | Retrieves a data object that represents the data available on the clipboard, calling AddRef on the IDataObject pointer returned. The consumer must call Release when it is done with the object. |
OleFlushClipboard | Clears the clipboard, calling Release on the data object passed to OleSetClipboard. |
OleIsCurrentClipboard | Answers whether a given data object is the one currently on the clipboard. |
The overall mechanism of a clipboard data transfer in OLE is shown in Figure 12-1. The source creates a data object (including its FORMATETC enumerator) and calls OleSetClipboard. OLE calls the Windows function OpenClipboard, followed by IDataObject::AddRef and IDataObject::EnumFormatEtc. For each enumerated format that uses TYMED_HGLOBAL, OLE calls the Windows function SetClipboardData(formatetc.cfFormat, NULL) to make the format available using delayed rendering. OLE finishes by calling the Windows function CloseClipboard. When any consumer, aware of OLE or not, calls the Windows function GetClipboardData for any of these formats, Windows, according to delayed rendering, sends a WM_RENDERFORMAT message.
Figure 12-1.
The OLE Clipboard involves OleGetClipboard, OleSetClipboard, and a data object.
But to which window is the message sent? It is sent to one inside OLE itself, the handle to which OLE passes in its call to OpenClipboard. This window is always hidden and is created inside OleInitialize. If you plan to use the OLE Clipboard, you must use OleInitialize instead of CoInitialize. Failure to do this will cause clipboard operations to fail.
When this window receives WM_RENDERFORMAT, OLE generates calls to IDataObject::QueryGetData (to validate the format) and to IDataObject::GetData. In other words, OLE provides delayed clipboard rendering by means of data objects. Delayed rendering, however, means that the source must make a snapshot of the data it places on the clipboard so that the data object placed there is not tied to changing information. (I'll treat this subject in more detail momentarily.)
The consumer that pastes data from the clipboard doesn't have to care about complications like this: it just calls OleGetClipboard to obtain an IDataObject pointer for the clipboard. This pointer is not the one the source might have provided; instead, it is an OLE-provided data object made especially for the clipboard. The reason for this is that OLE allows consumers to access clipboard data through this data object regardless of whether the data was copied to the clipboard using OLE. OLE's data object reflects the conceptual state of the Windows clipboard, not the state of any source's data object.
With the data object, the consumer can call the IDataObject members EnumFormatEtc, QueryGetData, and GetData, as it would call the EnumClipboardFormats, IsClipboardFormatAvailable, and GetClipboardData functions in Windows. Through the IDataObject interface, a consumer can access not only the TYMED_HGLOBAL-based data on the Windows clipboard but also any other data based on other mediums that the data source provides itself. When the consumer asks for data through IDataObject::GetData, OLE will either access data from the Windows clipboard itself or simply forward the call to the source's IDataObject interface. So the consumer has access to all the possible data on the clipboard, regardless of whether that data came from an OLE data object or from a non-OLE Windows application. The effort needed to obtain clipboard data through OLE is minimal.
I should mention that OLE's clipboard data object does not implement IDataObject::SetData or any of the advise-related members. Also, its GetDataHere will work only with limited formats. The data object itself exposes only IDataObject and IUnknown, so don't expect anything fancy.