Cascaded ON CLOSE handling
by Richard Russell, September 2010
The article Cascaded error handling explains how a procedure or function can take some 'local' remedial action in the event of an error (for example to cleanup after a Windows API operation) and then pass responsibility for dealing with the error to the code from which it was called. In principle there may be several cascaded procedures or functions, each of which needs to handle the error before passing it 'down the chain'.
A very similar situation can occur when the user closes the window. The procedure or function which is being executed when the ON CLOSE event occurs may need to perform some 'local' cleanup operations before the 'global' ON CLOSE handler finally quits the program. Again, in principle there may be several cascaded procedures or functions which each need to handle the ON CLOSE event.
The most elegant way to achieve this is to combine the cascaded ON ERROR and ON CLOSE handling, by allocating an error number (111 in this example) to the ON CLOSE event. The short program below illustrates this technique; the user is prompted either to press Escape (which results in an error) or to click Close (which triggers the ON CLOSE event). The code waits in an 'infinite loop' within PROC2 until one or other of these happens.
After the event is handled in PROC2 it is passed down to FN1 and then to PROC0; finally the catch-all ON ERROR or ON CLOSE statement in the main program is activated. For the purposes of illustration, the handling of the ON ERROR and ON CLOSE events at each stage consists simply of printing a message to the screen; in a practical example this would be replaced by the necessary cleanup code.
PRINT "Click Close to test cascaded ON CLOSE handling" PRINT "Press Escape to test cascaded ON ERROR handling" PRINT ON ERROR PRINT "Error handled in Main: " REPORT$ : END ON CLOSE PRINT "Close handled in Main" : END PROC0 END DEF PROC0 LOCAL dummy ON CLOSE LOCAL ERROR 111, "Close" ON ERROR LOCAL RESTORE LOCAL \ \ IF ERR = 111 PRINT "Close handled in PROC0" : PROCclose ELSE \ \ PRINT "Error handled in PROC0" : ERROR ERR,REPORT$ dummy = FN1 ENDPROC DEF FN1 ON CLOSE LOCAL ERROR 111, "Close" ON ERROR LOCAL RESTORE LOCAL \ \ IF ERR = 111 PRINT "Close handled in FN1" : PROCclose ELSE \ \ PRINT "Error handled in FN1" : ERROR ERR,REPORT$ PROC2 = 1 DEF PROC2 ON CLOSE LOCAL ERROR 111, "Close" ON ERROR LOCAL RESTORE LOCAL \ \ IF ERR = 111 PRINT "Close handled in PROC2" : PROCclose ELSE \ \ PRINT "Error handled in PROC2" : ERROR ERR,REPORT$ REPEAT WAIT 1 UNTIL FALSE ENDPROC DEF PROCclose LOCAL c%% c%% = PAGE - !340 + !392 IF !392 PROC(^c%%) ELSE QUIT ENDPROC
Note that in a real-world example the final ON CLOSE handler would probably QUIT the program. That isn't done here because the displayed output would disappear!
There is a theoretical possibility that an ON CLOSE event could occur between the ON CLOSE and ON ERROR statements in PROC0. In that very unlikely circumstance, the close would be handled as an error. Apart from the user receiving an unexpected message, it should be harmless.