How to make your macros work with Office 2007
Microsoft Office 2007 replaces most of the menus found in earlier versions of Office with a new ribbon control.
From the user’s perspective, the ribbon cannot be customised, but developers have full control. If you have existing Word macros that use menus or toolbars, they usually work in Office 2007, but the implementation is ugly.
Any custom menus get moved to the Add-Ins ribbon tab. What follows is a look at what it takes to revise an existing macro to work properly with the Office 2007 ribbon. The macro integrates media playback into Word so that you can play, pause and navigate an audio file through toolbar buttons or keyboard shortcuts. It’s ideal for transcribing audio, since you can control the sound without reaching for the mouse.
The macro is written in VBA and stored in a Word template. In Word 2007 it works, but the buttons are mixed with those for other compatibility macros on the Add-Ins ribbon.
VBA versus .NET
You may wonder if the VBA
macro
must be converted to C# or Visual Basic .Net. Fortunately, it’s not necessary,
despite Microsoft’s focus on .NET. In fact, it is better to leave it in VBA
unless there is a compelling reason to convert it. The Office Ribbon API is Com
based, and VBA works well with Com.
Leaving the macro in VBA avoids the overhead of loading the .Net runtime and means that code has no need to cross the Com/.Net boundary.
Converting the template
The first step is to convert the template to the Office 2007 format. Open the
old template in Word, and save as a Word macro-enabled template with a .dotm
extension. Alternatively, you could start a new macro-enabled template and paste
the old VBA code into it. You now have a template in the Open Office
XML
format.
To customise the ribbon, you need to specify the customisations in an XML
file and embed this in the new template according to Microsoft’s XML Packaging
specification. Here is an example:
<?xml version=”1.0” 4 encoding=”utf-8” ?>
<customUI
xmlns=”http://
schemas.
microsoft.
com/office
/2006/01/
customui”
onLoad=”This
Document.Ribbon
Loaded”>
<ribbon
startFromScratch=”false”>
<tabs>
<tab id=”MediaTab” label=”PCW
Media”>
<group id=”WordMedia”
label=”Word Media”>
<button id=”btnPlay” label=”Load” keytip=”A”
screentip=”Load and play an
audio file ALT+L” imageMso=”HappyFace”
onAction=”ThisDocument.Playx”/>
</group>
</tab>
This document creates a new tab in the ribbon with the label PCW Media. The tab contains one group, and the group contains one button. The button has the built-in image HappyFace as a placeholder. Normally you will set your own image, using an image attribute rather than imageMso.
When loaded, the ribbon calls a VBA routine called RibbonLoaded, and when the button is clicked it calls another routine called Playx. This is VBA code that you write in the normal way. You can write this XML with any editor, even Notepad, though the steps to include it in the document are arduous.
It involves renaming the .dotm file with a zip extension, extracting the zip , copying the XML file into a new subdirectory within the zip archive and editing the top-level .rels file to include the new XML content. This becomes more arduous if you add images to the template, since these require further sub-directories and a new .rels file, according to the Open Packaging Convention.
Fortunately there is an easier method. You can download a utility called the Office 2007 Custom UI editor. As an XML editor it’s basic, but it does handle the packaging aspect for you, saving a lot of time. It will also validate the XML against the correct schema. A disadvantage is that the UI editor has no pop-up help or auto-completion.
You might want to take a hybrid approach, using a better XML editor such as Visual Studio 2005. Create a new XML document, and set the schemas property to point to CustomUI.xsd, which gets installed with the Custom UI editor. This gives you pop-up help as well as validation. Once done, you can copy & paste the XML into the Custom UI editor for packaging.
Open the template in Word 2007. You will get errors if you have not yet written the VBA functions, but it should show a new ribbon tab with the controls as defined in the XML (see the attached PDF). A variety of controls are possible, though this example uses only two: a standard button and a toggleButton.
Writing the code
It’s not just a matter of hooking up the new buttons to existing code.
Functions called by the ribbon need the correct arguments or they will not run.
The arguments depend on the control. A button expects a routine like this:
Public Sub Playx(ByVal control
As IRibbonControl)
A toggleButton expects this:
Public Sub ToggleStatex(ByVal
control As IRibbonControl,
ByVal pressstate As Boolean)
The names are unimportant; it is the number and type of the arguments that counts. Clearly your existing macros will not have the correct signatures. You either need to amend them to match what is now required, or create new macros that call the old ones. An awkward issue is that macros called directly from the keyboard cannot take arguments.
However, you can reduce the amount of code by having several buttons call the same wrapper function, and using the properties of the IRibbonControl argument to detect which button was clicked. The toggleButton needs special attention. In this case, it is a pause control. When the audio file is paused, the button should appear depressed. When the file is playing, or no file is loaded, the button should appear in its up state.
This is different from the default behaviour, which toggles the state
whenever you click. You can achieve this by specifying an attribute for the
button, in the XML code, called getPressed. This must point to a macro like
this:
Sub IsPaused(control As
IRibbonControl, ByRef
isPressed)
In this code, you check the current state and set the isPressed argument accordingly. The getPressed function is called when the document loads. However it might not be called again unless you specifically trigger it by calling the InvalidateControl method of the ribbon. Therefore, whenever you want the state of the toggleButton to change, you must call InvalidateControl.
InvalidateControl is a method of the IRibbonUI interface, representing a
Ribbon control. The best way to get a reference to this interface is when the
document loads. In the example template, a global variable of type IRibbonUI is
declared in a code module. When the ribbon loads, it calls this function,
specified in the XML:
Public Sub
RibbonLoaded(theRibbon As
IRibbonUI)
Set ribbon = theRibbon
End Sub
This lets you call the ribbon methods elsewhere in your code, like this:
ribbon.InvalidateControl
“btnPause”
Even if you pause the file without clicking the toggleButton, it will still
change its state.
Keyboard shortcuts
Office 2007 supports several kinds of keyboard shortcuts. The ribbon itself
supports a two-step shortcut sequence. Pressing Alt followed by a letter lets
you switch between tabs in the ribbon, after which you can press another key to
trigger a control. These keys are defined in the XML. It is a good system,
especially since the shortcuts automatically appear in small boxes beside each
control, during the Alt sequence.
The main problem with this is that it takes two steps to fire any one control. It saves time if you can call a macro with a single keystroke combination. There are a couple of ways to do this. First, a user can add a ribbon control to the quick access toolbar. Word will automatically assign an immediate shortcut to the control.
Second, you can assign a keyboard shortcut directly to a macro. To do this, click the Office button, then Word options, then Customise, and then the Customise button next to Keyboard shortcuts. In the Customise Keyboard dialog, scroll down to Macros and select the macro required. Only macros without arguments are listed. Click the keyboard shortcut you want to use, and then click Assign.
These shortcuts are saved by default in the template. Unfortunately there appears to be a small bug, in that existing macro shortcuts are not shown in this dialog, even when they are present. It is almost impossible to find shortcuts that do not conflict either with the ribbon or with legacy Office shortcuts, so you will normally have to compromise.
Conclusion
The tools for customising the Office ribbon are not yet mature, but it’s not
difficult to adapt an existing template to make use of the new user interface.