Office Development with Visual Studio

Develop Office Business Applications using Visual Studio

June, 2010

Posts
  • Office Development with Visual Studio

    Channel 9 Interview: Office Add-in (VSTO) Performance Tips & Tricks (Beth Massi, Stephen Peters)

    • 3 Comments

    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

  • Office Development with Visual Studio

    Sharing a Ribbon Customization Between Office Projects in Visual Studio 2010 (McLean Schofield)

    • 1 Comments

    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.

    Targeting the .NET Framework 3.5

    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.

    1. In Visual Studio, open (or create) an Office project that targets the .NET Framework 3.5, and that targets an Office application that supports the Ribbon.
    2. Add a Ribbon (Visual Designer) item to the project.
    3. Design your Ribbon customization. Be sure to set the Modifiers property to Public for any controls/tabs/groups that you want to be able to access in other Office projects. Also be sure to set the RibbonType property of the Ribbon to all Ribbon types you want to support in other Office projects that consume the shared Ribbon. For example, if you want to use the Ribbon customization in Excel and Word projects, set RibbonType to Microsoft.Excel.Workbook and Microsoft.Word.Document.
    4. Save your changes.
    5. Create a class library project that targets the .NET Framework 3.5. Add the following reference:
      • Microsoft.Office.Tools.Common.v9.0
    6. Add the existing Ribbon code file to the class library project. The code-behind file (for example, Ribbon1.Designer.cs) will be copied over automatically.
    7. Optionally, open the Ribbon file and the code-behind file in the editor and change the namespaces for the Ribbon class in the main Ribbon file and code-behind file (for example, to SharedRibbonLibrary or some other namespace that identifies your component). Be sure to open the files in the editor by right-clicking them and choosing View Code. Do not double-click the files; this will attempt to open the Ribbon designer, and will result in a designer error.
    8. Build the class library project.
    9. In a new/different Office project that targets the .NET Framework 3.5, add a reference to the class library project.
    10. In the ThisAddIn, ThisDocument, or ThisWorkbook class in the Office project, override CreateRibbonObjects as follows (the following code assumes you changed the namespace of the shared Ribbon to SharedRibbonLibrary).
      protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
      {
      return new Microsoft.Office.Tools.Ribbon.RibbonManager(
      new Microsoft.Office.Tools.Ribbon.OfficeRibbon[] {
      new SharedRibbonLibrary.Ribbon1() });
      }

    11. Add the following class to the project. This code lets you access the shared Ribbon customization by using Globals.Ribbons in your code.
      partial class ThisRibbonCollection : Microsoft.Office.Tools.Ribbon.RibbonReadOnlyCollection
      {
      internal SharedRibbonLibrary.Ribbon1 Ribbon1
      {
      get { return this.GetRibbon<SharedRibbonLibrary.Ribbon1>(); }
      }
      }

    12. Now you can use Globals.Ribbons.Ribbon1 to access public items exposed by the shared Ribbon. For example:
      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!");
      }


    Targeting the .NET Framework 4

    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.

    1. In Visual Studio, open (or create) an Office project that targets the .NET Framework 4, and that targets an Office application that supports the Ribbon.
    2. Add a Ribbon (Visual Designer) item to the project.
    3. Design your Ribbon customization. Be sure to set the Modifiers property to Public for any controls/tabs/groups that you want to be able to access in other Office projects. Also be sure to set the RibbonType property of the Ribbon to all Ribbon types you want to support in other Office projects that consume the shared Ribbon. For example, if you want to use the Ribbon customization in Excel and Word projects, set RibbonType to Microsoft.Excel.Workbook and Microsoft.Word.Document.
    4. Save your changes.
    5. Create a class library project that targets the .NET Framework 4. Add the following references:
      • Microsoft.Office.Tools
      • Microsoft.Office.Tools.Common
      • Microsoft.Office.Tools.Common.v4.0.Utilities
    6. Add the existing Ribbon code file to the class library project. The code-behind file (for example, Ribbon1.Designer.cs) will be copied over automatically.
    7. Open the Ribbon file and code-behind file in the code editor by right-clicking them and choosing View Code. Do not double-click the files; this will attempt to open the Ribbon designer, and will result in a designer error.
    8. In the Ribbon code-behind file, change the constructor to the following.
      public Ribbon1(Microsoft.Office.Tools.Ribbon.RibbonFactory factory)

      : base(factory)

      {

      InitializeComponent();

      }

    9. In Ribbon code-behind file, remove the ThisRibbonCollection class definition at the bottom of the file. 
    10. Optionally, change the namespaces for the Ribbon class in the main Ribbon file and code-behind file (for example, to SharedRibbonLibrary or some other namespace that identifies your component).
    11. Build the class library project.
    12. In a new/different Office project that targets the .NET Framework 4, add a reference to the class library project.
    13. In the ThisAddIn, ThisDocument, or ThisWorkbook class in the Office project, override CreateRibbonObjects as follows (the following code assumes you changed the namespace of the shared Ribbon to SharedRibbonLibrary).
      protected override Microsoft.Office.Tools.Ribbon.IRibbonExtension[] CreateRibbonObjects()

      {

      return new Microsoft.Office.Tools.Ribbon.IRibbonExtension[] { new

      SharedRibbonLibrary.Ribbon1(Globals.Factory.GetRibbonFactory()) };

      }

    14. Add the following class to the project. This code lets you access the shared Ribbon customization by using Globals.Ribbons in your code.
      partial class ThisRibbonCollection : Microsoft.Office.Tools.Ribbon.RibbonReadOnlyCollection

      {

      internal SharedRibbonLibrary.Ribbon1 Ribbon1

      {

      get { return this.GetRibbon<SharedRibbonLibrary.Ribbon1>(); }

      }

      }


    15. Now you can use Globals.Ribbons.Ribbon1 to access public items exposed by the shared Ribbon. For example:
      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!");
      }

  • Office Development with Visual Studio

    Open XML Package Editor Power Tool for Visual Studio 2010 (Navneet Gupta)

    • 2 Comments

    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:

    • Open any Open XML Package file or XPS Package file directly in Visual Studio 2010.
    • Browse the contents of Package files in a tree view.
    • Open any XML part directly in Visual Studio's rich XML editor.
    • Add or remove parts and relationships directly in the user interface.
    • Import and export part contents to and from files.
    • Detect when a Package file that is opened in Visual Studio is modified externally. The Power Tool prompts user to reload the file without having to close any open XML part editors.
    • Create new Office Packages from a set of templates using Visual Studio's File > New dialog.

    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.

    image

     

    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.

    image

    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

  • Office Development with Visual Studio

    Troubleshoot VSTO Add-In Load Failures (Navneet Gupta)

    • 3 Comments

    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.

  • Office Development with Visual Studio

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

    • 8 Comments

    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

  • Office Development with Visual Studio

    VSTO Performance: Ribbon Reflection (Stephen Peters)

    • 4 Comments

    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.

  • Office Development with Visual Studio

    Fixing Compile and Run Time Errors after Retargeting VSTO Projects to the .NET Framework 4 (McLean Schofield)

    • 0 Comments

    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:

    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:

    MSDN articles:

Page 1 of 1 (7 items)