Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hooked events Outlook VSTO continuing job on main Thread

Tags:

I have developed an Outlook VSTO addin. Some tasks should be made on a background thread. Typically, checking something in my local db or invoking a web request. After reading several posts, I dropped the idea of calling the Outlook Object Model (OOM) in a background thread.

I have some wpf controls and I successfully managed to use the .NET 40 TPL to perform the async task and when completed to "finish" the job (i.e. accessing the UI or the OOM) in the Main VSTA Thread.

To do so I use a syntax of the form:

Task<SomeResult> task = Task.Factory.StartNew(()=>{
    //Do long tasks that have nothing to do with UI or OOM
    return SomeResult();
});

//now I need to access the OOM
task.ContinueWith((Task<SomeResult> tsk) =>{
   //Do something clever using SomeResult that uses the OOM
},TaskScheduler.FromCurrentSynchronizationContext());

So far so good. But now I want to do something similar when hooking an event in the OOM where there are no Form/WPF control. Precisely, my problem comes from the fact that TaskScheduler.FromCurrentSynchronizationContext() throws an exception.

For instance,

Items inboxItems = ...;
inboxItems.ItemAdd += AddNewInboxItems;

private void AddNewInboxItems(object item)
{
    Task<SomeResult> task = Task.Factory.StartNew(()=>{
    //Do long tasks that have nothing to do with OOM
    return SomeResult()});


   var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
   /* Ouch TaskScheduler.FromCurrentSynchronizationContext() throws an  InvalidOperationException, 'The current SynchronizationContext may not be used as    a TaskScheduler.' */
   task.ContinueWith((Task<SomeResult> tsk) =>{
       //Do something clever using SomeResult that uses the OOM
   }),scheduler};
}

/* Ouch TaskScheduler.FromCurrentSynchronizationContext() throws an InvalidOperationException, 'The current SynchronizationContext may not be used as a TaskScheduler.' */

Note that I tried to create a TaskScheduler in addin initialization and putting it in a singleton as suggested here. But it does not work, the continuation task is not performed in the desired VSTA Main thread but another one (inspected with VisualStudio).

Any idea ?

like image 830
Benoit Patra Avatar asked Sep 08 '15 10:09

Benoit Patra


2 Answers

There is known bug that SynchronizationContext.Current might be null in several places where it should not (including office add-ins). That bug was fixed in .NET 4.5. But since you cannot upgrade to .NET 4.5, you have to find a workaround. As a suggestion, try to do:

System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

when initializing your addon.

like image 164
Evk Avatar answered Oct 03 '22 22:10

Evk


You can use the SynchronizationContext class which provides the basic functionality for propagating a synchronization context in various synchronization models. The Post method dispatches an asynchronous message to a synchronization context, i.e. the Post method starts an asynchronous request to post a message. See Using SynchronizationContext for sending events back to the UI for WinForms or WPF for more information and sample code.

FYI The Current property allows to get the synchronization context for the current thread. This property is useful for propagating a synchronization context from one thread to another.

like image 33
Eugene Astafiev Avatar answered Oct 03 '22 20:10

Eugene Astafiev