The STGMEDIUM Structure

FORMATETC is merely half of the picture, of course, because it describes only the data format but says nothing about where the data actually is. This reference is provided by the STGMEDIUM (storage medium) structure, a generalization of the global-memory handle, which holds a mixture of different data references:


typedef struct tagSTGMEDIUM
{
DWORD tymed;
union
{
HBITMAP hBitmap;
HMETAFILEPICT hMetaFilePict;
HENHMETAFILE hEnhMetaFile;
HGLOBAL hGlobal;
LPOLESTR lpszFileName;
IStream *pstm;
IStorage *pstg;
} u;
IUnknown *pUnkForRelease;
} STGMEDIUM;

enum tagTYMED
{
TYMED_HGLOBAL = 1,
TYMED_FILE = 2,
TYMED_ISTREAM = 4,
TYMED_ISTORAGE = 8,
TYMED_GDI = 16,
TYMED_MFPICT = 32,
TYMED_ENHMF = 64,
TYMED_NULL = 0
} TYMED;

The STGMEDIUM fields store the following information:

Consumers of data (that is, of a storage medium) are usually responsible for freeing the data after they have finished with it. The richness of STGMEDIUM would typically make this process quite complex—you should have the image of a big ugly switch(stm.tymed) statement floating in your head. Don't bother—OLE itself provides a single cleanup function named ReleaseStgMedium, which does all the right things according to the contents of the structure:

tymed

Freeing Mechanism in ReleaseStgMedium

Any

pUnkForRelease->Release() if pUnkForRelease is non-NULL

TYMED_HGLOBAL

GlobalFree(hGlobal)

TYMED_FILE

DeleteFile(lpszFileName) followed by CoTaskMemFree(lpszFileName); the filename is assumed to be allocated with the task allocator

TYMED_ISTORAGE

pStg->Release()

TYMED_ISTREAM

pStm->Release()

TYMED_GDI

DeleteObject(hBitmap)

TYMED_MFPICT

LPMETAFILEPICT pMFP; pMFP=GlobalLock(hMetaFilePict);DeleteMetaFile(pMFP->hMF);GlobalUnlock(hMetaFilePict);GlobalFree(hMetaFilePict)

TYMED_ENHMF

DeleteEnhMetaFile(hEnhMetaFile)


The ReleaseStgMedium API is exactly the reason why the tymed fields of both STGMEDIUM and FORMATETC differentiate between handles for global memory, GDI objects, and metafile pictures. Only with such precise identification can ReleaseStgMedium know how to perform cleanup correctly.


The Practical Impact of FORMATETC and STGMEDIUM

The FORMATETC and STGMEDIUM structures open up a wide range of possibilities in data transfer and solve a number of the key problems with previous protocols and data transfer techniques. The most fundamental benefit of these richer descriptions is that data no longer has to live in global memory. If the data is better suited to a disk file, use TYMED_FILE; if a storage or stream element is preferable, use TYMED_ISTORAGE or TYMED_ISTREAM. For example, persistent moniker data—which is easily written to and read from a stream (using OleSaveToStream and OleLoadFromStream)—is ideally exchanged in TYMED_ISTREAM. In fact, we'll see a standard clipboard format for this named "LinkSource" (CFSTR_LINKSOURCE). In addition, you can easily exchange marshaling data for any interface pointer, where the source would write the stream with CoMarshalInterface, and the consumer would call CoUnmarshalInterface.

Very large data sets that do not fit in memory can be kept on disk even during a data transfer operation, either in a traditional file or in an element of a compound file. Data that exists in a database need not be extracted until called for because the act of transferring an IDataObject pointer doesn't transfer any data, only the means to get at the data. If the data itself is stored in a disk file or in a storage or stream element, the consumer has the advantage of incremental access. Overall, these two structures vastly improve data transfer; any particular data can remain on its most optimal medium until the consumer chooses to copy it elsewhere.