问题陈述
当 Outlook 退出时,通过 PIA 注册的任何事件都将丢失,并且当前在内存中的任何 PIA 对象都将无法访问。
重现
这是一个简单的控制台应用程序,说明了手头的问题:
static void Main(string[] args)
{
var outlookApp = new Application();
var ns = outlookApp.GetNamespace("MAPI");
var calendar = ns.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
var appointment = (AppointmentItem) calendar.Items.GetFirst();
((ApplicationEvents_11_Event) outlookApp).Quit +=
() => Console.WriteLine("Outlook is quitting");
while (true)
{
Console.WriteLine("Explorers: " + outlookApp.Explorers.Count);
Console.WriteLine("Folders: " + ns.Folders.Count);
Console.WriteLine("Items: " + calendar.Items.Count);
Console.WriteLine("Start date: " + appointment.Start);
Thread.Sleep(2000);
}
}
当我运行此应用程序时,如果 Outlook 尚未运行,它会在单独的进程(显示在系统托盘中)中启动 Outlook 实例。我知道有三种情况会导致Quit
事件触发:
- Outlook 处于“隐藏”状态,可通过从系统托盘图标的上下文菜单中选择立即退出来退出。
- 启动应用程序时 Outlook 已在运行,用户关闭或退出正在运行的资源管理器。
- 启动应用程序时 Outlook 未运行,因此以“隐藏”状态启动,但随后用户通过运行可执行文件或从系统托盘图标的上下文菜单中选择打开 Outlook启动了 Outlook 应用程序。然后用户关闭或退出正在运行的资源管理器。
这些中的每一个都对我的程序产生相同的影响:Quit
事件被触发,然后我访问 Outlook 对象的一次尝试失败,并显示COMException
.
问题
处理此问题的标准或推荐方法是什么?理论上,应用程序退出可以随时异步发生。如果发生异常,我是否需要捕获COMException
任何使用 PIA 的操作并从调用到重新启动操作?new Application()
这可能很棘手,具体取决于操作的复杂性。
事件处理程序呢?我是否需要跟踪已添加到 Outlook 对象的所有事件处理程序,然后在收到Application.Quit
事件时重新添加它们?
用户体验呢?假设用户从系统托盘的上下文菜单中选择了立即退出,然后图标立即重新出现,因为我的应用程序检测到退出并重新初始化了所有内容。我是否应该向用户弹出某种对话框,通知他们我需要 Outlook 才能使我的应用程序正常运行?
在系统关闭的情况下怎么办?大概我会在收到来自 Outlook的SystemEvents.SessionEnding
事件之前收到一个事件。Application.Quit
这是有保证的,还是我应该在恢复通信之前等待一段时间,看看系统是否正在停机?是否有其他方法可以检测我们是否处于会话结束状态?
为多方面的问题道歉。如果有文章已经解决了这个主题,欢迎提供阅读材料的链接。经过大量搜索,我还没有找到一个。