Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Gracefully shutting down Outlook from a .NET application using AppDomain

4.60/5 (4 votes)
8 Sep 20054 min read 1  
Shows how to utilize Outlook automation without leaving a mess behind.

Introduction

Microsoft Outlook offers an API in the form of a COM object, which allows for automation of the application. The COM object can also be used from any .NET application. However, when you are trying to build a robust application that requires high availability, or if you want to use Outlook over and over again without restarting your application, you can run into some major issues. This article seeks to address those issues, providing a robust solution while working with Microsoft Outlook.

Let's say you have a solution where you want to add an Outlook PST store to the Outlook application dynamically, do some work, and then remove the PST. The problem comes in that Outlook does not release the PST until the Outlook process exits, and thus the PST remains locked by Outlook until that time, unable to be used in any other process. If your application is built in standard fashion, the Outlook process will not exit until your application also exits. This also means that any resources being tied up by Outlook will be tied up until your application exits. This is a problem if you plan on processing multiple PST's at a time, or if you want to use Outlook from an application such as a Service or in Remoting. Another concern is how Outlook may inadvertently affect your application- if Outlook were to crash, it could bring down your application as well. That is what we want to prevent.

Normally, to use outlook, you would just use the add reference dialog in VS.NET and set a reference to Microsoft Outlook Object Model. But here we are going to approach it differently.

First, we are going to prepare the assembly for use across several applications by installing it on the Global Assembly Cache (GAC). Keep in mind that when you deploy your application, you will have to use a setup project that will install the DLL on the GAC on the target machine. Installing an assembly on the GAC involves a few easy steps:

  1. From the Visual Studio .NET command prompt, set the path to the location of MSOUTL.OLB.
    C:\Program Files\Microsoft Office\OFFICE11>
  2. Generate a strong name key pair using sn.exe. (This key pair will be used to create a strong name for the assembly, which is required for installing in the GAC.)
    C:\Program Files\Microsoft Office\OFFICE11>sn -k keypair.snk
  3. Run the Type Library Import tool to create the .NET assembly from MSOUTL.OLB file. Notice the use of the /keyfile option to specify the keyfile created in step 2. This will give the assembly a strong name and sign it. I also created a new path for the output DLL to be located. This path can be any path of your choice. I chose the name NetOutlook.dll to indicate that it was a .NET assembly for outlook, but you can choose any name you prefer.
    C:\Program Files\Microsoft Office\OFFICE11>tlbimp MSOUTLB.OLB 
     /keyfile:keypair.snk  /out:C:\NetOutlook\NetOutlook.dll
  4. Next, change directory to the path of the newly created NetOutlook.dll, and install the assembly on the GAC using gacutil.exe.
    C:\NetOutlook>gacutil -i NetOutlook.dll

OK, now you should have a .NET assembly installed on the GAC that you can use from any .NET application. From here, I will discuss how to use this DLL from your application in a way that will address the issues identified in the beginning of this article.

The first step is to add a reference to the DLL for your application. Select Project->Add Reference, click the Browse button in the dialog box, then browse to the location of NetOutlook.dll.

Now your application has all the definitions of the types you will be using, but you will not be instantiating them directly. The trick to keeping the Outlook separated from your application is to load it into a separate AppDomain. AppDomains are used to separate pieces of your application from one another. This way you can load and unload pieces of the application when they are needed and when they are finished. Also, a problem in one AppDomain cannot corrupt the process of the other AppDomain.

Here is the code, written in a console application.

C#
//Create the domain object by calling AppDomain.CreateDomain()

AppDomain domain = AppDomain.CreateDomain("Outlook");

In the following code, take note of the assembly name that is passed to domain.Load(). The assembly name must be fully qualified. To determine the fully qualified name of your assembly follow the approaches in this reference.

C#
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");
C#
//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() );
C#
// 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();

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here