Where Do Linked Objects Come From?

The short answer to this question is that given a moniker, a container can create a linked object that manages that moniker. But where does the container get a moniker? In OLE Documents, this can happen in a number of ways:

In all these cases, a container must specifically support linking by enabling the necessary options. With both the clipboard and drag and drop, the moniker appears in a data object as the format CFSTR_LINKSOURCE (the string "Link Source"), which is a stream (TYMED_ISTREAM) containing a moniker serialized with OleSaveToStream followed by the source object's CLSID written with WriteClassStm. So when a container checks whether a data object has usable formats in any transfer operation, it should also look for this link-source format to know whether a paste link or a drop link is possible in addition to other transfer operations. The standard Paste Special dialog box handles this by enabling the Paste Link button when the necessary data is available. This button uses the OLE API function OleQueryCreateLinkFromData, which a container also uses to determine whether a link can happen through drag and drop.

When a container creates a linked object from the contents of a data object, as happens in the first two cases above, it calls the OLE API function OleCreateLinkFromData. This extracts the moniker from CFSTR_LINKSOURCE and builds a linked object (using the class defined by the trailing CLSID in the link-source data) around it. Of course, the server that supplies the moniker must have the necessary structure itself to support binding to that moniker—for example, implementations of IPersistFile and IOleItemContainer, as we'll see in Chapter 21. Almost all of the work for a linking server involves the moniker binding requirements.

The third way to create a linked object is through the Insert Object dialog box. In this case, a container must leave out the IOF_DISABLELINK flag when calling OleUIInsertObject. When the user selects Create From File in that dialog, he or she will now see a Link check box, as shown in Figure 20-2. When the dialog returns and the user has selected the Link check box, the container passes the filename to OleCreateLinkToFile, which creates a File moniker with that string and wraps a linked object around it.

Figure 20-2.

The Link check box as it appears in the Insert Object dialog box.

Besides using the three methods described here, a container might obtain a moniker through some other means. Whatever the case, it can create a linked object with that moniker by calling OleCreateLink directly, which is used internally within the other creation calls mentioned above.

The result of creating any linked object is an instance of a handler in the container's process that manages the moniker and any other linking information. The handler in question is almost always OLE's default link handler, which provides an object with exactly those interfaces shown in Figure 20-1 on page 949. However, a link-source application can specify the use of its own custom link handler by providing the CFSTR_CUSTOMLINKSOURCE format ("Custom Link Source") and an in-process object implementation that supports all the necessary interfaces. Use of a custom link handler is rare, so we will not see any more about it in this book. See the OLE Programmer's Reference for more detailed information.

Before we take a look at the linked object in more detail, note that the CFSTR_LINKSOURCE format usually travels with CFSTR_LINKSRCDESCRIPTOR ("Link Source Descriptor"), which is the same as CFSTR_OBJECTDESCRIPTOR, as we saw in the previous chapters. It is given a different format so that separate information can be supplied for embedded and linked objects in a data transfer operation.

In addition, the user interface guidelines for OLE recommend that a container implement a Show Objects command, which outlines embedded objects with a solid line and linked objects with a dashed line, giving the user an easy way to distinguish the two, as shown in Figure 20-3.

Figure 20-3.

The effect of the Show Objects command for linked and embedded objects.

Obviously, a container needs a way to determine which type of object it has in each site. Simply said, it queries for IOleLink, the presence of which unmistakably marks an object as linked.