Saturday, August 06, 2005

.NET add-ins for both Office 2000 and XP/2003

My current project is implementing MSCRM and SharePoint with some enhancements such as archive documents and e-mails directly from Office/Outlook to SharePoint document archives integrated into the MSCRM account, contact and case modules. The enhancements are Office add-ins .NET components that we deliver as part of our MSCRM and/or SharePoint projects. The add-ins were implemented with the Office XP PIAs and as such support only Office XP and 2003 (version 10.x and 11.x) out-of-the-box.

This customer unfortunately has Office 2000 and Outlook 2000 (version 9.x), and has no money or willingness to upgrade to Office 2003. Thus, I had to figure out how to make the .NET add-ins support Office 2000. It turned out that this is actually quite possible, following these guidelines:

  • Use the Office XP PIAs, always install them to GAC (download from MSDN)
  • Use the Office object model interfaces, not the classes
  • Implement version switch code whenever Office 9 methods have different signatures than Office 10/11
  • Use .NET reflection and .GetType().InvokeMember(...) to call the Office 9 methods that are different from Office 10/11
Microsoft provides no PIAs for Office 2000, only for Office XP and for Office 2003.

The Office object model provides you with both interfaces and classes, typically in pairs. E.g. Application/ApplicationClass, Document/DocumentClass, MailItem/MailItemClass. Always declare your object references using the interface, not the class. The class is version specific, and you might get cast errors when your add-in runs on a different Office version.

Some methods have different number of parameters in Office 2000 than in XP/2003. This applies e.g. to Word.Documents.Open(...) and Word.Document.SaveAs(...). Thus, you cannot use these methods directly in your code as it will cause run-time errors when loaded in e.g. Word 2000. Note that the code will compile OK, afterall the code references the Office XP PIAs. Your code must check the version number at run-time and switch between calling the Office XP/2003 or the Office 2000 methods.

To be able to call some of the Office 2000 methods from your code, you must use .NET reflection to call the methods using .InvokeMember(...), which is similar to COM "late binding". The code will look like this:

string version = this._application.version;
if(version.StartsWith("9."))
{
Object[] params = new Object[]{fileUrl, Type.Missing, ...};
doc.GetType().InvokeMember("SaveAs", BindingFlags. InvokeMethod, null, doc, params);
}
else
{
doc.SaveAs(fileUrl, ref param1, ref param2, ...);
}

Deploying at this customer also required some changes to our installers. The .NET 1.1 add-ins (not VSTO 2005 add-ins) read settings from our Objectware.OfficeAddin.dll.config file which has to be installed to the Office executable folder, which differs between the versions:

C:\program files\microsoft office\
plus the applicable folder office\ or office10\ or office11\

In addition, this customer runs both Windows XP and Windows 2000, which requires the add-in registry settings to be modified to refer to the correct location of MSCorEE.DLL:

C:\winNT\system32\MSCorEE.DLL for Win2000Pro
C:\windows\system32\MSCorEE.DLL for WinXPPro

A final issue about using .NET web-services in your Office add-in: if the web-service uses serializable objects as parameters in the WSDL, the .NET framework will try to auto-generate and -compile classes for these objects on the client side at run-time. As your add-in runs within the Office process, this will most likely cause hard to track and resolve exceptions. I recommend using only basic .NET value types and array types (e.g. ArrayList) in any web-service that is to be consumed by an Office add-in.

Office 2000 object model reference at MSDN.
Office XP object model reference at MSDN.
Office 2003 object model reference at MSDN.
(Navigate to the VBA language reference using the treeview if the link does not)

4 comments:

Anonymous said...

Another option for Office 2000 - David Thielen has a set of PIAs for Word 2000 at http://dave.thielen.com/articles/Word2000_PIAs.zip

Anonymous said...

I also sent you an e-mail, I wrote about using the Office 2003 PIAs there. By now I found out some more things and I figured that the solution might be of use to others as well. I hope that you don't mind.

I can get this to work on my development machine (Windows XP, Visual Studio 2008, Office 2003 and 2000), but I cannot get it to work on a machine with just Office 2000.

The machine I need it to run on has Windows 2000, Office 2000 and versions 1.1 and 2.0 of the .Net framework. I installed the Office XP PIAs and they are indeed correctly placed into the GAC.

I made a simple .Net 2.0 app that starts Excel upon the push of a button. With only Excel 2000 on the machine starting Excel from managed code throws an exception:

System.InvalidCastException: Unable to cast COM object of type 'Microsoft.Office.Interop.Excel.ApplicationClass' to interface type 'Microsoft.Office.Interop.Excel._Application'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{000208D5-0000-0000-C000-000000000046}' failed due to the following error: Library not registered. (Exception from HRESULT: 0x8002801D (TYPE_E_LIBNOTREGISTERED)).

When I install Excel 2003 on the machine the button starts Excel 2003 just nicely. When I remove Excel 2003 the exception pops up again.

When I install Excel 2003 first and then Excel 2000 Excel 2000 is succesfully started from the application. It keeps working even when I remove Excel 2003 again afterwards.

Would you happen to know a way to get this to work on Office 2000 without the need to install Office 2003 anywhere in the process? I figure it kind of defeats the purpose of using PIAs with Office 2000 if this is not possible...

Thanks in advance.

Kjell-Sverre Jerijærvi said...

After 3,5 years, I have no clue, sorry. Try the Office 2000 PIAs provided by David Thielen, link in the first comment.

Anonymous said...

I "solved" it by making registry snapshots before and after the steps I mentioned. I had a diff reg file generated and merging this reg file into the registry of a computer with Office 2000 and the Office XP PIAs installed does the trick.

I probably should slim down the reg file a bit though, it generates an error now, quite awkward.

But still, I now can use Excel 2000 from .NET and that's what counts :) .