Data Objects and the IDataObject Interface

Any component that is a source of formatted data structures is a data object if it implements IDataObject. Any and all code that in one way or another has data to share can do so with a data object. The great benefit of doing this is that once you have a data object implementation around, you can use that data object in any transfer protocol, be it clipboard, drag and drop, compound documents, OLE Automation, and so on, and any new format you might support is instantly provided through all the protocols. A source can centralize the code that renders data into this data object implementation; a consumer can centralize the code necessary to check available formats in a data object and also centralize the code used to paste that data. Centralization reduces both the overall amount of code you must implement and the number of different API functions for dealing with each protocol.

Centralization is possible because the IDataObject interface combines the functionality of the existing data transfer protocols, thereby providing more functionality in an OLE data transfer than is available for any other existing protocol. The definition of the IDataObject interface is as follows:


interface IDataObject : IUnknown
{
HRESULT GetData(LPFORMATETC pFEIn, LPSTGMEDIUM pSTM);
HRESULT GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
HRESULT QueryGetData(LPFORMATETC pFE);
HRESULT GetCanonicalFormatEtc(LPFORMATETC pFEIn
, LPFORMATETC pFEOut);
HRESULT SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease);
HRESULT EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC *ppEnum);
HRESULT DAdvise(LPFORMATETC pFE, DWORD grfAdv, LPADVISESINK pAdvSink
, LPDWORD pdwConnection);
HRESULT DUnadvise(DWORD dwConnection);
HRESULT EnumDAdvise(LPENUMSTATDATA *ppEnum);
};

Many of the member functions have equivalents in specific Windows API functions; keep in mind, however, that data objects are used to describe data transferred by means of any protocol, and thus they provide the ability to treat data in a uniform fashion regardless of how you obtained the IDataObject pointer. The following list describes each IDataObject member in more detail and lists the similar (but not always exact) functionality that exists in the clipboard, DDE, and outdated OLE 1 transfer protocols:

Protocol

Similar API Function or Message

Clipboard

GetClipboardData

DDE

WM_DDE_REQUEST, WM_DDE_DATA

OLE 1

OleGetData


Protocol

Similar API Function or Message

Clipboard

SetClipboardData

DDE

WM_DDE_POKE

OLE 1

OleSetData


Protocol

Similar API Function or Message

Clipboard

IsClipboardFormatAvailable

DDE

None (perhaps handled through WM_DDE_CONNECT, WM_DDE_ADVISE)

OLE 1

None


Protocol

Similar API Function or Message

Clipboard

EnumClipboardFormats (get direction only)

DDE

None

OLE 1

None


Protocol

Similar API Function or Message

Clipboard

None

DDE

WM_DDE_ADVISE

OLE 1

None


Protocol

Similar API Function or Message

Clipboard

None

DDE

WM_DDE_UNADVISE

OLE 1

None


You can see from the preceding list that no existing protocol supports the full range of functionality that IDataObject provides for all protocols. This is not to say that any arbitrary data object that a client might obtain actually implements the full functionality of every member function. Some data objects—such as a static bitmap on the clipboard—will refuse any advisory connections. Others might not support any SetData calls. But you are always allowed to try to learn the data object's capabilities through error return values. With existing protocols, you are not even allowed to play a little.

Related to IDataObject is an OLE API function that you might find useful in your work: OleDuplicateData. This function will copy any global-memory–based format, including metafiles, bitmaps, and palettes. Its signature is as follows:


HANDLE OleDuplicateData(HANDLE hSrc, CLIPFORMAT cf, UINT uiFlags);

where hSrc is the handle of the source data, cf identifies the format of the data, and uiFlags specifies the flags to pass to GlobalAlloc if such memory needs allocation. If uiFlags is 0, the function assumes GMEM_MOVEABLE.

OleDuplicateData will perform a bytewise duplication of the data except in the case of CF_METAFILEPICT, CF_ENHMETAFILE, CF_PALETTE, and CF_BITMAP, for which special handling is required. Accordingly, hSrc must be a global-memory handle for any bytewise duplication, whereas it is the appropriate handle type when used with these other four formats.

3 The D in the function names identifies these functions as belonging to IDataObject. Prior to the release of OLE 2 both IDataObject and IOleObject had the member functions Advise Unadvise and EnumAdvise which played havoc with OLE Document content objects that used multiple inheritance. To ensure that the names will not conflict IDataObject's members are DAdvise DUnadvise and EnumDAdvise whereas those in IOleObject remain Advise Unadvise and EnumAdvise.