从 .NET 应用程序使用 AppDomain 优雅地关闭 Outlook






4.60/5 (4投票s)
2005年9月8日
4分钟阅读

83252
展示如何在不留下任何混乱的情况下使用 Outlook 自动化。
引言
Microsoft Outlook 以 COM 对象的形式提供了一个 API,该 API 允许应用程序自动化。COM 对象也可以从任何 .NET 应用程序中使用。但是,当您尝试构建一个需要高可用性的强大应用程序时,或者如果您想反复使用 Outlook 而无需重新启动应用程序时,您可能会遇到一些主要问题。本文旨在解决这些问题,提供一个在与 Microsoft Outlook 合作时的强大解决方案。
假设您有一个解决方案,您想动态地将 Outlook PST 存储添加到 Outlook 应用程序中,做一些工作,然后删除 PST。问题在于,Outlook 在 Outlook 进程退出之前不会释放 PST,因此 PST 会被 Outlook 锁定直到那时,无法在任何其他进程中使用。如果您的应用程序以标准方式构建,则 Outlook 进程在您的应用程序退出之前不会退出。这也意味着 Outlook 占用的任何资源都将被占用,直到您的应用程序退出。如果您计划一次处理多个 PST,或者您想从服务或 Remoting 等应用程序中使用 Outlook,这将是一个问题。另一个问题是 Outlook 可能会无意中影响您的应用程序 - 如果 Outlook 崩溃,它也可能导致您的应用程序崩溃。这就是我们想要阻止的。
通常,要使用 Outlook,您只需在 VS.NET 中使用添加引用对话框,并将引用设置为 Microsoft Outlook 对象模型。但在这里,我们将以不同的方式来处理它。
首先,我们将通过将其安装在全局程序集缓存 (GAC) 上来准备在多个应用程序中使用程序集。请记住,当您部署应用程序时,您将必须使用一个安装项目,该项目将在目标机器上的 GAC 上安装 DLL。在 GAC 上安装程序集涉及几个简单的步骤
- 从 Visual Studio .NET 命令提示符中,将路径设置为 MSOUTL.OLB 的位置。
C:\Program Files\Microsoft Office\OFFICE11>
- 使用 sn.exe 生成强名称密钥对。(此密钥对将用于为程序集创建强名称,这是在 GAC 中安装所必需的。)
C:\Program Files\Microsoft Office\OFFICE11>sn -k keypair.snk
- 运行类型库导入工具,从 MSOUTL.OLB 文件创建 .NET 程序集。注意使用 /keyfile 选项来指定在步骤 2 中创建的密钥文件。这将为程序集提供一个强名称并对其进行签名。我还为输出 DLL 创建了一个新路径。此路径可以是您选择的任何路径。我选择了名称 NetOutlook.dll,以表明它是一个用于 Outlook 的 .NET 程序集,但您可以选择任何您喜欢的名称。
C:\Program Files\Microsoft Office\OFFICE11>tlbimp MSOUTLB.OLB /keyfile:keypair.snk /out:C:\NetOutlook\NetOutlook.dll
- 接下来,将目录更改为新创建的 NetOutlook.dll 的路径,并使用 gacutil.exe 在 GAC 上安装程序集。
C:\NetOutlook>gacutil -i NetOutlook.dll
好的,现在您应该在 GAC 上安装了一个 .NET 程序集,您可以从任何 .NET 应用程序中使用它。从这里开始,我将讨论如何以一种能够解决本文开头中确定的问题的方式,从您的应用程序中使用此 DLL。
第一步是为您的应用程序添加对 DLL 的引用。选择 项目->添加引用,单击对话框中的浏览按钮,然后浏览到 NetOutlook.dll 的位置。
现在您的应用程序具有您将使用的所有类型的定义,但您不会直接实例化它们。让 Outlook 与您的应用程序分离的技巧是将其加载到单独的 AppDomain
中。AppDomain
用于将应用程序的不同部分相互分离。这样,您可以在需要时以及完成后加载和卸载应用程序的各个部分。此外,一个 AppDomain
中的问题不会破坏另一个 AppDomain
的进程。
这是代码,用控制台应用程序编写。
//Create the domain object by calling AppDomain.CreateDomain()
AppDomain domain = AppDomain.CreateDomain("Outlook");
在以下代码中,请注意传递给 domain.Load()
的程序集名称。程序集名称必须是完全限定的。要确定程序集的完全限定名称,请遵循 此参考中的方法。
System.Reflection.Assembly myassembly = domain.Load("NetOutlook,
Version=9.2.0.0, Culture=neutral,
PublicKeyToken=3ab4cb677c86f26d");
//Now you can insantiate the application
//object using the assembly you loaded
NetOutlook.Application app =
(NetOutlook.Application)myassembly.CreateInstance(
"NetOutlook.ApplicationClass");
//Do all your work with Outlook, for example:
NetOutlook.NameSpace ns = app.GetNamespace("MAPI");
NetOutlook.MAPIFolder folder =
ns.GetDefaultFolder(NetOutlook.OlDefaultFolders.olFolderInbox);
Console.WriteLine( folder.Items.Count.ToString() );
// Now for the crucial part - make sure you call
// Marshal.ReleaseComObject() for all COM objects in use
Marshal.ReleaseComObject(folder);
Marshal.ReleaseComObject(ns);
Marshal.ReleaseComObject(app);
Console.WriteLine("Press <Enter> to release Outlook");
// Delay, so that you can witness the
// process exit when you press enter
Console.ReadLine();
// The call that unloads the app domain and
// releases the Outlook Process
AppDomain.Unload(domain);
Console.WriteLine("Press <Enter> to exit");
Console.ReadLine();