Finding a New Purpose

Today's Guest Writer: Savraj Dhanjal

Savraj is a Program Manager on the Office User Experience team focused on user interface extensibility for Office developers.

Today we're going to take a break from control types to highlight one of the more powerful features exposed by RibbonX: Command Repurposing.

In our research to understand how people were using extensibility in Office 2003, we found that developers at corporations often modified the built-in UI. Beyond adding a few buttons to the menus and toolbars, developers fundamentally changed the behavior of built-in buttons. If you're not familiar with Office development, you might ask, "Why in the world would someone do that?"

Imagine the international law firm of Faller, Mogilevsky, and Luu. FML doesn't want its employees printing Word documents or PowerPoint presentations unless they conform to the firm's strict standards for document formatting and style. To ensure standards are met, FML's software development team builds, as one of their many add-ins, a solution that overrides a click on the Print button. Clicking on Print now runs FML's code that checks the document for errors. If there are any errors, the user is notified. If not, the code sends the document to the printer.

You can imagine this same scenario applying to the Save button. FML wants to make sure all the metadata attached to a document is properly formatted before the user saves it. So FML takes over the Save button as well. When the user clicks Save, FML's code runs, updates metadata, and permits Office to continue with the built-in Save operation.

A few ways to do it today

There are a few ways to do this in Office 2003. The first way is through specially named macros in Word. Hit Alt-F11, select Insert > Module in the Visual Basic Editor, and paste the following macro into the code window.

Sub FileSave()
MsgBox ("Surprise! This works!")
End Sub

Test the macro by pressing F5 while your insertion point is inside the macro code. If you see the message box, it works. Now select Save from Word's File Menu. Surprise, it really does work. Every time you select "Save" Word will run your Macro and display a message box, instead of the built-in Save command. As yet another testament to Office as a platform, this behavior was introduced well before 1996, as part of WordBasic. The Word MVP's have a nice write-up on this behavior, and there are a number of other special macro names. Since this functionality pre-dated CommandBars, it only works in Word, and it hooks all instances of the Save button, including the one on the toolbar, as well as the control key shortcuts. So if you hit CTRL-S, the macro runs. The same goes for a click on the floppy disk icon in the Standard Toolbar. Isn't that neat? With three lines of VBA code (in Word) you can change the behavior of Save.

If you wanted to match this precise behavior using CommandBars, you would need to find each instance of the Save button and give it a new "onAction" macro, and the user might have customized the interface, so you'll have to find all instances of it. The following code snippet changes the onAction of the Save button on just the Standard Toolbar. After you run the Macro below, the Save button in the Toolbar and the Save button in the File Menu will do different things, and this method doesn't capture CTRL-S.

Sub newSaveAction()
Application.CommandBars("Standard").Controls("Save").OnAction = "surprise"
End Sub

Sub surprise()
MsgBox ("Surprise!")
End Sub

Run the first macro above, and then a click on the Save button will call the second one. This general idea works in all of the Applications with CommandBars.

But wait, there's more!

It shouldn't surprise you that there's one more way to do this. If I want to take over the Print button in Office 2003, I can listen for the button click event. Once the right control comes through this event, I can run some code and decide whether the built-in action should continue. The following code repurposes the Print button on Word's File Menu. Just copy and paste the code below into the Visual Basic Editor (Alt-F11), and run the first Macro.

Private WithEvents buttonEvent As CommandBarButton

Sub RunMe()
Set buttonEvent = Application.CommandBars(
  "Menu Bar").Controls("File").Controls("Print...")
End Sub

Private Sub buttonEvent_Click(ByVal Ctrl As
  CommandBarButton, CancelDefault As Boolean)
MsgBox ("File has errors.")
CancelDefault = True
End Sub

After you run the macro called RunMe a click on the Print button in the File Menu will yield a message box that says "File has errors." The code above sets cancelDefault to true to cancel the default action, in this case, printing. If you set CancelDefault to false the built-in action will continue after you close the message box. With the event-based method, you get an additional feature of continuing or stopping the built-in event, and this works in VBA and COM for all of the applications.

