I'm using the Excel interop in C# (ApplicationClass
) and have placed the following code in my finally clause:
while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Although this kind of works, the Excel.exe
process is still in the background even after I close Excel. It is only released once my application is manually closed.
What am I doing wrong, or is there an alternative to ensure interop objects are properly disposed of?
UPDATE: Added C# code, and link to Windows Jobs
I spent sometime trying to figure out this problem, and at the time XtremeVBTalk was the most active and responsive. Here is a link to my original post, Closing an Excel Interop process cleanly, even if your application crashes. Below is a summary of the post, and the code copied to this post.
Application.Quit()
andProcess.Kill()
works for the most part, but fails if the applications crashes catastrophically. I.e. if the app crashes, the Excel process will still be running loose.I found this to be a clean solution because the OS is doing real work of cleaning up. All you have to do is register the Excel process.
Windows Job Code
Wraps the Win32 API Calls to register Interop processes.
Note about Constructor code
info.LimitFlags = 0x2000;
is called.0x2000
is theJOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
enum value, and this value is defined by MSDN as:Extra Win32 API Call to get the Process ID (PID)
Using the code
I cant believe this problem has haunted the world for 5 years.... If you have created an application, you need to shut it down first before removing the link.
when closing
When you new an excel application, it opens a excel program in the background. You need to command that excel program to quit before you release the link because that excel program is not part of your direct control. Therefore, it will stay open if the link is released!
Good programming everyone~~
The two dots rule did not work for me. In my case I created a method to clean my resources as follows:
I think that some of that is just the way that the framework handles Office applications, but I could be wrong. On some days, some applications clean up the processes immediately, and other days it seems to wait until the application closes. In general, I quit paying attention to the details and just make sure that there aren't any extra processes floating around at the end of the day.
Also, and maybe I'm over simplifying things, but I think you can just...
Like I said earlier, I don't tend to pay attention to the details of when the Excel process appears or disappears, but that usually works for me. I also don't like to keep Excel processes around for anything other than the minimal amount of time, but I'm probably just being paranoid on that.
To add to reasons why Excel does not close, even when you create direct refrences to each object upon read, creation, is the 'For' loop.
Excel does not quit because your application is still holding references to COM objects.
I guess you're invoking at least one member of a COM object without assigning it to a variable.
For me it was the excelApp.Worksheets object which I directly used without assigning it to a variable:
I didn't know that internally C# created a wrapper for the Worksheets COM object which didn't get released by my code (because I wasn't aware of it) and was the cause why Excel was not unloaded.
I found the solution to my problem on this page, which also has a nice rule for the usage of COM objects in C#:
So with this knowledge the right way of doing the above is:
POST MORTEM UPDATE:
I want every reader to read this answer by Hans Passant very carefully as it explains the trap I and lots of other developers stumbled into. When I wrote this answer years ago I didn't know about the effect the debugger has to the garbage collector and drew the wrong conclusions. I keep my answer unaltered for the sake of history but please read this link and don't go the way of "the two dots": Understanding garbage collection in .NET and Clean up Excel Interop Objects with IDisposable