2016-01-21 24 views
2

我的C#VSTO Outlook 2010 AddIn将数百个MAPI文件夹异步添加到导入的pst文件。 (PST在Outlook foldertree存在)Outlook 2010 VSTO AddIn:UI随意冻结,同时向PST异步添加文件夹

下面是一个例子:

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); 
}); 

观UI在rootFolder.Folders.Add(...)随机冻结2-3秒。有时在20之后,有时在50个添加文件夹之后。

任何帮助/提示将不胜感激。

回答

2

期望您的插件在Outlook 2013或更新版本中完全停止工作:OOM一旦检测到它是从主Outlook线程以外的线程调用,就会报错。请注意,这仅适用于COM插件,因为它们在outlook.exe地址空间内运行。 COM系统总是将外部进程访问封送到主Outlook线程中(但是这违背了从单独线程使用OOM的全部目的)。

只能在辅助线程上使用扩展MAPI(C++或Delphi)。如果使用Redemption是一个选项(可以使用包括C#的任何语言),则其RDO family of objects可用于辅助线程:将Namespace.MAPIOBJECT属性的值存储在主线程(它是IMAPISession MAPI接口)上,然后打开辅助线程将创建一个RDOSession对象的实例(将在该线程上初始化MAPI),并将RDOSession.MAPIOBJECT属性设置为存储在主线程中的值 - 这样两者将共享相同的MAPI会话。

关闭我的头顶:

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); 
} 
+0

+1写这篇详细的提示。我正在考虑使用C++/cli和IMAPIFolder :: CreateFolder(..)。如果失败,你的回答将被接受,我会购买你的赎回图书馆。 – eWilli

+0

我设法让它使用C++/cli和扩展MAPI。 [见MSDN](https://msdn.microsoft.com/en-us/library/office/cc815501.aspx)。速度的差异是惊人的。对于不熟悉托管C++的人,我建议使用Redemption!接受的答案。 – eWilli