“Hello World” in Access, Excel, PowerPoint and Word from a COM Add-In using .NET (C#) - Word StyleChooser
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
-
StyleChooser C# Add-In V1.1 (binary). 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.
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!

June 14th, 2006 at 13:09
Edited to include the Revisions section and changed the binary you can download. I won’t change the source code as I like it to match the post 100%. I will post the revised source code together with the VBA .NET in a separete post.
July 15th, 2006 at 5:12
Hi,
I am developing an application which should show some helps in the custom task pane , could you please tell me how can i achive this using .Net 2.0
Thanks i advance
Sajin
July 21st, 2006 at 14:33
Hi,
I’m trying to implement the ribbon in unmanaged C++ and am having problems with getting callback functions to run. Is implementing callbacks in unmanged C++ the same? Without reflection, how does Office know where to go for the callback function without a function pointer?
Kelvin
August 23rd, 2006 at 19:51
Sajin,
I haven’t looked at task panes at all. Maybe there is some content on MSDN?
Kelvin,
It should work with unmanaged C++ if you use the callbacks provided in the MSDN documentation. If you are still having problems, send me a sample project via email.
Sorry for not getting back to you both earlier,
Patrick
September 21st, 2006 at 2:38
Hi,
I made a com add in using VS 2003 + C# for word 2007 Beta . It was working fine but now when i changed my code and Built and installed again the add in is not reflecting the changes done by me. It is picking up yhe old thing only.
Noopur
October 7th, 2006 at 23:43
Thanks for the example. It’s really great. I would like to implement an add-in with two controls, for example: 1 dropdown and 1 button. Supose I have an callback that gets correctly fired when I press the button…what should I have to do to find out the contents of the dropdown to make a validation on button’s click? Thanks in advance.
October 12th, 2006 at 17:03
Daniel,
I am not quite sure what you are asking about?
Patrick
November 2nd, 2006 at 4:22
Hello Patrick,
you wrote:
“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.”
Does that mean, that it is not possible to use the GetCustomUI-Callback in VBA? I tried myself and put this into a new Word-VBA-Class-module:
Implements Office.IRibbonExtensibility
Then the VBA-IDE offered the creation of the following callback:
Private Function IRibbonExtensibility_GetCustomUI(ByVal RibbonID As String) As String
End Function
Anyway - I don’t know yet if it’s possible to make Word use this callback… Maybe you’ve got an idea how to make it work or even have some resource from Microsoft about that and could tell it to us?
Thanks, Stefan
November 2nd, 2006 at 7:33
Hi Stefan,
VBA does not support GetCustomUI. It’s offered by the IDE, because it is the same object model as the one used by COM add-ins.
The only way to load RibbonX with VBA is to embed the RibbonX file into the Excel/PPT/Word document or template.
Patrick
November 13th, 2006 at 10:39
Hi!
I have implemented a rather complex Word 2007 AddIn using a CustomTaskPane (Sajin, get back on that if you still need help), and running from VS2005 it works all fine. But, when installing it, Word 2007 doesn’t load it because of some error (”Runtime error when loading the AddIn”). I use a CustomAction to manage the security issues (grant FullTrust etc). Which deployment project did you use? Maybe the one the gets created automatically when opening a new AddiN-project, or did you create one yourself?
Thanks
M
November 20th, 2006 at 13:40
Michael,
take a look at http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=862733&SiteID=1
Patrick
December 24th, 2006 at 6:15
Thanks Dear,
Ur artical is really helpful for me .
Sourabh Khatri
January 31st, 2007 at 12:56
Hi,
I have been playing arround a little with custom ribbons. I want to store the XML data in an Excel file (customUI.xlam) using getLabel callbacks for all the strings (used for localization). The problem is that the labels are not updated correctly until I press my new ribbon tab several times. Does anyone else have similar problem?
I am using the “Microsoft office 2007 Custom UI Editor” with following XML:
And in the same file (customUI.xlam) using the following getLabel callback:
Public Sub GetLabel(ByVal control As IRibbonControl, Byref text)
text = GetLocalizedText(control.Tag)
End sub
Using simply “label” instead of callbacks no problems occurs… and the callback does get called you just have to keep clicking on the ribbon to get all labels updated…
/Henrik
January 31st, 2007 at 13:03
Hi Henrik,
please post the question in the forums: http://pschmid.net/office2007/forums
You can attach the XML file there and so it will actually show up.
Patrick