1

i m trying to get excel sheet-name of a excel file from vb.net 3.5 however it opens but excel.exe still remains in the process. How do i stop the process without killing the excel.exe from task manager?

i realise new excel.application starts new process.

i tried to use quit, close and dispose.......................nothing worked

Below is my code

   Dim sheetName As New Excel.XlSheetType
   Dim newExcell As New Excel.Application
   Dim newWorkBook As Excel.Workbook = app.Workbooks.Open(MyFileName)
   Dim worksheetName As String
   Dim ws As Excel.Worksheet = CType(WB.Worksheets.Item(1), Excel.Worksheet)
    worksheetName = ws.Name

I cannot use kill because there are other excel application running, so how do i close this particular excel.exe from processor. Please help

sam_33
  • 585
  • 5
  • 10
  • 20
  • possible duplicate of [How do I get the Process ID from a created "Excel.Application" object?](http://stackoverflow.com/questions/17759085/how-do-i-get-the-process-id-from-a-created-excel-application-object) – Hans Passant Jul 21 '13 at 16:36
  • There at least 3 other duplicates of this question, this is the proper way to do it: http://jake.ginnivan.net/vsto-com-interop – Jeremy Thompson Jul 22 '13 at 00:45

3 Answers3

5

This KB article describes the problem.

However, it's not an easy one to solve, as you must ensure you call Marshal.ReleaseComObject on every Excel object you instantiate - and it's very easy to miss one.

For example, the following code implicitly references a Workbooks object:

Dim newWorkBook As Excel.Workbook = app.Workbooks.Open(MyFileName) 

To release the Workbooks object you need to reference it explicitly, so that you have a reference on which you can call Marshal.ReleaseComObject:

Dim objWorkbooks As Excel.Workbooks = app.Workbooks
Dim newWorkbook As Excel.Workbook = objWorkbooks.Open(MyFileName)
...
Marshal.ReleaseComObject(objWorkbooks)
Marshal.ReleaseComObject(newWorkbook)
...

You also should use Try/Finally to ensure ReleaseComObject is called even if an exception is thrown.

Joe
  • 122,218
  • 32
  • 205
  • 338
2

Many people don't recommend killing the process; See How to properly clean up Excel interop objects and Understanding Garbage Collection in .net

Edit: On the other hand many people don't recommend using GC.Collect. See What's so wrong about using GC.Collect()?

In my experience killing the process is the fastest and easiest. This code kills only the exact process that it starts, no other.

Be sure to Close any open workbooks, Quit the application, Release the xlApp object. Finally check to see if the process is still alive and if so then kill it.

Here is the code I use: (works every time)

Sub UsingExcel()

    'declare process; will be used later to attach the Excel process
    Dim XLProc As Process

    'call the sub that will do some work with Excel
    'calling Excel in a separate routine will ensure that it is 
    'out of scope when calling GC.Collect
    'this works better especially in debug mode
    DoOfficeWork(XLProc)

    'Do garbage collection to release the COM pointers
    'http://support.microsoft.com/kb/317109
    GC.Collect()
    GC.WaitForPendingFinalizers()

    'I prefer to have two parachutes when dealing with the Excel process
    'this is the last answer if garbage collection were to fail
    If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then
        XLProc.Kill()
    End If

End Sub

'http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx
<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
    ByRef lpdwProcessId As Integer) As Integer
End Function

Private Sub ExcelWork(ByRef XLProc As Process)

    'start the application using late binding
    Dim xlApp As Object = CreateObject("Excel.Application")

    'or use early binding
    'Dim xlApp As Microsoft.Office.Interop.Excel

    'get the window handle
    Dim xlHWND As Integer = xlApp.hwnd

    'this will have the process ID after call to GetWindowThreadProcessId
    Dim ProcIdXL As Integer = 0

    'get the process ID
    GetWindowThreadProcessId(xlHWND, ProcIdXL)

    'get the process
    XLProc = Process.GetProcessById(ProcIdXL)


    'do some work with Excel here using xlApp

    'be sure to save and close all workbooks when done

    'release all objects used (except xlApp) using NAR(x)


    'Quit Excel 
    xlApp.quit()

    'Release
    NAR(xlApp)

End Sub

Private Sub NAR(ByVal o As Object)
    'http://support.microsoft.com/kb/317109
    Try
        While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
        End While
    Catch
    Finally
        o = Nothing
    End Try
End Sub
Community
  • 1
  • 1
D_Bester
  • 5,723
  • 5
  • 35
  • 77
  • Yeah. I've had to do the same in my experience. But I would nuance that by saying, I try to quit first. Then I try to detect if any orphaned Excel processes are around (means having to track Excel process ids that were spawned by my own app). – code4life Jul 21 '13 at 15:30
  • @code4life I agree; I think you will notice my code does exactly that: Quit, Release and if not exited then Kill. – D_Bester Jul 21 '13 at 15:33
0

Use the excel application object. Call Quit()

Like for e.g:

Dim app As New Excel.Application    
Try
    '...
    'After doing your stuff
    '...
    app.Quit()
Catch ex As Exception
    'Log your exception
    System.Diagnostics.Print("Error: " + ex.Message)
End Try
deostroll
  • 11,661
  • 21
  • 90
  • 161
  • I've had problems with strictly relying on this call. Especially if Excel is running on a server process, it's quite possible to end up with one or more orphaned Excel processes. Better to supplement with a method to task kill the orphaned processes (which means tracking the processid's of the Excel processes btw). – code4life Jul 21 '13 at 15:29
  • @code4life in my experience this happens when theres an exception, which ultimately lead to not calling that routine. I suggest you wrap your logic in a try-catch-finally constructs, and call `Quit()` in the `finally` block – deostroll Jul 21 '13 at 22:19
  • The OP says "i tried to use quit, close and dispose.......................nothing worked" – D_Bester Jul 22 '13 at 01:31
  • @code4life when you debugged did you put a breakpoint and verify that all those methods you've mentioned above actually got executed...i.e. did the breakpoints activate at those lines? – deostroll Jul 23 '13 at 12:20
  • Yeah, I think there are situations where the app.Quit() results in an exception being thrown or it doesn't actually quit the process. Which is why the orphan processes end up occurring. But this is on a server application. But still, even if an edge-case, still worth considering. – code4life Jul 24 '13 at 03:11
  • @code4life usually you are supposed to call `app.Quit()` in a Finally block. But since you are saying that "that" throws an error, try and see if you can share those details of the exception. (Modified code snippet likewise). – deostroll Jul 24 '13 at 12:16
  • @deostroll: Then you're assuming that app.Quit() is guaranteed to work, if it's in a Finally block? I'm saying that doesn't always happen, at least in my experience. I can't remember the exceptions off -hand, and I honestly don't keep my logs from years ago with me. – code4life Jul 24 '13 at 19:26