wordsite.com

   
 


Frequently Asked Questions about Macros

Introduction to VBA Programming

Programming fundamentals

Returning information

Working with tables

Miscellaneous routines

New Routines 1999-2000

Microsoft is a registered trademark of Microsoft Corporation
 
 

   


Miscellaneous Routines

Click a topic:

Move shape anchors away from heading paragraphs.

Interrupt the Document_Close event (or AutoClose macro).

Highlight any misspelled words, so that unrecognized words stand out prominently on a printout.

Change all dates in a document from MMMM DD, YYYY to DD MMMM YYYY.

Force the user to save documents into a particular folder or a subfolder of that folder.

Force the File New dialog to display in List view.

Select the page that the cursor is on.

Change headers and footers in a document protected for forms.

Replace each instance of the text string "Document One" with the contents of a file called c:\test\Doc1.doc.

Prevent a file from showing up on the recently used files list.

Replace one character with another wherever it appears in a string.

Cycle a paragraph through all available paragraph styles, eventually returning to the style the paragraph started with.

Scroll all open documents the same percentage as the active document.

Remove the underline attribute from characters with descenders.

Size the text in a textbox to fill the textbox.

Create a numbered list using SEQuence fields.

Move shape anchors away from heading paragraphs. <Top of Page>

Notes:
When shape anchors are located in heading paragraphs, the table of contents is unable to display heading numbers. This routine works even on shapes whose anchors are locked. It preserves the location of a shape even if the shape is positioned relative to paragraph!

Solution:
Cut offending shapes out of the document and paste them back into the document with their anchors at a new location, immediately below the heading paragraph. Do this without affecting the location of the shape on the page.

This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub MoveAnchorsOutOfHeadings()
For Each oShape In ActiveDocument.Shapes
If Left$(oShape.Anchor.Style, 7) = "Heading" Then
oShape.Select
Selection.Cut
Selection.MoveDown unit:=wdParagraph, Count:=1
Selection.Paste
End If
Next oShape
End Sub

Interrupt the Document_Close event (or AutoClose macro). <Top of Page>

Notes:
The best thing to do is to prevent the close command from being given in the first place, or trap it before it triggers the Document_Close event (or AutoClose macro).

Solution:
Place the following code into the Document_Close event (or AutoClose macro):
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
ActiveDocument.Saved = False
SendKeys "{ESC}"

Explanation:
Word waits to check a document's saved bit until after the Document_Close event (and/or AutoClose macro) runs. If you mark the doc dirty in the Document_Close event (or AutoClose macro) and use sendkeys to queue up an Escape keystroke, Word will prompt the user to save unsaved changes (yes, no, cancel ) but the sendkeys statement will already have the esc keystroke queued up, causing the prompt message to be closed and all action to be canceled.

Highlight any misspelled words, so that unrecognized words stand out prominently on a printout. <Top of Page>

Solution:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
The following macro highlights any misspelled words:
Sub HighlightMisspelledWords()
Dim oWord As Range
Dim StoryRange As Range
For Each StoryRange In ActiveDocument.StoryRanges
Application.CheckSpelling Word:=StoryRange
For Each oWord In StoryRange.Words
If Not Application.CheckSpelling(Word:=oWord.Text) Then
oWord.HighlightColorIndex = wdYellow
End If
Next oWord
Next StoryRange
End Sub

Clear all highlighting from a document.

Solution:
The following macro clears highlighting from all words:
Sub ClearHighlightFromAllWords()
Dim StoryRange As Range
For Each StoryRange In ActiveDocument.StoryRanges
StoryRange.HighlightColorIndex = wdNoHighlight
Next StoryRange
End Sub

Change all dates in a document from MMMM DD, YYYY to DD MMMM YYYY. <Top of Page>

Solution:
Create a macro based on Word's wildcard search-and-replace capabilities. Target only those month names that are followed by a one or two-digit day and then a comma. In other words, change the format of a date like January 12, 1904 but do nothing to a date like January 1904.

Notes:
Use text similar to the following for find what and replace with:
Find What: "(January) ([0-9]{1,2}),"
Replace With "\2 \1"

The text above is specific, of course, to the month of January. Here's how Word interprets the Find What text and Replace With text:

