Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VB.Net Office Interop - Excel process doesn't close

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
like image 822
Alex Avatar asked Nov 30 '22 14:11

Alex


2 Answers

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
like image 60
user1388706 Avatar answered Dec 05 '22 16:12

user1388706


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.

like image 21
Rob K. Avatar answered Dec 05 '22 16:12

Rob K.