[ Programmer's Guide ]

[ Coding Conventions ]

Error Handling #

The general scheme used to deal with errors is to follow an exception handling style as uniformly as possible.

VB #

VB supports the exception style fairly directly so it is not difficult to implement. A common form for routines is:

<initialization>

on error goto XXX_error

<body>

XXX_exit:
<tidy_up>
if error then re-throw error
exit sub

XXX_error:
<note_error>
resume XXX_exit

The idea is that the common tidy up code is executed irrespective of whether the routine is exited normally or due to an error. One of the functions of the <initialization> block is to set that there has not been an error (i.e., it sets an nErr variable to zero).

The <note_error> code sets nErr to the number of the error which has actually happened. Sometimes this is done via a routine called ErrorTrap which can be a useful point to locate a breakpoint to find where an error has happened.

C/C++ #

Microsoft has had the nerve to release a compiler (MSVC 1.0) which claims to support C++ but actually does not support exception handling - in the author's view, one of the major features of C++.

Exception handling is therefore implemented by hand.

Most routines in max2dll take as their first parameter a session handle (actually a pointer) which references a structure containing various information about the current Max2 database access (such as the name of the database directory, the current month, etc.) and also error handling information. In particular, there is a member called nErr which contains the number of the most recent error which has not yet been returned to the VB code.

When an error condition is detected this variable is set via a call to the routine dllSetErr (often via the #define'd macro INT_ERR which indicates a generic internal error) and then the routine executes a goto to an error handler label at its end. Often this executes tidy up code common to normal and error exits from the routine.

Often there is a boolean flag which is used to indicate to the common clean up code whether or not an error has been detected. At the top of the routine it is set to indicate by default that there has been an error then, just before the normal flow of the code enters the common exit code, it is set to indicate that there has not been an error after all.

Usually errors are set by routines called directly from VB but sometimes they are set in internal routines. In these cases, the higher level C/C++ routines can check for the error condition by looking at the value of nErr.

A routine which neatly illustrates most of the error handling techniques is tnSeekTransaction in file TRANSACT.CPP.

When a C/C++ error condition is set in the session structure the name of the module and the line number are also stored. In addition, on each entry to the DLL (from the VB code) the name of the routine being called is noted. If an error occurs the name of the called routine (which may not be the one which actually detected the error) is also recorded.

Many error conditions which "should not happen" are lumped together as internal errors. For these, the module name and line number serves to identify the error condition. This could be a problem if the source code is modified between the time of compilation of the version in use and the time at which the error is investigated - although in practice this has not happened yet.

C/C++ to VB #

If the C or C++ code detects an error condition it must return this to the calling VB code. Except for a few minor utility routines (such as the date and time parsing and formatting routines) this is done via the session structure.

Within the VB code each call to the C/C++ code is followed by a call to a VB routine called dllCheckError which makes a call to the DLL to return the error code and throws this as a VB error if one has occurred.