![]() |
You could try to prevent this error by explicitly checking each value for equality to zero before proceeding with the division. However, there are many conditions, in addition to divide-by-zero errors, that could throw an exception. Rather than coding prevention mechanisms for each anticipated condition, you could use an exception handler to better structure your DLL implementation, while allowing the process to continue to execute, even in the face of an error.
The remainder of this paper describes a technique, using the Windows NT (tm) Structured Exception Handling (SEH) mechanism, to allow you to create a DLL that captures exceptions generated in your DLL and prevent those exceptions from propagating back to the calling VEE process. We chose SEH over C++ style exceptions because a plain-old C function can use SEH and because some C++ compilers yield unpredictable results when exception handlers are used in conjunction with functions declared as extern "C"1.
The following code snippet illustrates the use of a try block:
__try{ x=5/divisor; }When any of the statements inside the try block cause an error, the operating system will look for an exception filter function willing to deal with the error. Your function can elect to:
__except(evaluateException(GetExceptionCode())){ /* We need to clear the condition which caused the exception. In the specific case of a divide-by-zero error, we can call '_clearfp', which will return the floating-point processor status word and clear the exception condition. */ fpStatus=_clearfp(); /* We pass back a big number to indicate that something went wrong. */ x=9.9e37; }Notice the call to the function GetExceptionCode. This function returns an indication of the error condition that caused us to generate an exception. It returns valid results only when called from within the parentheses immediately follwing the __except key word.
We said earlier that there are three possible actions a process can take in response to catching an exception. The function evaluateException, which is called from our exception filter, returns a value that indicates what action is to be taken in response to any given type of exception. If we have a divide-by-zero error, the return indicates that we should recover from the error by executing the code in the body of the __except block. Any other error condition results in a return value instructing the operating system to continue searching for an exception handler willing to deal with the error. If the operating system finds no exception handler willing to deal with the problem, it terminates the process (with extreme prejudice ;-) ).
If we are to prevent an exception from propagating back to the
application that loaded our DLL, we must clear the condition which
caused the error in the first place. In the case of a divide-by-zero
error, we can clear the floating-point processor by making a call to
the function _clearfp. This returns the floating-point
processor's status and clears the condition which caused the exception.
The following picture illustrates the result when we don't clear the
error condition:
![]() |
After executing the statements inside the exception filter, the process continues executing starting with the statements following the __except block. In this case, all we do is return a value indicating that something has gone wrong.
int evaluateException(DWORD exceptionCode){ int returnVal=EXCEPTION_CONTINUE_SEARCH; switch(exceptionCode){ case EXCEPTION_FLT_DIVIDE_BY_ZERO: returnVal=EXCEPTION_EXECUTE_HANDLER; break; default: break; } return returnVal; }Basically, what we're saying here is that if the error was caused by a divide-by-zero error, we should execute the code in our __except block. Otherwise, tell the operating system to continue looking for an exception handler.
1For more information about the behavior of C++ exceptions in functions declared extern "C", refer to John Robbins' Bugslayer column in the October, 1999 edition of Microsoft Systems Journal.