Find What:
Find the word January followed by a space followed by one or two occurrences of a digit from 0-9, followed by a comma. January occurs within parentheses so that it can be reused in the Replace With text. Likewise, the expression that specifies one or two occurrences of a digit from 0-9 also occurs within parentheses so that it fcan be reused in the Replace With text. The space after January and the comma after the one-or-two-digit expression do NOT occur within parentheses, because we don't need to reuse them in the Replace With text.

Replace With:
In place of the found text, insert the one-or-two-digit expression followed by a space followed by the word January. (No space is needed after the word January, because a space already follows the found text.)

Code:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub ChangeDateFormatWithReplaceCommand()
Dim myMonth(1 To 12) As String
myMonth(1) = "January"
myMonth(2) = "February"
myMonth(3) = "March"
myMonth(4) = "April"
myMonth(5) = "May"
myMonth(6) = "June"
myMonth(7) = "July"
myMonth(8) = "August"
myMonth(9) = "September"
myMonth(10) = "October"
myMonth(11) = "November"
myMonth(12) = "December"
For i = 1 To 12
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "(" & myMonth(i) & ")" & " ([0-9]{1,2}),"
.Replacement.Text = "\2 \1"
.Forward = True
.Wrap = wdFindAsk
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = True
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Next i
End Sub

Force the user to save documents into a particular folder or a subfolder of that folder. <Top of Page>

Solution:
Use a FileSave macro that will run in place of Word's own built-in File Save routine. The macro allows the user to save directly to a target folder or to a subfolder within that folder, but NOT to a location outside the target folder.

Code:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub FileSave()
'save changes if doc has been saved previously
If ActiveDocument.Path <> "" Then
ActiveDocument.Save
Exit Sub
End If
'preset Word's document folder to desired target
ChangeFileOpenDirectory "C:\My Documents\Test"
'display the File Save As dialog
Set UserSaveDialog = Dialogs(wdDialogFileSaveAs)
UserSaveDialog.Display
'Quit if user has switched out of target folder
'but don't quit if user has made a subfolder within
'the target folder
If Left$(CurDir, 20) <> "C:\My Documents\Test" Then
MsgBox "Documents can't be saved in that folder. Please try again."
Exit Sub
End If
'save the document according to user preferences
UserSaveDialog.Execute
End Sub

Force the File New dialog to display in List view. <Top of Page>

Solution:
Create a FileNew macro that will run in place of Word's own File New routine.

Code:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub FileNew()
SendKeys "%2"
Dialogs(wdDialogFileNew).Show
End Sub

Change the SendKeys statement to "%1" for Large Icon view or to "%3" for Detail view.

Select the page that the cursor is on. <Top of Page>

Solution:
Selection.GoTo what:=wdGoToBookmark, Name:="\page"

Change headers and footers in a document protected for forms. <Top of Page>

Solution:
Wrap the code in an unprotect/reprotect sandwich like so:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
ActiveDocument.Unprotect
ActiveDocument.Sections(1).Headers(1).Range.Text = "Hello"
ActiveDocument.Protect wdAllowOnlyFormFields

Replace each instance of the text string "Document One" with the contents of a file called c:\test\Doc1.doc. <Top of Page>

Code:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub ReplaceTagWithFile()
Selection.HomeKey unit:=wdStory
Selection.Find.ClearFormatting
With Selection.Find
.Text = "Document One"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
While Selection.Find.Execute()
Selection.InsertFile _
FileName:="c:\test\Doc1.doc", Range:="", _
ConfirmConversions:=False, _
Link:=False, _
Attachment:=False
Wend
End Sub

Prevent a file from showing up on the recently used files list. <Top of Page>

Solution:
Turn off the list when the document opens and turn it back on again when the document closes.

Notes:
In order to do this, you need to create some document variables to store the user's original settings. Then you need to capture those settings and store them in the document variables before turning off the list. Finally, you need to use the document variables to turn the list back on with the user's original settings. A separate subroutine is used for each of these actions. Generally speaking, you will want to call these routines from the Document_Open and Document_Close events.

Code:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub CreateDocumentVariables()
ActiveDocument.Variables.Add Name:="DisplayRecentFiles", Value:="0"
ActiveDocument.Variables.Add Name:="RecentFilesMaximum", Value:="0"
End Sub

