As we know from earlier chapters, all in-process modules, whether handlers or servers with objects or proxies, are structured identically. As far as OLE Documents are concerned, an in-process content object, be it supplied from the default handler, a custom handler, or a complete in-process server, exposes the interfaces IOleObject, IDataObject, IViewObject2, IPersistStorage, IOleCache2 (optionally IOleCacheControl), and IRunnableObject. This is the essence of the content object in the container's process. Any great ideas to the contrary are indeed hogwash.
So in exactly what way are the default handler, a custom handler, and an in-process server different? The difference lies in the completeness of the implementation of their respective objects. It's the same as the difference between the lowest-price economy car and the most expensive European luxury sports car—both have the same basic car structure: a body, a chassis, four wheels, a steering column, an engine and a transmission, and some seats inside. To make the most basic, lowest-priced car on the market, you have to be extraordinarily careful about what you put in the car so that no part is more expensive than necessary. In contrast, to make the most luxurious car, you spare no expense whatsoever. It is a fact that there is always a better car than the cheapest economy model and that there is no better or more complete car than the top-of-the-line luxury automobile.
If you choose to implement only a local server and use the default handler as is, there is nothing for you in this chapter. However, if you want some finer control over the implementation of certain in-process interfaces, or if you want to optimize specific member functions, then you might want to implement a custom handler. If you want to do more, you can go all the way to an in-process server for your object.
A custom handler is like the economy car: small, inexpensive (to load into memory, that is), and sporting minimal features. In other words, the handler implements only as much as it needs to get into the market, simply overriding specific member functions of specific interfaces and delegating all others to the default handler (which might ultimately end up in a local server). An in-process server is like a luxury car: there is no higher power to which to delegate requests on its interfaces; the in-process handler implements all of it.
I can tell by the look on your face that you are starting to feel the same way about these choices as you would if your only choice in automobiles were between a $4,500 car and a $45,000 car. Relax—you have more choices because any good dealer wants to sell you a car for a little more than what you think you can afford. Although the basic, most minimal handler is at one end of the spectrum and the complete in-process server is at the other, many options lie in between. Just as there are many models of cars to choose from between the two extremes, there are many choices for in-process object implementations. Every feature you add to the minimal handler brings you one step closer to luxury, and somewhere in the middle, the picture becomes very fuzzy as to whether your application is truly a handler or an in-process server, as shown in Figure 19-1. At any point between the two extremes, your product is still a car. (Below the low end, your product ceases to be useful as a car; above the high end, you are dabbling in unauthorized experimental sciences.)
There is one more aspect of all this that is comparable to luxury tax. At some point in car prices, luxury tax might kick in: suddenly you're paying an extra 10 percent. This is not a gradual change but a very sudden one. In the context of handlers and in-process servers, a handler is overqualified and must be called an in-process server when the handler no longer depends on a local server.
Figure 19-1.
Between the minimalist handler and the complete in-process server lie many possibilities for handler/servers, all of which still have the same structure.
That is the difference: a handler is designed to work in conjunction with a local server, whereas an in-process server operates exclusive of a local server. Handlers are designed to be smaller on disk—and therefore faster to load—and to provide only a few basic features. The handler can cut corners all it wants, delegating everything else to the default handler. The default handler then launches the local server as necessary. On the other hand, an in-process server is usually larger and implements the complete object, so it has no need for a local server.
Does that mean that implementing an in-process server is a prohibitive amount of work? Does that mean you have to implement all those interfaces yourself? Actually no, because just as a custom handler delegates much of its work to the default handler, an in-process handler can delegate a fair amount of work, especially work dealing with caching, to OLE's data cache service, which we saw in Chapter 11. Oh, yes, caching is still important because if the user opens a compound document on a machine without the in-process server, cached presentations must still be there for the purpose of the default handler. The in-process server must ensure, however, that it stuffs the cache itself because the cache cannot automatically reach out to a local server to obtain a rendering.
…three! Wait, don't tell me you just slept through all that!