Summary

The structures of an in-process object handler and an in-process server for embedded content objects are essentially identical. The only real difference is the relative completeness of the object implementation within the server. An object handler can implement almost nothing specific to an object, leaving most of the functionality to the default handler. (If there is nothing specific to do for the object, the default handler is sufficient.) An object handler thus depends on a local server to complete the implementation. At the point at which a handler no longer depends on a local server, it is a complete in-process server and contains the full object implementation itself. This dependency distinquishes a handler from a server.

The content object implemented in any sort of in-process module must expose IOleObject, IDataObject, IPersistStorage, IViewObject2, IOleCache2, IRunnableObject, and, for handlers, IOleCacheControl. Object handlers generally expose these interfaces through aggregation with the default handler, which is accomplished through the API function OleCreateDefaultHandler. The handler object implements an interface itself only when it has a reason to override one or more specific member functions in that interface, for example, for display optimization, speed, or document portability. On the other hand, a complete object implemented in an in-process server will provide most of these interfaces itself, relying on OLE's data cache for only a few of them (and for various display aspects). In this case, the object aggregates the data cache through the API function CreateDataCache. The behavior of the data cache's various interfaces was described in Chapter 11. This chapter covers all the interfaces exposed by the default handler.

This chapter also examines the implementation of an object handler for Cosmo, showing how to use the default handler as well as how to synchronize data between the object in the handler and the object in the local server when the server is running or active. Synchronization relies on the handler object exposing an IAdviseSink through which it receives data change notifications from the object in the local server. The handler object turns these data changes into IAdviseSink::OnViewChange notifications to the container. The container will then call the handler object's IViewObject2::OnDraw. In this chapter, we illustrate a full implementation of this interface.

We also examine the changes made to the Polyline component (last seen in Chapter 10) to make it an in-process server for content objects. This involves not only adding the necessary interfaces to the Polyline object, but also designing a user interface for the object's active state. In this case, Polyline uses a dialog box–style interface, making it look very much like part of the container itself, a perfect illustration of seamless integration between container and object, one of the goals of OLE Documents.