ErrHandler is a VFP programming tool that makes it easier to create, debug, and
maintain complex applications supporting comprehensive error handling.
It can be applied to any type of
application, either as a whole, or just selected program components and
sub-applications.
When to Use ErrHandler
It's a good idea to begin by considering appropriate use of conventional VFP
error handling practices:
- validate arguments by using built-in functions
- check for conditions that would lead to errors
- use error return codes and success/failure flags
- VFP's Error Event method
- VFP's ON ERROR command
Each of these techniques has limitations, however, which become more apparent
as applications grow in complexity. In general, very
simple programs and forms can be made reasonably robust without resorting to
ErrHandler, but complex applications will probably benefit from its use.
Benefits of Using ErrHandler
ErrHandler adds a number of useful error handling capabilities to those built
into VFP:
- comprehensive error detection with clean,
flexible error handling
- ErrHandler provides generic handlers for all types of unexpected errors,
including both those that trigger VFP Error events and those that generate
an ON ERROR condition. Property settings make it easy for the
developer to control default error handling options for each object.
Unlike VFP's rather heavy-handed default error handler (Cancel, Ignore?),
ErrHandler allows clean, localized failures that don't cause more disruption
than necessary.
- context-sensitive error reporting and
cleanup logic
- While VFP's Error Event method was a major advance over its older, less
selective ON ERROR command, this still represents a fairly coarse level of
context sensitivity because it applies to an object as a whole, not one
of its individual methods. ErrHandler makes it easier to distinguish
the exact context where errors occur, down to a specific segment of code in
a specific method. This makes it possible to generate more informative
error messages with application-specific error codes and cleanup steps.
- capturing, displaying, and returning detailed error
information
- VFP has lots of its own error codes, messages, and assorted parameters
giving the details associated with an error, along with a diverse collection
of built-in functions and arguments to obtain this information. ErrHandler
establishes standardized properties and methods for easily capturing
all of VFP's error details automatically, displaying error information, and
returning it in a consistent way. ErrHandler also extends VFP's
error information by adding application-specific error
codes and messages, for greater context sensitivity.
- diagnostic tracing, secondary outputs, and logging
- Besides displaying error messages, ErrHandler displays diagnostic tracing
messages, which can be enabled selectively and used in a VFP runtime
environment (unlike VFP's Debugger). Developers can easily extend and
customize tracing for the specific needs of their own applications.
Error and tracing messages can also be "echoed" or directed to one
or more secondary outputs, including the main screen background, the
Debugger's output window, and/or an ASCII text log file. In addition, ErrHandler
supports a simple API for supplying your own external logging function,
which will be invoked automatically as messages occur.
- additional debugging and diagnostic
facilities
- ErrHandler includes its own dialog for displaying error and tracing
messages, with controls for manually setting diagnostic, tracing, output,
and logging options. The dialog optionally lets runtime users choose
whether to Ignore, Retry, Abort, or proceed with the default program
behavior. Under the VFP Development System, users can also Suspend or
Resume program execution, or invoke the VFP Debugger.
Creating an ErrHandler-Based Application
You can easily adapt an existing application or application framework to
incorporate ErrHandler, or you can create an entirely new
application by building on ErrHandler from the outset. To convert an
existing form or class, you should redefine it to be based on one of the ErrHandler
foundation classes, instead of using VFP's corresponding base class.
If you use an application framework's class library, you may want to redefine some
of its "foundation" classes as subclasses of ErrHandler foundation
classes. VFP's Class Browser makes it easy to redefine classes in many cases, and you can directly edit the VCX/VCT or SCT/SCT in those cases that are
not supported via the Class Browser.
Once you have a form or class based on an ErrHandler foundation class, the
following steps should be taken:
- specify default values for selected error handling properties
- Supply your application's name as you want it to appear in error messages
via the ehp_appname
property. If you want to support target
indirection, initialize the ehp_targname,
ehp_targclass, and ehp_targlib
properties (or you can support an explicit target object reference as an Init
argument). Set the ehp_interactive
property as desired for interactive or non-interactive modes of operation.
Set ehp_diagmode = .T. to
enable diagnostic features, which will be helpful at least until you finish
testing and debugging. (Note that you can also establish diagnostic
options by a more flexible indirect
initialization procedure when target indirection is used, as opposed to
depending on hard-coded diagnostic property settings.)
- supply standard ErrHandler Init Event method logic
- If you supply any application-specific code at all for the Init method,
e.g. for processing arguments, be sure to incorporate the
necessary logic for performing the foundation class Init
logic at the beginning
of this method. For example, you could use the following prologue:
* invoke foundation class Init logic to complete preparations for handling errors
if not dodefault( ) && generic
parent class Init failed - can't handle errors
return .F.
&& failure - don't allow object to be instantiated
endif
This will assure that the proper ErrHandler initialization steps related to target
indirection are
performed automatically. (If your class' Init method accepts an
explicit target object reference argument, you would pass it to dodefault in
the above example.)
- adjust other methods for error handling appropriate to your application
- For starters, see what happens when you deliberately cause an application
error. In some cases, ErrHandler's default error handling behavior
will suffice, but you probably won't be satisfied with generic error
handling for common, predictable errors. The simplest remedy may be
error avoidance, such as the addition of an explicit check for a valid
argument type, but error avoidance is not always feasible. This is the
point where VFP's Error event comes into play.
Instead of the usual practice of writing code in a separate Error event
method, the ErrHandler approach places "error trapping" logic
directly in the vicinity of the method code where errors are anticipated. The
procedure for trapping errors, illustrated below, is
to surround each error-prone section with a small piece of code. This allows the method to control its own context-specific
error reporting and failure logic, instead of settling for a more global default error handling procedure. You should not
normally need to supply any code for the Error
Event method, because this is handled entirely by the generic ErrHandler
foundation classes.
Bear in mind that only the methods of an ErrHandler object, not those of its
member objects, trigger the ErrHandler's own Error event. For example
a form based on ErrHForm may contain various controls, like command buttons,
text boxes, etc. Errors in the methods of those controls are not
automatically detected by the form's Error event, but errors in the form's
own methods are detected. Thus you may want to introduce
additional form-level methods to perform any error-prone logic that might
otherwise have been attached directly to those controls. By making use
of the form-level Error event handler, you can avoid the need for
additional error-handling logic tied to individual controls on the form.
- check for proper subclassing of foundation methods
- If you need to put application-specific logic into any methods for which
there exists ErrHandler foundation class code, make sure you make
appropriate use of DODEFAULT( ) or the equivalent. This pertains to
the Activate, Deactivate,
Init, Refresh, and
Unload methods. Generally
you should not make any alterations to the Error event method or the
EHM_...
methods when you base a form or subclass one of the ErrHandler foundation
classes.
- create an include file of application-specific error codes and
messages
- While this step is not required, it is strongly recommended as a matter of
good programming practice. By creating a separate include file of your
application's error codes and messages (like errhandl.h
used by ErrHandler itself), you provide both a useful piece of documentation
and an easy way to maintain a well-organized system of assigning unique
numerical error codes. These macros also make it easier to deal with
localization (internationalization) and global revisions simply by
rebuilding.
Example of Context-Sensitive Error Reporting
The following example is from the ErrHandler
Demo form, errhdemo.scx. Here is the an excerpt of code in form-level method,
ErrHCM_Run, which is invoked
by clicking on the Run button:
* prepare to run the specified command line by &-macro expansion
cmd = trim(thisform.text1.value) && put command into local mvar
* enable error trapping to catch any errors during &-macro expansion
thisform.ehm_zero()
&& clear any previous error properties
thisform.EHP_TrapErrors = .t. && take responsibility for err checking
* execute command by &-macro expansion
&cmd
* check for errors trapped via generic Error event method
thisform.EHP_TrapErrors = .f. && relinquish err checking
responsibility
if not thisform.EHP_Success
&& an error was caught
* context-specific error message including general VFP error info.
thisform.EHM_ShowAppErr(ERRH_EC_EHCINI_RUNERR, ;
ERRH_EM_EHCINI_RUNERR ;
+ chr(13) + m.cmd + chr(13) ;
+ chr(13) + thisform.EHM_VFPErrmsg())
endif
In this example, the error-prone command is the one that executes a
macro-expanded command line, &cmd. Since a user could easily enter an
invalid command line and there is no way to test for such errors, the
ErrHandler error-trapping mechanism is an appropriate solution. Note the
use of a macro-defined error code (ERRH_EC_EHCINI_RUNERR) and error message (ERRH_EM_EHCINI_RUNERR),
which are defined in the errhandl.h include file.
By using the above approach instead of relying on a comparatively "dumb"
global error handler, a much more informative error message can be produced, in
this case including the value of the offending memory variable, m.cmd.. If it had
been left it to VFP's default error handler, the user would be told only that
the command line which failed was "&cmd". Giving more
detailed, context-sensitive error messages makes it much easier to debug
unexpected program behavior.
Example of Selective Tracing
Besides error reporting, the EHM_ShowAppErr
method can also be used to generate diagnostic tracing messages, where the error
code argument is 0. The following is another example from the ErrHandler
Demo form. This is the code in the Run button's Click method, which
invokes the method in the preceding example:
* invoke a form-level method in order to make use of the form's Error event
thisform.ErrHCM_Run && pass the job along to method of the form
* support optional diagnostic tracing
if thisform.ehp_tracelevel > 0 ;
and (thisform.ehp_tracelevel % ERRH_TRACEDEMO_ALL = 0)
thisform.EHM_ShowAppErr(0, ;
"Right after invocation of ErrHCM_Run." ;
+ chr(13) + 'ehp_success = ' + iif(thisform.ehp_success, '.T.','.F.') ;
+ ', ehp_aborted = ' + iif(thisform.ehp_aborted, '.T.','.F.'))
endif
The diagnostic tracing logic follows a call to the form-level method,
ErrHCM_Run, which supports the Run command. If the current trace level,
ehp_tracelevel, is non-zero and evenly divisible by a reserved code, ERRH_TRACEDEMO_ALL
(macro defined in errhandl.h), then a tracing message
displays the values of the ehp_success and ehp_aborted properties. (This
piece of tracing logic confirms that anticipated errors are handled properly
during the
call to ErrHCM_Run.)
Copyright © 2000 - 2002, SpaceTime Systems