OOM.NET: Part 5 - Event Planning

Plan For What You Can Control

One of the common scenarios in OOM programming in managed code that required calling GC.Collect() was handling events. As has been discussed earlier in this series, item references need to be released before they go out of scope. This includes items passed into event handlers. Take the ItemSend event for example...

 // This leaks 'Item'
void app_ItemSend(object Item, ref bool Cancel)
{
    
}

// This does not leak...
void app_ItemSend(object Item, ref bool Cancel)
{
    try
    {

    }
    finally
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(Item);
    }
}

...In most cases you would expect that the caller invoking the delegate and passing 'Item' would be responsible for releasing it since that is where it was created. However, that is not the case here - 'Item' must be released within the delegate, the caller does not call ReleaseCOMObject().

Know The Symptoms

The most common symptoms of this kind of leak (especially with the ItemSend event) are scenarios involving sending meeting requests and meeting updates. If there is a leak in the ItemSend event and a meeting request or update is sent out the appointment in the calendar is ultimately leaked. The user experience goes something like this...

  1. Organizer sends a meeting update.
  2. Organizer makes a change to the appointment item in his/her calendar.
  3. Outlook prompts the organizer to send a meeting update and save the changes.
  4. Organizer attempts to send the meeting update or save and close and Outlook throws a warning/error dialog stating that the appointment has been modified elsewhere and cannot be saved.

Another common scenario is there is a leak in the NewInspector event. Typically the symptom here is that a user will open a message and close it, then try to open the message again at which time Outlook displays a dialog stating that the "Operation failed."

Get Fixes For What You Can't Control

There were some scenarios in Outlook 2003 and Outlook 2007 where - even if the OptionPagesAdd event was the only event handled - users still saw the meeting request experience described above. To make a long story short the interop assembly is generated by tblimp.exe (more information here) in such a way that if one event on an interface such as ApplicationEvents_11_Events interface then "underneath the covers" they are all handled - in the case of OptionPagesAdd that means ItemSend and ItemLoad are handled too. Because these events are not handled in the AddIn code there is no way to release the reference the items passed to them. To address this issue, the Outlook team released a fix for Outlook 2003 and Outlook 2007. Any Outlook install that is using extensive or multiple .NET AddIns should have the following fixes installed to avoid this issue...

Description of the Outlook 2007 post-Service Pack 1 hotfix package: January 28, 2008

Description of the Outlook 2003 post-Service Pack 3 hotfix package: December 13, 2007