Outlook 2010 VSTO 加载项:UI 随机冻结,同时异步将文件夹添加到 PST



My C# VSTO Outlook 2010 AddIn 将数百个 MAPI 文件夹异步添加到导入的 pst 文件中。(pst 存在于 Outlook 文件夹树中)

下面是一个示例:

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

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

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

预计您的加载项将在 Outlook 2013 或更高版本中完全停止工作:OOM 在检测到从主 Outlook 线程以外的线程调用时,会立即引发错误。请注意,这仅适用于 COM 加载项,因为它们在 outlook.exe 地址空间内运行时。进程外访问始终由 COM 系统封送到主 Outlook 线程(但这违背了从单独线程使用 OOM 的全部目的)。

只能在辅助线程上使用扩展 MAPI(C++ 或 Delphi)。如果可以选择使用 Redemption(可以从任何语言(包括 C# - 我是它的作者)使用),则可以在辅助线程上使用其 RDO 系列对象:将 Namespace.MAPIOBJECT 属性的值存储在主线程(它是 MAPI 接口IMAPISession),然后在辅助线程上创建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);
}

最新更新