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
 
 

   


Programming Fundamentals

Click a topic:

Create a macro with no previous experience.

Assign a macro to a hot-key.

Assign a macro to the TAB key.

Change the behavior of the TAB key inside a table cell.

Force a keybinding to be stored in a particular template, using vba code.

Run a macro when a user double-clicks a button in the document.

Enable a user to double-click a "Y" to change it to an "N" and then to a "?" and then back to a "Y".

Add a menu to the menu bar and populate it with commands.

Add a toolbar button to launch an executable file.

Force a command bar to display all of its commands, even if this forces the command bar to wrap to a second or third line.

Protect command bars against changes.

Remove protection from command bars so they can be changed.

Create a module-level variable that can be used by any procedure (sub or function) within a module.

Prevent a user from interrupting a macro with Ctrl+Break.

Intercept the Close button (X) in the title bar of a user form.

Force the cursor back to its normal state at the end of a macro.

Save a preview image for a template, so the user can see the preview in the File New dialog box.

List in a text file all the code from a code module.

Making the transition from WordBasic to VBA.

Create a macro with no previous experience. <Top of Page>

Solution:
Word's macro recorder can help you acquaint yourself with macros and with Office 97's vba programming language.

Let's assume that you create several documents from scratch on a daily basis. After
composing the text, you press Ctrl+Home to position the cursor at the start
of the document. Then you click the Center tool on the Formatting toolbar to
center the first paragraph of your document. Eventually, it occurs to you
that you should be able to record a macro for these last actions. That is, a
macro that will automatically position the cursor at the start of the
document and center the first paragraph.

Technically, this scenario may call for a solution involving paragraph
styles. But for now let's create a macro solution and let's use the macro
recorder to create it.

