In traditional DP4 C programs there is usually very little in the way of error handling. It is assumed that a database can always be opened, that a fetch will either succeed or return information that there is no record. The reason this is OK is that the database manager will set error status information when something untoward happens, and the interface code checks this status information after every call and generates a system or fail error if an error has arisen. Typically these errors terminate the program more or less gracefully, displaying an appropriate error message first. If the program survives the error (for example because it filtered the system or fail error using the app_error() facility) then the return code of the function will usually be set to some safe value
With DP4DBAPI you are responsible for handling all errors that might arise. There are two possible techniques for doing so:
You can pass the address of a valid error callback function as the fourth parameter to dp4_srv_connect(). If you choose this method you are handling errors at the first available opportunity, and you can choose which errors you want to treat as fatal and which as recoverable. For example, if a program is collecting data from many servers, you might want to treat system error 87 (corrupt database) as being recoverable: you would simply stop collecting data from the affected machine, and move on the next. On the other hand, if a program is accessing only one database, then almost any system error reported against that database should be non recoverable.
A basic error handler of this type might look like this:
void DP4API my_dp4_error(CONN *conn,int flags,int error_level,
int error_nr,int p0,int p1)
{
if (flags & DP4_ERR_REPORT & error_level > 1)
printf("DP4 Error type %d Number %d Additional info %d %d\n",error_level,error_nr,p0,p1);
if (flags & DP4_ERR_HALT || errorlevel > 1)
exit(error_level);
}
Four error levels are defined: error level 3 and error level 4 correspond to system and fail errors, and are the most serious. Error level 1 messages are informational, and can be ignored - the most common such message is message 67 ("Log file nearly full"). The most problematical messages are those belonging to error level 2 - these are messages that require interaction from the user, but which do allow the program to continue execution. The reason they are problematical is that in some cases the API that encountered the problem will be retried inside the interface, so if your program simply ignores such an error your program may go into a tight loop in the DP4 interface. Most such error messages relate to loading and unloading log disks, and only apply if you choose to keep the database log files on removable media. If you do not do this, the only other message of this type which is at all likely to appear are ones that warn you that the database has been opened in read-only mode when write access was requested. So you may choose to treat all such errors as fatal.
The flags parameter to the error callback indicates whether an error report is required, and whether the application is advised to terminate. The DP4_ERR_REPORT flag will almost always be set for DP4DBAPI calls, when an error is encountered. The reason for this flag is that the DP4 C library uses a common error handler for both database and user interface APIs, and that user interface APIs have typicallt already been reported by the time the error handler is called. The DP4_ERR_HALT value will be set for all errors of level 3 and 4, but is advisory only. The one exception to this, is that if you get encounter error level 4 number 9 you must exit. This error is only generated when the DP4 service has failed, and once you encouter it you will not be able to call DP4 successfully again from this application.
You can choose not to set up an error callback function. In this case your program must call the dp4_error_status() function after every call to a function where the return value indicates an error has occurred, or for any return code where the particulat function being called does not define an error return value. This technique should probably only be used if you are creating your own wrapper API for DP4. Used in an ordinary application you would be vulnerable to leaving an error unhandled and thus misinterpretation of the functions results.
The error information returned to dp4_error status should be treated in more or less the same way as has already been described.
On Windows platforms, the best way to accurately report errors returned by DP4 is to include the header file dp4error.h and global.h in your code and to call the dp4_xerror_report() function via the dp4_error_report() macro. This will produce an appropriate message for each error. It is the function now used by the DP4 terminal manager when reporting errors, but it does not itself use the terminal manager.
This function requires a window handle as the parent of the message box that will be displayed. You can use HWND_DESKTOP, but this may sometimes cause problems with Windows activation, so a real window handle is to be preferred.
void dp4_xerror_report(int flags,
HWND hWnd,int error_type,int error_nr,
const void *error_p0,const void *error_p1,
const char * filename,
const char * src_file,int linenr,
gmem_type * gptr);
#define dp4_error_report(flags,hWnd,error_type,error_nr,p0,p1,filename) \
dp4_xerror_report(flags,hWnd,error_type,error_nr,p0,p1,\
filename,__FILE__,__LINE__,gmem_ptr)
A typical call to dp4_error_report() would look like this:
dp4_error_report(DP4ERR_NO_SOURCE,pWnd->m_hWnd,m_level,m_msgNr,&m_para0,&m_para1,0);
If you want to take responsibility for displaying the error message yourself, but would still like to get the error text you can call dp4_message_get() instead.
LPTSTR dp4_xmessage_text_get(int flags, int error_level,
int error_nr,
const void * error_p0,
const void *error_p1,
const char *filename,
gmem_type * gptr);
#define dp4_message_text_get(flags,level,nr,p0,p1,filename) \
dp4_xmessage_text_get(flags,level,nr,p0,p1,filename,gmem_ptr)