Click here to Skip to main content
15,884,913 members
Please Sign up or sign in to vote.
4.67/5 (3 votes)
See more:
Hi everyone,

I started an Application which creates a Excel list with Interop. The problem is, after saving the excel list I have an open Process in the Task Manager. I've searched in the Internet for a solution already, but I'ven't found a solution for my problem to close (not to kill) the Process.

Heres the part where I try to close the excel application:
C#
if (xlsApplication != null)
            {
                if (xlsApplication.Workbooks != null)
                {
                    if (xlsApplication.Workbooks.Count < 0)
                    {
                        xlsWorkbook.Close(true, @"C:\test.xls", null);
                        xlsApplication.Workbooks.Close();
                        xlsApplication.Quit();
                        missing = null;
                        ReleaseObjects();
                        r_Time = null;
                        r_Name = null;
                        r_ReceivedTime = null;
                        r_Received = null;
                        r_OrderedTime = null;
                        r_Ordered = null;
                        xlsRange = null;
                        xlsWorksheet = null;
                        xlsWorkbook = null;
                        xlsApplication = null;
                    }
                }
            }
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            //GC.WaitForFullGCComplete();
            GC.WaitForPendingFinalizers();


A little explanation to the snippet:
In the "ReleaseObjects()" method I Release all com objects and ranges with "System.Runtime.InteropServices.Marshal.ReleaseComObject()".
Some things in the snippet, like to set the System.Reflection .Missing.Value missing to null, are more acts of desperate than helpful code. (Because I try to close the application since a week! :omg: )

I looked, while debugging, for open Com Objects, but there aren't any of them.
The only thing is, when I save the Excel list, and then press "Close", where I run again through the GC - part(in another method, but it does the same), then the application will close "normally".

I tryed to automate, that after every saving process the form will close. It's function(to close the form and so on) is the same, but it doesn't close the excel app. :doh:

It seems that the Com objects aren't released in time.

Have anyone experience with that problem.

thx
Posted
Updated 8-Jan-20 13:47pm

Don't use ReleaseComObject or FinalReleaseComObject that's an anti pattern. In the situations where Excel is going to hang those are unlikely to help.

Using the window handle to get the process and then using the process to kill it is the real answer for when Excel is hangs. And Excel will hang sometimes - bad add-ins for example can cause it to hang.

Excel can take a while to close even after your COM instances are gone. I like to use a loop like this:

static void WaitForComCleanup()
{
    int tryCleanUp = 0;
    do
    {
        GC.WaitForFullGCComplete();
        GC.WaitForPendingFinalizers();
    }
    while (Marshal.AreComObjectsAvailableForCleanup() && tryCleanUp++ < 10);
}

To let the CLR clean up the COM objects. Then wait for the process to exit for a few seconds. If it doesn't then kill it. Like so..

if (!excelProcess.WaitForExit(5000))
{
    excelProcess.Kill();
}

One final note would be that you should be testing this with a release mode build. Debug builds will keep the COM instances around so you can see them in the debugger which means they don't clean up after themselves as aggressively which can lead you to think it's hung.
 
Share this answer
 
Comments
Kats2512 14-Aug-19 2:32am    
9 Year too late though
I just noticed you (implicitly) aquire a com pointer to the xlsApplication.Workbooks object without ever calling ReleaseComObject on it.
If you put that in a variable and release it excel should close cleanly.
 
Share this answer
 
Comments
Member 10881033 25-Dec-14 3:20am    
This is perfect work... Thanks a lot dear! Great JOB... I spent too much time looking for a solution to this problem
Member 11804380 28-Sep-18 2:32am    
hiii, how did u code it, can you please share to me, i am new to c Sharp
Thanks
Mohini
Really?

It seems that I looked for the wrong solution!

Thanks a lot
 
Share this answer
 
No, that is a different approach. This one kills a single process. As soon as it makes a new process it tracks the ID rather than killing all Excel.exe processes.

I have tested this and it does work ;)
 
Share this answer
 
Hi Jordy,

Thanks for your answer.

I've already read about killing the process but, unless i'm very much mistaken, if the user of the app has an open excel sheet, and you kill the process, then you kill the process of the manually opened excel too.

And that isn't what I want to do.

Isn't there a clean way to close excel by the app???:confused:
 
Share this answer
 
v3
Hey there,

This is an issue I had for a long time aswell. I'm afraid that I did not find a solution by using the Interop. However I did create some code that killed the process automatically for me. Now I don't know if this is what you want because i found it somewhat vague but here it goes:

First we have to Import a Dll to make use of the GetWindowThreadProcessId() function. (Don't mind the class names it's just my code).

C#
using System.Runtime.InteropServices;

...

public partial class Quotation : Form
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

...
}


Then we are going to create a variable which is going to store the processId. (I included your variable names for this)

C#
uint processId = 0;

if (xlsApplication != null)
{
   if (xlsApplication.Workbooks != null)
   {
      if (xlsApplication.Workbooks.Count < 0)
      {
         GetWindowThreadProcessId(new IntPtr(xlsApplication.Hwnd), out processId);
      
      // All your actions here
      }
   }
}


And finally the cleanup. The killing of the process needs to be inside try and catch statements. This because the closing of Excel does appear to happen sometimes.

C#
if (xlsApplication != null)
{
   if (xlsApplication.Workbooks != null)
   {
      if (xlsApplication.Workbooks.Count < 0)
      {
         xlsWorkbook.Close(true, @"C:\test.xls", null);
         xlsApplication.Workbooks.Close();
         xlsApplication.Quit();
         missing = null;
         ReleaseObjects();
         r_Time = null;
         r_Name = null;
         r_ReceivedTime = null;
         r_Received = null;
         r_OrderedTime = null;
         r_Ordered = null;
         xlsRange = null;
         xlsWorksheet = null;
         xlsWorkbook = null;
         xlsApplication = null;
      }
   }
}

try
{
    if (processId != 0)
    {
        Process excelProcess = Process.GetProcessById((int)processId);
        excelProcess.CloseMainWindow();
        excelProcess.Refresh();
        excelProcess.Kill();
    }
}
catch
{
    // Process was already killed
}

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();


I hope this helps
 
Share this answer
 
Comments
Dalek Dave 7-Sep-10 4:15am    
Good Answer!
Khaled Kokah 23-Apr-13 3:21am    
Brilliant, GetWindowThreadProcessId did the trick and will close the opened excel file. My vote of 5.
Kothari Brijesh 8-Jan-15 4:23am    
Thanks a lot..this has really solved my problem....my vote of 5 for you.
Karthik_Mahalingam 23-Aug-17 2:43am    
its working, Thank you

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900