PRODUCT : Borland C++ NUMBER : 1304 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 1/6 TITLE : How to write exception handlers in OS/2 Using the OS/2 2.0 Operating System Exception Management OS/2 2.X supports operating system level exception handling. The Control Program Interface provides a complete set of functions to trap exceptions in a program as they occur during the execution of a program. Some of the functions that the Control Program Interface provides for exception management are DosSetExceptionHandler(), DosUnsetExceptionHandler(), and DosRaiseException(). The function DosSetExceptionHandler() is used to install a user-defined exception handler that will be called when an exception occurs in the program execution. An exception is an abnormal condition that can occur during program execution. One example of an exception is a memory write to a invalid memory location. The following program will generate an exception from writing to a null pointer declared local to main(). This exception, 'The memory access violation' is commonly produced by programmer error. #include void main(void) { char *ptr = 0L; strcpy(ptr, "You are in big trouble buddy!"); } In the preceding code the pointer 'ptr' has no memory associated with it which makes it a null pointer, and it is invalid to write data into the pointer. The strcpy() attempts to copy the string 'You are in big trouble buddy' into this area causing an exception. You can use the DosXXX Control Program Interface functions to manage your exceptions under Borland C++, but there are some serious drawbacks. Any exception handler set using the DosSetExceptionHandler() is only good for the current stack frame and stack frames that reside below the current stack frame. This attribute of the OS/2 exception management is referred to as "Stack based exception management". In C/C++ terms, this means that any exception handler set via the DosSetExceptionHandler() is only good for the current function and any function that is called by the current function. The following pseudo code illustrates a common pitfall encountered when using the DosSetExceptionHandler(). PRODUCT : Borland C++ NUMBER : 1304 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 2/6 TITLE : How to write exception handlers in OS/2 void aCustomExceptionHandlerFunction() { // Catch any and all exceptions in here... } void aFunctionToRegisterTheHandler() { // Set the current exception handler to be the // handler function defined above. DosSetExceptionHandler() /* Call to OS/2 API */ // At this point in the code the user defined handler is set // and will be used. // A call to another function here will still use the exception // handler // set above, unless the called function sets a new // handler then that handler will be used. } // Upon return the handler set in this function will be removed. void main(void) { // Here handler function is not set. // Call a function that in turn calls DosSetExceptionHandler() // to set a user defined exception handler. aFunctionToRegisterTheHandler(); // The previous function set the user defined handler function // but since it returned, and our exception handling is 'stack // based', the return from the function cleared the setting of // the user defined handler. } The Borland C++ Run-Time library provides a function that allows you to circumvent this behavior of 'stack based' exception management. The function _SetUserHandler() allows the programmer to set an exception handler that will be used for the entire program, regardless of the program stack frame. The _SetUserHandler() function has the following prototype: ERR _SetUserHandler(ERR); PRODUCT : Borland C++ NUMBER : 1304 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 3/6 TITLE : How to write exception handlers in OS/2 The _SetUserHandler() function takes as a parameter of the new handler function. The _SetUserHandler() returns the previous handler function or the default handler if no handler was set. The following code shows how to use the _SetUserHandler() to trap a memory protection violation that would occur from the previous code. #define INCL_DOSEXCEPTIONS #include #include #include #include // Turn of the parameter not used warning #pragma option -w-par // The user defined exception handler. ULONG APIENTRY UserExceptionHandler( PEXCEPTIONREPORTRECORD ptr1, struct _EXCEPTIONREGISTRATIONRECORD *ptr2, PCONTEXTRECORD ptr3, PVOID ptr4) { // Check if the exception is an access violation. if (ptr1->ExceptionNum == XCPT_ACCESS_VIOLATION) { // Handle the access violation. Handling the // access violation includes exiting the program. printf("Problem occurred in program...\n"); printf("Exiting program\n"); DosExit(EXIT_PROCESS, 1); /* Exit the program */ } // The exception that occurred _WAS_ _NOT_ a protection // violation. Allow the exception management to pass // the exception on to the next handler in the chain. return XCPT_CONTINUE_SEARCH; } void main(void) { char *ptr = 0L; /* a null pointer */ PRODUCT : Borland C++ NUMBER : 1304 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 4/6 TITLE : How to write exception handlers in OS/2 // Set the exception handler function. _SetUserHandler(UserExceptionHandler); // Generates a memory protection violation. strcpy(ptr, "Your in big trouble buddy!"); } The preceding code shows how to trap an access violation that may result anywhere in the executing program. The return value to the handler function is critical in notifying OS/2 if the exception has been handled by the currently executing handler or if it should be passed to the default exception handler function. When an exception is not handled by the currently executing handler a return value of XCPT_CONTINUE_SEARCH can be specified to give the exception to default exception handler. When the currently executing exception handler has handled the incoming exception a XCPT_CONTINUE_EXECUTION should be returned. The Borland C++ for OS/2 Run-Time library provides the function _unsetuserhandler(). This function can be called to remove all user-defined installed exception handlers for the program. The _unsetuserhandler() function sets the exception handler to the system default. To provide a much more systematic way to remove a single exception handler, the programmer should call _SetUserHandler() with the previous exception handler returned from the previous call to _SetUserHandler(). This allows the programmer to replace the current exception handler with a new or old exception handler, storing the current exception handler from the return value. The following code illustrates this method. // Required header files #define INCL_DOSEXCEPTIONS #include #include #pragma option -w-par // The user defined exception handler. ULONG APIENTRY NewExceptionHandler( PEXCEPTIONREPORTRECORD ptr1, PRODUCT : Borland C++ NUMBER : 1304 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 5/6 TITLE : How to write exception handlers in OS/2 struct _EXCEPTIONREGISTRATIONRECORD *ptr2, PCONTEXTRECORD ptr3, PVOID ptr4) { // trap the exception here... } // The old exception handler. ULONG APIENTRY (*OldExceptionHandler) (PEXCEPTIONREPORTRECORD ptr1, struct _EXCEPTIONREGISTRATIONRECORD *ptr2, PCONTEXTRECORD ptr3, PVOID ptr4); // This function sets a user defined exception handler void SetHandler(void) { // Set a new user-define exception handler called // 'NewExceptionHandler' // Store the old exception handler in the variable // 'OldExceptionHandlr'. OldExceptionHandler = _SetUserHandler(NewExceptionHandler); } // Set exception handler to OldExceptionHandler, removing // NewExceptionHandler. OldExceptionHandler was obtained // from the previous call to _SetUserHandler() that set // NewExceptionHandler(). void RemoveHandler(void) { _SetUserHandler(OldExceptionHandler); } void main(void) { SetHandler(); RemoveHandler(); } Using the exception management mechanism of OS/2 2.0 and Borland C++, you can build a safe application that will check for any PRODUCT : Borland C++ NUMBER : 1304 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 6/6 TITLE : How to write exception handlers in OS/2 abnormal condition that may arise during the execution of your program. DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.