danBhentschel
danBhentschel

Reputation: 883

How to handle application lifetime in an Outlook PIA implementation

Problem Statement

When Outlook exits, any events registered for via PIA will be lost, and any PIA objects that are currently in memory will be inaccessible.

To Reproduce

Here is a simple console app that illustrates the issue at hand:

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);
    }
}

When I run this application, it starts up an instance of Outlook in a separate process (shown in the system tray) if Outlook isn't already running. There are three scenarios that I know of that can cause the Quit event to fire:

  1. Outlook is in a "hidden" state, and is exited by selecting Exit Now from the context menu of the system tray icon.
  2. Outlook was already running when the application was started, and the user closes or exits the running explorer.
  3. Outlook was not running when the app was started, so was started in a "hidden" state, but then the user started the Outlook application, either by running the executable, or by selecting Open Outlook from the context menu of the system tray icon. Then the user closes or exits the running explorer.

Each of these has the same effect on my program: The Quit event is fired, and then one of my attempts to access an Outlook object fails with a COMException.

Question

What is the standard or recommended way to deal with this? Theoretically, the application exit could happen asynchronously at any time. Do I need to catch COMException on any operation that uses PIA and restart the operation from the call to new Application() if that exception occurs? That could be tricky, depending on the complexity of the operation.

What about event handlers? Do I need to keep track of all event handlers that I have added to Outlook objects and then re-add them if I receive an Application.Quit event?

What about the UX? Suppose the user selected Exit Now from the context menu of the system tray, and then the icon instantly reappears because my application detected the exit and re-initialized everything. Should I pop up some kind of dialog to the user informing them that I need Outlook for my application to operate properly?

What about in a system shutdown situation? Presumably I would receive a SystemEvents.SessionEnding event before I receive an Application.Quit from Outlook. Is that guaranteed, or should I wait some amount of time before restoring communications to see if the system is in the process of going down? Is there some other way to detect if we are in a session ending state?

Apologies for the multi-faceted question. Links to reading material are welcome if there is an article that already addresses this topic. I haven't found one after a good amount of searching.

Upvotes: 0

Views: 118

Answers (1)

Dmitry Streblechenko
Dmitry Streblechenko

Reputation: 66255

If Application.Quit does not fire, you can hook up Explorer.Close and Inspector.Close events and check if Aplication.Explorers.Count and Aplication.Inspectors.Count are both 0 (or 1 since the event you are processing still has the window open).

To hook up these events, track the Application.Explorers.NewExplorer and Application.Inspectors.NewInspector events. To hook up explorers and inspectors already displayed by Outlook, loop through the Application.Explorers and Application.Inspectors collections on startup.

Upvotes: 0

Related Questions