Word Crimes

Microsoft Word has many, many, many failings, but there are usually ways to tame it. Most of them require code. And, as is usual with writing computer programs or scripts, one piece of the puzzle is usually rather picky about one thing or another. In this case, it’s spelling, but I’ll give it a pass for that, and there are some simple workarounds which I’ll leave to the user to figure out.

Today’s conundrum: how to create a sequence, then programmatically create hyperlinked references to that sequence. Let’s pretend you want a sequence that progresses like this (and we’ll keep it simple for now):

  • Foo 00001
  • Foo 00002
  • Foo 00003
  • (etc)

Problem number 1 is creating this in the first place. If you aren’t familiar with the Sequence field code, this will be a basic primer.

In your document, press Ctrl+F9. You’ll see a pair of curly braces and your cursor will be in the middle. Note: you cannot type these curly braces! That won’t work! You must insert them with the Ctrl+F9 hotkey! Next, type SEQ Bar \# “‘Foo ‘00000”

You’ll see something like this:

{ SEQ Bar \# “‘Foo ‘00000” }

If you press Shift+F9, hopefully you’ll see your first number! We’re calling this sequence “Bar”. This is important—more important than the number formatting.

To get the next number in the sequence, there are a few options. The simplest is to copy this text and paste it elsewhere. When you do so, it’ll still say “Foo 00001”; just press F9 to update it, and it’ll refresh to the appropriate number. A second option is to use the Ctrl+F9 hotkey and retype that whole thing again. If you just use

{ SEQ Bar }

You’ll end up with “5” or whatever the sequence number happens to be at that point in the document.

But! We’re not to a programming stage. This is all well and good, and may be sufficient for many applications, but what happens when you want to reference Foo 00532 at some arbitrary location in the document? The standard answer is, create a Bookmark reference for each and every one of these Foo number sequences, each called, say, “Foo 00001”. This gets tedious really fast. When you’re creating hundreds of these, it’s not at all practical.

What you would like to be able to do, step one, is be able to insert a cross reference to this as a numbered item.

If you insert a cross reference (References tab, Captions group, Cross-reference button; Insert, Reference, Cross-reference… for Word versions prior to 2007), though, you won’t find Foo or Bar anywhere! This is a problem!

If you don’t want to do any coding, you can use the “Insert Caption” button (References tab, Caption group; or Insert, Reference, Caption… prior to 2007). In the dialog that appears, Click “New Label…” and enter “Bar”. Then click close. You don’t need to do anything more here. Now go to insert a cross reference (see previous paragraph), and, voila, “Bar” is in the Reference Type drop-down! And all sequence numbers are in the list below!

But we want to make this easy on everyone, so now we must turn to the blessing and bane of every Word expert’s existence: VBA. Step 1: add the caption label. This turns out to be simple:

Application.CaptionLabels.Add "Bar"

And, also, nicely enough, if it already exists, it won’t nag you or call you nasty names. Though, if you want to do it right, you might use one of the following methods:

Function AddCaption(label As String) As String
    Dim labeltext as Variant, i as Long
    For labeltext in Application.CaptionLabels
        If labeltext = label Then
            AddCaption = label
            Exit Function
        End If
    Application.CaptionLabels.Add label
    AddCaption = label
End Function
Function AddCaption(label As String)
    Dim test As String
    On Error Resume Next
    test = Application.CaptionLabels(label)
    If Err.Number = 5941 Then
        Application.CaptionLabels.Add label
    End If
    On Error GoTo 0
End Function

I prefer the first because it doesn’t rely on VBA’s terrible methods of handling errors.

Anyway, next step! How does one programmatically insert the next item in a sequence into the document? Again, it turns out to be fairly simple:

Selection.Collapse wdCollapseStart
ActiveDocument.Fields.Add selection.Range, wdFieldSequence, "Bar \# ""'Foo '00000""", False

First, I “collapse” the selection to the beginning. This step is optional; if a bunch of text is selected before running this code, this forces the cursor to go to the beginning of that selection instead, so whatever text is selected doesn’t get overwritten. Second, note that in VBA, doubling up the quotation marks actually inserts them into the field. Third, we don’t have to enter “SEQ”, because wdFieldSequence  does that for us.


One last step, to make our macro suite complete. Cross references! But we don’t want to have to go through that whole rigamarole of References tab, Captions group, Cross-reference button every time, especially when the cross reference dialog contains hundreds of the things! Type it out! Type “Foo 00532”, highlight it, and run the following macro:

Sub ChangeSelectedTextToLink()
    Dim fld As Field
    Dim findref As String
    findref = Trim(Selection.text)
    For Each fld In ActiveDocument.Fields
    If LCase(Left(fld.Code, 8)) = " seq bar" Then
        If fld.Result.text = Selection Then
            Selection.InsertCrossReference "Bar", wdEntireCaption, Int(Val(Right(fld.Result.text, 4))), True, False
            Exit Sub
        End If
    End If
    MsgBox "Can't find a field numbered '" & findref & "'.", vbInformation
End Sub

Be sure to update the appropriate sections (lines 6 and 8, specifically) when you create your named sequence.

I’m sure that this whole thing can be made more generic, but that’s not something I’m up to doing right now, so I’ll leave that as an exercise to the reader.

Some resources to help you out:

Also (and as a separate note), for those interested in making a custom ribbon, you’ll want a reference that shows you what the imageMso values actually look like, and since Microsoft isn’t nice enough to provide one, I finally found someone who is, here.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.