Reputation: 107
My C# VSTO Outlook 2010 AddIn adds hundreds of MAPI folders to an imported pst file asynchronously. (pst exists in Outlook foldertree)
Here is an example:
Task.Factory.StartNew(() => {
... //get pstStore
var rootFolder = pstStore.GetRootFolder();
for (int i = 0; i < 500; i++)
{
var folder = rootFolder.Folders.Add("Test" + DateTime.Now.Ticks);
Thread.SpinWait(1000); //emulate work
Marshal.ReleaseComObject(folder);
}
Marshal.ReleaseComObject(rootFolder);
});
The Outlook UI freezes randomly at rootFolder.Folders.Add(...)
for 2-3 sec. Sometimes after 20, sometimes after 50 added folders.
Any help / tip will be much appreciated.
Upvotes: 3
Views: 331
Reputation: 66276
Expect your addin to stop working completely in Outlook 2013 or newer: OOM raises an error as soon as it detects that it is being called from a thread other than the primary Outlook thread. Note that this applies to the COM addins only as they run inside the outlook.exe address space. Out-of-proc access is always marshaled to the main Outlook thread by the COM system (but that defeats the whole purpose of using OOM from a separate thread).
Only Extended MAPI (C++ or Delphi) can be used on a secondary thread. If using Redemption is an option (it can be used from any language including C# - I am its author), its RDO family of objects can be used on secondary threads: store the value of the Namespace.MAPIOBJECT
property on the primary thread (it is IMAPISession
MAPI interface), then on the secondary thread create an instance of the RDOSession
object (that will initialize MAPI on that thread) and set the RDOSession.MAPIOBJECT
property to the value stored on the main thread - this way the two will share the same MAPI session.
Off the top of my head:
object mapiObject; //on the class/global level
..
mapiObject = Application.Session.MAPIOBJECT;
...
Task.Factory.StartNew(() => {
Redemption.RDOSession session = new Redemption.RDOSession();
session.MAPIOBJECT = mapiObject;
Redemption.RDOStore pstStore = session.Stores["YourStoreName"];
Redemption.RDOFolder rootFolder = pstStore.IPMRootFolder;
Redemption.RDOFolders folders = rootFolder.Folders;
for (int i = 0; i < 500; i++)
{
var folder = folders.Add("Test" + DateTime.Now.Ticks);
Marshal.ReleaseComObject(folder);
}
Marshal.ReleaseComObject(folders);
Marshal.ReleaseComObject(rootFolder);
Marshal.ReleaseComObject(session);
}
Upvotes: 3