OOM.NET Part 1 – Introduction and Why Events Stop Firing…
Matt Stehle used to be on my team prior and had blogged on the usage of Outlook Object Model (OOM) under .NET. However, his blog is being closed and I am re-blogging his content here.
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.