Outlook插件:如何处理邮件线程

6
我正在开发 Outlook 插件,需要处理大量的项目。这需要相当长的时间,因此我尝试将处理程序放在不同的线程中运行(使用 Task.Factory.StartNew)。但是,这会导致 Outlook 随机崩溃。
为了减轻工作负担并仅加载相关数据,我使用 Redemption 来处理 MAPITable。
以下是我的尝试:
- 我尝试在主线程和工作线程中初始化 RDOSession。 - 我尝试在主线程中获取 MAPIFolders,在工作线程中只处理 MAPITable。
目前,唯一有效的方法是在主线程上运行所有逻辑(在按钮单击事件中),但是这会锁定 Outlook 的用户界面很长一段时间,从用户的角度来看是不可接受的。
是否有人能提供关于如何在 Outlook 插件中使用后台线程的指导?
2个回答

3
在我的项目中有类似的代码,我建议如下:
  1. 使用Thread类创建新线程并将其公寓设置为STA。

  2. 使用"session.Logon("profileName", NoMail: true, NewSession: false);"登录到会话,而不是使用MAPIOBJECT。我发现它比使用MAPIOBJECT具有更好的性能,我猜测它仍然将一些调用返回到主线程,因为MAPIOBJECT是在主线程上创建的。

  3. 在每个使用完毕的COM对象上都使用“Marshal.ReleaseComObject”。这可能是导致不稳定的原因,因为Outlook不能容忍对象留置时间过长。例如,这行代码"var table = rdoFolder.Items.MAPITable;"创建了两个COM对象:RDOItems和MAPITable,两者都必须被释放,所以你需要将这行代码拆分为持有对RDOItems对象的引用。

  4. 调用GC.CollectApplication.DoEvents,因为如果没有在所有COM对象上调用Marshal.ReleaseComObject,最终器将尝试释放它们,并且将挂起,因为COM对象是在不循环消息的线程上创建的,它的终结器方法必须在创建它们的线程上运行。

  5. 如果可以的话,请启动一个辅助进程并在单独的进程中执行此循环。这将最大限度地分离UI和后台工作。


1
只要在次要线程上创建RDOSession,MAPI 就应该被正确初始化。使用 RDO 对象存在的问题是什么?此外,TaskFactory 使用线程池,最好使用显式的 Thread 类,或者确保 RDOSession 不在不同的线程之间共享 - 必须在每个线程上初始化 MAPI。请注意保留 HTML 标签。

这是一个示例不工作的代码,会导致 Outlook 崩溃:https://gist.github.com/saguiitay/5565244 - SaguiItay
尝试使用{}来限定RDOSession变量的作用域,并在所有RDO对象超出作用域后调用GC.Collect()。 - Dmitry Streblechenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接