[AccessD] Get event sinks working

jwcolby jwcolby at colbyconsulting.com
Mon Feb 9 15:06:19 CST 2009


Let’s do something USEFUL!

OK are you READY?  I can’t HEAR YOU (shouts like a rock star)

So far we have learned a lot of stuff about classes and events but nothing very useful has been done 
yet. So let’s make something happen.

•	Open clsFrm in the VB editor.
•	Notice that just above the editable code there are two combo boxes.  The left box displays OBJECTS 
  that the class knows about, the right combo displays EVENTS of the currently selected object.
•	In the LEFT combo select the mFrm object.  Notice that the editor created a new event sink for us 
called mfrm_Load and placed the cursor in that event sink.

It turns out that this event is useless to us since that Load event is the very first event to fire 
as a form loads, and thus has already come and gone by the time that we can get our class loaded. 
It also turns out that the Open event is also useless to us simply because we are loading the class 
in the Open event so it has already gone by by the time this class finishes loading.

•	However with the mfrm object selected, drop down the right combo and select the BeforeUpdate 
event.  Notice that the editor creates an event sink for us and places the cursor in it for us to 
start coding there.
•	Place the following code in that event sink:

Private Sub mfrm_BeforeUpdate(Cancel As Integer)
     MsgBox "Before Update: " & mfrm.Name
End Sub

•	In the menu, click debug / compile and notice that the LOAD event sink vanishes.  The VB editor 
will very kindly remove unused but valid event sinks for us, and since we placed no code in that 
event sink, it is unused and thus removed by the editor.
•	Before we go on, drop down the LEFT combo again and select the class object.  Notice that a 
Class_Initialize() event stub was created.  Place the following code in that event stub:

Private Sub Class_Initialize()
     MsgBox "Initialize"
End Sub

•	Drop the right hand combo down again and select the Terminate event.  Place the following code in 
that event stub.

Private Sub Class_Terminate()
     MsgBox "Terminate"
End Sub

•	Save the class and open the form.

The first thing that you should notice is that the events of the class fire, displaying the 
“Initialize” message box.  Remember I said that unlike regular modules, classes have two events that 
fire.  We have created sinks in the class module to sink these events and so the message box will 
execute when we instantiate and the class.

•	Close the form.

But wait… what happened to that Terminate message box from the class?  The answer is that the 
Class_Terminate event did not fire, and THAT means that the class never unloaded.  Ooooops!

The class never unloading means that the pointer to the class was never set to nothing back in the 
form.  And THAT means that the form did not close properly!!!

Remember I mentioned back in the beginning that an object only unloads when the last pointer to it 
is set to nothing?  Well guess what, we have a pointer to the form in the class itself.  This is 
called a circular reference.  The form has a pointer to the clsFrm and clsFrm has a pointer to the 
form.  Since each points to the other, (so far) neither pointer is set to nothing and so BOTH the 
form and the class remain in memory.  That is a definite No-No!  Can you say memory leak?

In order to get around this, we need to sink the Close event in the clsFrm, and in that event sink 
we need to get rid of the pointer to the form.

•	In the editor with clsFrm loaded, select the form object in the left hand combo.
•	In the right hand combo select the Close event and the editor will create a close event stub for you.
•	In that event stub place the following code:

Private Sub mfrm_Close()
     Set mfrm = Nothing
End Sub

•	Now, back up in mInit() you need to add one more line of code:

Function mInit(lfrm As Form)
     Set mfrm = lfrm
     mfrm.BeforeUpdate = cstrEvProc
     mfrm.OnClose = cstrEvProc
End Function

Notice the line just before End Function which places that cstrEvProc into the mfrm.OnClose 
property.  As we discussed before, that “hooks” the close event and allows this class to sink the 
event and thus run the close event of the form.

•	Save the clsFrm and open and then close the form.  This time the form should correctly close 
BECAUSE we set the reference to the form to nothing inside of the clsFrm instance.  Because the form 
correctly closes, the pointer is set to nothing in the form’s class module, and NOW the msgbox in 
the clsFrm instance will fire, displaying the message box “Terminate”.

I understand that you will probably need to read over that and probably even ask questions about 
this “circular reference” so I am going to stop here.

In this lecture we created three event sinks in clsFrm.  The mfrm_BeforeUpdate() we have not used 
yet but we created it.  The Initialize() and Terminate() of clsFrm itself we have used.  To this 
point we have just caused a message box to run and display the name of the event, nothing 
spectacular, but events are now being sunk in the clsFrm and code is running when events fire.

We also discovered a circular reference, the form references the class and the class references the 
form.  In order to correctly close the form we had to sink the close event of the form, and in that 
event sink we set the variable that points to the form back to nothing.  Doing that “released the 
last reference” to the form and allowed it to correctly close.  When it closed, VBAs garbage 
collector set the fclsFrm variable in the form’s header to nothing, releasing the last pointer to 
fclsFrm and the fclsFrm instance closed.  When it closed, the Terminate() event fired, displaying 
the “Terminate” message box.

We now have a class that stores a pointer to an object (the form), sinks events from the object 
(form) and causes code to run when those object (form) events run.  We also have a form that loads 
and initializes an instance of that class.  We have come a long way.

-- 
John W. Colby
www.ColbyConsulting.com



More information about the AccessD mailing list