Troubleshooting the Form Class

By John Colby

 

Because the form’s class no longer holds the event stubs, it may be a bit disconcerting to follow events as they fire. Fortunately, there are special functions and constants that turn on and off messages that are sent to the Debug window. These messages are the first line of attack when troubleshooting.

 

At the top of each module you will find a declared constant called DebugPrint:

 

Private Const DebugPrint As Boolean = False

 

By setting this constant to True, we can print to the Debug window from anywhere in this module. Each module has its own DebugPrint constant that you can turn and off printing in any specific module.

 

In the basClassGlobal module, there is a similar constant:

 

'*+ Compiler directives

#Const DebugPrint = True  'TURNS ON/OFF ALL DEBUG PRINTING THROUGHOUT THE PROJECT

'*- Compiler directives

 

This constant is known as a compiler directive (notice the # in front), and instructs the VB compiler what to include or not to include code in the program. In our case we will use it as follows:

 

Public Sub assDebugPrint(ByVal vstrMsg As String, boolPrint As Boolean)

#If DebugPrint Then

  If boolPrint = True Then Debug.Print vstrMsg

#End If

End Sub

 

The #if directive tells the compiler do include for compilation all code between the “Then” and the “#endif” if the DebugPrint constant evaluates to True.

 

If DebugPrint evaluates to False, the following line is completely removed from the program. This behavior marginally speeds up the program if you leave calls to assDebugPrint in your code because the test doesn’t need to be performed. More importantly it demonstrates how to comment out entire sections of code from your program. Once you have debugged your class, you can remove these debug function calls to marginally speed up the operation of the class. (The keystroke combination Ctrl+G will open the Debug window, at least in A97.)

Watching form events:

I have broken the debug printing into two pieces, with a function just for watching the events. This function is controlled by:

 

#Const DebugPrintEvent = False  'TURNS ON/OFF ALL EVENT DEBUG PRINTING THROUGHOUT THE PROJECT

 

Function assDebugPrintEvent(frm As Form, str As String , boolPrint As Boolean)

#If DebugPrintEvent Then

    Debug.Print mfrm.Name & ":" & str

#End If

End Function

 

We can now place a call from inside an event

 

    assDebugPrintEvent mfrm, "Frm_Activate", DebugPrint

 

and pass the form and a string, which will typically be the name of the event being monitored. This allows us to watch the sequence of events as we move around the forms, change the focus to another form, and so on. It is a fascinating education just to open two different forms, turn on all event debugging, then watch the event sequence as you click in a control on one open form, then click in a control on another form, use the keyboard to tab from control to control etc. All of the events will be printed out in the debug window in the order that they occur.

Breakpoints in classes:

Watching the code execute in classes can be a bit problematic if more than a single instance of the class is instantiated. For example the timer event of a form would fire asynchronously and if several forms were open, they could fire in any order. In itself this is no different than if the code was running directly in the class’ form, however since it is running in a class instance, it may appear that code is running for a given form when in fact it is running for another. It is for this reason that I pass the form reference to the assDebugPrintEvent function–to allow us to print the name of the form whose class is currently executing code.

 

Other than this caveat, debugging a class is very similar to debugging anywhere else. Setting a breakpoint in function in a class will cause execution to pause when that breakpoint is encountered.

 

You can simply open the class module directly and set the breakpoint. The next time execution reaches that point, for any instance of the class, the breakpoint will pause the code. If there is any possibility that the class could be instantiated twice, be sure to check which control’s or form’s (or both) class is currently executing.

 

You can also click on any method of a class pointer and hit Shift-F2 to jump to that function in the class. To illustrate this behavior,

 

  1. Open frmClassDemo in design view.
  2. Open the code module for the form.
  3. In form_open click on the word Init in fclsFrm.Init.
  4. Hold down the shift key and tap F2.

 

You will be taken to the Init() function in dclsFrm. From here you can move around the class as desired, setting your breakpoints.

ObjectCounter:

As I mentioned in the first article, we have a set of functions for counting the instances of classes. I include (and leave in permanently) calls to these functions in Initialize() and Terminate() to count up and down an instance counter. Another function ObjCounter() simply returns the count for debug purposes.

 

In other words, as you open a form, the form’s class increments the counter. If that is all you did, ObjCounter() would return a 1, meaning that one class had instantiated. If that form had 10 controls, and all of those controls instantiated a class, then ObjCounter() would return an 11 after the form finished opening. As the form closes down, the classes count back down the counter so that, when this form finished closing, ObjCounter() would return a 0 again.

 

It is critical as you work with your classes to periodically check ObjCounter(). If the classes are not being removed from memory, ObjCounter() will return an ever higher number. If you are building a form for example, and the form instantiates two dozen classes, trying to figure out what is not unloading can become complicated. As you introduce each class and hook it in to the form, make sure you open and close the form checking ObjCounter() to reset the counter to zero before hooking into the next class. I probably don’t need to tell you that if you don’t remove your classes, you will have problems. This is called a memory leak and if not found and corrected can cause the computer to crash.

John Colby©2001
May be distributed as long as the copyright remains.

John Colby Bio