Now that you know what a handler is, you're ready for a description of the four states that an embedded object can assume.
State | Description |
Passive | The object exists only in a storage. |
Loaded | The object handler is running and has a metafile in its cache, but the EXE component program is not running. |
Running | The EXE component program is loaded and running, but the window is not visible to the user. |
Active | The EXE component's window is visible to the user. |
Now for the container side of the conversation. Look at Figure 28-4. The container consists of a document and one or more sites. The IOleContainer interface has functions for iterating over the sites, but we won't worry about iterating over the client sites here. The important interface is IOleClientSite. Each site is an object that the component accesses through an IOleClientSite pointer. When the container creates an embedded object, it calls IOleObject::SetClientSite to establish one of the two connections from component to container. The site maintains an IOleObject pointer to its component object.
One important IOleClientSite function is SaveObject. When the component decides it's time to save itself to its storage, it doesn't do so directly; instead, it asks the site to do the job by calling IOleClientSite::SaveObject. "Why the indirection?" you ask. The handler needs to save the metafile to the storage, that's why. The SaveObject function calls IPersistStorage::Save at the handler level, so the handler can do its job before calling the component's Save function.
Another important IOleClientSite function is OnShowWindow. The component program calls this function when it starts running and when it stops running. The client is supposed to display a hatched pattern in the embedded object's rectangle when the component program is running or active.
Figure 28-4. The interaction between the container and the component.
The Advisory Connection
Figure 28-4 shows another interface attached to the siteIAdviseSink. This is the container's end of the second component connection. Why have another connection? The IOleClientSite connection goes directly from the component to the container, but the IAdviseSink connection is routed through the handler. After the site has created the embedded object, it calls IViewObject2::SetAdvise, passing its IAdviseSink pointer. Meanwhile, the handler has gone ahead and established two advisory connections to the component. When the embedded object is created, the handler calls IOleObject::Advise and then calls IDataObject::DAdvise to notify the advise sink of changes in the data object. When the component's data changes, it notifies the handler through the IDataObject advisory connection. When the user saves the component's data or closes the program, the component notifies the handler through the IOleObject advisory connection. Figure 28-5 shows these connections.
When the handler gets the notification that the component's data has changed (the component calls IAdviseSink::OnDataChange), it can notify the container by calling IAdviseSink::OnViewChange. The container responds by calling IViewObject2::Draw in the handler. If the component program is not running, the handler draws its metafile from the cache. If the component program is running, the handler calls the component's IDataObject::GetData function to get the latest metafile, which it draws. The OnClose and OnSave notifications are passed in a similar manner.
Figure 28-5. Advisory connection details.
A Metafile for the Clipboard
As you've just learned, the container doesn't deal with the metafile directly when it wants to draw the embedded object; instead, it calls IViewObject2::Draw. In one case, however, the container needs direct access to the metafile. When the container copies an embedded object to the clipboard, it must copy a metafile in addition to the embedded object and the object descriptor. That's what the handler's IDataObject interface is for. The container calls IDataObject::GetData, requesting a metafile format, and it copies that format into the clipboard's data object.