1

I am facing an issue where Excel Process remains active even after calling ReleaseComObject and GC.Collect method.

My Excel Process terminates but ONLY after I close User Form

Below is sample code which shows what all things I am doing to get rid of Excel Process:

Public Class frmTEST
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim objExcel As xl.Application
        Dim wbReport As xl.Workbook = Nothing

        objExcel = CreateObject("Excel.Application")

        Try
            wbReport = objExcel.Workbooks.Open("D:\EL\Nicolas\VS Online\Classe A v2\Launcher-v2.2\Resources\Modules\Zoom.xlsm")
        Catch ex As Exception
            Common.WriteDebugLog("Exception line 44")
        End Try
        If wbReport Is Nothing Then
            MsgBox("Erreur d'ouverture du reporting - Code 745.", vbExclamation)
            Exit Sub
        End If

        With objExcel
            .Visible = False
            .ScreenUpdating = False
            .Calculation = xl.XlCalculation.xlCalculationManual
            .DisplayAlerts = False
        End With

        '' Here I do all my processing which I have removed to make the question more simplified

        With objExcel
            .Calculation = xl.XlCalculation.xlCalculationAutomatic
            .ScreenUpdating = True
            .DisplayAlerts = True
        End With

        ''~~> Close & Clean Up
        wbReport.Close(SaveChanges:=False)
        objExcel.Quit()

        Me.ReleaseObject(wbReport)
        Me.ReleaseObject(objExcel)

        MsgBox("Done")
    End Sub

    Private Sub ReleaseObject(ByVal obj As Object)
        Try
            Dim intRel As Integer = 0
            Do
                intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
            Loop While intRel > 0
            MsgBox("Final Released obj # " & intRel)
        Catch ex As Exception
            MsgBox("Error releasing object" & ex.ToString)
            obj = Nothing
        Finally
            GC.Collect()
        End Try
    End Sub
End Class

UPDATE: Based on comments I received, I made changes in my code following the other thread, but it still doesn't help. My Excel Process terminates but ONLY after I close User Form

Community
  • 1
  • 1
TechGeek
  • 2,172
  • 15
  • 42
  • 69
  • 1
    Delete Try/Catch from your ReleaseObject() method, it is hiding a bug in your code. Never write try-catch-em-all code like that. – Hans Passant Apr 11 '16 at 14:29
  • Thanks but it didn't help. Please check my updated question. – TechGeek Apr 11 '16 at 19:07
  • I voted to reopen this question, because it is not a duplicate of the one selected. This question followed the COM release mumbo jumbo/ dot rule advise and it still fails because that _solution_ is not the answer. – TnTinMn Feb 05 '18 at 19:34

1 Answers1

5

If you are using .Net V4 or greater, give this a try. Move all your Button1_Click code into a subroutine and call it from Button1_Click. This will allow the objects that are local to that subroutine to go out of scope and thereby be eligible for garbage collection.

Then call a cleanup method that uses the Marshal.AreComObjectsAvailableForCleanup function to determine how many garbage collection cycles are required to free the COM objects.

Remarks

If there are a lot of references between managed and native code with deep dependency graphs it can take a long time for all the objects to clean up. Each time a GC runs it will free up some number of RCWs, which will in turn release the underlying COM objects. Those COM objects will then release their managed references and make more objects available for cleanup the next time a GC runs, which starts the process over again.

The AreComObjectsAvailableForCleanup method provides a way for the application to determine how many cycles of GC.Collect and GC.WaitForPendingFinalizers need to happen in order to clean everything up.

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ExcelWork()
    Cleanup()
End Sub

Private Sub ExcelWork()
    Dim objExcel As xl.Application
    Dim wbReport As xl.Workbook = Nothing

    objExcel = CreateObject("Excel.Application")

    Try
        wbReport = objExcel.Workbooks.Open("D:\EL\Nicolas\VS Online\Classe A v2\Launcher-v2.2\Resources\Modules\Zoom.xlsm")
    Catch ex As Exception
        Common.WriteDebugLog("Exception line 44")
    End Try
    If wbReport Is Nothing Then
        MsgBox("Erreur d'ouverture du reporting - Code 745.", vbExclamation)
        Exit Sub
    End If

    With objExcel
        .Visible = False
        .ScreenUpdating = False
        .Calculation = xl.XlCalculation.xlCalculationManual
        .DisplayAlerts = False
    End With

    '' Here I do all my processing which I have removed to make the question more simplified

    With objExcel
        .Calculation = xl.XlCalculation.xlCalculationAutomatic
        .ScreenUpdating = True
        .DisplayAlerts = True
    End With

    ''~~> Close & Clean Up
    wbReport.Close(SaveChanges:=False)
    objExcel.Quit()

    MsgBox("Done")
End Sub

Private Sub Cleanup()
    Do
        GC.Collect()
        GC.WaitForPendingFinalizers()
    Loop While Marshal.AreComObjectsAvailableForCleanup
End Sub
Community
  • 1
  • 1
TnTinMn
  • 11,522
  • 3
  • 18
  • 39
  • Thanks. That worked very well ! – TechGeek Apr 14 '16 at 21:14
  • One reason why moving the COM access into a separate scope is that the debugger will hold on to objects inside the method and prevent them from being garbage collected, even if they are no longer accessible by any code. That can keep COM objects alive longer than you expect, even when doing an explicit GC.Collect(). – Govert Jul 04 '16 at 12:12