Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class_Terminate not firing on object from form

Tags:

vba

ms-access

I have a very simple form, that uses a very simple class to handle some things. And that class has a Class_Terminate sub to clean up after itself. However, that doesn't seem to be firing when the form gets closed.

MCVE:

Form Form1, one text box named Text0, no further controls

Private myClass1 As Class1

Private Sub Form_Load()
    Set myClass1 = New Class1
    myClass1.InitForm Me
End Sub

Class Class1

Public theForm As Form
Private WithEvents SomeTextbox As TextBox
Public Sub InitForm(frm As Form)
    Set theForm = frm
    Set SomeTextbox = frm.Text0
End Sub
Private Sub Class_Terminate()
    MsgBox "Class1 terminated succesfully"
End Sub

However, the class terminate handler doesn't fire when I close the form.

I tried unsetting the Form object in the class:

Private Sub Form_Unload(Cancel As Integer)
    Set myClass1.theForm = Nothing
End Sub

But chaos ensued: The class terminate handler fires after closing the form, but immediately afterwards Access hard-crashes without any error message!

like image 293
Erik A Avatar asked Oct 26 '18 14:10

Erik A


1 Answers

Access doesn't gracefully clean up the form object when you close a form.

That means: if an object has open references to a form, the form object persists. It only can get removed by the garbage collector if there are no references to it.

The first version of the form was creating a memory leak: the form object Form_Form1 had a reference to Class1 (through the MyClass1 variable), Class1 had a reference to the form object through the theForm variable. This caused a reference loop. The terminate handler didn't fire because the class never terminated, it remained in memory indefinitely, and closing and reopening the form just opened up a new instance of the class.

The second version caused a problem: while the reference loop was broken, references to Form1 were released first (because there still was a reference to Class1 on Form1), causing the garbage collector to clean that up, then references to Class1 were released and the garbage collector tried to clean up Class1, including the textbox object SomeTextbox, causing Access to hard-crash since the form object was already cleaned up and the textbox object was invalid.

The solution is to break the reference loop by removing all references to Class1 first. This doesn't cause crashes.

Private Sub Form_Unload(Cancel As Integer)
    Set myClass1 = Nothing
End Sub

This causes the garbage collector to clean up the Class1 instance first, releasing references to Text0, then cleans up the form objects because no-one has open references to that.

like image 151
Erik A Avatar answered Nov 01 '22 06:11

Erik A