Resting Anchor

The Anchorage

Personal website of Gregory K. Maxey, Commander USN (Retired)

How To Modify A Recorded Macro
(A Microsoft Word Help & Tip page by Gregory K. Maxey)

DISCLAIMER/TERMS OF USE

The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.

Click to acces PayPal Verification Service Click to acces PayPal Verification Service

However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.

If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!

Click to donate British Pound Sterling                   Click to donate US dollars                   Click to donate EU euros

Site Note IconNote: Adapted from content originally published by Word MVP Jay Freedman.

Lots of articles advise you to use the macro recorder to get started with Word macros. An example is my own Create a Macro Using The Recorder. Although it's good advice, the macros you record often need tweaking—and sometimes they don't work at all.

What's wrong with the recorder, anyway?

The macro recorder's job is to translate your actions into programming code, using a language called Visual Basic for Applications (VBA). That's easy to do when you simply type some words into a document, or when you give a simple command such as Edit > Copy. It's harder for the recorder to make good code for more complicated commands such as File > Open or Edit > Replace. Sometimes the recorded code doesn't do exactly what you want it to do, and in a few situations the code is incorrect.

Cleaning out unneeded dialog arguments

You can record a macro while you make a change in the document by using a dialog, such as Format > Font or Format > Paragraph. You might think the macro recorder should capture only the settings that you changed, but it doesn't—instead, it throws into the macro every setting in the whole dialog! Look at what you might get if you just change the font size to 10 pt:

VBA Script:
Sub Macro1() 
  With Selection.Font 
    .Name = "Times New Roman" 
    .Size = 10 
    .Bold = False 
    .Italic = False 
    .Underline = wdUnderlineNone 
    .UnderlineColor = wdColorAutomatic 
    .StrikeThrough = False 
    .DoubleStrikeThrough = False 
    .Outline = False 
    .Emboss = False 
    .Shadow = False 
    .Hidden = False 
    .SmallCaps = False 
    .AllCaps = False 
    .Color = wdColorAutomatic 
    .Engrave = False 
    .Superscript = False 
    .Subscript = False 
    .Spacing = 0 
    .Scaling = 100 
    .Position = 0 
    .Kerning = 0 
    .Animation = wdAnimationNone 
  End With 
End Sub 

The lines that say "With Selection.Font" and "End With" mean that the lines between them set the properties of the font of the selected text. This is a shorthand way to refer to many properties of the same item, instead of writing "Selection.Font" at the beginning of each property's name.

In this macro the one property that you changed during recording is buried among the many that you didn't change, which take extra storage and extra execution time. That's bad enough. But suppose you replay the macro after you select text that's in a different font or a different color, thinking that it will just change the size to 10 pt. In fact, the macro will also change the text to Times New Roman and Automatic color, because the recorder captured every setting in the dialog.

That probably isn't what you intended the macro to do. Whenever you record the result of a dialog, you should inspect the code and delete all the extra settings. In this case, to apply only the size change.  Since there is only one desired property change, the With ... End With is redundant and all you need is this:

VBA Script:
Sub Macro1()
  Selection.Font.Size = 10
End Sub 

Site Note Icon If you aren't sure of the name of the property you need to keep, record a macro while you set a property to one value, and then record another macro while you set the same property to a different value. Compare the two macros—the property you want to keep is the one whose value changes, and the others can be deleted from the revised macro.

Making a macro more general

Suppose you record a macro that opens a document and then does something to it, such as changing the view. The beginning of the macro may look like this:

VBA Script:
 Sub Macro2() 
  Documents.Open FileName:= "Lorem.doc" , _ 
      ConfirmConversions:= False , _ 
      ReadOnly:= False , AddToRecentFiles:= False , _ 
      PasswordDocument:= "" , PasswordTemplate:= "" , _ 
      Revert:= False , WritePasswordDocument:= "" , _ 
      WritePasswordTemplate:= "" , _ 
      Format:=wdOpenFormatAuto, XMLTransform:= "" 
  'more code, for example ... 
  ActiveWindow.View = wdPrintView 
