Antoine Gautier
Antoine Gautier

Reputation: 653

C# VSTO add-in task sequence

Within VSTO add-in for Outlook a button click fires 2 methods: first one performs simple actions on MailItem Object and runs quick, second one performs several other tasks requiring more computing time. I would like the second one to run in "background" so that the actions on MailItem Object quickly respond. Right now I could not figure out how to do that and the effects of actions on MailItem Object are only visible in Outlook once the 2 methods are completed.

public void ButtonAction(Office.IRibbonControl control)
{
    bool processed = ActionsOnMailItem();
    string output = OtherTasks(processed);
}

public static bool ActionsOnMailItem()
{
    Outlook.Selection selected = olApplication.ActiveExplorer().Selection;
    bool isEmailProcessed = false;
    try
    {
        foreach (Outlook.MailItem mailItem in selected)
        {
            mailItem.SaveAs(saveItemPath, Outlook.OlSaveAsType.olMSG);
        }
        isEmailProcessed = true;
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
        isEmailProcessed = false;
    }
    return isEmailProcessed;
}

public static string OtherTasks(bool isEmailProcessed)
{
    if (isEmailProcessed)
    {
        // Perform several tasks requiring computing time
        ...
    }
}

I have already tried with async methods but without success (no deadlock but no quick response for first method neither). Before I dig deeper into that I would like to know if this is the right path to follow or if there is a more straightforward way to do that.

Upvotes: 2

Views: 786

Answers (2)

Dmitry Streblechenko
Dmitry Streblechenko

Reputation: 66276

As of Outlook 2016, a exception will be raised as soon as Outlook detects access on a thread other than the main Outlook thread. This really applies to the COM addins only as in out-of-proc (external) applications all calls will be marshalled to the main Outlook thread anyway, so multithreading in your app becomes a moot point.

You can use Extended MAPI (C++ or Delphi) on a secondary thread - read the Namespace.MAPIOBJECT property on the main thread (it returns IMAPISession object) and store it in a variable. On a secondary thread, call MAPIInitialize and use the IMAPISesion from the main thread - unlike OOM objects, it can be used from multiple threads. For languages other than C++ or Delphi, you can use Redemption (I am its author) and its RDO family of objects - it is a wrapper around Extended MAPI and can be used on secondary threads. Create an instance of the RDOSession on the secondary thread and set its MAPIOBJECT property to the value retrieved on the main thread from Namespace.MAPIOBJECT.

Upvotes: 2

tinamou
tinamou

Reputation: 2292

First of all you must to be aware that accessing COM object from background thread involves marshaling which, in short, takes time. Further reading...

For your task you need to develop solution which uses BackgroundWorker class. BackgroundWorker has two events that works on MainThread which are:

  • ProgressChanged
  • RunWorkerCompleted

Your OtherTasks method should use one of them to process result from background task.

For VSTO it is also important to use WindowsFormsSynchronizationContext before using BackgroundWorker class For example:

// Forces BackgroundWorker to run ProgressChanged and RunWorkerCompleted events on VSTA_Main thread. It's important,
// because this thread manages Word COM objects. 
System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;

worker.DoWork += delegate(object sender, DoWorkEventArgs e)
{
    // do stuff not using COM object
    worker.ReportProgress(0);
};
worker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs e)
{
    // do stuff on main thread (on COM objects)
};
worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
{

};

worker.RunWorkerAsync();

Upvotes: 2

Related Questions