Sub RecordUserOptions()
''make a record of user settings so they can be restored after my
''last document is closed
ActiveDocument.Variables("DisplayRecentFiles") =
Application.DisplayRecentFiles
ActiveDocument.Variables("RecentFilesMaximum") =
Application.RecentFiles.Maximum
End Sub

Sub SetTemporaryOptions()
'Change user options to suit my requirements
'Application.DisplayRecentFiles = True
'Application.RecentFiles.Maximum = 4
End Sub

Sub RestoreUserOptions()
'restore user settings to what they were before my first doc was opened
Application.DisplayRecentFiles =
ActiveDocument.Variables("DisplayRecentFiles")
Application.RecentFiles.Maximum =
ActiveDocument.Variables("RecentFilesMaximum")
End Sub

Replace one character with another wherever it appears in a string. <Top of Page>

Solution:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
' the following code calls the "ReplaceACharacter" function
Sub TestTheFunction()
Dim myString As String
Dim OldCharacter As String
Dim NewCharacter As String
myString = "Hello, I love you. Let me jump in your game."
OldCharacter = "e"
NewCharacter = "u"
myString = ReplaceACharacter(InWhat:=myString, FindWhat:=OldCharacter,
ReplaceWith:=NewCharacter)
MsgBox myString
End Sub
'here's the function itself
Function ReplaceACharacter(InWhat As String, FindWhat As String, ReplaceWith
As String) As String
Dim StartAtCharacter As Integer
StartAtCharacter = 1
StartAtCharacter = InStr(StartAtCharacter, InWhat, FindWhat)
Do While StartAtCharacter <> 0
InWhat = Left$(InWhat, StartAtCharacter - 1) _
& ReplaceWith _
& Mid$(InWhat, StartAtCharacter + 1)
StartAtCharacter = InStr(StartAtCharacter, InWhat, FindWhat)
Loop
ReplaceACharacter = InWhat
End Function

Cycle a paragraph through all available paragraph styles, eventually returning to the style the paragraph started with. <Top of Page>

Notes:
The following macro includes a line that prevents execution when text is selected. (The cursor must be flashing for the macro to run.)

I played with this a bit because someone else thought it would be a nice feature. I assigned the macro to a button, then to a keystroke. I found the keystroke much easier to use. But Word has so many built-in styles that it can be tedious to keep cycling through the styles until the original style comes back around.

Code:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub CycleThroughStyles()
Dim NeedToRollOver As Boolean
Dim i, j, k As Integer
NeedToRollOver = True
'quit if cursor isn't flashing.
'This limits action to one paragraph
If Selection.Type <> wdSelectionIP Then GoTo EndGracefully
'find the current paragraph style, then
'find the next available paragraph style
For i = 1 To ActiveDocument.Styles.Count - 1
If Selection.Paragraphs(1).Style = ActiveDocument.Styles(i) Then
For j = i + 1 To ActiveDocument.Styles.Count - 1
If ActiveDocument.Styles(j).Type = wdStyleTypeParagraph Then
Selection.Paragraphs(1).Style = ActiveDocument.Styles(j)
NeedToRollOver = False
Exit For
End If
Next j
End If
If NeedToRollOver = False Then
Exit For
End If
Next i
'if we reached the last paragraph style, then
'roll over to first available paragraph style
If NeedToRollOver = False Then GoTo EndGracefully
For k = 1 To ActiveDocument.Styles.Count
If ActiveDocument.Styles(k).Type = wdStyleTypeParagraph Then
Selection.Paragraphs(1).Style = ActiveDocument.Styles(k)
Exit For
End If
Next k
'tell user what current style is.
'clear the undo buffer to prevent error message
'about document formatting being too complex.
EndGracefully:
Application.StatusBar = Selection.Paragraphs(1).Style
ActiveDocument.UndoClear
End Sub

Scroll all open documents the same percentage as the active document. <Top of Page>

Solution:
Scroll the active document to the desired point, then run a macro that scrolls all other open documents to the same percentage.

Notes:
The following code is written for Word 97. It looks at how far you've scrolled the active window, then scrolls all other document windows the same percentage. Of course, if one document is 10 pages long and another is 100 pages long, then a 50% vertical scroll would put you on page 5 in one document and page 50 in the other.

Code:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub ScrollAllWindowsALike()
Set myWindow = ActiveWindow
ScrollPercent = myWindow.VerticalPercentScrolled
For Each oWindow In Application.Windows
oWindow.Activate
oWindow.VerticalPercentScrolled = ScrollPercent
Next oWindow
myWindow.Activate
End Sub

