OOM.NET: Part 1 - Introduction and Why Events Stop Firing...
OOM.NET is not a special API set that was created in managed code. It is the name I've given to a series of posts I'll do about the “gotchas” of Outlook Object Model development in .NET. I've compiled some notes over time of the most common issues, how to resolve them, and why they exist. I'd love to hear back from you on other issues you face with OOM programming in .NET as well so that I can add them to this series...
With the introduction of Visual Studio Tools for Office and the maturity of .NET languages in general more and more Outlook developers are using .NET languages like C# and VB.NET. The nice thing about .NET is that it encapsulates a lot of common functionality into a framework, manages memory, provides a framework for inter-operating with COM, and allows you to quickly write applications with very little concern for how all this happens.
The bad thing about .NET is that it allows you to quickly write applications with very little concern for how all that happens...
Developers can get caught up in the ease and speed of development in .NET. They can suffer from an "It Just Works Addiction" - meaning in the bliss of swiftly writing code that just happens to compile and run it is possible to lose sight of what is making everything work. This mentality simply will not work with Outlook development; especially in .NET because there is just too much that can happen to adversely affect your application. So on with the show...
Why Events Stop Firing
Typically, the events stop firing problems come from adding an event handler from a locally scoped object or calling ReleaseCOMObject on an object which you are listening to events on. The code below will eventually stop handling the NewInspector event because inspectors is locally scoped here and when GC runs it will get cleaned up thus stopping the event to fire…
private void ThisAddIn_Startup(object sender, EventArgs e)
{
Outlook.Inspectors inspectors;
inspectors = Application.Inspectors;
inspectors.NewInspector += Inspectors_NewInspector;
}
To fix it you would need to make inspectors a module level variable and call ReleaseCOMObject within a dispose method or in this case inside ThisAddIn_Shutdown. You wouldn’t want to call ReleaseCOMObject on inspectors within ThisAddIn_Startup because it would free the underlying COM object and also cause your event to stop firing.
private Outlook.Inspectors inspectors;
private void ThisAddIn_Startup(object sender, EventArgs e)
{
inspectors = Application.Inspectors;
inspectors.NewInspector += Inspectors_NewInspector;
}
However, in Inspectors_NewInspector you *would* want to call ReleaseCOMObject on inspector once you were done with it. For example…
private void Inspectors_NewInspector(Outlook.Inspector inspector)
{
try
{
MessageBox.Show(inspector.Caption);
}
finally
{
Marshal.ReleaseComObject(inspector);
}
}
You wouldn’t want to call ReleaseCOMObject until you were done with that particular reference though. In this case all the work is done within the try/finally block so we can safely release when we are done. Also, it is highly recommended that you use a try/finally block to release objects in this scenario because it ensure the reference will get released even if there is an exception.
Comments
Anonymous
December 15, 2007
Exchange Admin 101: Exchange 2003 and Exchange 2007 admin privileges Troubleshooting Exchange GlobalAnonymous
February 18, 2008
The Outlook Developer Reference on MSDN has great information on .NET and COM interop which I would considerAnonymous
July 16, 2008
I've been encouraging him to blog his "Matt Stehle's Tenents of OOM Programming" for a while now, andAnonymous
February 17, 2009
Recently, I was helping someone with a Outlook item leak type issue involving a Task FormRegion.