Click here to Skip to main content
15,880,956 members
Articles / Programming Languages / C#
Article

Gracefully shutting down Outlook from a .NET application using AppDomain

Rate me:
Please Sign up or sign in to vote.
4.60/5 (4 votes)
8 Sep 20054 min read 81.9K   33   15
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


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionFile or assembly name NetOutlook, or one of its dependencies, was not found. Pin
Chamak794-Jun-07 12:17
Chamak794-Jun-07 12:17 
GeneralNetOutlook, or one of its dependencies not found Pin
sinanju5-Sep-06 0:15
sinanju5-Sep-06 0:15 
GeneralExcellent article Pin
Alexandru Ceausu22-Jul-06 22:44
Alexandru Ceausu22-Jul-06 22:44 
QuestionDoing the same with 2 DLLs Pin
s0m0s6-Feb-06 4:02
s0m0s6-Feb-06 4:02 
AnswerRe: Doing the same with 2 DLLs Pin
Jonathan183-May-06 4:23
Jonathan183-May-06 4:23 
GeneralReleaseComObject Pin
HakunaMatada14-Sep-05 21:02
HakunaMatada14-Sep-05 21:02 
GeneralRe: ReleaseComObject Pin
jmh100016-Sep-05 5:55
jmh100016-Sep-05 5:55 
GeneralRe: ReleaseComObject Pin
HakunaMatada16-Sep-05 18:40
HakunaMatada16-Sep-05 18:40 
GeneralRe: ReleaseComObject Pin
bharr28-Jan-06 2:37
bharr28-Jan-06 2:37 
QuestionWhy not use Offfice Primary Interop Assemblies? Pin
stupiddumbguy13-Sep-05 18:39
stupiddumbguy13-Sep-05 18:39 
AnswerRe: Why not use Offfice Primary Interop Assemblies? Pin
jmh100016-Sep-05 5:48
jmh100016-Sep-05 5:48 
AnswerRe: Why not use Offfice Primary Interop Assemblies? Pin
wolvever17-Jul-07 23:42
wolvever17-Jul-07 23:42 
GeneralRe: Why not use Offfice Primary Interop Assemblies? Pin
stupiddumbguy18-Jul-07 3:20
stupiddumbguy18-Jul-07 3:20 
QuestionCom Objects Pin
TheDarkMan8-Sep-05 22:01
TheDarkMan8-Sep-05 22:01 
AnswerRe: Com Objects Pin
jmh100012-Sep-05 3:05
jmh100012-Sep-05 3:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.