Share via


How to: Implement Undo Management

Note

This article applies to Visual Studio 2015. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here

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

  1. Call QueryInterface on the IServiceProvider interface on the window frame for IOleUndoManager, from the document view object to access the undo manager (IID_IOLEUndoManager).

  2. 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

  1. Call QueryInterface on the object returned from ILocalRegistry2 for IID_IOleUndoManager. Store the pointer to IOleUndoManager.

  2. Call QueryInterface on IOleUndoManager for IID_IOleCommandTarget. Store the pointer to IOleCommandTarget.

  3. Relay your QueryStatus and Exec calls into the stored IOleCommandTarget interface for the following StandardCommandSet97 commands:

    • cmdidUndo

    • cmdidMultiLevelUndo

    • cmdidRedo

    • cmdidMultiLevelRedo

    • cmdidMultiLevelUndoList

    • cmdidMultiLevelRedoList

  4. 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.

  5. Call QueryInterface on IOleUndoManager for IID_IVsLinkCapableUndoManager.

  6. Call AdviseLinkedUndoClient with your document, which should also implement the IVsLinkedUndoClient interface. When your document is closed, call IVsLinkCapableUndoManager::UnadviseLinkedUndoClient.

  7. When your document is closed, call QueryInterface on your undo manager for IID_IVsLifetimeControlledObject.

  8. Call SeverReferencesToOwner.

  9. 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.

See Also

IVsChangeTrackingUndoManager
IVsLifetimeControlledObject
How to: Clear the Undo Stack