Version-Specific UI in Add-ins


Continuing on from my earlier posts on building add-ins for multiple versions of Office, avoiding the PIA version conflict, and add-ins for multiple versions without PIAs, a reasonable way to design your solution would be to use the lowest-common-denominator PIAs (let’s say, the Office 2003 PIAs) and then use ComImports for any additional features introduced in later versions of Office. This way, you avoid having to declare ComImports for the vast majority of the Office and Office app object models, since you can generally rely on Office maintaining close to 100% backward compatibility within the core features. The changes in the Office OMs, as new versions are released, tend to be almost completely additive.


This model also means that even though you reference say the Office 2003 PIAs in your solution at design-time, when it comes to runtime, your add-in will run against whatever PIAs are registered on the machine. In other words, you can expect that on an Office 2003 machine, your add-in will run with the Office 2003 PIAs – and on an Office 2007 machine, your add-in will run with the Office 2007 PIAs. This is, of course, exactly the behavior you want. Moreover, it doesn’t require you to stray into unsupported territory by deploying multiple PIA versions on a machine with only one Office version, or building an Office 2003 add-in that references the Office 2007 PIAs, or any other dodgy behavior.


I’m attaching the sample solution to this post, and here’s what it looks like in VS:




As you can see, I have 3 projects:


          An Excel 2003 add-in.


          A class library that implements Office 2003 UI (CommandBar-based features), and that references the Office 2003 PIA.


          A class library that implements Office 2007 UI (custom task pane and Ribbon-based), and that does NOT reference the Office PIA, but instead uses ComImports to declare the Office interfaces I’m using (ICustomTaskPaneConsumer, IRibbonExtensibility, etc).


Here’s how they fit together:




As before, the ThisAddIn class is split into 4 partial classes:


          The “hidden” wizard-generated part of the partial class (in ThisAddIn.designer.cs), that you don’t normally want to edit.


          The usual “visible” part of the class (in ThisAddIn.cs). In this example, this contains code commonly shared regardless of Office version, specifically the Startup and Shutdown behavior.


          A part of the class containing code specific to Office 2003 (in ThisAddIn2003.cs). This uses the Ui2003 class library to implement custom CommandBar-based UI.


          A part of the class containing code specific to Office 2007 (in ThisAddIn2007.cs). This uses the Ui2007 class library to implement custom task pane and Ribbon UI.


 


When the add-in is loaded, in ThisAddIn_Startup, it checks to see which version of the Office host it is running in: if it’s running in Office 2003, it branches out to initialize the CommandBar-based UI.


private void ThisAddIn_Startup(object sender, System.EventArgs e)


{


    // 2003: If we’re running in 2003, setup a custom commandbar menu.


    if (Application.Version == “11.0”)


    {


        Initialize2003Ui();


    }


}  


 


The part of the partial class in ThisAddIn2007.cs contains an override of RequestService, which will not be called in Office 2003. Therefore, if RequestService is called, we can assume we’re running in Office 2007 (or later), and can therefore set up custom task pane and Ribbon UI.


So, the solution only references one version of the Office PIAs (the LCD version), and uses ComImport declarations for the OM features that are not in that version. Then, at runtime, the correct version of the PIAs are loaded that match the running version of Office. I could take this further, and dispense with the PIAs altogether, using ComImports for everything – but that’s normally unnecessary, as you can generally rely on  the PIAs being installed, or you can pre-req them as part of the install for your solution. Plus, I don’t really want to re-declare vast tracts of the Office OM unless I really have to. This model provides an optimal solution: using the PIAs for the core Office behavior that does not change between versions, and using ComImports for the additional features added in later versions.

VersionedUI.zip

Comments (7)

  1. Matt Davis says:

    This is pretty similar to the way I built multi-version managed Office add-ins for years- it works great with one caveat: There are a few methods on some dual interfaces that can’t be ComImport declared in C#. There are one or two in Office (and numerous cases in non-Office interfaces- take a look at StdOle.IPicture, for instance) where a vtable interface can’t be correctly expressed in C# because a prop-get and prop-set for a particular property aren’t in consecutive order in the IDL (this is also why they should be defined directly from the IDL, not from MSDN’s watered-down interface descriptions). This isn’t a problem if you call the dispatch side of the interface, but if you call the vtable side and there’s a mismatch (eg, arg/return value difference), you can corrupt the stack and the process usually just goes poof. No Watson, no error report, just poof. If the args and return value byte counts work out the same, you’ll just get really odd behavior when it tries to marshal the args back in. tlbimp.exe gets around this by generating directly to IL, which allows the more expressive out-of-order declaration. In cases where I’ve needed that, I usually just do the declaration in IL and build to a netmodule, then link that into my assembly.

  2. Tom B says:

    Matt, what are the other dual interfaces (Office and non-Office) you’ve found to be problematic in this way besides StdOle.IPicture?

  3. satya says:

    Hi Andrew

    would you Please provide us the sample solution  code for this project.

    Thanks

    Satya Prakash.

  4. andreww says:

    satya – the code is attached to the post (VersionedUI.zip).

  5. In my last post , I looked briefly at MEF, and I’m wondering how this model can be applied to Office

  6. Vadim says:

    Hi Andrew !

    I see that in your VersionedUI project you reference Office2007 libraries (Microsoft.Office.Interop.Excel v12, Microsoft.Office.Tools.v9.0, office v12, etc).

    I understood from your article that I need change them to Office2003 libraries, but when I tried to do this, I discovered that on my computer I have only Office2007 version of Microsoft.VisualStudio.Tools.Office (v9) and no v8 version.

    Please advise.

    Thanks,

    Vadim.

  7. andreww says:

    Vadim – If you’re building a VSTO solution with VS 2008, you should have both Office 2003 and 2007 PIAs – they are installed in a location like this:

    C:Program FilesMicrosoft Visual Studio 9.0Visual Studio Tools for OfficePIAOffice11(12)