Documents can customize ribbons as well
Andrew Whitechapel was blogging about IRibbonExtensibility and how it can be used in AddIns to customize a ribbon in Office 12. I am not sure how many people have noticed this but VSTO v3 June CTP document customizations can also customize ribbons and we are going to see how. Interestingly enough, there is at least one person who noticed this was possible and left a comment on Eric's blog.
What I am about to discuss is pre-release state of the product and things might still change between now and when we actually ship. So be warned and let's get started.
As the commenter on the Eric's blog noticed Document level customizations projects do not support Ribbon Support item templates but Application level AddIn projects do. Let's use this template as a start. To do this let's create a Word 12 Document project first and then add Word AddIn project to the solution, right click on the Addin project item and choose Add New Item. Next select Ribbon Support template, name it MyRibbon.cs and click OK. You will notice that 2 files are added to the project - MyRibbon.cs and MyRibbon.xml. The XML file looks like this:
<customUI xmlns="https://schemas.microsoft.com/office/2006/01/customui" onLoad="OnLoad">
<ribbon startFromScratch="false">
<tabs>
<tab id="VSTO.Tab" label="My Tab" visible="1">
<group id="VSTO.Group" label="Hello World Group" visible="1">
<toggleButton id="toggleButton"
label="Hello World"
screentip="Hello World Screentip"
onAction="OnToggleButton" />
</group>
</tab>
</tabs>
</ribbon>
</customUI>
Now, select the 2 Ribbon files and copy&paste those into your word document project. Delete the Word AddIn and Word AddIn Setup projects from the solution since they are no longer needed. Open MyRibbon.cs file, change the namespace and remove the extension of ThisApplication class. Something like this:
namespace WordAddin1
{
#region service request implementation
public partial class ThisApplication
{
protected override object RequestRibbonService()
{
return new MyRibbon();
}
}
#endregion
namespace WordDocument1
{
Next, let’s modify the constructor on MyRibbon class to listen to ServiceRequest event and react appropriately when IRibbonExtensibility service is requested:
using Microsoft.Office.Tools;
....
public MyRibbon()
{
Globals.ThisDocument.ServiceRequest += ThisDocument_ServiceRequest;
}
void ThisDocument_ServiceRequest(object sender, ServiceRequestEventArgs e)
{
if (e.Guid == typeof(Office.IRibbonExtensibility).GUID)
e.Service = this;
}
Now, all that is left to do is just instantiate MyRibbon object on document start up. Change ThisDocument_Startup method in ThisDocument.cs file:
MyRibbon r;
private void ThisDocument_Startup(object sender, System.EventArgs e)
{
r = new MyRibbon();
}
Press F5 and watch .NET Add-In Tab appear in the ribbon!
Hmmm, there is still one little problem. If you have “Show add-in user interface errors” option checked in Word’s Advanced Options, you will notice an error message saying “The callback function “OnLoad” was not found by GetIDsofNames()”. This simply means that Office was not able to find OnLoad callback method as it was specified in the ribbon XML file. I do not want to bother you with the exact details of what is going on under the hood – but this issue will be fixed when Office 2007 ships. Meanwhile here is a workaround. Replace the declaration of MyRibbon class as follows:
[ComVisible(true)]
public class MyRibbon : Office.IRibbonExtensibility
[ComImport()]
[Guid("000C0396-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMyRibbonExtensibility
{
[DispId(1)]
string GetCustomUI(string RibbonID);
[DispId(2)]
void OnLoad(Office.IRibbonUI ribbonUI);
[DispId(3)]
void OnToggleButton(Office.IRibbonControl control, bool isPressed);
}
[ComVisible(true)]
public class MyRibbon : IMyRibbonExtensibility
The change is to derive the Ribbon class not from the standard Office’s IRibbonExtensibility interface, but from a custom defined IMyRibbonExtensibility interface. The latter is almost identical to IRibbonExtensibility (most importantly it shares the same Guid attribute), but also has all the callback methods (OnLoad and OnToggleButton) defined on it. F5 now and see your ribbon fully functional. In case you want to add more callbacks from the ribbon remember to add these new callbacks to IMyRibbonExtensibility interface first.
[Update 06/06] I should add that the technique of overriding somebody else's interfaces is deemed dangerous. I am presenting it here only for the sake of getting you to see how doc-level ribbons work in Office 12 Beta2. Please throw this code away once final bits of Office 12 are released and underlying bug is fixed.
Happy VSTOing.
Comments
Anonymous
July 10, 2006
The comment has been removedAnonymous
October 09, 2006
Hi. I have implemented COM add-in for office2000, xp, 2003 with Visual C++ 6.0 project. Now i want to implement office2007 COM add-in(Customizing Ribbon) and integrate existing project. But i have problem with getting callback functions to run. In my code(GetCustomUI method), Ribbon XML code is the same as you mentioned. But callback function(onLoad, onAction) doesn't occur. My questions are: Can i implement callbacks in Visual C++ 6.0 ? (How ?) How Office2007 know where to go for the callback function without a function pointer? Thanks for reading.Anonymous
October 09, 2006
Office QIs the IRibbonExtensibility interface for IDispatch and then calls the callback functions using the late-bound technique (i.e. GetIDsofNames followed by Invoke). As for how this can be implemented in VC++ 6.0 - this requires pretty much straightforward implmentation of IDispatch. I do not have enough room to write code in this comment though :)Anonymous
November 21, 2006
Hi Misha, With the release of Office 2007 RTM and VSTO 2005 SE, now how do I go about creating an Excel 2007 Workbook / Word 2007 Document solution. I have used your concept of document customization to start of my project and now this is not supported any more in the final release. How do I go about now?? I need a document solution some how. Please help!!! MarkandAnonymous
November 30, 2006
Hi Misha, I am also using VC++ 6.0 and I tried to implement the IRibbonExtensibility through IDispatch. But I get the error C2259: ATL::CComObject<Base>: cannot instantiate the abstract class. I wonder if I am missing any header files for it. Thanks, TeenaAnonymous
February 08, 2007
i am creating a print preview that is shown for Office 2007 has the options for save / save as etc thro' the tool bar. This is not the case with Word 2003. Please take a look at disabling the Tool bar or better still the ideal solution would be the same behavior as office 2003.Anonymous
June 06, 2007
Hi Misha, I'm trying to repeat the steps above customizing ribbon from a customized document but it looks the final implementation of VSTO/Word 2007 is somehow different. There is no ServiceRequest/RequestService method in VSTO Document class. Could you please confirm that this approach is still valid? Did I overlook something? Is there any other way to modify the ribbon from within VSTO Document/Document Template? Thanks.