In this interview, I sit down with Stephen Peters, a developer on the Office client tools team in Visual Studio. Steve shows us a couple of tricks for how you can squeeze the best performance out of Office solutions built with Visual Studio (VSTO). He also shows how to finely control the way your custom ribbons load, as well as how to eliminate references to the Utilities assembly. Check it out:
Channel 9 Interview: Office Add-in (VSTO) Performance Tips & Tricks
For more information, see his blog post: VSTO Performance: Ribbon Reflection
Enjoy, -Beth Massi, Visual Studio Community
A customer on the VSTO forums recently noticed that the steps we blogged about for sharing a single Ribbon customization between multiple projects in Visual Studio 2008 no longer works in Visual Studio 2010. When following the instructions in the blog post, you get an error when you try to open the Ribbon code file in the class library project. This is because of some changes to the way the Ribbon designer was implemented in Visual Studio 2010. The upshot is that you can no longer open the Ribbon designer outside of Office projects. In addition, because Office projects that target the .NET Framework 4 have a different programming model in Visual Studio 2010, the instructions in the old blog post will also result in other errors in projects that target the .NET Framework 4.
This blog post tells you how to share a single Ribbon customization (created by using the Ribbon designer) between multiple Office projects in Visual Studio 2010. Disclaimer – what I am about to show you in this blog post is not supported, and has not been officially tested by the product team in any way.
If your Office projects target the .NET Framework 3.5, then the instructions in the old blog post still apply, with just one change. Rather than design your Ribbon customization in the class library project, now you must design it in an Office project, because of the change to the implementation of the Ribbon designer noted above. Here are the modified instructions.
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject(){ return new Microsoft.Office.Tools.Ribbon.RibbonManager( new Microsoft.Office.Tools.Ribbon.OfficeRibbon[] { new SharedRibbonLibrary.Ribbon1() });}
partial class ThisRibbonCollection : Microsoft.Office.Tools.Ribbon.RibbonReadOnlyCollection{ internal SharedRibbonLibrary.Ribbon1 Ribbon1 { get { return this.GetRibbon<SharedRibbonLibrary.Ribbon1>(); } }}
private void ThisAddIn_Startup(object sender, System.EventArgs e){ Globals.Ribbons.Ribbon1.button1.Click += new EventHandler<Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs>(button1_Click);}void button1_Click(object sender, Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs e){ System.Windows.Forms.MessageBox.Show("it works!");}
If your Office projects target the .NET Framework 4, you’ll need to make a number of other changes to the Ribbon code. Here are the full instructions.
public Ribbon1(Microsoft.Office.Tools.Ribbon.RibbonFactory factory) : base(factory){ InitializeComponent();}
protected override Microsoft.Office.Tools.Ribbon.IRibbonExtension[] CreateRibbonObjects(){ return new Microsoft.Office.Tools.Ribbon.IRibbonExtension[] { new SharedRibbonLibrary.Ribbon1(Globals.Factory.GetRibbonFactory()) };}
private void ThisAddIn_Startup(object sender, System.EventArgs e){ Globals.Ribbons.Ribbon1.button1.Click += new Microsoft.Office.Tools.Ribbon.RibbonControlEventHandler(button1_Click);}void button1_Click(object sender, Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs e){ System.Windows.Forms.MessageBox.Show("it works!");}
We are happy to announce that today we are releasing the Open XML Package Editor Power Tool for Visual Studio 2010 on Visual Studio Gallery. This Power Tool is a Visual Studio add-in that provides an easy way to parse and edit Open Packaging Conventions files, including Word, Excel and PowerPoint documents. This Power Tool enables you to do the following tasks:
This Power Tool was originally shipped for Visual Studio 2008 as part of VSTO Power Tools v1.0.0.0. This new version for Visual Studio 2010 contains all the original features from the previous version and it works the same.
Figure 1 shows the tree view that is provided when you open an Open XML Package file in Visual Studio.
Figure 1 – Open XML Package treeview in Visual Studio
When you double-click on any XML part in the file that is open in the tree view, that part is opened in the standard Visual Studio XML editor, as shown in Figure 2.
Figure 2 - XML part open in the Visual Studio XML editor
The Open XML Package Editor Power Tool for Visual Studio 2010 is available for download at Visual Studio Gallery
We have helped many developers in troubleshooting VSTO add-in load failures. Hamed has written a very nice blog post explaining the basic steps to troubleshoot VSTO add-in load failures. Even if you have not faced this issue yet, I recommend reading the post because it contains basic information about Office add-ins that developers should know.
Although every scenario is unique to itself; there are some common diagnostic steps that are repeated for every investigation. This PowerShell script complements Hamed’s blog and automates the troubleshooting steps; you may find it useful.
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:
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; }}
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
It is very easy to customize the Ribbon in your VSTO extension. All you need to do is to add a Ribbon (Visual Designer) to your solution, and it will appear when your solution is run without needing to do any more work. Behind the scenes, the VSTO runtime reflects through your entire addin assembly looking for Ribbon extensions to instantiate. This reflection can cause a significant performance hit, especially on larger solutions.
During an addin’s startup, the VSTO Runtime needs to discover and instantiate any user-created Ribbon extensions. The runtime does this by calling CreateRibbonExtensibilityObject, which is implemented by VSTO in the addin base class. It will then call CreateRibbonObjects, another method on the addin base class. This implementation of CreateRibbonObjects will reflect over every type in the addin assembly looking for classes that implement Microsoft.Office.Tools.Ribbon.IRibbonExtension (4.0) or Microsoft.Office.Tools.Ribbon.OfficeRibbon (3.5), instantiating each one, and then returns these in an array.
The performance hit comes from the reflection that happens in CreateRibbonObjects. For simple VSTO addins, this isn’t very significant. But if you link in a large library, then the reflector will pull in any types referenced in your assembly, and any types that those types reference, and so forth. This can result in having to spend a lot of time reading these types from disk, and it is completely unavoidable.
In order to avoid this, we can override either of these two methods so that the default implementation of CreateRibbonObjects is not called. If the addin has no ribbons, then it’s best to override CreateRibbonExtensibilityObject in order to execute as little code as possible.
protected override Office.IRibbonExtensibility CreateRibbonExtensibilityObject() { return null; }
If your addin includes a Ribbon, then it’s better to override CreateRibbonObjects. Note that if you are creating an addin for .Net 3.5, you’ll need to return OfficeRibbon[] instead of IRibbonExtension[].
using Microsoft.Office.Tools.Ribbon;
protected override IRibbonExtension[] CreateRibbonObjects() { return new IRibbonExtension[] { new Ribbon1(), new Ribbon2() }; }
In our perf lab, we ran some benchmarks using the method described in this blog entry to generate the numbers. Of interest were two tests involving an Outlook addin that had a Form Region with a single WPF control, before and after removing the Ribbon reflection. The results were that removing reflection saved over a second off of the cold startup time. So if you have larger VSTO solutions you may want to try to this technique to speed up performance.
Now that Visual Studio 2010 is released, some of you might be itching to upgrade your existing VSTO projects so that you can take advantage of the new features in the .NET Framework 4 that improve the Office development experience. Or, you might have already started using Visual Studio 2010 to develop a VSTO project targets the .NET Framework 3.5, and now you want to switch over to the .NET Framework 4. The purpose of this post is to shed some light on scenarios where retargeting a VSTO project to the .NET Framework 4 can cause compile or run time errors in your project, and how to resolve these errors. Retargeting a VSTO project to the .NET Framework 4 is pretty straightforward. If you created your project in Visual Studio 2010, you can retarget the project in the project properties by following the instructions here. If you are upgrading an existing project to Visual Studio 2010, you can choose to have the upgraded project target the .NET Framework 4 if the .NET Framework 3.5 is not installed on the computer; otherwise, you can always retarget it in the project properties later. For more information, see the “Retargeting During Project Upgrade” section in this blog post. After you retarget your VSTO project, in many cases your work is done and you can jump right in and start writing code. However, for some projects – including any project that uses the Ribbon designer, any Outlook project that has a form region, and Excel and Word projects that use certain features such as smart tags and the GetVstoObject/HasVstoObject methods – you will get compile errors after you retarget the project, or the add-in might no longer run. In these scenarios, you must make some additional changes to your code. For the full list of scenarios that require code changes along with examples of the required changes, see the following MSDN articles: Required Changes to Run Office Projects that You Migrate to the .NET Framework 4 Updating Excel and Word Projects that You Migrate to the .NET Framework 4 Updating Ribbon Customizations in Office Projects that You Migrate to the .NET Framework 4 Updating Form Regions in Outlook Projects that You Migrate to the .NET Framework 4 For step-by-step tutorials and “How do I?” videos that demonstrate several specific retargeting scenarios, see the following links: How Do I: Retarget an Outlook Add-In from .NET Framework 3.5 to .NET Framework 4? How Do I: Retarget a Word 2007 Add-In from .NET Framework 3.5 to .NET Framework 4? Migrating an Outlook Client to .NET Framework 4 in Visual Studio 2010 (Beth Massi). Background When the VSTO team implemented support for the new “embedded interop types” feature (also sometimes referred to as “no-PIA”) of the .NET Framework 4, they had to also make some changes to the programming model of certain VSTO runtime features. For example, because the embedded interop types feature works only with interfaces, most types in the portion of the VSTO runtime that supports the .NET Framework 4 are now interfaces rather than classes. These and other changes have a trickle-down effect on some of the generated code and developer-written code in VSTO projects, and therefore require some manual code changes after you retarget a project. If you’re interested in reading more about the embedded interop types feature in the .NET Framework 4 and the changes to the design of the Visual Studio 2010 Tools for Office runtime to support this feature, the following MSDN articles and blog posts. Blog posts: Design of VSTO 2010 runtime (Misha Shneerson) VSTO 2010 Runtime components explained (Aaron Cathcart) Why Should I Upgrade from .Net Framework 3.5 to .Net Framework 4? (Navneet Gupta) Upgrading VSTO Projects to use with Visual Studio 2010 (Navneet Gupta) MSDN articles: Changes to the Design of Office Projects that Target the .NET Framework 4 Visual Studio Tools for Office Runtime Overview Designing and Creating Office Solutions
Now that Visual Studio 2010 is released, some of you might be itching to upgrade your existing VSTO projects so that you can take advantage of the new features in the .NET Framework 4 that improve the Office development experience. Or, you might have already started using Visual Studio 2010 to develop a VSTO project targets the .NET Framework 3.5, and now you want to switch over to the .NET Framework 4. The purpose of this post is to shed some light on scenarios where retargeting a VSTO project to the .NET Framework 4 can cause compile or run time errors in your project, and how to resolve these errors.
Retargeting a VSTO project to the .NET Framework 4 is pretty straightforward. If you created your project in Visual Studio 2010, you can retarget the project in the project properties by following the instructions here. If you are upgrading an existing project to Visual Studio 2010, you can choose to have the upgraded project target the .NET Framework 4 if the .NET Framework 3.5 is not installed on the computer; otherwise, you can always retarget it in the project properties later. For more information, see the “Retargeting During Project Upgrade” section in this blog post.
After you retarget your VSTO project, in many cases your work is done and you can jump right in and start writing code. However, for some projects – including any project that uses the Ribbon designer, any Outlook project that has a form region, and Excel and Word projects that use certain features such as smart tags and the GetVstoObject/HasVstoObject methods – you will get compile errors after you retarget the project, or the add-in might no longer run. In these scenarios, you must make some additional changes to your code. For the full list of scenarios that require code changes along with examples of the required changes, see the following MSDN articles:
For step-by-step tutorials and “How do I?” videos that demonstrate several specific retargeting scenarios, see the following links:
When the VSTO team implemented support for the new “embedded interop types” feature (also sometimes referred to as “no-PIA”) of the .NET Framework 4, they had to also make some changes to the programming model of certain VSTO runtime features. For example, because the embedded interop types feature works only with interfaces, most types in the portion of the VSTO runtime that supports the .NET Framework 4 are now interfaces rather than classes. These and other changes have a trickle-down effect on some of the generated code and developer-written code in VSTO projects, and therefore require some manual code changes after you retarget a project.
If you’re interested in reading more about the embedded interop types feature in the .NET Framework 4 and the changes to the design of the Visual Studio 2010 Tools for Office runtime to support this feature, the following MSDN articles and blog posts.
Blog posts:
MSDN articles: