Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Outlook Addin: Working with threads

I'm working on an Outlook Addin, and I have to process a large amount of items. This takes quite a lot of time, and I therefore tried to have the processing running in a different thread (using Task.Factory.StartNew). However, that results in Outlook randomly crashing.

I'm using Redemption to work with MAPITable, in order to reduce workload and load only relevant data.

  • I've tried initializing my RDOSession from both my main thread, and my worker thread.
  • I've tried getting the MAPIFolders on the main thread, and working with only the MAPITable on the worker thread

Currently, the only thing that works for me is running all my logic on the main thread (in the button click event), however that locks Outlook's user interface for a long period of time, which is unacceptable from a user's point of view.

Does anyone have some pointer on how to work with background threads from within an Outlook Addin?

like image 684
SaguiItay Avatar asked May 12 '13 08:05

SaguiItay


2 Answers

Having similar code in my project I would suggest the following:

  1. Create new thread using the Thread class and set it apartment to STA.

  2. Loggin to session using "session.Logon("profileName", NoMail: true, NewSession: false);" and not using MAPIOBJECT. I found it has better performance than using MAPIOBJECT, my guess is it still marshal some calls back to the main thread as MAPIOBJECT was created on the main thread.

  3. Use "Marshal.ReleaseComObject" on each and every COM object you use as soon as you are done with them. This is probably what causing the instability as Outlook really doesn't like when it's object are left too long. For example this line of code "var table = rdoFolder.Items.MAPITable;" create two COM objects: RDOItems and MAPITable, both of them must be released so you need to split this line to hold reference to RDOItems object.

  4. Call GC.Collect and Application.DoEvents because if you don't call Marshal.ReleaseComObject on all COM object the finalizer will try to release them and will hang because the COM objects were created on thread that don't pump message loop and it's finalizer method must run on the thread that created them.

  5. If you can, fire a secondary process and do this loop in the separate process. This will make maximum separation between the UI and your background work.

like image 101
Arthur Avatar answered Nov 04 '22 17:11

Arthur


What was the problem using RDO objects in a secondary thread? As long as RDOSession is created on the secondary thread, MAPI should be properly initialized.

Also, TaskFactory uses a thread pool, you'd be better off using an explicit Thread class, o at least make sure that RDOSession is not shared between different threads - MAPI must be initialized on each thread.

like image 20
Dmitry Streblechenko Avatar answered Nov 04 '22 18:11

Dmitry Streblechenko