Working with the UndoRecord Object

As end users work in Word, the actions they take that can be undone are recorded in a queue—the "undo stack"—so that if the user decides to reverse the action, Word can recall the action taken and undo it. The undo stack is visible through the Word user interface on the ribbon through the Undo button, where each action is listed as a discrete record in the stack. Automation using the Word object model also writes these "undo records" to the undo stack, but working with undo stack using can be problematic.

Developers sometimes write code that performs one logical task using a series of actions, where each action is recorded as a separate entry on the undo stack. However, even though the end user can undo each action separately, sometimes it is logical to undo all the steps of the task as a unit and not individually.

For example, a developer might write code that performs the task of inserting document metadata into the footer of a Word document as shown in the following code example.

Sub AddDocMetadata() 
Dim rngFooter As Range 
 
    Set rngFooter = ActiveDocument.Sections(1) _ 
        .Footers(wdHeaderFooterPrimary).Range 
         
    With rngFooter 
        .Delete 
        .Fields.Add Range:=rngFooter, Type:=wdFieldFileName, Text:="\p" 
        .InsertAfter Text:=vbTab & vbTab 
        .Collapse Direction:=wdCollapseStart 
        .Fields.Add Range:=rngFooter, Type:=wdFieldAuthor 
    End With     
End Sub 

The resulting undo records appear on the undo stack for the actions performed by the code.

Undo button expanded with several entries.

If the end user then needs to rollback or undo the "insert metadata" task, each action associated with the task must be undone individually (by pressing CTRL+Z or clicking the dropdown arrow on the Undo button and then selecting the actions to undo). In this situation, the potential exists for the end user to only partially undo the series of actions associated with the single task, possibly leaving the document in an undesired state.

The Word object model offers a way to avoid this problem by providing developers the ability to link a series of individual actions into a custom undo record that can then be used to undo the actions as a single unit. A custom undo record is represented in the Word object model by the UndoRecord object.

Using the UndoRecord Object

The UndoRecord object is a property of the Application object in Word. You create a custom undo record using the StartCustomRecord and EndCustomRecord methods of the UndoRecord object. Consider the following code example which modifies the previous example to include a custom undo record.

Dim objUndo As UndoRecord 
 
Sub AddDocMetadata() 
Dim rngFooter As Range 
 
Set objUndo = Application.UndoRecord 
 
'Begin the custom undo record and provide a name for the record 
objUndo.StartCustomRecord ("Add Doc Metadata") 
     
 Set rngFooter = ActiveDocument.Sections(1) _ 
        .Footers(wdHeaderFooterPrimary).Range 
         
 With rngFooter 
        .Delete 
        .Fields.Add Range:=rngFooter, Type:=wdFieldFileName, Text:="\p" 
        .InsertAfter Text:=vbTab & vbTab 
        .Collapse Direction:=wdCollapseStart 
        .Fields.Add Range:=rngFooter, Type:=wdFieldAuthor 
 End With 
 
'End the custom undo record 
objUndo.EndCustomRecord 
     
End Sub 

The StartCustomRecord method begins recording the actions that are included in the custom undo record. You can give the custom undo record a name as an argument to the StartCustomRecord method, but this is optional. If you don't specify a name, Word uses the Visual Basic name of the first command executed as the name of the record. The name of the custom undo record is the string that appears in the user interface in the dropdown next to the Undo button.

The EndCustomRecord method stops recording the custom undo record. All the actions taken by the code between the StartCustomRecord call and the EndCustomRecord call are linked into one UndoRecord object. When you run code that creates a custom undo record, as in the previous code example, the custom undo record is listed in the undo stack as a single entry.

Undo button expanded with one entry.

UndoRecord Object Members

The following table lists other important members of the UndoRecord.

Name Member Type Description
CustomRecordLevel Property Returns a Long that specifies the number of custom undo action calls that are currently active. Read-only.
CustomRecordName Property Returns a String that specifies the entry that appears on the undo stack when all custom undo actions have completed. Read-only.
IsRecordingCustomRecord Property Returns a Boolean that specifies whether a custom undo action is being recorded. Read-only.

Best Practices

  • Close each custom undo record with a call to EndCustomRecord. Word will attempt to determine where to end the record, but it may not be at the desired point of code execution.

  • Call the Document object's Undo method in the right order when calling from within a custom undo record. Calling the Undo method in the wrong order within a custom undo record can have undesired effects on your code execution. The following code example shows the Undo method being called from inside a custom undo record.

Sub UndoInUndoRecord() 
   
  Set objUndo = Application.UndoRecord 
  
  objUndo.StartCustomRecord ("New Paragraph") 
  
  ActiveDocument.Content.InsertAfter Text:=" The end." 
  ActiveDocument.Undo 
  ActiveDocument.Content.InsertAfter Text:=" The end, again." 
  ActiveDocument.Content.InsertAfter Text:=" The last end." 
 
  objUndo.EndCustomRecord 
 
End Sub

When this code is run, each action in the custom undo record prior to the Undo method call is undone. Each action in the custom undo record after the Undo method call is placed the undo stack.

  • Avoid switching documents inside a custom undo record. The following code example switches from one document to another inside a custom undo record.
Dim objUndo As UndoRecord 

Sub SwitchDocsInsideUndo() 
  Set objUndo = Application.UndoRecord objUndo.StartCustomRecord ("New Paragraph") 
  
  'Insert some text into the first document Documents(1).Content.InsertAfter "A new paragraph in doc1." 
  
  'Switch documents to the second document 
  'The custom undo record will terminate here Documents(2).Content.InsertAfter "A new paragraph in doc2." 
  
  objUndo.EndCustomRecord 
End Sub

When this code is run, Word terminates the custom undo record when the code begins to write to the second document. When the procedure is finished, only the first document will have a custom undo record with the name "New Paragraph."

  • Avoid using Breaks when running code that contains custom undo records in Debug mode. When code that contains undo records is run in Debug mode in the Visual Basic editor and the code encounters a breakpoint, Word automatically ends all custom records that are currently in progress.

Support and feedback

Have questions or feedback about Office VBA or this documentation? Please see Office VBA support and feedback for guidance about the ways you can receive support and provide feedback.