You can enhance or alter the functioning of OpenDoc in ways even more fundamental than implementing extension interfaces, dispatch modules, and focus modules. Because OpenDoc is modular and object-oriented, you can directly replace certain of its objects with your own versions.
OpenDoc allows you to patch any of its session-level objects. The session-level objects are those directly referenced by the session object, as shown in Figure 70. They are represented by these OpenDoc classes:
This section discusses the mechanics of writing a patch to a session-level object, although it does not discuss the capabilities of the individual objects or the reasons for patching them. Before patching any object, be sure you are very familiar with its purpose and its interface. See information elsewhere in this book for more information.
Because your OpenDoc patch replaces a specific object with a known public interface, you should write it as a subclass of the class of object you are patching. You must override every method, and your overrides (other than somInit, somUninit, and your initialization method) should not call their inherited versions. If you want only partial replacement of OpenDoc's functionality, delegate to the patched-out object (the one you have replaced) those methods that you do not wish to change.
Immediately after creating your replacement object, your patch installer (see "Installing a Patch") should call the object's initialization method (InitClassName). For example, if you are replacing the drag-and-drop object, you would call your replacement object's InitDragAndDrop method immediately after calling new to create it.
Your replacement object's initialization method should call the GetClassName method of the session object to get a reference to the current object and then store that reference in a field. For the drag-and-drop example, your InitDragAndDrop method would call the session object's GetDragAndDrop method, and store the returned reference in a field such as fOldDragAndDrop.
At the end of initialization, your InitClassName method should assign the replacement object as the current object. It should call the SetClassName method of the session object and passing itself (somSelf) as the new object reference. For example, if you were replacing the drag-and-drop object, you would make this call:
theSession->SetDragAndDrop(ev, somSelf); |
Your destructor method (somUninit) should delete the patched-out object (the one referenced in the fOldDragAndDrop field, for example) before calling inherited somUninit.
If the object you are replacing has additional entry points besides those based on the session object's reference to it, you will need to patch those also. For example, the drag-and-drop object registers callbacks with the Drag Manager; your replacement object would have to re-register those callbacks to point to itself.
Once you have written your patch, you need to install it so that OpenDoc uses it in place of the original object. Depending on what your patching needs are, you can place your patch installer in either of two places.
When called, your installer instantiates and initializes the patch object.
Every time it opens a document, the document shell installs, in order, all shell plug-ins, and then the root part opens its window. This installation sequence can lead to patching conflicts. Because you do not control the order in which shell plug-ins are installed, you cannot ensure that your patch will not itself be patched out by a subsequently installed patch.
You can minimize the potential for conflicts by writing your patch correctly. Properly written patch objects always delegate everything but their specific functionality to the object that was previously in place. Consistently following this convention ensures the proper chaining of patch functionality.
Ultimately, the root part controls which patches remain, because it has the final opportunity to install its own patches.