Professional Documents
Culture Documents
com/
word_vba_examples.htm
Some useful macro examples - page 1
Frequently the Word forums throw up some interesting exercises in macro
programming. Some of the better examples that my fellow MVPs and I have
come up with appear elsewhere in the Word pages on this site. This page
offers a place to present some code examples that may have wider use, which
you can adapt to your own requirements. I will add to the examples as they
come up, but for the moment we will start with the InsertField dialog:
Sub InsertField()
SendKeys "{Tab 2} +{Tab 2}"
Dialogs(wdDialogInsertField).Show
lbl_Exit:
Exit Sub
End Sub
This worked fine, until fellow MVP Paul Edstein, who uses the pseudonym
Macropod in the forums, baited me to produce a version which gave the user
the opportunity to add a CHARFORMAT switch as an alternative to the
MERGEFORMAT switch.
Inserting a field from the Insert > Field menu option (Insert > Quick Parts >
Field in Word 2007/2010) opens the dialog with the check box unchecked,
using the same method as above, but if you check the box, you are presented
with a message box which offers the opportunity to choose the type of
formatting switch, then adds the appropriate switch to the field.
Check the box and you will see the further dialog
The result is that the field may be inserted with either switch as appropriate
e.g.
by selecting YES
{ CREATEDATE \@ "dddd, dd MMMM yyyy" \* MERGEFORMAT }
by selecting No
Sub InsertField()
Dim oRng As Range
Dim i As Variant
Dim iSwitch As Long
Dim strChoice As String
SendKeys "{Tab 2} +{Tab 2}"
Dialogs(wdDialogInsertField).Show
On Error GoTo lbl_Exit 'User has cancelled
Set oRng = Selection.Range
oRng.Start = oRng.Start - 1
With oRng.Fields(1)
If InStr(1, .Code, "MERGEFORMAT") <> 0 Then
iSwitch = MsgBox("Use charformat in place of the mergeformat
switch?", _
vbYesNo, _
"Insert Field")
If iSwitch = vbYes Then
.Code.Text = Replace(.Code.Text, _
"MERGEFORMAT", _
"CHARFORMAT")
End If
End If
.Update
End With
oRng.End = oRng.End + 1
oRng.Collapse 0
oRng.Select
lbl_Exit:
Exit Sub
End Sub
The following will work in other Windows versions also, but requires an extra
step to overcome the SendKeys issue.
Sub InsertField()
Dim oRng As Range
Dim i As Variant
Dim iSwitch As Long
Dim strChoice As String
Dialogs(wdDialogInsertField).Show
On Error GoTo lbl_Exit 'User has cancelled
Set oRng = Selection.Range
oRng.Start = oRng.Start - 1
With oRng.Fields(1)
If InStr(1, .Code, "MERGEFORMAT") <> 0 Then
iSwitch = MsgBox("Use charformat in place of the mergeformat
switch?", _
vbYesNo, _
"Insert Field")
If iSwitch = vbYes Then
.Code.Text = Replace(.Code.Text, _
"MERGEFORMAT", _
"CHARFORMAT")
ElseIf iSwitch = vbNo Then
iSwitch = MsgBox("Remove switch?", _
vbYesNo, _
"Insert Field")
If iSwitch = vbYes Then
.Code.Text = Replace(.Code.Text, _
" \* MERGEFORMAT ", _
"")
End If
End If
End If
.Update
End With
oRng.End = oRng.End + 1
oRng.Collapse 0
oRng.Select
lbl_Exit:
Exit Sub
End Sub
The Vista version of the macro has two message boxes. One of them is
identical to the previous version, the other is displayed when the user responds
to the first box with 'No'
Number documents
Option Explicit
Sub AddNoFromINIFileToBookmark()
Dim SettingsFile As String
Dim Order As String
Dim rRecNo As Range
Dim strCount As String
Dim i As Long
On Error GoTo err_Handler
strCount = InputBox("Print how many copies?", _
"Print Numbered Copies", 1)
If strCount = "" Then GoTo lbl_Exit
SettingsFile = Options.DefaultFilePath(wdStartupPath) & "\
Settings.ini"
Order = System.PrivateProfileString(SettingsFile, "DocNumber",
"Order")
If Order = "" Then
Order = 1
End If
For i = 1 To Val(strCount)
With ActiveDocument
Set rRecNo = .Bookmarks("RecNo").Range
FillBM "RecNo", Format(Order, "00000")
.Fields.Update
.ActiveWindow.View.ShowFieldCodes = False
.PrintOut
End With
Order = Order + 1
Next i
System.PrivateProfileString(SettingsFile, "DocNumber", "Order") =
Order
lbl_Exit:
Exit Sub
err_Handler:
If Err.Number = 5941 Then
MsgBox "The bookmark 'RecNo' is not in the current document."
End If
GoTo lbl_Exit
End Sub
Sub ResetStartNo()
Dim SettingsFile As String
Dim Order As String
Dim sQuery As String
SettingsFile = Options.DefaultFilePath(wdStartupPath) & "\
Settings.ini"
Order = System.PrivateProfileString(SettingsFile, "DocNumber",
"Order")
sQuery = InputBox("Reset start number?", "Reset", Order)
If sQuery = "" Then Exit Sub
Order = sQuery
System.PrivateProfileString(SettingsFile, "DocNumber", "Order") =
Order
lbl_Exit:
Exit Sub
End Sub
Option Explicit
Sub AutoNew()
Dim SettingsFile As String
Dim Order As String
Dim rRecNo As Range
On Error GoTo err_Handler
SettingsFile = Options.DefaultFilePath(wdStartupPath) & "\
Settings.ini"
Order = System.PrivateProfileString(SettingsFile, "DocNumber",
"Order")
If Order = "" Then
Order = 1
End If
Set rRecNo = ActiveDocument.Bookmarks("RecNo").Range
FillBM "RecNo", Format(Order, "00000")
Order = Order + 1
System.PrivateProfileString(SettingsFile, "DocNumber", "Order") =
Order
lbl_Exit:
Exit Sub
err_Handler:
If Err.Number = 5941 Then
MsgBox "The bookmark 'RecNo' is not in the current document."
End If
GoTo lbl_Exit
End Sub
The two previous macros use the following sub to fill the bookmark with the
value. This sub may be used to fill any named bookmark with a supplied
value.
If you paste text from the internet for example, the paste will bring across all
the formatting of the web page, whereas users frequently require the pasted
text to adopt the formatting of the document into which it is pasted. This can be
achieved with Paste Special > Unformatted text, but the macro recorder will not
accurately record that action so....
Sub PasteUnfText()
On Error GoTo err_Handler
Selection.PasteSpecial _
DataType:=wdPasteText, _
Placement:=wdInLine
lbl_Exit:
Exit Sub
err_Handler:
Beep
GoTo lbl_Exit
End Sub
Send the current document from Word by e-mail as an attachment, with
the message body and header details pre-completed, e.g. for the return
of a completed form document.
Option Explicit
Sub Send_As_Mail_Attachment()
' Send the document as an attachment
' in an Outlook Email message
Dim oOutlookApp As Object
Dim olInsp As Object
Dim wdDoc As Object
Dim oRng As Object
Dim oItem As Object
You receive the "Opening this will run the following SQL command" message
when you open a Word mail merge main document that is linked to a data
source - https://support.microsoft.com/en-us/help/825765
This linked page explains how to create registry entries to turn off the security
message. Some users have been concerned about the security implications of
turning off this warning message. The following code was conceived with that
issue in mind. The macro creates the registry entry if it is not present and then
toggles the setting between 0 and 1 each time the macro is run. It could
therefore be adapted for use in a mail merge macro to switch off the warning
while the particular merge was run, then switch it back on again on completion.
Option Explicit
Sub ToggleSQLSecurity()
Dim WSHShell As Object
Dim RegKey As String
Dim rKeyWord As String
Dim wVer As String
If Val(Application.Version) < 10 Then
'The security issue relates to
'Word versions from 10.0 (Word 2002)
MsgBox "This macro is for Word 2002 and later!", vbOKOnly, "Wrong
Word Version"
Exit Sub
End If
wVer = Val(Application.Version) & ".0"
Set WSHShell = CreateObject("WScript.Shell")
Start:
RegKey = "HKEY_CURRENT_USER\Software\Microsoft\Office\" & wVer &
"\Word\Options\"
On Error Resume Next
'The registry key does not exist
rKeyWord = WSHShell.RegRead(RegKey & "SQLSecurityCheck")
If rKeyWord = "" Then
WSHShell.regwrite RegKey & "SQLSecurityCheck", 1, "REG_DWORD"
'set it at zero
GoTo Start: 'and read it again
End If
If rKeyWord = 1 Then
WSHShell.regwrite RegKey & "SQLSecurityCheck", 0, "REG_DWORD"
MsgBox "SQL Security checking is switched off", vbInformation,
"SQL Check"
Else
WSHShell.regwrite RegKey & "SQLSecurityCheck", 1, "REG_DWORD"
MsgBox "SQL Security checking is switched on", vbInformation,
"SQL Check"
End If
lbl_Exit:
Exit Sub
End Sub
http://www.gmayor.com/word_vba_examples_2.htm
Word has the ability to set a block of text in title case, i.e. each of the words
formatted so that its first letter is capitalized, thus:
Word has no built-in function to perform this type of formatting, but it can be
achieved with a macro. The following sets the selected text in Word's title case
and then sets all the words in the first array:
If one of the listed words was the first word in the selected text, then it too
would be set in lower case, so that too needs to be corrected, and similarly if
there is a colon in the selected text, the word following the colon would need to
be corrected. The macro forces capitalization on the first letters of all words
that appear in either position.
Option Explicit
Sub TrueTitleCase()
'Graham Mayor - https://www.gmayor.com - Last updated - 18 Mar
2022
Dim rSel As Range, oRng As Range
Dim vFindText As Variant
Dim vReplText As Variant
Dim i As Long
Dim k As Long
Option Explicit
Sub ExtractAcronyms()
Dim rText As Range
Dim oSourceDoc As Document
Dim oTargetDoc As Document
Set oSourceDoc = ActiveDocument
Set oTargetDoc = Documents.Add
oSourceDoc.Activate
With Selection
.HomeKey wdStory
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Text = ""
Do While .Execute(findText:="[A-Z.]{2,}", _
MatchWildcards:=True, _
Wrap:=wdFindStop, Forward:=True) = True
Set rText = Selection.Range
oTargetDoc.Range.InsertAfter rText & vbCr
rText.Collapse wdCollapseEnd
Loop
End With
End With
With oTargetDoc
.Range.Sort ExcludeHeader:=False, _
FieldNumber:="Paragraphs", _
SortFieldType:=wdSortFieldAlphanumeric, _
SortOrder:=wdSortOrderAscending
.Paragraphs(1).Range.Delete
.Activate
End With
lbl_Exit:
Exit Sub
End Sub
Format part of a found text string
OR
You could create a macro to do so. The following shows two techniques for
selecting a digit from a found item.
Option Explicit
Sub Subscript2_in_H2O()
Dim rText As Range
With Selection
.HomeKey wdStory
With .Find
.ClearFormatting
.Replacement.ClearFormatting
Do While .Execute(findText:="H2O", _
MatchWildcards:=False, _
Wrap:=wdFindStop, _
Forward:=True) = True
Set rText = Selection.Range
'The found text
With rText 'Do what you want with the found text
'move the start position of the found text one character right
.MoveStart Unit:=wdCharacter, Count:=1
'move the end position of the found text one character to the
left
.MoveEnd Unit:=wdCharacter, Count:=-1
'the text string is now one character long i.e. the "2"
.Font.Subscript = True
'apply subscript to the remaining text string
End With
Loop 'and look for the next match
End With
End With
lbl_Exit:
Exit Sub
End Sub
or even simpler
Option Explicit
Sub Subscript2_in_H2ORev1()
With Selection
.HomeKey wdStory
With .Find
.ClearFormatting
.Replacement.ClearFormatting
Do While .Execute(findText:="H2O", _
MatchWildcards:=False, _
Wrap:=wdFindStop, _
Forward:=True) = True
'Do what you want with the found text (Selection.Range)
'In this case format the second character as subscripted
Selection.Range.Characters(2).Font.Subscript = True
Loop 'and look for the next match
End With
End With
lbl_Exit:
Exit Sub
End Sub
Extending the above procedure, you may wish to format a number of similar
items - eg chemical formulae.
The following version defines the list of items as variants. Note that the
subscripted numbers are located in different parts of the text string. The macro
loops through the list searching for each variant throughout the document in
turn. It then uses Case statements to process the range for each variant to
achieve the required results.
In the cases where there are two or digits to format, they are processed
separately. You could adapt this technique to format any character in the
search strings in any manner you require.
Option Explicit
Sub FormatChemicalFormulae()
Dim rText As Range
Dim vFindText(4) As Variant
'match the number in the brackets
'to the last number in the list below
Dim i As Long
vFindText(0) = "H2O"
vFindText(1) = "CO2"
vFindText(2) = "H2SO4"
vFindText(3) = "SO42-"
vFindText(4) = "[CO(NH3)6]3+"
'add more numbers as required
'increment the number 'n' in the brackets vFindText(n)
For i = 0 To UBound(vFindText)
With Selection
.HomeKey wdStory
With .Find
.ClearFormatting
.Replacement.ClearFormatting
Do While .Execute(findText:=vFindText(i), _
MatchWildcards:=False, _
Wrap:=wdFindStop, Forward:=True) = True
Set rText = Selection.Range 'The found text
With rText 'Do what you want with the found text
Select Case i
Case Is = 0
'H2O
.Characters(2).Font.Subscript = True
Case Is = 1
'CO2
.Characters(3).Font.Subscript = True
Case Is = 2
'H2SO4
.Characters(2).Font.Subscript = True
.Characters(5).Font.Subscript = True
Case Is = 3
'SO42
.Characters(3).Font.Subscript = True
.Characters(4).Font.Superscript = True
.Characters(5).Font.Superscript = True
Case Is = 4
'[CO(NH3)6]3+
.Characters(3).Case = wdLowerCase
.Characters(7).Font.Subscript = True
.Characters(9).Font.Subscript = True
.Characters(11).Font.Superscript = True
.Characters(12).Font.Superscript = True
End Select
End With
Loop 'and look for the next match
End With
End With
Next i
lbl_Exit:
Exit Sub
End Sub
The following macro when run on exit from the last formfield in the last row of
the table copies the last row of the table, complete with its fields and
associated macros, and pastes it at the end of the table. It then removes the
on exit macro from what was previously the last row, so that there can be no
false triggering of the macro if a user goes back to amend a field's content in
the last column of a previous row.
The code here can be applied to multiple tables in the same form.
Option Explicit
Sub AddRow()
'Run on exit from the last form field in
'the last row of the table
Dim oTable As Table
Dim oRng As Range
Dim oNewRow As Range
Dim oCell As Range
Dim oLastCell As Range
Dim sResult As String
Dim iRow As Long
Dim iCol As Long
Dim CurRow As Long
Dim i As Long, j As Long
Dim sPassword As String
sPassword = ""
'password to protect/unprotect form
With ActiveDocument
.Unprotect Password:=sPassword
'Unprotect document
Set oTable = Selection.Tables(1)
'Establish which table the cursor is in
For j = 1 To .Tables.Count
If oTable.Range.Start = .Tables(j).Range.Start Then
'Table is j
Exit For 'Stop checking
End If
Next j
'Select the appropriate table
iCol = oTable.Columns.Count 'Record the last column number
'Set a range to the last cell0
Set oLastCell = oTable.Cell(iRow, iCol).Range
'Record the last cell field value
Select Case oLastCell.FormFields(1).Type
Case 70 'wdFieldFormTextInput
sResult = oLastCell.FormFields(1).Result
Case 71 'wdFieldFormCheckBox
sResult = oLastCell.FormFields(1).CheckBox.Value
Case 83 'wdFieldFormDropDown
sResult = oLastCell.FormFields(1).DropDown.Value
End Select
'Get the value in the last cell
Set oRng = oTable.Rows.Last.Range
'Add the last row to a range
Set oNewRow = oTable.Rows.Last.Range 'Add the last row to another
range
oNewRow.Collapse wdCollapseEnd 'Collapse the second range to the
end of the table
oNewRow.FormattedText = oRng
'insert the content of the last row into the new range
'thereby adding a new row with the same content as the last row
CurRow = oTable.Rows.Count 'Determine the new last row of the
table
For i = 1 To iCol 'Repeat for each column
Set oCell = oTable.Cell(CurRow, i).Range 'process each cell in
the row
oCell.FormFields(1).Select 'Select the first field in the cell
With Dialogs(wdDialogFormFieldOptions) 'and name it
.Name = "Tab" & j & "Col" & i & "Row" & CurRow 'eg Tab1Col1Row2
.Execute 'apply the changes
End With
Next i
'Select the formfield in the last cell of the previous row
oLastCell.FormFields(1).Select
'Remove the macro
oLastCell.FormFields(1).ExitMacro = ""
'Restore the field value according to type
Select Case oLastCell.FormFields(1).Type
Case 70
oLastCell.FormFields(1).Result = sResult
Case 71
oLastCell.FormFields(1).CheckBox.Value = sResult
Case 83
oLastCell.FormFields(1).DropDown.Value = sResult
End Select
.Protect NoReset:=True, _
Password:=sPassword, _
Type:=wdAllowOnlyFormFields
'Reprotect the form
.FormFields("Tab" & j & "Col1Row" _
& CurRow).Select 'and select the next field to be completed
End With
lbl_Exit:
Set oTable = Nothing
Set oRng = Nothing
Set oNewRow = Nothing
Set oCell = Nothing
Set oLastCell = Nothing
Exit Sub
End Sub
http://www.gmayor.com/word_vba_examples_3.htm
Option Explicit
Private mstrFF As String
Sub ColTable1Row1()
Dim oFld As FormFields
Dim i As Long
Dim sCount As Long
Dim sRow As Long
Dim oCol As Long
Dim bProtected As Boolean
Dim sPassword As String
sPassword = ""
'Insert the password (if any), used to protect the form
between the quotes
With GetCurrentFF 'Establish which dropdown field is
current
mstrFF = GetCurrentFF.name
End With
Set oFld = ActiveDocument.FormFields
sCount = oFld(mstrFF).Result
'Get the dropdown field value
sRow = Right(mstrFF, 1)
'Get the number at the end of the bookmark name
'Check if the document is protected and if so unprotect it
If ActiveDocument.ProtectionType <> wdNoProtection Then
bProtected = True
ActiveDocument.Unprotect Password:=sPassword
End If
For i = 2 To 11
'Select each column of the active row in turn and colour
the cell white
ActiveDocument.Tables(1).Rows(sRow).Cells(i).Shading.Backg
roundPatternColor = wdColorWhite
Next i
If sCount = 0 Then GoTo lbl_Exit 'If user enters 0, the
row is already white so quit
Select Case sRow
Case 1 'Row 1 colour is red
oCol = wdColorRed
Case 2 'Row 2 colour is blue
oCol = wdColorBlue
Case 3 'Row 3 colour is gold
oCol = wdColorGold
Case 4 'Row 4 colour is green
oCol = wdColorGreen
Case Else
End Select
For i = 2 To sCount + 1
'Colour the cells in the row from column 2 to the number
entered
ActiveDocument.Tables(1).Rows(sRow).Cells(i).Shading.Backg
roundPatternColor = oCol
Next i
lbl_Exit: 'Re-protect the form and apply the password (if
any).
If bProtected = True Then
ActiveDocument.Protect _
Type:=wdAllowOnlyFormFields, _
NoReset:=True, Password:=sPassword
End If
Exit Sub
End Sub
Repeat a block of formatted text and form fields based upon the content
of another form field
Note that some of the text is underlined, some is emboldened and some both
underlined and emboldened. There are eight fields in the selection, each of
which will be provided with a new bookmark name. The bookmark names of
the fields in that marked section will be replaced by the macro, with the names
"MortTextn" where 'i' is a numeric digit from 1 to 8. Subsequent iterations will
be numbered from 8 - 16, 16 -24 etc.
The user may return to the Mortgages field and change the number and the
number of entries will be readjusted to take account of that changed number.
Sub Mortgages()
Dim sNum As Long
Dim oRng As Range
Dim bProtected As Boolean
Dim fCount As Long
Dim i As Long
Dim j As Long
'Unprotect the file
If ActiveDocument.ProtectionType <> wdNoProtection Then
bProtected = True
ActiveDocument.Unprotect Password:=""
End If
sNum = ActiveDocument.FormFields("Mortgages").Result
Selection.GoTo What:=wdGoToBookmark, Name:="bMortgage"
'Define the range object. This is where the cursor is at (start
point)
Set oRng = Selection.Range
For i = 1 To sNum
With Selection
'Insert two blank lines
.TypeParagraph
.TypeParagraph
'Set the underline option
.Font.Underline = wdUnderlineSingle
'Set the bold option
.Font.Bold = False
'Ensure that the paragraphs stay together on the same page
.ParagraphFormat.KeepWithNext = True
.TypeText "Plaintiff: "
.Font.Underline = wdUnderlineNone
'Add a form field
.FormFields.Add Range:=Selection.Range,
Type:=wdFieldFormTextInput
.TypeParagraph
.TypeParagraph
.Font.Underline = wdUnderlineSingle
.Font.Bold = True
.TypeText "Mortgage:"
'Turn off the underline
.Font.Underline = wdUnderlineNone
'Turn off the bold option
.Font.Bold = False
.TypeParagraph
.TypeParagraph
.TypeText "From: "
.FormFields.Add Range:=Selection.Range,
Type:=wdFieldFormTextInput
.TypeParagraph
.TypeParagraph
.TypeText "To: "
.FormFields.Add Range:=Selection.Range,
Type:=wdFieldFormTextInput
.TypeParagraph
.TypeParagraph
.Font.Bold = True
.TypeText "Dated: "
.Font.Bold = False
.FormFields.Add Range:=Selection.Range,
Type:=wdFieldFormTextInput
.TypeText Chr(32) 'Add a Space
.Font.Bold = True
.TypeText "Recorded: "
.Font.Bold = False
.FormFields.Add Range:=Selection.Range,
Type:=wdFieldFormTextInput
.TypeText Chr(32)
.Font.Bold = True
.TypeText "OR Book: "
.Font.Bold = False
.FormFields.Add Range:=Selection.Range,
Type:=wdFieldFormTextInput
.TypeText Chr(32)
.Font.Bold = True
.TypeText "Page: "
.Font.Bold = False
.FormFields.Add Range:=Selection.Range,
Type:=wdFieldFormTextInput
.TypeText Chr(32)
.Font.Bold = True
.TypeText "Original Amount: $"
.Font.Bold = False
.FormFields.Add Range:=Selection.Range,
Type:=wdFieldFormTextInput
'Turn off the Keep with next option
.ParagraphFormat.KeepWithNext = False
.TypeParagraph
.TypeParagraph
End With
Next i
'The selection has moved down the page. Redefine the end of the
range object.
oRng.End = Selection.Range.End
'Recreate the bookmark.
ActiveDocument.Bookmarks.Add "bMortgage", oRng
'Count the form fields added to the range
fCount = oRng.FormFields.Count
'Give each of the added fields a unique bookmark name
For j = 1 To fCount
With oRng.FormFields(j)
.Name = "MortText" & j 'Add a unique bookmark name
.Enabled = True 'Enable the field for user entry
.CalculateOnExit = False 'Uncheck the calculate on exit check box
End With
Next j
'Reprotect the document.
If bProtected = True Then
ActiveDocument.Protect _
Type:=wdAllowOnlyFormFields, NoReset:=True, _
Password:=""
End If
'Select the first of the fields in the range
ActiveDocument.FormFields("MortText1").Select
lbl_Exit:
Exit Sub
End Sub
Colour a form field check box with a contrasting colour when it is
checked.
In the following illustration the checked form field check box is coloured red.
This can be achieved by checking the value of the check box and formatting
the check box when the value is 'True'.
Option Explicit
A user in a Word forum asked how to total the number of times associated with
documented sound bites grouped in sections, similar to that shown in the
illustration below. The macro below will count all the times in the format
HH:MM:SS in the section where the cursor is located.
Option Explicit
Sub CountTimes()
'Totals times in the current section
'Times should be in the format HH:MM:SS
Dim sNum As Long
Dim oRng As Range
Dim sText As String
Dim sHr As Long
Dim sMin As Long
Dim sSec As Long
sHr = 0
sMin = 0
sSec = 0
sNum = Selection.Information(wdActiveEndSectionNumber)
Set oRng = ActiveDocument.Range
With oRng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "[0-9]{2}:[0-9]{2}:[0-9]{2}"
'Look for times in the format 00:00:00
.Wrap = wdFindStop
.MatchWildcards = True
Do While .Execute = True
sText = oRng.Text
'To count the whole document, omit the next line
If oRng.Information(wdActiveEndSectionNumber) = sNum Then
'Split the found time into three separate numbers
'representing hours minutes and seconds and add to
'the previously recorded hours, minutes and seconds
sHr = sHr + Left(sText, 2)
sMin = sMin + Mid(sText, 4, 2)
sSec = sSec + Right(sText, 2)
'To count the whole document, omit the next line
End If
Loop
End With
If sSec > 60 Then
'Divide by 60 and add to the minutes total
sMin = sMin + Int(sSec / 60)
sSec = sSec Mod 60 'The remainder is the seconds
End If
If sMin > 60 Then
'Divide by 60 and add to the hours total
sHr = sHr + Int(sMin / 60)
sMin = sMin Mod 60 'The remainder is the minutes
End If
MsgBox sHr & " hours" & vbCr & _
Format(sMin, "00") & " Minutes" & vbCr & _
Format(sSec, "00") & " Seconds"
lbl_Exit:
Exit Sub
End Sub
Transpose Characters
The macro works with either two selected characters or the characters either
side of the cursor. The macro also takes account of the case of the transposed
characters.
If the first character to be transposed is upper case and the second not, then
after transposition the first character will be upper case and the second lower
case. Where both or neither characters are upper case, the case of the
characters is retained.
Option Explicit
Sub Transpose()
Dim oRng As Range
Dim sText As String
Dim Msg1 As String
Dim Msg2 As String
Dim Msg3 As String
Dim MsgTitle As String
Msg1 = "You must place the cursor between " & _
"the 2 characters to be transposed!"
Msg2 = "There are no characters to transpose?"
Msg3 = "There is no document open!"
MsgTitle = "Transpose Characters"
On Error GoTo err_Handler
If ActiveDocument.Characters.Count > 2 Then
Set oRng = Selection.Range
Select Case Len(oRng)
Case Is = 0
If oRng.Start = oRng.Paragraphs(1).Range.Start Then
MsgBox Msg1, vbCritical, MsgTitle
Exit Sub
End If
If oRng.End = oRng.Paragraphs(1).Range.End - 1 Then
MsgBox Msg1, vbCritical, MsgTitle
Exit Sub
End If
With oRng
.Start = .Start - 1
.End = .End + 1
.Select
sText = .Text
End With
Case Is = 1
MsgBox Msg1, vbCritical, MsgTitle
Exit Sub
Case Is = 2
sText = Selection.Range.Text
Case Else
MsgBox Msg1, vbCritical, MsgTitle
Exit Sub
End Select
With Selection
If .Range.Characters(1).Case = 1 _
And .Range.Characters(2).Case = 0 Then
.Text = UCase(Mid(sText, 2, 1)) & _
LCase(Mid(sText, 1, 1))
Else
.Text = Mid(sText, 2, 1) & _
Mid(sText, 1, 1)
End If
.Collapse wdCollapseEnd
.Move wdCharacter, -1
End With
Else
MsgBox Msg2, vbCritical, MsgTitle
End If
lbl_Exit:
Exit Sub
err_Handler:
If Err.Number = 4248 Then
MsgBox Msg3, vbCritical, MsgTitle
End If
GoTo lbl_Exit
End Sub
When you request an autotext entry, looks into the active template first, then in
add in templates and finally in the normal template. This appears rather
complex to arrange with VBA.
While you can insert an autotext entry using VBA from the attached (active)
template or from the normal template, if it is present relatively simply, provided
you know its location and it is present. The problems arise when the location is
not known or may not be present.
The following macro first checks whether the document template is the normal
template. If it is not, then the document template is checked for the entry. If it is
or if the entry has not been found, the macro then checks all installed add-ins.
Finally, if the normal template was not checked in the first step, it is now
checked. If the entry is found in any of these locations the entry is inserted and
the macro quits. If not the user is given a message to that effect.
Word 2007 introduced building blocks which added a whole lot of other
parameters and a separate building blocks template where autotext entries
could be stored. Provided the autotext entry that you wish to insert is defined in
the autotext gallery (or it is included in a Word 97-2003 format template or add-
in, then the first macro will work as it stands.
If you want to check all the galleries, then you will need some extra code. In
addition to checking the active template, add-in templates and the normal
template, the second macro looks in the building blocks.dotx template.
It is to be hoped that if you are using VBA to insert entries, you might have a
better idea of where they are stored beforehand, but the macro below should
do the trick wherever they are.
Option Explicit
Sub InsertMyAutotext()
Dim oAT As AutoTextEntry
Dim oTemplate As Template
Dim oAddin As AddIn
Dim bFound As Boolean
Const strAutoTextName As String = "AutoText Name" 'Define the
required autotext entry
Sub InsertMyBuildingBlock()
Dim oTemplate As Template
Dim oAddin As AddIn
Dim bFound As Boolean
Dim i As Long
'Define the required building block entry
Const strBuildingBlockName As String = "Building Block Name"
http://www.gmayor.com/word_vba_examples_4.htm
Items from the first list are replaced with the corresponding item from the
second list
Option Explicit
Sub ReplaceQuotes()
Dim vFindText As Variant
Dim vReplText As Variant
Dim sFormat As Boolean
Dim sQuotes As String
Dim oRng As Range
Dim i As Long
sQuotes = MsgBox("Click 'Yes' to convert smart quotes to straight
quotes." & vbCr & _
"Click 'No' to convert straight quotes to smart quotes.", _
vbYesNo, "Convert quotes")
sFormat = Options.AutoFormatAsYouTypeReplaceQuotes
If sQuotes = vbYes Then
vFindText = Array(Chr(132), Chr(147), Chr(148), ChrW(171) &
ChrW(160), ChrW(160) & ChrW(187), Chr(145), Chr(146))
vReplText = Array(Chr(34), Chr(34), Chr(34), Chr(34), Chr(34),
Chr(39), Chr(39))
Options.AutoFormatAsYouTypeReplaceQuotes = False
For i = LBound(vFindText) To UBound(vFindText)
Set oRng = ActiveDocument.Range
With oRng.Find
Do While .Execute(vFindText(i))
oRng.Text = vReplText(i)
oRng.Collapse wdCollapseEnd
Loop
End With
Next i
Else
Options.AutoFormatReplaceQuotes = True
ActiveDocument.Range.AutoFormat
End If
Options.AutoFormatAsYouTypeReplaceQuotes = sFormat
lbl_Exit:
Exit Sub
End Sub
The table could also have more than two columns, but only the first two
columns are used.
Option Explicit
Sub ReplaceFromTableList()
Dim oChanges As Document, oDoc As Document
Dim oTable As Table
Dim oRng As Range
Dim oStory As Range
Dim rFindText As Range, rReplacement As Range
Dim i As Long
Dim sFname As String
Dim sAsk As String
sFname = "C:\Path\Changes.docx"
Set oDoc = ActiveDocument
Set oChanges = Documents.Open(Filename:=sFname, Visible:=False)
Set oTable = oChanges.Tables(1)
For i = 1 To oTable.Rows.Count
For Each oStory In oDoc.StoryRanges
Set oRng = oStory
Set rFindText = oTable.Cell(i, 1).Range
rFindText.End = rFindText.End - 1
Set rReplacement = oTable.Cell(i, 2).Range
rReplacement.End = rReplacement.End - 1
With oRng.Find
.ClearFormatting
.Replacement.ClearFormatting
Do While .Execute(findText:=rFindText, _
MatchWholeWord:=True, _
MatchWildcards:=False, _
Forward:=True, _
Wrap:=wdFindStop) = True
oRng.Select
sAsk = MsgBox("Replace - " & vbCr & oRng & vbCr + vbCr & _
"with - " & vbCr & rReplacement, vbYesNo, _
"Replace from Table")
The final example in this trilogy of replacements using lists was prompted by a
Word forum question. The user wanted initially to highlight words and phrases
in a document from a list, which was easily achieved using a variation of one of
the above macros, and the he ventured the possibility of the user choosing
from a number of possible replacements. How practical this is in a real life
situation I cannot say, but the principles involved I felt were interesting enough
to repeat them here.
In this instance the macro uses a multi-column table. The first column contains
the words to be located, the subsequent columns contain the replacement
choices. The columns should be filled from left to right. Not all the columns
(except the first) need contain any data, but the columns must be filled from left
to right with no gaps.
If only the second column has data, the found item is replaced with the content
of the second column If more columns to the right of the second column have
data, the choices from the second and subsequent columns are presented as
numbered choices in a list.
If none of the columns, except the first, contains data, then the found word is
merely highlighted.
Option Explicit
Sub ReplaceFromTableChoices()
Dim oChangesDoc As Document
Dim oDoc As Document
Dim oTable As Table
Dim oRng As Range
Dim oldPart As Range
Dim newPart As Range
Dim oFound As Range
Dim i As Long, j As Long, iCol As Long
Dim iAsk As Long
Dim sReplaceText As String, sNum As String
Const sFname As String = "C:\Path\Changes.docx"
The following macro sets a centre aligned tab, centred between the current
margins, and a right aligned tab at the right margin.
Option Explicit
Sub AddTabs()
Dim iLeft As Long
Dim iRight As Long
Dim iCentre As Long
Dim iWidth As Long
With Selection
iLeft = .Sections(1).PageSetup.LeftMargin
iRight = .Sections(1).PageSetup.RightMargin
iWidth = .Sections(1).PageSetup.PageWidth
iCentre = (iWidth - iLeft - iRight) / 2
.ParagraphFormat.TabStops.Add Position:=iCentre, _
Alignment:=wdAlignTabCenter, _
Leader:=wdTabLeaderSpaces
.ParagraphFormat.TabStops.Add Position:=iWidth - (iRight +
iLeft), _
Alignment:=wdAlignTabRight, _
Leader:=wdTabLeaderSpaces
End With
lbl_Exit:
Exit Sub
End Sub
The following macro will extract all the e-mail addresses from a document to a
new document. The macro works on the principle that autocorrect is capable of
converting e-mail addresses and web links to hyperlinks. The macro then
examines those hyperlinks and extracts any that contain e-mail addresses to a
new document. the original document is unaffected.
Sub ExtractEMailAddresses()
Dim oSource As Document, oTarget As Document
Dim strPath As String
Dim oHLink As Hyperlink
Dim oPara As Paragraph
'Ensure there is a document to process
If Documents.Count = 0 Then
MsgBox "Open the document
with the e-mail addresses first!", _
vbCritical, _
"Extract e-mail addresses"
Exit Sub
End If
Set oSource = ActiveDocument
oSource.Save
'Store the document name and path
strPath = oSource.FullName
'Create a new document to receive the e-mail addresses
Set oTarget = Documents.Add
'Autoformat the original document to set hyperlinks
With Options
.AutoFormatReplaceHyperlinks = True
oSource.Range.AutoFormat
End With
'Ascertain which hyperlinks are to e-mail addresses
For Each oHLink In oSource.Range.Hyperlinks
If InStr(1, oHLink.Address, "mailto:") > 0 Then
'and copy them to the target document, each to a new line
With oTarget.Range
.InsertAfter oHLink.Address
.InsertAfter vbCr
End With
End If
Next oHLink
'Remove the unwanted text from the hyperlink address
oTarget.Range = Replace(oTarget.Range, "mailto:", "")
'Sort the list alphabetically
oTarget.Range.SortAscending
'Remove any blank lines
For Each oPara In oTarget.Range.Paragraphs
If Len(oPara.Range) = 1 Then oPara.Range.Delete
Next oPara
'Format the paragraphs to remove unwanted space
oTarget.Range.ParagraphFormat.SpaceAfter = 0
oTarget.Range.ParagraphFormat.SpaceBefore = 0
'Close the original document without saving to preserve the
original format
oSource.Close wdDoNotSaveChanges
'Ask whether the user wants to re-open the source document
If MsgBox("Re-open the source document?", _
vbYesNo, _
"Extract e-mail addresses") = vbYes Then
Documents.Open FileName:=strPath
End If
lbl_Exit:
Exit Sub
End Sub
It has been observed that occasionally some open type fonts display
incorrectly in Word 2010, as in the following illustration, or the display becomes
completely scrambled with the words all stacked together. It has also been
observed that switching to an alternative printer will fix the issue. The following
macro does just that, using the One Note driver that comes with all versions of
Office 2010, then restores the original printer driver.
Sub FixDisplay()
Dim sPrinter As String
sPrinter = ActivePrinter
ActivePrinter = "Send To OneNote 2010"
ActivePrinter = sPrinter
lbl_Exit:
Exit Sub
End Sub
2010, the print preview was changed to part of the print dialog on the File Tab
of the ribbon. The familiar print preview from earlier versions can be added to
the QAT (Quick Access Toolbar) with Print Preview Edit Mode from the All
Commands group of the QAT editor. The following macro intercepts that
function and sets the zoom level from the default of full page to 100%. Change
the 100 to reflect any personally preferred zoom level.
Sub PrintPreviewEditMode()
ActiveDocument.PrintPreview
ActiveWindow.View.Zoom = 100
lbl_Exit:
Exit Sub
End Sub