Enter RibbonX...

The sample code to repurpose the built-in Save and Print buttons, in RibbonX, looks like this:

CustomUI Markup

<customUI xmlns="">

  <command idMso="Save" onAction="mySave"/>
  <command idMso="Print" onAction="myPrint"/>


C# Code

public void mySave(IRibbonControl control, ref bool
    CancelDefault = true;

public void myPrint(IRibbonControl control, ref bool
    CancelDefault = false;

As you can see from the markup, we've endeavored to make it as simple as possible. Just tell us the control IDs of the built-in controls you would like to repurpose in the <commands> section. A click on that command, wherever it appears in the user interface, will trigger the onAction callback you specify. Your onAction callback can then, just like the buttonClick_event, decide whether to continue with the built-in functionality.

We've also added a little more functionality -- control over state. You can specify if this control should always be disabled, or give us a callback to manage the enabled state.

CustomUI Markup

<customUI xmlns="">

  <command idMso="Save" enabled="false"/>
  <command idMso="Print" getEnabled="myState"/>


In the example above, the Save button is permanently disabled, and the Print button gets its state from the "AND" of its built-in state and the getEnabled callback "myState." When both Office says it's enabled, AND when your callback says it's enabled, the control is enabled. If either your code or Office says the Print button should be disabled, it's disabled.

In RibbonX, just give us one line of XML and you completely own what happens when the control is clicked. Best of all, in Word and PowerPoint, keyboard shortcuts are also captured, a marked improvement over Office 2003 events behavior.

Comments (14)

  1. Today without screenshots?? Somehow unusual… 😉

    PS: a good article!

  2. Gabe says:

    Under what circumstances would I want a control to be always disabled?

    Let’s say I’m using Word on a public access kiosk so I don’t want people to be able to save documents. I would want to hide the save button altogether, not just disable it.

  3. Justme says:

    HELP! I performed those things mentioned in this blog and now I can’t use my ‘Save’ icon from the toolbar because it says ‘Macro cannot be found or disabled because of your Macro security settings’ … Luckily, my Ctrl-S and File-Save are still working. How do I get around this though? …:P thanks

  4. James Bray says:

    I would say allowing complete programmatic control of the office application is generally a good thing.

    So long as we dont head back to the Macro Virus days of WM.Concept, etc…

    Nice article btw 🙂


  5. DevUser says:

    Thanks for this important information!

    As an Office developer I’m doing a great deal of commandbar customization, especially in Word for law firms.

    Four questions

    (1) Hiding / Adding controls

    As Gabe pointed out, we need the possibility to hide/delete commands. This is necessary to streamline the UI in the corporate environment. Up to now I’ve done this either through COM Addins or Word global templates. Group policies only allow to *disable* UI elements, which is awkward, because the button resides inactivated and provokes calls to the help desks ("Why I’m getting this message, that the admin has disabled the button?"). Group policies also do not provide the option to add commands needed in a certain environment, e.g. access to print or formatting macros.

    Question 1: How can we hide/delete RibbonX elements?

    (2) Deployment

    Currently I can configure the COM addin to be loaded on a per-machine basis. So users cannot unload it by using the COM addin-dialog. Or we have a Word addin loaded on each startup, and the path is set through a group policy.

    Question 2: Where will the RibbonX XML customization files reside? How can we configure the path to it? How are they protected? How about multiple configuration files – which leeds to Question 3.

    (3) War between addins

    As far as I understand your explanations in the earlier articles, each addin can change the customization, or can "talk" to RibbonX.

    Question 3: How are conflicts handled? By the order in which addins are loaded – the last wins?

    (4) Keep your hands away, user!

    In a corporate environment I always disable the customization for the standard and formatting commandbars together with the main menu bar. Reason: I’ve reorganized the menu bar(adding / hiding buttons) to streamline it, to reduce command overhead (no need to have a "Create Web Page" command in Word if the users are secretaries and lawyers), and to give users the feeling of a "default" command set. Help desk support is much more easy, if the default commandbars are not individualized. However, users are trained to have their "personal commandbars", which they can customize as they like and which is saved in

    Question 4: How and where can I do a "Commandbar.Protection = msoBarNoCustomize"


    A small P.S. as a warning to other developers:

     Set buttonEvent = Application.CommandBars(

     "Menu Bar").Controls("File").Controls("Print…")

    – this works only in a pure english environment. I understand that in this blog it’s more the issue to show the idea behind, not to respect all real world circumstances. But if you must deal with international customization, you’re addin won’t find "File", because it’s called "Fichier" or "Datei" or anything else. So better to use the Command-IDs, e.g. like

    Set objCmdCtl = objContextBar.FindControl(ID:=783)  ‘Bullets and Numbering

    I hope that the Office 2007 developer kit will contain a list of all command ids. Currently each developer has his macro for each office app writing them out to a file …

  6. Step says:

    A great article.  I found myself wondering about security, though….it seems this could easily be hijacked and lead to quite disastrous results.  It might be good to have an write-up on what the team has done to improve security.

  7. Savraj says:

    Hey everyone, here are some answers:

    1) Under what circumstances would you want a control to always be disabled?

    There are a bunch of scenarios, but a good one is the document-based UI scenario.  You can make document-level solutions with RibbonX by including a customUI part in your document. Perhaps your document requires that certain controls are always disabled. When your doc is opened the controls disabled.  In Office 2003, people achieved this by rummaging through the commandBars OM.

    2) Help! I messed up my UI with your instructions!

    Oh, right, should have included the undo instructions as well. 🙂 The best way to fix this is by opening the Tools > Customize dialog.  Now, right-click on the Save button, and select "RESET." That should do it!

    3) How can we hide / delete elements?

    For corporate developers that want to streamline the UI, we’ve made it so you can hide tabs, groups, and individual controls in the file menu by setting their visibility to false.

    4) Deployment and RibbonX – where does the XML reside?

    In an earlier <a href="">post</a&gt; I briefly mentioned where the XML resides in COM and VBA solutions.  Basically, Office asks your COM add-in for XML via getCustomUI method on the IRibbonExtensibility interface, that you implement in your Connect class.  Your COM add-in can get the XML file from anywhere — it could be part of the add-in or on a share somewhere — and you can return it to us when your add-in loads.   It’s up to you.  You’ll see more documentation about this with Beta 2.

    5) Yes, as far as conflicts go, the last add-in wins.

    6) Protection bits on customization?

    With the new UI there are no protection bits. End users can move your custom buttons to the QAT. Since the Ribbon will be customized by your add-in, you still will have a ‘default’ command set.

    7) Application.CommandBars("Menu Bar").Controls("File").Controls("Print…") doesn’t localize.

    Yes, you are right, this only works in English.  We fixed this problem with RibbonX — you used the fixed, named control IDs and they work across languages.  We are publishing the Command IDs, and in the Beta 2 build they will be visible in the QAT customization dialog, when you hover over controls.

    Thanks for the interest. I’ll ping the security team to see if they want to chime in as well. 😉

  8. Pranav Wagh says:

    >> Yes, as far as conflicts go, the last add-in wins.

    Last installed addin, last loaded addin, alphabatically last or something else ..?

    I have two questions with me my TLs my EEs struggled like anything.. finally with the answer that "predection of addin call is non-deterministic by nature", so please let me know what changed with 2007.

    1) If i want’ to *insure* that my addin gets called last what do i do ?

    2) Is there anything like AfterSave in 2007 , i have seen many issues where people are trying to use something like that, although we did gave them *workarounds*  but they were non dependable as such.

  9. Thanks!!!”> auto site insurance. [URL=]home insurance[/URL]: car site insurance, The autos insurance company, compare car insurance. Also [url=]cars insurance[/url] from website .

Skip to main content