Creating an Add-in for Office 2007 and Office 2010 that "Lights Up" on Office 2010 (McLean Schofield)

Managed Office add-ins traditionally have been able to run in the targeted application (the version of the application whose PIAs the add-in references) and in later versions of the application. Therefore, if you need to create a single VSTO add-in that can be run in multiple versions of an application, the typical guidance is to develop the add-in by using a project template for the oldest version of Office that you want to support. For example, if your add-in needs to work with Office 2003 and Office 2007, you should create an Excel 2003 add-in (by using VSTO 2005 SE with Visual Studio 2005, or by using Visual Studio 2008).

However, this strategy has several inconveniences:

  • If you want to test/debug/run the add-in on your development computer, you must have the earliest version of Office you are targeting installed. Since side-by-side installations of Office are not supported on the development computer for VSTO development,if you’re targeting an older version of Office this means that you cannot use the current version of Office on your development computer (for example, if you need to do some non-development work in Office).
  • Your add-in is limited to using only those features that are available in the earliest version of Office that you are targeting. You can work around this by creating a different add-in for each version of the application you are targeting and refactoring any common business logic into a shared assembly, or by using more advanced (and unsupported) methods, but this adds to the complexity of the development and deployment process.

With Visual Studio 2010, this scenario gets better. If you target the .NET Framework 4, you can now create a single add-in that targets both Office 2007 and Office 2010, and uses features that are available only to Office 2010 (this is the “lights up” part of the title of this blog). This is possible by virtue of the new embedded interop types feature in Visual Studio 2010 (also sometimes referred to as no-PIA or by the related /link compiler option). When you compile an add-in project that targets the .NET Framework 4, by default* the type information for all the PIA types referenced in the add-in code is embedded in the add-in assembly. At run time, this type information is used to resolve calls to the underlying COM type, rather than relying on type information in the PIAs.

The most commonly touted benefit of this feature is that because the add-in is no longer tightly coupled with the PIAs at compile time, the PIAs are no longer necessary on end user computers. However, this also means that you can now create an add-in that targets Office 2010, and the add-in will also run in Office 2007. The one caveat is this: when the add-in is loaded in Office 2007, it can use only those types/members that are available in Office 2007. You can achieve this by using the Application.Version property, and writing conditional code that uses an Office 2010-specific type/member only if the add-in is loaded in Office 2010. If the add-in is loaded in Office 2007, your code can do something else.

The following example demonstrates this technique in a Word 2010 add-in project that targets the .NET Framework 4. If the add-in is loaded in Word 2010, the code adds a check box content control (this is a new type of content control that was introduced in Word 2010) to the beginning of the active document. If the add-in is loaded in Word 2007, then it instead adds a Windows Forms check box, since this type of control can be added to a document in either version of Word.

if (Globals.ThisAddIn.Application.ActiveDocument != null)
{
Word.Document activeDoc = Globals.ThisAddIn.Application.ActiveDocument;
activeDoc.Paragraphs[1].Range.InsertParagraphBefore();

string majorVersionString = Globals.ThisAddIn.Application.Version.Split(new char[] { '.' })[0];
int majorVersion = Convert.ToInt32(majorVersionString);

if (majorVersion >= 14)
{
// Add a check box content control.
Word.ContentControl checkBoxContentControl1 = activeDoc.ContentControls.Add(
Word.WdContentControlType.wdContentControlCheckBox, activeDoc.Paragraphs[1].Range);
checkBoxContentControl1.Checked = true;
}
else if (majorVersion >= 12)
{
// Add a Windows Forms check box. This code requires a reference to Microsoft.Office.Tools.v4.0.Utilities
Microsoft.Office.Tools.Word.Document vstoDoc = Globals.Factory.GetVstoObject(activeDoc);
Microsoft.Office.Tools.Word.Controls.CheckBox checkBox1 = vstoDoc.Controls.AddCheckBox(
vstoDoc.Paragraphs[1].Range, 15, 15, "checkBox1");
checkBox1.Checked = true;
}
}

Here’s another example that demonstrates this technique in an Outlook 2010 add-in that targets the .NET Framework 4. When the PageChange event of an Inspector is raised, this code uses the new ActivateTab method in Office 2010 to activate a custom Ribbon tab if the user navigated to a custom form region page. This code assumes the add-in project has a Ribbon (Visual Designer) item named Ribbon1 that defines a custom tab named MyCustomTab, and a Form Region item (of type Separate) named MyCustomFormRegion.
void Inspector_PageChange(ref string ActivePageName)
{
string majorVersionString = Globals.ThisAddIn.Application.Version.Split(new char[]{'.'})[0];
int majorVersion = Convert.ToInt32(majorVersionString);

if (majorVersion >= 14)
{
Outlook.Inspector inspector = Globals.ThisAddIn.Application.ActiveInspector();
Microsoft.Office.Tools.Ribbon.RibbonTab tabToActivate = Globals.Ribbons[inspector].Ribbon1.MyCustomTab;

if (string.Equals(ActivePageName, "MyCustomFormRegion"))
{
tabToActivate.RibbonUI.ActivateTab(tabToActivate.ControlId.ToString());
}
}
}

Note that different Office applications apparently return differently formatted Application.Version strings. For example, on my computer Word 2010 returns “14.0”, but Outlook 2010 returns “14.0.0.4374”. To deal with these differences in a consistent way, the code above uses String.Split to extract the “major” version number out of this string (the number before the first period).

*This is the default behavior in projects that target the .NET Framework 4. If you change the Embed Interop Types property of a PIA reference in your project from True to False, the type information for that PIA is no longer embedded, and the add-in will be effectively bound to the specific PIA (or a later version) that is referenced. In other words, a Word 2010 add-in cannot be loaded in Word 2007, etc.

______________

McLean Schofield