Andrei Smolin

On using threads in managed Office extensions

Briefly: There are cases when using threads in your .NET-based Office add-in is okay; but in the general case, using threads isn’t recommended.

Consider a typical Outlook add-in scanning a lot of e-mails which should not prevent a user from working with the Outlook UI (the UI always runs in the main thread). An obvious solution is to move the scanning process to a thread. But…

Calling the Outlook object model in a thread is a wrong solution because the object model is almost not thread-safe. Almost? Well, yes, almost[i], but that means “always” for a developer!

Case studies:

a) An add-in using threads causes Outlook to hang or crash in a way that makes it look like another add-in is responsible[ii].

b) A while back, Add-in Express checked Inspectors.Count in a thread; this interfered with entering text in a message somehow.

Need to know more? Here are some extra details:

a) All calls to Office object models are executed in the main thread[iii], this is true even if you do such calls on a background thread.

A sample of such a call is nCount = theFolder.Items.Count. The described behavior is inherent to any Office object model because they all are STA[iv].

b) To transfer a COM call from a thread to the main thread, marshaling[v] is used.

What should normal people know about marshaling in managed Office extensions[vi]? It is sort of magic that your code invokes beside your knowledge. When or why this occurs seems to be inessential. What is essential is that it takes some time to marshal a COM call between threads[vii].

Conclusions:

a) A background thread in your add-in incurs some extra overhead, so if you run your business logics in the main thread, it works faster.

b) A background thread not using any Office object model is absolutely okay.

But how to scan Outlook items in the main thread in a way not interfering with the UI?

Add-in Express provides a solution: you use the SendMessage method and OnSendMessage event of your add-in module. This constitutes a kind of smart one-time timer. You call the method; and the event occurs only when Outlook is ready to process it. Find code samples via this search through Add-in Express forums.

Good luck!

Updated on 12-Oct-2011:
Here’s a citation from this MSDN blog: “There has been a rash of developers in recent months who are reporting problems with their Outlook add-ins crashing Outlook when doing multi-threading.”


[i] Geoff Darst from the VSTO Team talks on this in Is ApplicationClass Thread Safe?


[ii] See an article on OutlookCode.com, this is about non-managed add-ins, though


[iii] See All Outlook object model calls run on the main thread


[iv] If you really need it, see Single-Threaded Apartments (STA) on MSDN


[v] See What is Marshalling on Wikipedia


[vi] See Interop Marshaling on MSDN


[vii] See Marshaling Details on MSDN

2 Comments

  • https://secure.gravatar.com/avatar/c0fc80cd6d6bb8dced35d09cf4b633da?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G Samuel Jack says:

    Thanks for that Andrei!

    I think the worst thing about this whole issue is that calling into Office on a Background thread does appear to work at the time – it’s only later on (when you come to close the application, say) that you find there’s a problem. This makes tracking down the cause of the problem a real headache.

    I wrote a blog post on the subject: “Back from a bug hunt [or, Don’t Call Excel on a Background Thread]” – http://blog.functionalfun.net/2010/04/back-from-bug-hunt-or-dont-call-excel.html

  • https://secure.gravatar.com/avatar/3d5360573f76a974ebca4bbe617b4246?s=32&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G johnny says:

    Excellent news. Now i know why what i am trying for weeks now simply doesn’t work.
    i try in outlook tonshow some notifications and the entire ui freezes. And thats maybe because my entire addin i thought would be faster if multithreaded so i used a lot of background workers and dispatcher.invoke to do my job….. weird think is when it was all done in the main thread was working faster but i couldn’t realize it until i read this….

    Back to the drawing board i quess.

Post a comment

Have any questions? Ask us right now!