Where Does It All Start?

Now that we've seen the interfaces involved and where they are implemented, we can follow an in-place session from start to finish to see how these interfaces are used. Let's say we have a container—Patron, for example—in which we have opened a compound document containing an embedded graphic from a server such as Cosmo. This is shown in Figure 22-4. We now want to change that graphic, so we double-click on the graphic to activate it, at which time the container calls IOleObject::DoVerb(OLEIVERB_PRIMARY) as it always has. With the basic form of activation we've seen in previous chapters, the object would open in a separate window, in which we can make changes.1

Figure 22-4.

An example of a container with a compound document in which an embedded object lives.

In-place activation thus begins with a container's innocent call to DoVerb. At this point, we do not know whether in-place activation will actually happen. That is for the object to decide.

When an in-place–capable object receives a call to DoVerb (for verbs other than OLEIVERB_OPEN, which expressly means "activate in a separate window"), the object first checks whether the container is also in-place capable. It does this by asking the IOleClientSite pointer passed as an argument to DoVerb whether it supports IOleInPlaceSite. If the site fails this query, it is simply not in-place capable, and the object proceeds to activate normally. This shows again the power of QueryInterface to perform feature negotiation. Through this simple query, an in-place–capable object determines, at run time, whether it can use in-place activation. Thus, an in-place–capable object remains entirely compatible with in-place–capable containers that are not, but it's integrated better with in-place–capable ones.

Why, however, does the object query the IOleClientSite pointer passed to IOleObject::DoVerb rather than the pointer from IOleObject::SetClientSite? The former IOleClientSite pointer allows the container to activate an object in place in a different site from the one that manages the object otherwise. The container might want to activate an object in place in a specific location in its user interface outside the compound document itself. This alternative site is called the active site, and its IOleClientSite pointer is the one that shows up in DoVerb as the pActiveSite argument.

For whatever site is being used, the object will know that the container is in-place capable when the container returns an IOleInPlaceSite pointer. With this pointer, the object must now check whether in-place activation is allowed on this particular object at this particular time by calling IOleInPlaceSite::CanInPlaceActivate. This call separates the container's general in-place support for all objects—expressed by its support for IOleInPlaceSite—from its ability to activate a specific object in place. A container will, for example, refuse to activate the embedded object in place if the object is being displayed as an icon or if the object is linked and not embedded. If CanInPlaceActivate returns S_FALSE, the object is activated in a separate window.

If the container says that in-place activation is allowed, however, the object can start the full activation process by first calling IOleInPlaceSite::OnInPlaceActivate, which tells the container to allocate any necessary structure for handling the in-place process. This process generally involves three steps: moving the object's editing window to the container, merging container and server menus into one shared set of menus, and creating editing tools (toolbars and so on) for the object in the container window. To accomplish these things, the object needs the container frame's IOleInPlaceFrame interface and the container document's IOleInPlaceUIWindow (if available). It retrieves these by calling IOleInPlaceSite::GetWindowContext. As interfaces on separate objects, they are not available through the site's QueryInterface!

1 The exceptions are video objects and the like, which can use the hWnd and RECT arguments passed to DoVerb to temporarily play inside the container window.