Remove the underline attribute from characters with descenders. <Top of Page>

Solution:
Select the text that you want to fix, then run the following macro:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub FixUnderlinedText()
For Each oCharacter In Selection.Characters
If oCharacter Like "[qypjg]" Then oCharacter.Font.Underline = wdUnderlineNone
Next oCharacter
End Sub

Size the text in a textbox to fill the textbox. <Top of Page>

Solution:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub ResizeTextToFitTextBox()
If Selection.StoryType <> _
wdTextFrameStory Then Exit Sub
Dim myTextRange As Range
Dim myShape As Shape
Set myShape = Selection.ShapeRange(1)
Set myTextRange = myShape.TextFrame.TextRange
myTextRange.Font.Size = 2
If myShape.TextFrame.Overflowing = True Then
ActiveDocument.Undo
MsgBox "Even when set to a size of 2 points, the text overflows the textbox."
Exit Sub
End If
Do Until _
myShape.TextFrame.Overflowing = True
myTextRange.Font.Size = _
myTextRange.Font.Size + 0.5
Loop
myTextRange.Font.Size = _
myTextRange.Font.Size - 0.5
End Sub

Create a numbered list using SEQuence fields. <Top of Page>

Solution:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.

Notes:
The following code was developed by fellow MVP Doug Robbins. I commented the code and added a bit of code at the top of Doug's routine to make sure that at least one full paragraph of text has been selected ahead of time. The code is provided in the hope that it might help you explore how to work with fields in general and sequence fields in particular. Thank you to Doug Robbins for providing the code.

Code:
This code is provided for illustrative purposes only and is not warranted to be suitable for any particular business purpose. The code may be freely copied for any lawful business purpose.
Sub CreateNumberedList()
'Macro created 2 January, 1999 by Doug Robbins
'to apply/re-apply numbering to a range of paragraphs
'
'Quit if less than a full paragraph is selected
If Selection.Start > Selection.Paragraphs(1).Range.Start _
Or Selection.End < Selection.Paragraphs(1).Range.End Then
MsgBox "Select at least one full paragraph and try again."
Exit Sub
End If

'Count the paragraphs, then position
'cursor at start of first paragraph
Numparas = Selection.Paragraphs.Count
Selection.Collapse Direction:=wdCollapseStart

'toggle field codes on (presumably they were off)
ActiveWindow.View.ShowFieldCodes = _
Not ActiveWindow.View.ShowFieldCodes

'delete existing sequence field, if present
Selection.Extend
Selection.MoveRight Unit:=wdCharacter, Count:=1
If Mid(Selection.Text, 3, 3) = "SEQ" Then
Selection.MoveRight Unit:=wdCharacter, Count:=2
Selection.Delete
Else
Selection.Collapse Direction:=wdCollapseStart
End If

'insert new sequence field, set to start at 1
Selection.Fields.Add Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:="SEQ numberedlist\r 1", _
PreserveFormatting:=True

'Set paragraph indents as desired for list
With Selection.ParagraphFormat
.LeftIndent = CentimetersToPoints(1.27)
.FirstLineIndent = CentimetersToPoints(-1.27)
End With
Selection.TypeText Text:="." & vbTab
Counter = 1

'repeat above actions for remaining paragraphs
'in the selection
While Counter < Numparas
Selection.Move Unit:=wdParagraph, Count:=1
Selection.Extend
Selection.MoveRight Unit:=wdCharacter, Count:=1
If Mid(Selection.Text, 3, 3) = "SEQ" Then
Selection.MoveRight Unit:=wdCharacter, Count:=2
Selection.Delete
Else
Selection.Collapse Direction:=wdCollapseStart
End If
Selection.Fields.Add Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:= _
"SEQ numberedlist", PreserveFormatting:=True
With Selection.ParagraphFormat
.LeftIndent = CentimetersToPoints(1.27)
.FirstLineIndent = CentimetersToPoints(-1.27)
End With
Selection.TypeText Text:="." & vbTab
Counter = Counter + 1
Wend

'toggle field codes back off and refresh the screen
ActiveWindow.View.ShowFieldCodes = _
Not ActiveWindow.View.ShowFieldCodes
Application.ScreenRefresh
End Sub