The Container Site

However a container decides to provide storage elements, it will also need some sort of data structure or internal C++ object to manage that storage and all the other information about the content object itself. This structure or object is called a client site, or container site. For every content object in a compound document, the container creates a site to manage that content object. The site itself also exposes container-side functionality to the content object in question through two interfaces of its own: IOleClientSite and IAdviseSink, as illustrated in Figure 17-4.

Figure 17-4.

The structure of a container site. The container creates one site for each content object in the compound document.

The member functions of both of these interfaces are either notifications or requests. IAdviseSink is full of notifications, as we saw in Chapters 10 and 11. IOleClientSite has a few notifications, a few requests, and a few members that simply provide information about the container:


interface IOleClientSite : IUnknown
{
HRESULT SaveObject(void);
HRESULT GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker
, IMoniker **ppmk);
HRESULT GetContainer(IOleContainer **ppContainer);
HRESULT ShowObject(void);
HRESULT OnShowWindow(BOOL fShow);
HRESULT RequestNewObjectLayout(void);
};

SaveObject is a request that allows the object to ask the container to fully save all the object's information. Why can't the object save itself? Well, the object's storage includes not only the object's native data but also the entire cache, various other OLE-managed streams, and any private streams that the container might want to save. Much of this information, especially when the object is running in another process, is not available to the object at all. This request tells the container not only to save the object's native data through IPersistStorage::Save but also to update the cache and save container streams.

GetMoniker and GetContainer are specific requests for information about the container itself. GetMoniker asks the container for either the name of the compound document or the name of the object in the container. (We'll see more of this when we discuss linking.) GetContainer provides the object with an IOleContainer interface through which one can enumerate other objects in the container and lock the container in memory if necessary. This too applies mostly in linking, so we'll come back to it in later chapters.

ShowObject is a request that tells the container to make the object's presentation area visible in the compound document. For example, if the object image is currently scrolled out of view, ShowObject must scroll it back into view. A content object will call ShowObject in the course of activation before the object's own user interface becomes visible. When that UI does become visible, the object will send the notification OnShowWindow(TRUE). At this time, the container draws a hatch pattern across the image of the object in the compound document to indicate that the content is active, as shown in Figure 17-5 on the following page. (When in-place activation is used, the object does not appear in a separate window for editing, so a thin hatch border appears around the object in the document itself, as discussed in Chapter 22.)

Figure 17-5.

Activating a content object will bring the object's image into view in the container and will draw a hatch pattern across it to indicate its active status.

When the user closes or otherwise hides the object's user interface, the object calls OnShowWindow(FALSE), at which time the container removes the hatching.

The final member of IOleClientSite is RequestNewObjectLayout, which OLE Documents does not currently use. It is, however, used with OLE Controls, so we'll examine this member in Chapter 24.

As for IAdviseSink, we've already seen the use of its OnDataChange and OnViewChange members. A container will receive these notifications for a content object if it wants. OnDataChange is actually not all that interesting to a container because a container generally doesn't deal with the object's native data directly. This member is useful only when a container has more intimate knowledge about the object type and can understand the object's private formats. OnViewChange is of more interest. This function tells the container to redraw the object in the compound document. Doing so results in a call to the object's IViewObject2::Draw, causing the image of the object to be updated in the document. The primary use of this notification in OLE Documents is to synchronize the image of the object in the document with its image in whatever editing user interface the object displays when active. If we added another point to Cosmo's polyline data in Figure 17-5, Cosmo would send OnViewChange to Patron, which would then redraw the object to reflect the change. In this way, the user always sees the same data in both the document (with the hatching) and the object's own user interface.

The other members of IAdviseSink also notify the container of important events in the object's user interface. OnSave tells the container that the object has been completely saved and is always sent after the object calls IOleClientSite::SaveObject. OnClose tells the container that the user has closed the object's user interface, at which time the container can clean up whatever state it manages for an active object as opposed to a loaded object. Finally, OnRename tells the container that a linked object was saved to a different location, as we'll see in Chapter 20.