Programming for Outlook using managed code is hard

Background

Programming for Outlook using managed code is hard. I take that back. Programming for Outlook is relatively easy if you can figure out where to stick your code. Working out the problems you’ll encounter is hard (and I’m still working on them). I’ll try and give you some best practices. There will actually be some follow up to this specifically on:

  1. How to keep your objects from going out of scope
  2. How to prevent the dreaded security pop-up in Outlook from appearing.

You aren't the only managed add-in

The hardest part to getting your addin to work is to be enlightened. You see, your add-in may work very well if it's the only add-in installed. However, if there are any other add-ins installed, and there are many excellent add-ins, your add-in may fail to load. Some of the reasons your add-in may fail to load are:

  1. Another add-in is installing the Office 2003 Primary Interop Assemblies in their own application directory.
  2. Another add-in is using a private version of the Office XP Primary Interop Assemblies that conflicts with the version that you are loading. Depending on an number of factors, your assumption that the set of assemblies you targeted will not be loaded.
  3. Another add-in installed a version of the Office PIAs in the GAC that are incompatible with yours, or, are getting loaded in place of the assemblies you targeted.
  4. Another add-in is calling Release COM Object and you are getting hosed (see https://blogs.officezealot.com/whitechapel/ for even more info on the subject).
  5. Some other reason that I am sure exists and I am not aware of.

You have no control

So, given these things it seems to me that it's really difficult to have a lot of control over your deployment given the eco system for managed add-ins out there. Bottom line, other products and add-ins can invariable affect you whether you like it or not. The only sure way to protect yourself is to implement a shim as outlined in this article. I've forgone the shim route because I find it overly complicated and to me it taints the whole .NET developer experience I've grown to love. Everything else is so darn simple and elegant why does this have to be so hard? That article is about 14 pages and the other 15 pages of reading to get your own AppDomain. Not to mention C++ code (I don't do C++). It's wonderful that we publish a documentation on how to get your own AppDomain but I don't currently know what my own AppDomain will buy me.

However, even if you go the shim route, there is nothing preventing another application from messing with the Interop Assemblies and horking your assumptions about what you've targeted.

Office XP PIAs, Office 2003 PIAs Oh My!

To make things even more complicated, you are only supposed to use the Office 2003 PIAs for Office 2003, and the XP PIAs for Office 2000 and Office XP. If you read this article, you'll find this statement:

"Microsoft does not guarantee that the Office PIAs will be backwardly compatible or that the Office XP PIAs and the Office 2003 PIAs can be run side-by-side in the same instance of an Office application. Office XP managed code add-ins must be built against the Office XP PIAs. The Office 2003 managed code add-ins must be built against the Office 2003 PIAs. Therefore, if you build an add-in solution that you intend to use with both versions of Office, Microsoft recommends that you build a version of your add-in for each version of Office that you intend to support."

So, what this basically means to me is that if my add-in fails to load because I'm using the Office 2003 PIAs and Application Y is using the Office XP PIAs, my only recourse is to convince the developer of Application Y to stop doing this. Meanwhile the developer of Application Y is like, huh? You mean I have to target and test against two different versions of the PIAs for 3 different versions of Office? And to make matters worse, it's actually more like Developer A, B, C, D, E, F and G and so on. From what I can tell there are very few add-ins that target or install the Office 2003 PIAs... although I know of at least two. Finally it seems that if one add-in loads the 2003 PIAs and one loads the XP PIAs bad things can happen.

I started building my add-in by creating the Shared Add-in project in VS.NET 2003. By default, if you are using Office 2003, the PIAs will get added to your setup and installed in your App directory. This is a No-No and to make matters worse, you can really mess things up for other add-ins when your add-in is uninstalled. When I stopped installing the PIAs (after a few dozen people installed my add-in) problems started to ensue. I spent many days with Kent Compton as my willing guinea pig tracking down (Thanks Kent!). I also spent some time discussing this with many fine folks who work on this stuff in Office. The end result was that the only way I could get Kent's issues resolved (as well as some I was having) was to remove my dependency on the Office 2003 PIAs and instead rely on the Office XP PIAs (I found this out after 40 or so hours of trial and error and lots of head scratching as well as some conversations I've had with Mike who works on Lookout). So far (knock on wood) this works well for him and I'm able to use Lookout, and Newsgator without any problems. However, this solution is not a silver bullet and not something I plan on doing long term. I will go the shim route and load my add-in into it's own AppDomain and link to the Office 2003 PIAs.

What to do?

So where does this leave the managed Office add-in developer? I just close my eyes and hope for the best. To me the managed add-in eco system is a bit like a public swimming pool. There are a set of posted rules, but there is no one really there to "police" the rules being enforced... anyone can swim in the pool and not everyone will be barred from entering the pool because they didn't shower before hand. This is a far cry from doing Windows Forms programming or ASP.NET development.

How it should work

Based on what I've learned, and my limited knowledge of COM and the Office Object Model, if I could change this here is what I would do:

  1. Give each add-in it's own AppDomain
  2. Ship a set of PIAs for Office that go into the GAC during the default installation that work against Office 2000, Office XP and Office 2003 (as well as the next version of Office). Don't make me worry about installing any necessary Interop Assemblies or what version of Office is installed.
  3. Make this as easy as developing a Windows Forms app, Class library or Console App.
  4. Add better intellisense for the Office properties, methods, and classes (as well as integrated VS.NET help) - I just had to throw this one in there ;-).

Why this matters to me

You may wonder why I care about all this stuff. Well I am working on an Add-in for OneNote called Outlook2OneNote. This add-in will allow you to copy items from Outlook such as e-mail, notes and post items into OneNote for annotating and archiving or whatever. I am also working on a simple Office Button SDK with Dan Crevier that will allow you to easily create buttons, popup buttons and combo boxes in Office toolbars that react to the Click event allowing you to do all sorts of nifty things.

BTW, here are a list of managed Outlook Add-ins that I know of:

  • Newsgator - RSS Aggregator
    • Office XP PIA installed in GAC (thanks for the correction Greg!)
  • DataLens - nifty calendar view
    • Office 2003 PIA installed in GAC
  • Tablet Enhancement Pack for Outlook - use your pen to create tasks, appointments and contacts
    • Office 2003 PIA not installed in GAC
  • Lookout - fast search tool for Outlook
    • Latest version: Office XP PIA installed in GAC
    • Current version: Office XP PIA not installed in GAC

I have a few more things to try to feel sure that my add-in will work in the real world. Preliminary results indicate that ditching the Office 2003 PIA for the XP PIA was the ticket, but I have something else to try before I can be confident. Also, I've had cases where things worked, failed and then worked on my own machine and I don't have any explanation for why. I'm going to have to mess around with Virtual PC to test out some theories of mine as my current machines aren't good "testing" environments any more!

update: while using the Office XP Interop Assemblies seemed like a silver bullet, it's not the "right solution". The right solution is to use the 2003 PIAs and write a Shim that will give me my own AppDomain and insulate me from other add-ins. See this post on the my thoughts on creating and using a Shim for Outlook2OneNote.