Proceed as follows:
1. Choose Macro|Record New Macro on the Tools menu (or simply double-click
the REC button in the Status bar.)
2. Enter a macro name (sorry, no spaces or punctuation allowed).
3. Click the Assign Macro To Keyboard button.
4. Press Ctrl+F8, then click Assign and click Close.
Word will display the Stop Recording toolbar, which lets you know that Word
is recording your actions and will continue recording them until you click
the Stop Recording button on this toolbar. (Don't click it yet!)
5. Press Ctrl+Home to position your cursor at the start of your document.
6. Click the Center tool on the Formatting toolbar.
7. Click the Stop Recording tool on the Stop Recording toolbar.
8. Open some other document.
9. Position the cursor in the middle of the document (doesn't matter where).
10. Press Ctrl+F8.
11. Smile with satisfaction as Word moves the cursor to the start of the
document and centers the first paragraph.

So far, so good. Now to see what the macro looks like under the hood:
1. Choose Macro|Macros on the Tools menu.
2. Select the macro that you just created.
3. CLick Edit.

Word will open up the vba editor and display something like the following
macro:
Sub MyFirstRecordedMacro()
'
' MyFirstRecordedMacro Macro
' Macro recorded 10/31/98 by Elgin
'
Selection.HomeKey Unit:=wdStory
Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter
End Sub

4. To learn more about the code, position the cursor somewhere in
Selection.HomeKey and press F1 to view a related help topic.
5. Close the help window and repeat Step 4 with the cursor in other
locations.
6. On the vba editor File menu, choose Close and Return to Microsoft Word.

If you have the patience to try these steps, you'll be well on your way. The
rest is just details. There are lots of them but you can always search the
vba help system and return to the newsgroups for additional information.

Assign a macro to a hot-key. <Top of Page>

Solution:
1. Choose Customize on the Tools menu, then click Keyboard...
2. In the Categories list, choose Macros.
3. In the Macros list, choose a macro.
4. Enter a key combination in the space provided.
5. Before clicking Assign, select the template where you want the assignment
to be stored.
6. Click Assign.
7. Click Close.

Assign a macro to the TAB key. <Top of Page>

Solution:
Since the TAB key isn't accepted as a legitimate choice in the Customize dialog, use a macro to make the assignment.

Notes:
The following macro assigns the tab key to a macro called MacroNameGoesHere. Simply replace
"MacroNameGoesHere" with the name of the macro that you want to run and you'll be all set, except for the limitations noted afterward.

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 AssignTabKey()
KeyBindings.Add KeyCode:=BuildKeyCode(wdKeyTab), KeyCategory:= _
wdKeyCategoryMacro, Command:="MacroNameGoesHere"
End Sub

Limitation #1:
When the cursor is situated in a table cell, the tab key isn't interpreted
as a tab key. Instead, it is interpreted as a NextCell command. If you want
to control the action of the tab key in this situation, you must create a
subroutine called NextCell. For example:
Sub NextCell()
'Code listed here will control tab key inside a table cell
End Sub

Limitation #2:
When the cursor is situated in a form field in a protected section of a
protected document, the tab key isn't interpreted as a tab key. Instead, it
executes a built-in routine that lies beyond vba's reach.

Change the behavior of the TAB key inside a table cell. <Top of Page>

Note:
When the cursor is inside an unprotected table and you press the Tab key, Word runs a built-in routine called NextCell. If you create a custom version of this routine, Word will run your version instead of the built-in version. If the table is in a section of a document protected for forms, Word runs a built-in routine that lies beyond the reach of Visual Basic for Applications.

Solution:
Use a macro to move the cursor downward through each column when the tab key is pressed. Design the macro so that, when the cursor reaches the bottom of a column, it moves to the top of the next column.

Caveat:
The following routine has been tested only on tables where all rows have the same number of columns and all columns have the same number of rows.

1. Click Macro on the Tools menu, then click Macros... on the submenu.
2. Under Macro Name, enter NextCell, then click Create.
Word will show the following code, which represents the built-in NextCell routine:
Sub NextCell()
'
' NextCell Macro
' Moves to the next table cell
'
Selection.MoveRight Unit:=wdCell

End Sub

3. Replace the built-in code with the following 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 NextCell()
While Selection.Information(wdStartOfRangeColumnNumber) > _
Selection.Information(wdMaximumNumberOfColumns)
Selection.MoveLeft
NeedToSelect = 1
Wend
If NeedToSelect = 1 Then
Selection.Cells(1).Select
Selection.MoveEnd unit:=wdCharacter, Count:=-1
Exit Sub
End If
CurrentRow = Selection.Information(wdStartOfRangeRowNumber)
CurrentColumn = Selection.Information(wdStartOfRangeColumnNumber)
If CurrentRow < Selection.Information(wdMaximumNumberOfRows) Then
Selection.Tables(1).Cell(CurrentRow + 1, CurrentColumn).Select
Selection.MoveEnd unit:=wdCharacter, Count:=-1
ElseIf CurrentColumn < Selection.Information(wdMaximumNumberOfColumns) Then
Selection.Tables(1).Cell(1, CurrentColumn + 1).Select
Selection.MoveEnd unit:=wdCharacter, Count:=-1
Else
Selection.Tables(1).Cell(1, 1).Select
Selection.MoveEnd unit:=wdCharacter, Count:=-1
End If
End Sub
4. Select Save Normal on the File menu.
5. Select Close and Return to MS Word on the File menu.
6. Position the cursor in a table and press the TAB key.
7. If not satisfied with the results, modify the code in the NextCell macro.
8. To return the TAB key to its normal functionality, delete or rename the NextCell macro.

Force a keybinding to be stored in a particular template, using vba code. <Top of Page>

Solution for normal.dot:
CustomizationContext = NormalTemplate
KeyBindings.Add KeyCode:=BuildKeyCode(wdKeyControl, wdKeyAlt, wdKeyW), _
KeyCategory:=wdKeyCategoryCommand, Command:="FileClose"

Solution for other templates:
'run this code while viewing a document attached to the template
'where you want the keybinding to be stored
CustomizationContext = ActiveDocument.AttachedTemplate
KeyBindings.Add KeyCode:=BuildKeyCode(wdKeyControl, wdKeyAlt, wdKeyW), _
KeyCategory:=wdKeyCategoryCommand, Command:="FileClose"

Run a macro when a user double-clicks a button in the document. <Top of Page>

Solution: Insert a macrobutton field into the document and format it to look like a button.


1. Press Control+F9 to insert a set of Field Code Braces. { } DO NOT SIMPLY TYPE THE BRACES. YOU MUST USE Control + F9.
2. Type the following between the braces:
MACROBUTTON MyMacroName Double-Click To Run Macro
NOTE: Use the name of an actual macro, instead of MyMacroName
You should end up with something like this:
{ MACROBUTTON MyMacroName Double-Click To Run Macro }
3. Right-click the area between the braces and select Toggle Field Codes.
4. Format the macro button to look like a button, using Format Font, Format
Paragraph, and Format Borders and Shading.

Enable a user to double-click a "Y" to change it to an "N" and then to a "?" and then back to a "Y". <Top of Page>

Solution:
Use a macrobutton field.

Notes:
A macrobutton field is a placeholder that displays a value (such as "Y", "N", or "?") and runs a macro when you double-click it. The macro can do anything you want it to do, including change the displayed value.

1. Before creating the macrobutton, create the macro that you want to run when the field is double-clicked. The following macro will exactly fit the needs described above:
Sub SymbolCarousel()
Select Case Selection.Fields(1).Code.Characters(29)
Case "Y"
Selection.Fields(1).Code.Characters(29) = "N"
Case "N"
Selection.Fields(1).Code.Characters(29) = "?"
Case "?"
Selection.Fields(1).Code.Characters(29) = "Y"
Case Else
End Select
End Sub

2. After creating the SymbolCarousel macro, create the macro button by positioning
the cursor where you want the N/Y/? value displayed. Then press Ctrl+F9 to
insert a set of field braces { }. (Don't just type the braces. You must insert
them using Ctlr+F9.)

3. Within the braces, type very carefullly the exact character string shown
between braces below (but don't type the braces). Be sure to leave a space before the word
MACROBUTTON, before SymbolCarousel, and before N. Do NOT put a space after
the N.
{ MACROBUTTON SymbolCarousel N}

4. Right-click the field expression and choose Toggle Field codes.
5. Double-click and see if the N changes to a ?. Double-click again and see if it changes to a Y. Again and it should change back to N.

Add a menu to the menu bar and populate it with commands. <Top of Page>

Solution:
Add a menu called "MyMenu" to the menu bar, then add several commands to the menu. In this case, all of the commands do the same thing: they run a macro called TestMacro.

**Before running this code, take a minute to make a macro called TestMacro. Otherwise, the commands on the new menu will generate an error when Word realizes that the commands are trying to run a non-existent macro.**

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.
'specify where new menu will be stored
CustomizationContext = ActiveDocument.AttachedTemplate
'add a menu to the Menu Bar
With CommandBars("Menu Bar").Controls
.Add(Type:=msoControlPopup, Before:=3).Caption = "&MyMenu"
End With
'add commands to the new menu
With CommandBars("Menu Bar").Controls("MyMenu").Controls
Set myButton = .Add(Type:=msoControlButton)
myButton.FaceId = 18
myButton.Caption = "Run Test Macro"
myButton.OnAction = "TestMacro"
Set myButton = .Add(Type:=msoControlButton)
myButton.FaceId = 23
myButton.Caption = "Run Test Macro"
myButton.OnAction = "TestMacro"
Set myButton = .Add(Type:=msoControlButton)
myButton.FaceId = 201
myButton.Caption = "Run Test Macro"
myButton.OnAction = "TestMacro"
myButton.BeginGroup = True
Set myButton = .Add(Type:=msoControlButton)
myButton.FaceId = 208
myButton.Caption = "Run Test Macro"
myButton.OnAction = "TestMacro"
End With

Add a toolbar button to launch an executable file. <Top of Page>

Solution:
1. Create a macro to launch the executable file.
2. Assign the macro to a toolbar.

To create the macro, proceed as follows:
1. Choose Macro|Macros... on the Tools menu.
2. Enter a name for the macro, such as LaunchMyProgram
3. Click Create
4. In the vba macro editing window, enter the Shell statement, something like:
Shell c:\MyProgram.Exe

(Place the filename within double quotes if it contains any spaces.)
5. Choose Save Normal on the File menu.
6. Choose Close and Return To Word on the File menu.

To assign the macro to a toolbar:
1. Rightclick any toolbar and select Customize.
2. Click the Commands tab at the top of the dialog box.
3. In the Categories list, choose Macro.
4. In the Macros list, choose LaunchMyProgram and drag it up to the toolbar
of your choice.
5. Right-click the resulting button and choose Change Button Image and
select an image.
6. Right-click the button again and choose Default Style.
7. Click Close to close the Customize dialog box.

Force a command bar to display all of its commands, even if this forces the command bar to wrap to a second or third line. <Top of Page>

Notes:
When a command bar has too many controls to fit on one line, the command bar first drops any controls that don't have priority. If the command bar still doesn't fit on one line, then the command bar wraps to the next line.

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.
For Each oControl In CommandBars("Standard").Controls
oControl.Priority = 1
Next oControl

Protect command bars against changes. <Top of Page>

Solution:
Protect the command bars.

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.
'NOTE: enable exactly one CustomizationContext statement:
'CustomizationContext = NormalTemplate
'CustomizationContext = ActiveDocument.AttachedTemplate
For Each oCommandBar In CommandBars
If oCommandBar.Visible = True Then
oCommandBar.Protection = msoBarNoChangeDock + _
msoBarNoChangeVisible + msoBarNoCustomize + _
msoBarNoMove + msoBarNoResize
End If
Next oCommandBar

Remove protection from command bars so they can be changed. <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.
'NOTE: enable exactly one CustomizationContext statement:
'CustomizationContext = NormalTemplate
'CustomizationContext = ActiveDocument.AttachedTemplate
For Each oCommandBar In CommandBars
oCommandBar.Protection = msoBarNoProtection
Next oCommandBar

Create a module-level variable that can be used by any procedure (sub or function) within a module. <Top of Page>

Notes:
Any code outside a procedure is referred to as module-level code.

Solution:
Place the following code at the start of a code module (say, NewMacros) and run each subroutine in turn.

Dim myString As String
Sub Test()
myString = "Hello"
End Sub
Sub Test2()
myString = "Goodbye"
End Sub
Sub Test3()
MsgBox myString
End Sub

Prevent a user from interrupting a macro with Ctrl+Break. <Top of Page>

Solution:
Application.EnableCancelKey = wdCancelDisabled

Intercept the Close button (X) in the title bar of a user form. <Top of Page>

Solution:
Place some code into the user form's QueryClose event.

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.
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode <> 1 Then Cancel = 1
End Sub

Force the cursor back to its normal state at the end of a macro. <Top of Page>

Solution:
Add one of the following lines to the end of the macro:
System.Cursor = wdCursorIBeam
System.Cursor = wdCursorNormal

Save a preview image for a template, so the user can see the preview in the File New dialog box. <Top of Page>

Solution:
Choose Properties on the File menu and click the Summary tab. Then place a
checkmark next to Save Preview Picture.

List in a text file all the code from a code module. <Top of Page>

Solution:
Go to the Project Explorer window of the Visual Basic Editor, right-click the module you want to export and select Export File.

Making the transition from WordBasic to VBA. <Top of Page>

The most difficult part about making the transition from WordBasic to VBA is learning to use Word's object model (instead of Word's user interface) as an organizing principle.

As a WordBasic programmer, you could view macros as silent, behind-the-scenes users of Word. Indeed, if you read through a WordBasic macro, you find a series of commands that might just as well have come from a user. When Word 6 or 7 executed a macro, it behaved exactly as it would have behaved if a user were sitting at the keyboard and executing the commands manually.

Sure, WordBasic offered looping and branching, but these were merely tools for managing the order in which commands were to be executed. The commands themselves might just as well have come from a user.

As a Visual Basic programmer, you can view your macros as object manipulators. You can drill down to a particular object and then manipulate it. In the end, the types of manipulations that you can perform aren't all that different from what the user can accomplish via the user interface. But your macros can "reach" objects in more powerful and flexible ways than user interface commands could ever do. Moreover, your macros can reach those objects without regard to the current position of the selection. Plus, you can branch and loop in new, more powerful ways than you could with WordBasic.

Consider the following statement, which allows you to manipulate the entire range of text found in the second row of the first table of the active document:

ActiveDocument.Tables(1).Rows(2).Range.Bold = True

Now consider this looping structure, which allows you to manipulate the same range within ALL tables in the document:

Dim oTable as Table
For each oTable in ActiveDocument.Tables
oTable.Rows(2).Range.Bold = True
Next oTable

Powerful stuff, eh?