If you are not interested in the implementation details, you can download the Word StyleChooser add-in directly. If you installed an earlier version this morning, please uninstall that one first. I made a few changes to have the add-in behave nicer. Please note that you need to open the zip file and run setup.exe from there.
I had originally planned to do another “Hello World” example to cover COM Add-Ins, but I decided to rather do something more useful. The example I am going to do here is going to be for Word only. It is going to implement a sorely missing functionality in Word 2007, namely a simply combo box to see the current style and choose another one. Microsoft provides the style gallery and style task pane, but neither one is really useful to heavy users of Word styles. All the RibbonX related topics I will discuss in this example can be transferred straight to Access, Excel and PowerPoint. Outlook has some peculiarities which I will discuss in separate post. Let me apologize to most of you for using C# here. I installed a 400 GB hard drive in my desktop today and currently all my data is being copied over. Unfortunately the hard drive on my Tablet PC has only 40 GB and wasn’t big enough to support C# and VB.NET, which is why I ended up installing only C# (my preferred language). A 100 GB hard drive for my tablet to address this issue arrived today as well, but this will have to wait until my desktop is usable again. I’ll provide the VB.NET source code for this example soon.
For this post, I am going to assume that you know how to create a COM Add-In for Office using Visual Studio .NET. If you don’t know how to do that, consult the Visual Studio help, the MSDN library, an Office programming book or search on Google. I will use Visual Studio .NET 2003.
Getting started
I am going to call this add-in StyleChooser and using the Visual Studio Add-In Wizard, I am making it a Microsoft Word add-in with the full name of “Microsoft Word 2007 StyleChooser Add-In”. In VS 2003, I need to add a reference to the Word 12 PIA as well as the Office 12 Object Library. The Office Object Library reference that the VS add-in wizard added needs to be removed. The Word 12 PIA can be found under the .NET tab and is called “Microsoft.Office.Interop.Word” with the version 12.0.0.0. The Office 12 Object Library can be found under the COM tab and is called “Microsoft Office 12.0 Object Library” with the version 2.4. With these references, the add-in will now load correctly in Word 2007.
Determining the version of Word
The add-in will not only load in Word 2007, but also Word 2003 (I don’t have any earlier Office version so I don’t know if it will load in those as well). As it is specifically geared to 2007 though, there is no point in having the add-in loaded in 2003 as well. For the user, that would be just a waste of memory. Note that the add-in will correctly load in 2003, but do nothing, as 2003 does not retrieve the RibbonX code from the add-in. This is important to know when you want to write an add-in that displays a UI in 2003 and 2007. If it is being loaded in 2003, you need to push the UI to Office. If it is being loaded in 2007, Office will pull the UI from the add-in.
In order to be nice to the user, we should therefore automatically unload the add-in if it is not loaded in Word 2007 (or any later version). We can determine the current version in the OnConnection method. As publishing code via the Word blogging feature isn’t simple, I am not going to show code in the example, but rather refer you to the C# source code file. The version can be determined using the Application.Version method. This returns a string which isn’t necessarily a number. My own add-in in fact kept crashing with Access 2007 B1TR until I realized that the version string returned by Access included the word “Beta” after the version number. Hence the code tries to strip out anything but the major version number (12) and catches any error the number conversion might trigger.
If the add-in is not loaded in Word 2007, it unloads itself using the Microsoft.Office.Core.COMAddIn.Connect value (setting it equal to false).
The code so far loads the add-in into Word 2007 and unloads it if an earlier version is detected. With only this rudimentary code, the add-in can be installed into Word and its presence can be checked via Word Options, Add-Ins.
While developing a COM Add-in, you probably want to run it in debugging mode, which means you want to hit Run in Visual Studio which should then open Word and give you the full VS debugging options for it. If you are, like me, using VS 2003, this won’t work if you have the .NET 2.0 Framework installed. The only currently known workaround for this issue is to uninstall the 2.0 Framework. Microsoft has yet to find a better workaround.
Loading the RibbonX code
In order to load RibbonX code, the add-in needs to implement the IRibbonExtensibility interface. This interface requires the implementation of the string GetCustomUI(string) method. The string argument that is passed to GetCustomUI contains the ribbon ID. You can ignore this argument for Access, Excel, PPT and Word. I will discuss its significance with Outlook.
GetCustomUI needs to return the full RibbonX code as string. In contrast to VBA this allows you to dynamically create the RibbonX code you are returning to Office. I personally prefer to store the entire XML code as a resource file in the add-in instead of some long and cumbersome string in the code. Therefore I added an XML file called RibbonX.xml to the project (make sure to set its build action to “embedded resource”). The code to get the XML from that embedded resource can be found in the GetCustomUI method. The most noteworthy thing here is the string attribute of the System.Reflection.Assembly.GetManifestResourceStream(string) method. It needs to include your add-in name as well as the full file name. In my example it is “StyleChooser.RibbonX.xml”. You should always verify that your resource file is actually being loaded. If you have trouble figuring out the correct parameter, use the code I commented out. I should also tell you that at least with VS 2003, the RibbonX.xml will not be recompiled unless you use “Rebuild Solution”. This means, if you make a change to the file and use “Build Solution”, the change won’t be compiled into your add-in and you’ll be wondering what is going on. Therefore, if you change anything in the embedded RibbonX file, rebuild the solution always.
RibbonX code
The RibbonX code for this example is going to be simple. I will add one group with a combo box and a button to the Home tab. I chose the Home tab, because choosing a style is among the 80% most used functions in Word (as you can tell from the MS-Styles group being on the Home tab). It won’t be pretty, but it will serve its purpose. Following is the RibbonX code for the example:

