How to properly release Excel COM objects

You’ll see a lot of complaints on the internet about Excel and other Microsoft Office applications not quitting properly after using the object model to perform certain actions, or showing sporadic and unpredictable behavior in COM add-ins. In the end most of these issues boil down to developers not properly disposing of COM objects.

The challenge is that despite the fact that, as .Net developers we can use the Office Interop Assemblies to access the various Office object models using managed code, the PIA’s are still essentially wrapping around COM objects. So what is the problem?

The code above will build and run without a problem, it will create a new Excel workbook, add a new sheet and set the value of the first cell in the newly created sheet. However, even after calling the Quit method of the Excel.Application object, you’ll still see the Excel.exe process in the Windows Task Managers’ list of background processes.

This strange phenomenon occurs because in the above code, we’re not releasing any COM objects and we’re also “chaining” object references by using double dots. You must ALWAYS release COM objects, even if you see no adverse effects, it might work perfectly on your PC but behave entirely different on a user’s computer.

Let’s look at how to change the code in order to safely dispose of any COM objects:

Pay close attention to the above code, we never used more than one dot when working with objects. We also wrapped all the code in a try-finally, so even if the code throws and exception we will still safely release the COM objects using the ReleaseComObject method on the Marshal object.

For or ForEach Loops

There is no obvious reason why you should use a for-loop rather than a ForEach loop, however it is recommended that you rather use a for loop since a for-each might cause some unexpected behavior and your code to hang. Consider the following code:

In the above code, everything appears to be fine. We did not use more than one dot and we safely released all COM objects using a try-finally code clock. However, using a foreach loop to loop through the Sheets collection of the Excel.Workbook object automatically generates the enumerator behind the foreach statement that uses an internal COM object, which needs to be released..

To be on the safe side, you should avoid using a foreach loop and rather use a normal for loop, and release each COM object in the collection, as illustrated below:

ReleaseComObject & FinalReleaseComObject?

When you access an Office COM object via the interop assemblies, the .Net framework automatically wraps it in a Runtime Callable Wrapper, the RCW object is also responsible for controlling the objects’ lifetime.

Keep in mind that the .Net runtime creates one RCW for each COM object. So, no matter how many references you have to a specific COM object, there will always be just one Runtime Callable Wrapper for it. As you create more references to a certain COM object the RCW’s reference count will increase and this is where the ReleaseComObject and FinalReleaseComObject come into play.

Both methods are used to release references to a RCW, ReleaseComObject simply decreases the reference count of a specific RCW, whereas FinalReleaseComObject releases ALL references to the RCW and sets the reference count to zero.

Essentially, calling FinalReleaseComObject would be similar to creating a for-loop and calling ReleaseComObject until its reference count is zero. When the reference count is zero, it means the object is ready to be garbage collected.

Both methods need to be used with a relative degree of caution, if you release a COM object and try to access it afterwards an InvalidComObjectException will be shown with the following message:

“COM object that has been separated from its underlying RCW cannot be used”

As a rule we never use FinalReleaseComObject, by calling ReleaseComObject the reference counter should be decreased and if everything is correct the COM object should be properly released with a single call. FinalReleaseComObject is redundant and might cause unexpected results and a whole lot of pain.

GC.Collect & GC.WaitForPendingFinalizers

The generally accepted best practice is not to force a garbage collection in the majority of cases; however, you can release COM objects using the .Net garbage collector, as long as there are no references to the objects. In other words, the objects are set to null. Be aware that GC.Collect can be a time consuming process depending on the number of objects.

You would also need to call GC.Collect and GC.WaitForPendingFinalizers twice when working with Office COM objects since the first time you call the methods we only release objects that we are not referencing with our own variables. The second time the two methods are called is because the RCW for each COM object needs to run a finalizer that actually fully removes the COM Object from memory.

So, it is totally acceptable to see the following code in you COM add-in projects:

Ways to kill the Excel.exe process

WM_CLOSE

Of course, there are ways to kill the Excel process if you have to. One such way is to send a WM_CLOSE message to the Excel windows in order for it to terminate. First, you’ll need to use the DLLImport attribute to invoke the SendMessage method contained in the user32 dll. Do this by adding the following code at the top of your class:

The trickiest part of this is to get the window id or hWnd of the main Excel window. Luckily, if you’ve accessed the Excel object model you can retrieve the main windows’ hWnd by checking the Hwnd property on the ActiveWindow object. The ActiveWindow object is a property on the Excel.Application object. If the Excel version you’re targeting does not have the Hwnd property on the Application object, you can use late-binding to access it, as illustrated below.

Excel.Application app =new Excel.Application();
hWnd = app.Hwnd;

After you’ve retrieved the hWnd value, call the SendMessage method as indicated below, to force the main Excel window to close:

SendMessage((IntPtr)hWnd, 0x10, IntPtr.Zero, IntPtr.Zero);

Process.Kill

An easier way kill all Excel processes, is to use the Kill method of the .Net Process object. The object can be found in the System.Diagnostics namespace. The following code will retrieve all the Excel processes and kill each one:

Awesome !! Very good explanation and I learned new things. Struggled many hours with the Excel process not going away before finding this very helpful explanation. And great examples that helped explain it. Thanks !

First of all thanks for all the valuable information that you present here at this blog. I have developed an Excel 2013 Add In using Visual Studio 2013 (VB.NET). The Add In is published by VS as a .VSTO Add In. I have the following questions:

1) I have read that the .dll.deploy file can be easily read by some programs and the source code can be re-generated by specialized software. My question, is there a function / program that allow me to release my .VSTO Add In in an obscured format, in such manner that the original code would not be compromised?

2) After installing .VSTO Add In, I have noticed that Excel doesn’t access the VSTO installation folder at all , so the question, where does my installed Add In reside after I have installed it in a Windows machine?

This technology is now available for our custom development services only. Based on the Add-in Express for Office core, it is designed for building custom-tailored Office add-ins with far less coding than you usually have to do. Plus, it includes all Add-in Express features such as True RAD, visual designers, Outlook view and form regions, etc.

Get the best platform for building version-neutral, fast and easy deployable plug-ins by using Add-in Express projects templates, visual designers, components and wizards in combination with a perfect Delphi compiler.

This is an extension for Visual Studio that allows developers to quickly create WiX-based setup projects in a familiar Visual Studio way.

The Designer for WiX Toolset lets you forget the plain Windows Installer XML and concentrate on your deployment logic. It integrates several editors with the Visual Studio IDE and provides a set of vdproj designers to configure the file system, registry, user interface, custom actions, launch conditions and more for your setup projects.

The innovative technology for customizing Outlook views and forms. It is included in all Add-in Express for Office products and can be used to extend Outlook views, e-mail, task and appointment windows, To-Do bar, Reading and Navigation panes with your own custom sub-panes.

Microsoft and the Office logo are trademarks or registered trademarks of Microsoft Corporation in
the United States and/or other countries. All other trademarks are property of their respective owners.