Rude Operator

If you are automating Outlook in a standalone application or other app outside of Outlook and have trouble on some machines with your CreateObject call succeeding when Outlook is not already running, this article may be for you.

Have you ever called someone only to be put on hold as soon as they answer? Do you hang up immediately, or do you hold on for a few minutes to see if they pick up? If you’ve ever ordered a pizza where I order mine, I know you’ve experienced this. Well, it turns out, Outlook [or any Office application for that matter] acts just like this rude operator. When you try to automate Outlook, the Outlook.exe process has to be running in order to serve your requests. Outlook is what’s called a COM server. So your call to CreateObject (or "new”) makes a call into the COM subsystem which does the work of spinning up an instance of Outlook for you to work from using the –Embedding switch which tells Outlook not to display any UI by default. Part of Outlook’s start up logic involves loading all the COM add-ins and calling into the OnConnect and OnStartupComplete events. This is where things could go badly for you.

If your user is an comaddinophile they may have some add-ins installed that take a looooooong time to load. They may be calling into a database or a webservice or just have really poor code that takes a long time to execute. Outlook does all this work on its main thread – they aren’t spun off to a background thread – so all the time it takes for these add-ins to load and run is time the COM subsystem is spending growing very impatient. It can, after a while, just time out or it could succeed the initial load, but if Outlook is busy handling other requests your call to get the Application dispatch object could be actively refused because Outlook is blocking. In these cases, you could end up with a RPC_E_SERVERCALL_RETRYLATER error bubbling up in your .net automation code. The error you get will be something like “Call was rejected by callee.”

Oftentimes, you can follow up your failed CreateObject call with a second one and it succeeds because at this time Outlook.exe is running and may be unblocked and ready to service your request. However, it may just block again. In these cases, you will need to implement an IMessageFilter to be able to tell the COM subsystem that you’re ok waiting and to keep retrying your call until it succeeds or you get a different error.

The best sample I found for this was describing implementing this to solve this same problem when doing Visual Studio automation, but the same logic applies. Andrew Whitechapel wrote a sample also. In his case he was describing a similar problem when you try to make object model calls on a background thread from an add-in. Here’s a VB.NET sample I wrote.