Some of these things are already familiar to you, some are not. New are a bunch of callbacks and the comboBox tag. As I will discuss the callbacks later, let me point out a few attributes to you. You already know the “id”, “idMso”, “label” and “size” attributes. “insertAfterMso” does what its name implies, it inserts the group after the Font group on the Home tab. “screentip” specifies a simple tooltip. If you look at the tooltip for this group, you’ll see the screentip above the line and the supertip will be displayed below it. As I don’t define a supertip, it shows the name of the add-in. “maxLength” specifies the maximum length of a string that a user can input. I set it rather arbitrarily to 50.
About button
The about button is straightforward to implement and similar to the “Hello World” example I showed for VBA. The only difference is that I check this time in the code the id for the control and make sure it is equivalent to the id of the about button. I do this, because I personally prefer to write only one method for each ribbon callback signature and decide within the method on which control to apply it. The about button displays a simple message box. You have to include the Systems.Windows.Forms .NET reference to be able to do this though.
Populating the comboBox
The main goal of the add-in example is to let a user select a style from the list of all styles. The comboBox is supposed to show all styles when the drop down arrow is pressed and show in its field the currently active style.
Let me first insert the information for the currently active style. To do this, we need to use the “getText” callback. From the callback, we need to return the string that is to be displayed in the comboBox field itself. Note that the string has to match a string given to the drop down list, if you want the comboBox to correctly highlight the currently active style in the drop down list. As this is post is not about Word programming itself, please refer to the code to see the details of how the information is obtained from Word.
I also need to fill the entire drop down list with all available styles. To do this we need to implement two callbacks: “getItemCount” and “getItemLabel”. “getItemCount” tells Word how many items the drop down list will contain. “getItemLabel” is called for every single item to determine the string to display. “getItemLabel” will be called back as many times as “getItemCount” specified. Its signature contains an integer which is simply a reference to a zero based array. This means that the add-in itself needs to maintain internally the full drop-down list to display. As styles can be hidden, the example doesn’t reference directly the built-in Word Styles collection, but rather maintains its own styles list.
At this point, I need to introduce the IRibbonControl.Context property. This property is a handle to currently active window. Keep in mind that although Word has only one ribbon, many documents can be displayed at the same time. For each document, there is a different list of styles and a different currently active style. Therefore the add-in needs to account for it somehow. I chose to do that by using a Hashtable that has as key a Document object and as value an ArrayList of strings. When the “getItemCount” is executed, I build the Hashtable for that particular document and then return its count. For each “getItemLabel” callback, I simply access the Hashtable, then the ArrayList stored within and return the appropriately indexed element. Note that the “getItemCount” callback (and subsequently any “getItemLabel” callbacks) is only executed when the user clicks the drop-down arrow.
Reacting to a change in the comboBox
If the user selects a different style in the comboBox, that style should be applied to the current selection. In order to do this, I implemented the “onChange” callback for the comboBox. This callback passes the method the selected text, which can be passed on as is to the Selection.Style property of the Word object model (notice that I had to pass a reference to the object due to a PIA requirement).
Displaying the currently active style
The only problem the add-in has now is that it cannot react to any change in style in the document. For example, if the user moves the cursor to a paragraph that has a different style, this change is not reflected in the comboBox field. In order to be able to reflect the change, the add-in needs to implement the WindowSelectionChange event of the Application object. But what should the event trigger? This is finally where the last of the callbacks comes into play: “onLoad”. The “onLoad” callback is mainly there to give you access to the IRibbonUI object for your add-in. With that object, you can invalidate either all UI elements or just one particular one. Invalidation means that Office considers all values returned by the element’s callbacks to be invalid and also triggers a refresh of those callbacks. In other words, by invalidating a control you force Office to call its callbacks again, but of course only if the particular UI element is currently visible. To finish the add-in, I added the “onLoad” callback and included in that particular callback the statement to add a method to the WindowSelectionChange event. That method has one statement only, namely one to invalidate the comboBox control. If the Home tab is displayed when the event is triggered, Word will reload the text of the comboBox field and therefore display the correct style. You might notice a performance hit when you press the drop-down arrow of the comboBox. Recreating the ArrayList every time the drop-down arrow is pressed is unnecessary and this could be optimized.
Conclusion
I hope this COM add-in example illustrated a lot about RibbonX and COM Add-Ins in Office 2007. There is nothing in this example by the way that could not be implemented using documents or templates and VBA. If you don’t feel like implementing anything yourself, give the binary version of the add-in a try. You can add the comboBox to your QAT by right-clicking the drop-down arrow and choosing “Add to Quick Access Toolbar”.
Downloads
Revisions
- V1.1 solves some of the setup issues, e.g. the add-in installing itself in weird program files folder (HCT).
- I changed the location of the group to the right of the Styles group
- Thanks to Bob Buckland for his helpful suggestions and comments!