The FORMATETC and STGMEDIUM Structures
Before you're ready for the IDataObject member functions, you need to examine two important COM structures that are used as parameter types: the FORMATETC structure and the STGMEDIUM structure.
FORMATETC
The FORMATETC structure is often used instead of a Clipboard format to represent data format information. However, unlike the Clipboard format, the FORMATETC structure includes information about a target device, the aspect or view of the data, and a storage medium indicator. Here are the members of the FORMATETC structure:
Type | Name | Description |
---|---|---|
CLIPFORMAT | cfFormat | A structure that contains Clipboard formats, such as standard interchange formats (for example, CF_TEXT, which is a text format, and CF_DIB, which is an image compression format), custom formats (such as rich text format), and OLE formats that are used to create linked or embedded objects. |
DVTARGETDEVICE* | ptd | A structure that contains information about the target device for the data, including the device driver name. (It can be NULL.) |
DWORD | dwAspect | A DVASPECT enumeration constant (such as DVASPECT_CONTENT, or DVASPECT _THUMBNAIL) |
LONG | lindex | Usually - 1. |
DWORD | tymed | Specifies the type of media used to transfer the object's data (such as TYMED_HGLOBAL, TYMED_FILE, or TYMED_ISTORAGE). |
An individual data object accommodates a collection of FORMATETC elements, and the IDataObject interface provides a way to enumerate them. A useful macro for filling in a FORMATETC structure is shown here:
#define SETFORMATETC(fe, cf, asp, td, med, li) ((fe).cfFormat=cf, (fe).dwAspect=asp, (fe).ptd=td, (fe).tymed=med, (fe).lindex=li)
STGMEDIUM
The other important structure for IDataObject members is the STGMEDIUM structure. This structure is a global memory handle used for operations involving data transfer. Here are the members:
Type | Name | Description |
---|---|---|
DWORD | tymed | A storage medium value used in marshaling and unmarshaling routines |
HBITMAP | hBitmap | Bitmap handle[*] |
HMETAFILEPICT | hMetaFilePict | Metafile handle[*] |
HENHMETAFILE | hEnhMetaFile | Enhanced metafile handle[*] |
HGLOBAL | hGlobal | Global memory handle[*] |
LPOLESTR | lpszFileName | Disk filename (double-byte)[*] |
ISTREAM[*] | pstm | IStream interface pointer[*] |
ISTORAGE[*] | pstg | IStorage interface pointer[*] |
IUNKNOWN | pUnkForRelease | Used by clients to call Release for formats with interface pointers[*] |
[*]This member is part of a union, including handles, strings, and interface pointers used by the receiving process to acciss the transferred data. |
As you can see, the STGMEDIUM structure specifies where data is stored. The tymed variable determines which union member is valid.
IDataObject Interface Member Functions
The IDataObject interface has nine member functions. Both Brockschmidt and the MFC Library Reference do a good job describing all of them. We'll look in detail at the functions that are important for this chapter.
HRESULT EnumFormatEtc(DWORD dwDirection,
IEnumFORMATETC ppEnum);
If you have an IDataObject pointer for a data object, you can use EnumFormatEtc to enumerate all the formats that it supports. This is an ugly API that the MFC library insulates you from. You'll learn how this happens when you examine the COleDataObject class.
HRESULT GetData(FORMATETC* pFEIn, STGMEDIUM* pSTM);
GetData is the most important function in the interface. Somewhere, up in the sky, is a data object, and you have an IDataObject pointer to it. You specify, in a FORMATETC variable, the exact format you want to use when you retrieve the data, and you prepare an empty STGMEDIUM variable to accept the results. If the data object has the format you want, GetData will fill in the STGMEDIUM structure. Otherwise, you'll get an error return value.
HRESULT QueryGetData(FORMATETC* pFE);
You call QueryGetData if you're not sure whether the data object can deliver data in the format specified in the FORMATETC structure. The return value says, "Yes, I can" (S_OK) or "No, I can't" (an error code). Calling this function is definitely more efficient than allocating a STGMEDIUM variable and calling GetData.
HRESULT SetData(FORMATETC* pFEIn,
STGMEDIUM* pSTM, BOOL fRelease);
Data objects rarely support SetData. Data objects are normally loaded with formats in their own server module; clients retrieve data by calling GetData. With SetData, you'd be transferring data in the other direction—like pumping water from your house back to the water company.
Other IDataObject Member Functions: Advisory Connections
The interface contains other important functions that let you implement an advisory connection. When the program using a data object needs to be notified whether the object's data changes, the program can pass an IAdviseSink pointer to the object by calling the IDataObject::DAdvise function. The object will then call various IAdviseSink member functions, which the client program will implement. You don't need advisory connections for drag-and-drop operations.