Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

vba - Class_Terminate not firing on object from form

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!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...