End Sub

The recorded macro for opening a document, like the recording of the Format>Font dialog, contains unneeded things. In this case, they are parameters that contain information about the file, such as a password.

The only parameter that's necessary is the FileName. You can remove the other parameters from the command, and Word will use its default values for them.

A more important problem is that every time you run the recorded macro, it will open the same document. This may be what you intend, but more likely you want the macro to let you choose which document to open.

One way to get the file's name into the macro is to display an input box, where you can type it in. The InputBox function shows a message box with a text entry field, and its result is the name that you type into the field.

VBA Script:
Sub Macro2A() 
Dim strFileName As String 
  strFileName = InputBox( "Enter file name to open:" , "Open a Document" ) 
  If strFileName <> "" Then 
    Documents.Open FileName:=strFileName 
    'more code, for example ... 
    ActiveWindow.View = wdPrintView 
  End If 
End Sub

But this isn't very friendly and there is a good chance of making a typing mistake.

A better approach is to use the File > Open dialog that's already built into Word.  This lets you browse to and select the proper document. When you click the OK button in the dialog, Word opens the selected document.

 The method is also simpler, because it doesn't need a separate Documents.Open statement as the dialog handles it all for you:

VBA Script:
Sub Macro2B() 
  If Dialogs(wdDialogFileOpen).Show = - 1 Then 
    'more code, for example ... 
    ActiveWindow.View = wdPrintView 
  End If 
End Sub

The word "Dialogs" in this code refers to a list of all of Word's built-in dialogs. Each dialog has a name that starts with "wdDialog."

 In this case, wdDialogFileOpen is the name of the built-in File>Open dialog, and the expression "Dialogs(wdDialogFileOpen)" selects that particular dialog from the list.

 To see list of available dialogs, press F2 in the VB editor to display the Object Browser, type wdDialog into the search box, and press Enter.

The word ".Show" refers to a method of the dialog. A method is an action that can be done—the .Show method causes the dialog to appear and execute (carry out its function).

 Many methods also have a value after they execute, which tells the macro something about what just happened (this is called "returning" the value). In this case, if you click the OK button in the dialog then the .Show method returns the value –1, but if you click the Cancel button or the X in the title bar then .Show returns the value 0.

 The VBA help topic for each method tells you what values that method can return and what they mean. You can use the returned value in an If statement, as in Macro2B, to decide what to do. Similar changes to recorded code let you make macros that save files to variable locations, search for variable strings, and many other unrecordable variations.

 You can find out more at Getting help with calling Word's built-in dialogs using VBA.

Making toggle macros

The Italic, Bold, and Underline buttons on the toolbar are toggles—click the button once to turn it on, and again to turn it off. If you want to make your own toggle for something else, you can record separate macros for turning it on and off, but how do you combine them into one?

As an example, let's make a macro to toggle the font's outline property on and off. If you record the change to turn it on, and remove the unnecessary properties, you get this:

VBA Script:
Sub Macro3() 
  Selection.Font.Outline = True 
End Sub

One way to make a toggle macro from this code is to use an If statement. You test the current value and then assign the opposite value to the property:

VBA Script:
Sub Macro3A() 
  With Selection.Font 
    If .Outline = False Then 
      .Outline = True 
    Else 
      .Outline = False 
    End If 
  End With 
End Sub

But a more efficient way is to use the Not operator. If the value is False, then applying Not to the value returns True, and vice versa. With this operator the macro can be written as:

VBA Script:
Sub Macro3B() 
  With Selection.Font 
    .Outline = Not .Outline 
  End With 
End Sub

Fixing broken Replace macros

One of the most common actions to record is a Replace operation. A macro can be a great time-saver, since setting up the same Replace over and over can be time-consuming and it's easy to make a mistake. In one circumstance, though, the recorder creates a macro that simply doesn't work.

Suppose you record the replacement of all italic text with the same text in bold italic. While you're recording this operation, it works perfectly well. If you replay the macro on another document, though, nothing happens! What's the matter?

