Why doesn't my form close?

If you run the code below, you’ll get an error message. The grid height is being set to 19, which is too small for a vertical scrollbar. Dismiss the message and try to close the form. If you hit Ctrl-F4 or click on the close box, the close box gets dim, but the form doesn’t close. If you CLEAR ALL in the command window, the form is released.

If you change the 19 to 39 so it is a valid height, the form can close.

Why?

To figure out the answer, I used the VS debugger to trace through the VFP internal code that closes the form. When an object is asked to be released, VFP tries to see if the object can close. If there are any member objects on the form, each one must have a reference count of one. If there is any member object that has an outstanding reference, then the form says that it cannot close. As you can imagine, this process is recursive.

For example, change it to 39 for the non-error case, run the form and get an outstanding reference to the form by typing NewVar=oForm.spin1. This creates a new variable called NewVar which references the spinner. Now the form cannot close as in the error case. Set NewVar to 0, and the form disappears.

Internally, for a routine that handles for example, a spinner keypress event, VFP will increment the refcount on the spinner, call the code to handle the event, then decrement the refcount. This protects VFP from user code that releases the object in the event.

There was some code that was incrementing the refcount, encountering the error, and the error caused that code’s matching refcount decrement to be bypassed. This code was processing CanLoseFocus, which was storing the spinner value to the grid height, which caused the error.

The fix is simple: don’t bypass the decrement if an error occurs.

Thanks to Fabio Lunardon for this bug report.

PUBLIC oform

oForm = NEWOBJECT("form1")

oForm.Show

KEYBOARD '19{TAB}' PLAIN

DEFINE CLASS form1 AS form

      ADD OBJECT grid1 AS grid

     

      ADD OBJECT spin1 AS spinner WITH ;

            format = 'K',;

            Left = 108, ;

            Top = 96, ;

            ControlSource = "thisform.grid1.height"

ENDDEFINE