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
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]” – https://blog.functionalfun.net/2010/04/back-from-bug-hunt-or-dont-call-excel.html
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.