A look at the recorded code reveals the problem:

VBA Script:
Sub Macro4() 
  Selection.Find.ClearFormatting 
  Selection.Find.Replacement.ClearFormatting 
  With Selection.Find 
    .Text = "" 
    .Replacement.Text = "" 
    .Forward = True 
    .Wrap = wdFindContinue 
    .Format = True 
    .MatchCase = False 
    .MatchWholeWord = False 
    .MatchWildcards = False 
    .MatchSoundsLike = False 
    .MatchAllWordForms = False 
  End With 
  Selection.Find.Execute Replace:=wdReplaceAll 
End Sub

There is no mention of italic or bold italic anywhere in this code. Except for the notation
".Format = True" (which tells Word to use formatting information about the .Text or .Replacement properties while searching or replacing), the recorder has completely missed the fact that you were replacing one format with another. To make this macro work as intended, you have to add these lines:

.Font.Italic = True
.Replacement.Font.Bold = True

The first of these lines tells Word to search for italic text. The second line tells it to make the replacement text bold—because it's already italic, it will become bold italic.

Besides making the macro correct, I like to make it consistent. The "With" and "End With" statements are meant to replace the references to Selection.Find; that both speeds up the macro and makes it easier to read. You can pull the ClearFormatting and Execute statements inside the With clause as well, to get this code:

VBA Script:
Sub Macro4A() 
  With Selection.Find 
    .ClearFormatting 
    .Replacement.ClearFormatting 
    .Text = "" 
    .Replacement.Text = "" 
    .Font.Italic = True 
    .Replacement.Font.Bold = True 
    .Forward = True 
    .Wrap = wdFindContinue 
    .Format = True 
    .MatchCase = False 
    .MatchWholeWord = False 
    .MatchWildcards = False 
    .MatchSoundsLike = False 
    .MatchAllWordForms = False 
    .Execute Replace:=wdReplaceAll 
  End With 
End Sub

Naming and storing macros

When you record a macro, Word suggests a name like Macro1. By default, it puts the macro in a module named NewMacros in the Normal.dot template. You should make it a habit to rename your macros to give them descriptive names, and macros that are useful enough to keep should be stored in a more organized manner.

To rename a macro, all you need to do is change the word that follows "Sub" in the first line. For example, you could change the first line of Macro4A to

Sub ItalicToBoldItalic()

That name will appear in the Tools>Macro>Macros dialog, and you can tell what it does without having to look at the code.

You can organize macros into modules, just as you organize files into folders. In the VBA editor, use the View menu to display the Project Explorer and the Properties pane. On the Insert menu, click Module and notice that a folder named Module1 appears in the Project Explorer. Click that folder, and change its name in the Properties pane.

To move a macro from one module to another, cut its code from the editing pane, double-click the destination module in the Project Explorer, and paste the code into the destination's editing pane. Unfortunately, the Project Explorer doesn't support drag-and-drop movement of macros.

You can move an entire module from one template to another by using the Organizer (Tools> Macro>Macros>Organizer). Macros that are useful for a  specific type of document should be stored in modules in the template used to create that type of document. Macros that useful and applicable to a range of documents or processes should be stored in a global template, as explained in: Templates Types - What They Define and Store

More fun to come

There are lots of other situations in which the macro recorder gives you code that's inefficient or doesn't do what you want or expect, and you should practice by improving it.

As you learn more about macros, sometimes you'll find it useful to record an action just to discover what statements in VBA are involved. Then you can throw away the recorded macro and write good code of your own.

There are times when you can't get the recorder to record anything useful because the commands you want to use are grayed out. Then you can usually find out more by looking at articles here, or asking questions in the VBA newsgroups.

That's it! I hope you have found this tips page useful and informative.

Share

DISCLAIMER/TERMS OF USE

The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.

Click to acces PayPal Verification Service Click to acces PayPal Verification Service

However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.

If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!

Click to donate British Pound Sterling                   Click to donate US dollars                   Click to donate EU euros

Search my site or the web using Google Search Engine

Google Search Logo