How to: Implement Undo Management
The primary interface used for undo management is IOleUndoManager, which is implemented by the environment. To support undo management, implement separate undo units (that is, IOleUndoUnit, which can contain multiple individual steps.
How you implement undo management varies depending on whether your editor supports multiple views or not. The procedures for each implementation are detailed in the following sections.
Cases where an editor supports a single view
In this scenario, the editor does not support multiple views. There is only one editor and one document, and they support undo. Use the following procedure to implement undo management.
To support undo management for a single-view editor
Call QueryInterface on the IServiceProvider interface on the window frame for IOleUndoManager, from the document view object to access the undo manager (IID_IOLEUndoManager).
When a view is sited into a window frame, it gets a site pointer, which it can use to call QueryInterface for IServiceProvider.
Cases where an editor supports multiple views
If you have document and view separation, then there is normally one undo manager associated with the document itself. All undo units are placed on one undo manager associated with the document data object.
Instead of the view querying for the undo manager, of which there is one for each view, the document data object calls CreateInstance to instantiate the undo manager, specifying a class identifier of CLSID_OLEUndoManager. The class identifier is defined in the OCUNDOID.h file.
When using CreateInstance to create your own undo manager instance, use the following procedure to hook your undo manager into the environment.
To hook your undo manager into the environment
Call QueryInterface on the object returned from ILocalRegistry2 for IID_IOleUndoManager. Store the pointer to IOleUndoManager.
Call QueryInterface on IOleUndoManager for IID_IOleCommandTarget. Store the pointer to IOleCommandTarget.
Relay your QueryStatus and Exec calls into the stored IOleCommandTarget interface for the following StandardCommandSet97 commands:
cmdidUndo
cmdidMultiLevelUndo
cmdidRedo
cmdidMultiLevelRedo
cmdidMultiLevelUndoList
cmdidMultiLevelRedoList
Call QueryInterface on IOleUndoManager for IID_IVsChangeTrackingUndoManager. Store the pointer to IVsChangeTrackingUndoManager.
Use the pointer to IVsChangeTrackingUndoManager to call the MarkCleanState, the AdviseTrackingClient, and the UnadviseTrackingClient methods.
Call QueryInterface on IOleUndoManager for IID_IVsLinkCapableUndoManager.
Call AdviseLinkedUndoClient with your document, which should also implement the IVsLinkedUndoClient interface. When your document is closed, call IVsLinkCapableUndoManager::UnadviseLinkedUndoClient.
When your document is closed, call QueryInterface on your undo manager for IID_IVsLifetimeControlledObject.
Call SeverReferencesToOwner.
When changes are made to the document, call Add on the manager with an OleUndoUnit class. The Add method keeps a reference to the object, so generally you release it right after the Add.
The OleUndoManager class represents a single undo stack instance. Thus, there is one undo manager object per data entity being tracked for undo or redo.
Note
While the undo manager object is used extensively by the text editor, it is a general component that has no specific support for the text editor. If you want to support multi-level undo or redo, you can use this object to do so.