In Chapter 20, we saw that a container creates a linked content object using a moniker that it obtains either from the clipboard, from a drag-and-drop operation, from a filename, or through some other means not specified as part of OLE Documents itself. As far as the client is concerned, the linked object that wraps this moniker is almost the same as an embedded object, except that it also has the interfaces IOleLink and IExternalConnection. We also saw that activating a linked object basically means binding the moniker and asking for IOleObject in return.
This gives us the requirements for any local server that wants to support linking to its own objects:
The simplest linking scenario involves a single file moniker to describe the link. The version of Cosmo we'll create in this chapter supports this type of linking. A file moniker, if you remember, requires some implementation of IPersistFile, which must be implemented on the object named by that moniker. This file object must also implement IOleObject and IDataObject, as shown in Figure 21-1 on the following page. In Cosmo, the Figure object we implemented in Chapter 18 is already attached to the document and already supports most of these interfaces by virtue of its embedding support. Here we'll need to add IPersistFile and complete the implementation of IOleObject::SetMoniker and IOleObject::GetMoniker. In addition, we need to register the Figure object in the running object table, which is required for any link source.
Figure 21-1.
A linked object in a local server named with a file moniker must implement both IOleObject and IDataObject to support OLE Documents and IPersistFile to support moniker binding.
Some servers might want to support linking to a specific portion of a file—for example, a paragraph in a document, a range of cells in a spreadsheet, or a small part of a larger drawing. In these cases, the server provides a File!Item moniker to name what we call pseudo-objects in that larger data set. When a container wants to talk to a specific pseudo-object, it will bind that File!Item moniker. The server's implementation of IOleItemContainer::GetObject will then create a structure for the pseudo-object and provide the container with IOleObject and IDataObject interfaces for that structure. Pseudo-objects don't exist as individual entities before that time, and they are not persistent individually because they are saved with the larger file. In addition, the data that makes up multiple pseudo-objects might overlap. For example, the cell ranges R1C5:R10C8 and R3C2:R12C10 overlap, as shown in Figure 21-2. This same spreadsheet is the source of a vast number of potential pseudo-objects. Wildcard monikers exist so that a server like this need not register every pseudo-object as individually running.
A server that supports linking to items in this way must implement IPersistFile and IOleItemContainer on the document, or file object, named by the File portion of the composite moniker. Whatever object is returned from IOleItemContainer::GetObject is the pseudo-object. This defines a server structure, as shown in Figure 21-3.
Figure 21-2.
Pseudo-objects are named portions of a file to which a container can link with a File!Item moniker. In the source file, pseudo-objects can overlap.
Figure 21-3.
The structure of a server that supports linking to pseudo-objects.
The implementation of the pseudo-object structure is the same as that for a file object in a simple server such as Cosmo. The server itself must register a wildcard moniker for the file and for all items within it after it has opened the file. It must also be sure to implement IOleItemContainer::ParseDisplayName to support the Change Source feature of the container's Links dialog box.
We won't see a sample of a pseudo-object server in this chapter because we can go one step further, using Patron to demonstrate linking to embeddings and a File!Item!Item linking case.