Writing an Outlook Add-in with C# (Part 4)

In the last 3 sessions, we have developed an Outlook Add-in that adds a tab to a Contact window when it is opened. We began to discuss some further issues with which we must grapple.

Problem #1. There is a Microsoft documented problem with Outlook hanging in memory after closing it even if an Outlook Add-in is properly written. It doesn’t always happen, but it is a known issue and can really be annoying. The answer here is to implement a manual “disposer” class. More on this later.

Problem #2. Because our Add-in is in C# Outlook doesn’t load it directly (discussed earlier). Outlook really loads mscoree.dll instead of our Add-in, and mscoree.dll loads our Add-in. Why is this a problem? As noted before, if Outlook thinks our Add-in misbehaved, it will unload mscoree.dll (our Add-in loader).

What is worse, Outlook will then refuse to load ANY other .NET Add-in. This also means that another managed Add-in that misbehaves could also cause our Add-in not to get loaded. (Supposedly this has been remedied in Outlook 2007). The answer here is not exactly easy. The only real solution I found was to write a shim in unmanaged C++ that would be registered with Outlook, and it would, in turn, load our managed Add-in. It does work well. I can post on this if anyone is interested.

So let’s look at Problem #1 - Outlook hangs in memory.  Amazing but true.  There is a problem with Outlook and the way it handles unloading Add-ins.  What makes it worse, is that it doesn’t always happen.  Yuck.   You just have to deal with it.  So what do we do?

This is a problem that Microsoft has documented, and this is the solution I have come up with (with the assistance of the Microsoft Office site).  So if you have been following along, you may have been wondering why we registered for
ExplorerEvents_10_Event_Close in the first place. Your patience is about to be rewarded. In the event handler
Explorer_ExplorerEvents_10_Event_Close we need to do the following. First, tell the explorer class we don’t want any more callbacks like so:

m_explorerclass.ExplorerEvents_10_Event_Close
-= new Outlook.ExplorerEvents_10_CloseEventHandler(
Explorer_ExplorerEvents_10_Event_Close);

We also have to unregister for “NewInspector” events:

m_inspectors.NewInspector -= new
Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);

Then, in the part that really hails back to the days of COM, we have to manually dispose of any object that has registered as an event listener. You heard me right. So much for the glories of managed code. It’s time to get your hands dirty! For all you who have never had the pleasure of releasing a COM object, your time has come!

What we need to do next is, in the same
Explorer_ExplorerEvents_10_Event_Close callback, manually release the m_explorerclass and m_inspectors objects. They were the objects that originally registered as event listeners (see Part 3 of this article if you missed that).
Here’s how we release the objects:
Make sure you have a “using” statement for System.Runtime.InteropServices and then put in the following code.

try
{
  if (m_explorerclass != null)
  {
    int iCount = Marshal.ReleaseComObject(m_explorerclass);
    while (iCount > 0)
    {
     iCount = Marshal.ReleaseComObject(m_explorerclass);
    }
  }
}
catch (SystemException ex)
{
}
finally
{
  GC.Collect();
  GC.WaitForPendingFinalizers();
}

You have to do this for the m_explorerclass and m_inspectors objects. What we are doing here is performing an old-time COM Release(), then telling the managed garbage collector to do its thing and waiting on it.  This is actually the solution Microsoft proposes as the answer to the problem of Outlook hanging in memory when it is supposed to exit.

If you don’t believe me you can read more about it on the MSDN technical articles site (http://msdn2.microsoft.com/en-us/library/aa155703(office.10).aspx).  Just look for Calling UnInitHandler and Disposing of Objects. Even though this Microsoft article is about Outlook 2002, I don’t see any indication that it is different for Outlook 2007.  If so, someone please correct me.

There were a few other strange things about this manual disposing business.  I ended up putting the above code in a routine and calling it both from Explorer_ExplorerEvents_10_Event_Close and Connect.OnDisconnection just to make sure it always happened.

See the epilogue for final issues and comments.

Leave a Reply

You must be logged in to post a comment.