Structured Storage and Monikers are about integrating the storage of objects and names of objects, but clients also like to retrieve data from the objects, as well. OLE's Uniform Data Transfer mechanism is the technology for handling the exchange of "formatted data structures," that is, data with a known format. For example, the CF_TEXT format identifies a C-style string of characters. Besides data exchange, Uniform Data Transfer also handles the ability of the source of data, called the data object, to notify a client (or consumer) when data changes.
As we'll see in Chapter 10, data objects implement an interface named IDataObject, which includes functions to get data, set data, query and enumerate formats, and establish or terminate notifications. Notifications happen through an interface named IAdviseSink—a consumer interested in data changes will implement IAdviseSink and will pass a pointer to IDataObject to establish notifications.11 It is interesting to note that IAdviseSink is specifically designed to be an asynchronous interface—that is, its marshaling proxy fires off an RPC call to its connected stub and immediately returns to the data object without waiting for the stub to reply. This has a few interesting consequences, as we'll also see in Chapter 10.
The "uniform" in Uniform Data Transfer arises from the fact that IDataObject separates exchange operations (get, set, and so on) from specific transfer protocols such as the clipboard. Thus, a data source implements one data object and uses it in any OLE transfer protocol such as the OLE Clipboard and OLE Drag and Drop (and is even usable in OLE Documents). The OLE protocols (unlike the existing Windows protocols) are specifically concerned with getting an IDataObject pointer (with the pointer representing an impending transfer) from the source to the consumer. Then the protocol disappears, and the consumer deals uniformly only with IDataObject. So source and consumers can implement a core set of functions based on IDataObject and build little protocol handlers on top of that core.
OLE makes two other significant improvements to the existing Windows mechanisms for data exchange (clipboard, DDE, and so forth): you can now describe data with more than a clipboard format, and you can exchange it using mediums other than global memory. A structure called FORMATETC (literally, "format, etcetera") contains only a clipboard format, but it also has a specification about the detail (full content, thumbnail sketch, and so forth), the target device (screen, printers, and so forth), and the transfer medium. The actual reference to the data on whatever medium (for example, memory, disk file, IStorage, IStream) is passed in a STGMEDIUM structure, which is far more powerful than a simple global memory handle. Where you've traditionally been able to say only "I have a bitmap" that is always in global memory, OLE let's you say "I have, saved in a storage object, a thumbnail sketch of a bitmap rendered for a 300-dot-per-inch (dpi) black-and-white PostScript 52.3 printer." You can choose, as a source of data, the best possible medium in which to transfer data, and you can make it the preferred format, providing other mediums as backups (such as global memory, the lowest common denominator). So if you happen to generate 30-MB 24-bit bitmaps, you can keep those in disk files or storage objects, even during a data exchange. This can lead to tremendous performance gains for applications that were up to now forced to load large data sets into global memory, just to have them swapped out to the disk again (virtual memory paging)! This overhead is what OLE helps you avoid.
11 Note that IDataObject and IAdviseSink were an ad hoc solution designed long before the advent of IConnectionPointContainer and IConnectionPoint so the more generic connectable object mechanisms are not used here. |