Can't kill Excel.Exe after using Excel component in vb.net

Hi ,

I'm using Excel.Application generating excel report via vb.net 2003 , the problem is excel.exe process reminds even after generated excel report closed . I have been using the followed code to close or dispose the process , but it does'nt work either.

thenks

Dim procList() As Process = Process.GetProcesses()

Dim k As Integer

For k = 0 To procList.GetUpperBound(0) Step k + 1

If procList(k).ProcessName = "EXCEL" Then

procList(k).Close()

procList(k).Dispose()

End If

Next



Answer this question

Can't kill Excel.Exe after using Excel component in vb.net

  • c.g rajesh kumar

    Use a new thread to do all the excel stuff. Do still use the marshal stuff but once the thread quits excel will quit if you called excel.quit.

  • chrismpace

    If you have a few references to each object, then you need to call ReleaseComObject once for each reference. ReleaseComObject returns a count of the number of references remaining, so you can use a loop and keep calling it until the count <1.
    In v2.0 of the framework you get FinalReleaseComObject that does the loop for you.

  • TA123

    I strongly agree with Denton! Every other approach is a waste of time and energy. This is simple and effective.

    Denton wrote:

    Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, _
    ByVal wParam As Int32, ByVal lParam As Int32) As Int32

    Const WM_QUIT = &H12

    Dim App As new Excel.Application

    Do Excel stuff

    PostMessage(App.Hwnd, WM_QUIT, 0, 0)

    Rather than terminate all instances of Excel this will terminate the instance you created in code.

    Denton


  • R.Tutus

    Hi,

    The above method will kill the process. However if there are multiple applications or batch program running independant of eachother and each of them create their own excel object, the above method will kill all of the processes.

    Is there anyway to uniquely identify the process pertaining to your application so that we can try to find the process by its id and kill the same

    Another way is to do the following

    objExcel.Workbooks.Close()

    objExcel.Quit()

    Marshal.ReleaseComObject(objExcel)

    objExcel = Nothing

    GC.Collect()

    GC.WaitForPendingFinalizers()

    GC.Collect()

    But using GC is a performance issue. However this can be used if it does not occur frequently, in the sense that this GC.Collect does not happen at places where the user will have frequent access.



  • Sanjeev K Purohit


    When all else fails I use API function calls:

    Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Int32

    Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, _

    ByVal wParam As Int32, ByVal lParam As Int32) As Int32

    Public Function TerminateExcel()

    Dim ClassName As String = "XLMain"

    Dim WindowHandle As Int32

    Dim ReturnVal As Int32

    Const WM_QUIT = &H12

    Do

    WindowHandle = FindWindow(ClassName, Nothing)

    If WindowHandle Then

    ReturnVal = PostMessage(WindowHandle, WM_QUIT, 0, 0)

    End If

    Loop Until WindowHandle = 0

    End Function



  • Matthijs Koopman

    thank's
  • Chinwa KneeHo

    Sadly that (the Interop Marshal release) doesn't always work because Excel XP and lower suck at releasing.  I had to use your loop, but replace the Process.Close() and Process.Quit()  with Process.Kill().  Works like a charm.  Just be careful that you want ALL versions of excel.exe to be killed, because they will.

     

    I use this:

     

    Workbook.Save()
    Workbook.Close()
    Application.Quit()

    System.Runtime.InteropServices.Marshal.ReleaseComObject(Application)

    Worksheet = Nothing
    Workbook = Nothing
    Application = Nothing

    Dim proc As System.Diagnostics.Process

    For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")
    proc.Kill()
    Next



  • pritha

    The FinalReleaseCOMObject and all forms of it do not kill the EXCEL.EXE in the windows task manager. I've run loops, do until, etc.... and nothing.

    Unless an actual Microsoft VB Programmer (someone who developed it for MS) comes on here and gives me the specific code that kills an instance of excel using the Marhsall.ReleaseComObject or Marshall.FinalReleaseComObject then I will continue to work under the assumption that Excel XP cannot be shut down without process.kill().

    It just doesn't release. Period. (For Office XP)



  • Blast

    Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, _
    ByVal wParam As Int32, ByVal lParam As Int32) As Int32

    Const WM_QUIT = &H12

    Dim App As new Excel.Application

    Do Excel stuff

    PostMessage(App.Hwnd, WM_QUIT, 0, 0)

    Rather than terminate all instances of Excel this will terminate the instance you created in code.

    Denton


  • David Maynard

    Hi Swade,

    you might be right about Excel but I am not convinced by your code. Every COM wrapper variable has to be passed to ReleaseComObject. In your case you do not call ReleaseComObject on Workbook and Worksheet. Setting them to Nothing has no immediate effect as those objects are just collectable if not referenced any more, but the collection and with that the Release call on the internal COM interface pointer is only down upon garbage collection.

    Good candidates for holding references one might forget are event handlers. I don't know how the WithEvents semantics are when it comes to remove the event connections. Being explicit with AddHandler and RemoveHandler might help.

    If Excel is still not exiting you might try calling GC.Collect(). Yes, I know, this is bad practice in general, but if you really used all possible ways to release your COM "connections" to Excel and there still seems to be some object holding onto Excel which is maybe unreachable and so collectable, that might be less "rude" than killing excel.exe.

    If that all doesn't work, well, go for killing excel...

    --
    SvenC


  • PepsiWales

    I agree with you 100%. I hadn't thought of releasing the other COM objects. I was merely using the MSDN reference. I had been adding the other stuff to get it to work (killing the process) and found that it works that way. I'll try yours.

  • davros51

    Hi,

    that is really not the supposed way of releasing a COM server ;)

    Call System.Runtime.InteropServices.Marshal.ReleaseComObject on every COM variable when you do not need that COM variable any more. Unfortunately COM wrappers do not follow the IDisposable pattern so you cannot use the using statement but have to remember to put that call in your code at the appropriate places.

    After the last COM reference is released excel.exe should go away if it was not started interactively before.

    --
    SvenC


  • aguess

    Still didn't work.  It may be easier using Office 2003, but Office XP just will not release without killing the proc.  Even if I do it in debug and then shut down the program (where it should drop the connection to the COM object), it still stays connected. 

    Workbook.Save()

    Workbook.Close()

    Application.Quit()

    System.Runtime.InteropServices.Marshal.ReleaseComObject(Worksheet)

    System.Runtime.InteropServices.Marshal.ReleaseComObject(Workbook)

    System.Runtime.InteropServices.Marshal.ReleaseComObject(Application)

    Worksheet = Nothing

    Workbook = Nothing

    Application = Nothing

    GC.Collect()

    Dim proc As System.Diagnostics.Process

    For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL")

    proc.Kill()

    Next



  • kcchesnut

    you could try this

    Public Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hWnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer

    Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _

    (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr

    Dim proc As System.Diagnostics.Process

    Dim intPID As Integer

    Dim intResult As Integer

    Dim iHandle As IntPtr

    Dim strVer As String

    Try

    objExcel = New Excel.Application

    objExcel.Caption = "test"

    objExcel.DisplayAlerts = False

    strVer = objExcel.Version

    iHandle = IntPtr.Zero

    If CInt(strVer) > 9 Then

    iHandle = New IntPtr(CType(objExcel.Parent.Hwnd, Integer))

    Else

    iHandle = FindWindow(Nothing, objExcel.Caption)

    End If

    objExcel.Workbooks.Close()

    objExcel.Quit()

    Marshal.ReleaseComObject(objExcel)

    objExcel = Nothing

    intResult = GetWindowThreadProcessId(iHandle, intPID)

    proc = System.Diagnostics.Process.GetProcessById(intPID)

    proc.Kill()

    Catch ex As Exception

    End Try

    this will kill only the associated excel.exe and not all the exe's in the task manager.

    Cheers

    Ganesh



  • Can't kill Excel.Exe after using Excel component in vb.net