The proper way to dispose Excel com object using VB.NET?

I have following code (obtained from online tutorial). The code is working but I suspect the way to dispose the Excel com object is somewhat not proper. Do we need really need to call GC.Collect? Or what is the best way to dispose this Excel com object?

Public Sub t1() Dim oExcel As New Excel.Application Dim oBook As Excel.Workbook = oExcel.Workbooks.Open(TextBox2.Text) 'select WorkSheet based on name Dim oWS As Excel.Worksheet = CType(oBook.Sheets("Sheet1"), Excel.Worksheet) Try oExcel.Visible = False 'now showing the cell value MessageBox.Show(oWS.Range(TextBox6.Text).Text) oBook.Close() oExcel.Quit() releaseObject(oExcel) releaseObject(oBook) releaseObject(oWS) Catch ex As Exception MsgBox("Error: " & ex.ToString, MsgBoxStyle.Critical, "Error!") End Try End Sub Private Sub releaseObject(ByVal obj As Object) Try System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) obj = Nothing Catch ex As Exception obj = Nothing Finally GC.Collect() End Try End Sub 
asked Apr 25, 2012 at 4:27 1,034 2 2 gold badges 12 12 silver badges 20 20 bronze badges possible duplicate of How to properly clean up Excel interop objects in C# Commented Apr 25, 2012 at 4:43

@Petr Abdulin, C# is a foreign language to me. Not duplicate exactly. I even struggle to understand the accepted answer in the so called duplicate.

Commented Apr 25, 2012 at 5:19 You should never need to call GC.Collect() Commented Apr 25, 2012 at 6:00 @Seph, is that required to call 'releaseObject() Sub' in order to dispose the Excel com object? Commented Apr 25, 2012 at 6:04 Commented Apr 25, 2012 at 6:55

4 Answers 4

First - you never have to call Marshal.ReleaseComObject(. ) or Marshal.FinalReleaseComObject(. ) when doing Excel interop. It is a confusing anti-pattern, but any information about this, including from Microsoft, that indicates you have to manually release COM references from .NET is incorrect. The fact is that the .NET runtime and garbage collector correctly keep track of and clean up COM references. For your code, this means you can remove the whole releaseObject(. ) Sub and calls to it.

Second, if you want to ensure that the COM references to an out-of-process COM object is cleaned up when your process ends (so that the Excel process will close), you need to ensure that the Garbage Collector runs. You do this correctly with calls to GC.Collect() and GC.WaitForPendingFinalizers() . Calling twice is safe, end ensures that cycles are definitely cleaned up too.

Third, when running under the debugger, local references will be artificially kept alive until the end of the method (so that local variable inspection works). So a GC.Collect() calls are not effective for cleaning object like rng.Cells from the same method. You should split the code doing the COM interop from the GC cleanup into separate methods.

The general pattern would be:

Sub WrapperThatCleansUp() ' NOTE: Don't call Excel objects in here. ' Debugger would keep alive until end, preventing GC cleanup ' Call a separate function that talks to Excel DoTheWork() ' Now Let the GC clean up (twice, to clean up cycles too) GC.Collect() GC.WaitForPendingFinalizers() GC.Collect() GC.WaitForPendingFinalizers() End Sub Sub DoTheWork() Dim app As New Microsoft.Office.Interop.Excel.Application Dim book As Microsoft.Office.Interop.Excel.Workbook = app.Workbooks.Add() Dim worksheet As Microsoft.Office.Interop.Excel.Worksheet = book.Worksheets("Sheet1") app.Visible = True For i As Integer = 1 To 10 worksheet.Cells.Range("A" & i).Value = "Hello" Next book.Save() book.Close() app.Quit() ' NOTE: No calls the Marshal.ReleaseComObject() are ever needed End Sub 

There is a lot of false information and confusion about this issue, including many posts on MSDN and on StackOverflow.