4

Closing an excel using microsoft.office.interop.excel to release the ranges, sheets and workbook doesn't close the process in Windows.

I can fully close all excel instances but do not know if the user has another excel instance running at the same time.

Here's everything I've tried

Marshal.ReleaseComObject(myWorksheet)
Marshal.FinalReleaseComObject(myWorksheet)
Marshal.ReleaseComObject(xlRange)
Marshal.FinalReleaseComObject(xlRange)
Marshal.ReleaseComObject(.activeworkbook)
Marshal.FinalReleaseComObject(.activeworkbook)
Marshal.ReleaseComObject(excelApplication)
Marshal.FinalReleaseComObject(excelApplication)
MSExcelControl.QuitExcel()
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

Friend Shared Sub QuitExcel()
    If Not getExcelProcessID = -1 Then
        If Not excelApp Is Nothing Then
            'Close and quit
            With excelApp
                Try
                    Do Until .Workbooks.Count = 0
                        'Close all open documents without saving
                        .Workbooks(1).Close(SaveChanges:=0)
                    Loop
                Catch exExcel As Exception
                    'Do nothing
                End Try
                Try
                    .ActiveWorkbook.Close(SaveChanges:=0)
                Catch ex As Exception
                    'Do nothing
                End Try

                Try
                    .Quit()
                Catch ex As Exception
                    'Do nothing
                Finally
                    myExcelProcessID = -1
                End Try
            End With
            excelApp = Nothing
        End If
    End If
End Sub
Alex
  • 718
  • 3
  • 11
  • 26

5 Answers5

11

Good solution Alex, we shouldn't have to do this, but we do, EXCEL just won't end. I took your solution and created the code below, I call ExcelProcessInit before my app imports or exports with Excel, then call ExcelProcessKill after it's complete.

Private mExcelProcesses() As Process

Private Sub ExcelProcessInit()
  Try
    'Get all currently running process Ids for Excel applications
    mExcelProcesses = Process.GetProcessesByName("Excel")
  Catch ex As Exception
  End Try
End Sub

Private Sub ExcelProcessKill()
  Dim oProcesses() As Process
  Dim bFound As Boolean

  Try
    'Get all currently running process Ids for Excel applications
    oProcesses = Process.GetProcessesByName("Excel")

    If oProcesses.Length > 0 Then
      For i As Integer = 0 To oProcesses.Length - 1
        bFound = False

        For j As Integer = 0 To mExcelProcesses.Length - 1
          If oProcesses(i).Id = mExcelProcesses(j).Id Then
            bFound = True
            Exit For
          End If
        Next

        If Not bFound Then
          oProcesses(i).Kill()
        End If
      Next
    End If
  Catch ex As Exception
  End Try
End Sub

Private Sub MyFunction()
  ExcelProcessInit()
  ExportExcelData() 'Whatever code you write for this...
  ExcelProcesKill()
End Sub
user1388706
  • 191
  • 1
  • 6
4

I found a rough work around to get the process ID (PID) when you open excel and close it using the same PID afterwards

Get all excel processes before opening (in-case another is already running):

            msExcelProcesses = Process.GetProcessesByName("Excel")
            'Get all currently running process Ids for Excel applications
            If msExcelProcesses.Length > 0 Then
                For i As Integer = 0 To msExcelProcesses.Length - 1
                    ReDim Preserve processIds(i)
                    processIds(i) = msExcelProcesses(i).Id
                Next
            End If

Then repeat the process straight after opening excel, the new PID should be yours

Then all you need to do at the end is iterate list again and kill the one with your ID

                Dim obj1(1) As Process
                obj1 = Process.GetProcessesByName("EXCEL")
                For Each p As Process In obj1
                    If p.Id = MSExcelControl.getExcelProcessID Then
                        p.Kill()
                    End If
                Next
Alex
  • 718
  • 3
  • 11
  • 26
  • I don't think that this is a good idea. If you cleanly quit Excel the process should exit on its own. – Enigmativity Aug 02 '12 at 12:03
  • 5
    @Enigmativity if you could help anymore than just downvoting and telling me things I've already tried then I'd much appreciate it – Alex Aug 02 '12 at 12:15
  • 2
    I added too much stuff in my code, including data analyse tools to create histogram, and a huge amount of cells... Seems that this is the only way for me to kill excel. Thanks for providing this solution. – Joe Jan 08 '15 at 18:20
4

I know this is an old thread, but if anyone comes back to this, you actually have to call every Interop.Excel object you touch in the workbook. If you pull in an instantiated class from Excel into your code, when you're done with it, Marshal.ReleaseComObject. Even every cell. It's crazy, but it's the only way I was able to get the same issue resolved.

And make darn sure you don't have a fatal exception and leave something unreleased... Excel will stay open.

Excel.Applicaiton? Marshal.ReleaseComObject.

Excel.Workbook? Marshal.ReleaseComObject.

Excel.Workshet? Marshal.ReleaseComObject.

Excell.Range? Marshal.ReleaseComObject.

Looping through Rows? Marshal.ReleaseComObject every row and cell you loop through.

Exce.Style? Marshal.ReleaseComObject... At least this is what I had to do...

If you plan on using the PIA to access Excel, from the first line of code you write, plan how you're going to release your objects. The best approach I've had is to make sure that I pull an excel value out of the Excel object and load it into my own internal variable. Then imediately call Marshal.ReleaseComObject you accessed. Looping through excel objects via a list in a Application, Workbook, Sheet, ListObject, Table, etc, tends to be the hardest to release. Hence planning is rather critical.

Rob K.
  • 519
  • 6
  • 16
  • Ouch. I don't work with this application or VB.net anymore but this sounds like plausible – Alex Aug 10 '21 at 10:09
3

I had the same problem a while ago, try using Marshal.ReleaseComObject on your excel objects. It's located ed in the System.Runtime.InteropServices namespace. Also remember to close down your excel objects beforehand.

xlWorkbook.Close();
xlApp.Close();
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
Francis Dean
  • 2,386
  • 2
  • 22
  • 29
0

I encountered this a while back. I needed to fix an error with spaces included in a Path, Opening MS Excel and successfully closing it on each close. The below code worked for me. Hope this helps.

Sub Main(ByVal CmdArgs() As String)

'path with spaces with cause errors
Dim DestinPath As String = "D:\ReflexCosting Ver.2\Excel\Order.xlsx"

Dim TAProcess1 As New Process

TAProcess1.StartInfo.FileName = "EXCEL.EXE"
TAProcess1.StartInfo.UseShellExecute = True
TAProcess1.StartInfo.Arguments = " """ & DestinPath & """"
TAProcess1.StartInfo.WorkingDirectory = " """ & DestinPath & """"
TAProcess1.StartInfo.WindowStyle = ProcessWindowStyle.Normal

AddHandler TAProcess1.Exited, New EventHandler(AddressOf p_Exited)

TAProcess1.EnableRaisingEvents = TAProcess1.Start()
TAProcess1.WaitForExit()

End Sub

'Called on Process exit "Will close any process started
Private Sub p_Exited(ByVal sender As Object, ByVal e As EventArgs)
Try
    ' remove the event
    RemoveHandler DirectCast(sender, Process).Exited, New EventHandler(AddressOf p_Exited)
    Console.WriteLine("Process has exited.")

Catch ex As Exception
    MsgBox(ex.Message, MsgBoxStyle.Critical, "Error: 09112")
End Try

End Sub