cObject
---cBaseErrorHandler
------cWindowsErrorHandler
---------ErrorSystem
This class is obsolete. It has been replaced with the cWindowsErrorHandler and cWebErrorHandler classes.
The DfError.pkg package creates the class ErrorSystem and an error-handling object based on this class. This object supports DataFlex's interactive interface for all errors generated in a program.
Use DFError.pkg
An instance of this class named Error_Object_Id is created by use of the DFError package. You should not create an instance of this class by any other means. When the object is created, its object ID is placed in the global Integer error_object_id. All access to this object should be through this Integer ID and not through the object's name. This package is a standard part of DFAllEnt.pkg, so there is usually no need to explicitly add this package to your application.
In most applications, you will not need to make any changes in the error handling as supplied and described here. This handler works well for most data-entry programs. The DataFlex report- and batch-processing objects provide their own custom error-redirection logic to handle batch errors, and can be easily customized. The information provided below is provided for advanced usage.
A global integer named error_object_id identifies the object that should receive errors. Anytime an error occurs, the error_report message is sent to the object identified by this global integer. It is expected this will handle the error as required.
When the standard error package, DfError.Pkg, is used, a global error object is created and its object ID is moved to error_object_id. Anytime an error occurs, the message error_report is sent to the error object.
Never call error_report directly to generate an error. Errors should be generated through the use of the error command. The message error_report may be sent if the sending object is itself an error object. This occurs when a custom error handler within an object has been created to handle a process.
DataFlex distinguishes between two types of errors - user errors and unhandled errors.
When handled error occurs, a message box is presented with text with no technical information - no instruction address, no error number. If error numbers are meaningful to your application, you can choose to display error numbers by setting the pbShowErrorNumber property. The default caption text for a user error is "Error", which can be changed by setting the psUserErrorCaption property.
When an unhandled error occurs, a completely different dialog is presented. This dialog provides a complete message stack dump. If the error occurs at a deployment site, the error stack can be easily copied to the clipboard, added to an email message and sent to you. If the error occurs while you are testing (debugging) your application a "Debug" button will appear in the error dialog. Press this button and the application will break and enter debug mode at the error source. The default caption text for an unhandled error is the name of the executable followed by "Unhandled Program Error", which can be changed by setting the psUnhandledErrorCaption property.
The ErrorSystem object determines if an error is a user error by checking the error against a list of user error numbers. The class has a pre-defined list, which may be customized using the AddUserError, RemoveUserError and RemoveAllUserErrors methods.
A special global procedure, UserError, is defined along with this class definition and it should be used to generate user errors. While the Error command can be used to generate unhandled errors or user errors, it will mostly be used to generate unhandled errors. Note that many if not most of the unhandled errors will be generated by the runtime or the framework.
The following is an example of generating a user error.
Function Validate_Save Returns Integer Integer iRetVal Forward Get Validate_Save To iRetVal If iRetVal Function_Return iRetVal If (Invt.On_Hand < 0) Begin Send UserError "Insufficient Inventory Stock" "" Function_Return 1 End End_Function
The following is an example of generating an unhandled error.
Procedure ProcessList String[] ArrayOfNames Integer iNames Get GetUserNames to ArrayOfNames Move (SizeOfArray(ArrayOfNames)) to iNames If (iNames=0) Begin Error DFERR_PROGRAM "GetUserNames should never have 0 names" Procedure_Return End : End_Procedure
Note that unhandled errors are not supposed to happen. The above example show how the Error command is used to identify and track down problems in an application's logic.
Prior to revision 14.1, the error handling system did not distinguish between user errors and handled errors. All errors were reported with the error number and the instruction address and a debug stack was never presented. If you need your application to behave exactly as it did in prior revisions you can set the pbUnhandledErrorSupport to False.
An error can be fatal, ignored, or trapped. If an error is fatal, an error message is displayed and the program is terminated. If an error is trapped, it is displayed with a pop up error dialog. If an error is ignored, it is ignored. When initialized, the error system will trap all errors except Error 41 (Find past end of file) and Error 42 (Find prior to beginning of file). You may choose to trap or ignore other errors. You may change this through the use of the trap_error, ignore_error, trap_all, and ignore_all messages.
There is a single error that will never be passed to the error object, Error 10 (Out of memory). Since the message-passing mechanism uses dynamically allocated memory, this would most-certainly cause a system failure.
You can turn any object into an error-handling object. This is done as follows:
1. The global integer error_object_id must be assigned to this object. Usually this assignment is temporary.
2. The Integer Property error_processing_state must be created within the object and supported within your custom error_report procedure.
3. The procedure error_report must be created within the object to handle the error.
Custom error handlers are created when you need to change the way errors are handled during a process. Usually you will turn the object that is running the process into its own error handler. When the process begins, you save the current value of error_object_id (usually to a property) and set the value of error_object_id to the current object. At this point, all errors will be directed to the current object. When the process is complete, error_object_id should be restored to its original value. This is typically done as follows:
// create property to keep track of previous error handler Property integer OldErrorId 0 : Procedure Run_Process integer hID Set OldErrorId to Error_object_id // remember old error object Move Self to Error_object_id // make self the error object // At this point, all errors will be directed to error_report // within this object. Repeat //run the process Until (done) Get OldErrorId to hId Move hId to Error_object_id // restore original error object // At this point, all errors will again be directed to // the previous (presumably standard) error handler End_Procedure
While custom error handler error_report can be made to do anything you wish, you must provide logic to prevent recursive error reports (i.e., an error creating an error). You do this by creating a property named error_processing_state and setting this property to true while within the error_report procedure and resetting it to false when the procedure is complete. Because other objects may check the value of this property to see if an error is in process, this is a public property and must be provided in all error handlers. Here is a typical example of how this property is used:
// This property MUST be created within the object or the object's class. Property Integer Error_Processing_State False : Procedure Error_Report Integer iErrNum Integer iErrLine String sErrText // if we are already within an error, do nothing If (Error_Processing_State(self)) ; Procedure_Return // mark that we are now processing an error Set Error_Processing_State to True // perform custom error handling // mark that we are no longer processing an error Set Error_Processing_State to False End_Procedure
Often a custom error handler will want to augment the behavior of the standard error handler. For example, an error handler may wish to log an error and, if the error is of the right type, display a standard pop-up error dialog. Your custom error_report procedure does this by sending the message error_report to the standard error handler (usually the previous error handler). This is done as follows:
Procedure Error_Report Integer iErrNum Integer iErrLine String sErrText Integer hId If (Error_Processing_State(Self)) ; Procedure_Return Set Error_Processing_State to True // perform custom error handling // Now direct the error to the standard error handler Get OldErrorId to hId Send Error_Report of hId iErrNum iErrLine sErrText Set Error_Processing_State to False End_Procedure
More information is provided in the error_report procedure's documentation.
The Error_Report event gets called when an error is generated and this procedure may be used to customize error reporting. When customizing unhandled error reporting a special command, CallStackDump, is provided that allows you to retrieve the message stack information.
The CallStackDump command retrieves the same message stack information you would see in your error dialog and places it in a string. You can use this do other things with the error information such as logging it to a file or sending an error report. The CallStackDump command should only be used within the error handler's Error_Report event.
The following example creates a replacement error handler that logs all unhandled errors. Because this is an example, the logging will simply display the error in the showln dialog.
Object oError is a ErrorSystem Property Boolean pbInError False Procedure Error_Report Integer iError Integer iLine String sErrMsg String sStack Boolean bUnhandled bBusy // augment to log unhandled errors Get pbInError to bBusy If not bBusy Begin Set pbInError to True Get IsUnhandledError iError to bUnhandled If bUnhandled Begin CallStackDump sStack Send LogUnhandledError iError iLine sErrMsg sStack End Set pbInError to False End // now do the normal error report. Forward Send Error_Report iError iLine sErrMsg End_Procedure Procedure LogUnhandledError Integer iError Integer iLine String sErrMsg String sStack Showln "Unhandled Error: " iError " at " iLine Showln sErrMsg Showln sStack Showln End_Procedure Move Self to Error_Object_Id End_ObjectSee Also