So far, we have been discussing hardware exceptions in which the CPU catches an event and raises an exception. It is also possible for your code to
An alternative approach is to have functions raise exceptions when they fail. With this approach, the code is much easier to write and to maintain. Plus, the code typically
Unfortunately, most developers do not get into the habit of using exceptions for error handling. There are two basic reasons for this. The first reason is that most developers are unfamiliar with SEH. Even if one developer is acquainted with it, other developers might not be. If one developer
The second reason why developers avoid SEH is that it is not portable to other operating systems. Many companies target multiple operating systems and would like to have a single source code base for their products, which is
However, if you decide to return errors via exceptions, I
If you want to take advantage of this exception, you can code your
try
block as though the memory allocation will always succeed; if the allocation fails, you can either handle the exception by using an
except
block or have your function clean up by matching the
try
block with a
finally
block. How
Your application traps software exceptions exactly the same way that it traps hardware exceptions. In other words, everything I said in the last chapter applies equally well to software exceptions.
What we want to concentrate on in this section is how to have your own functions forcibly raise software exceptions as a method for indicating failure. In fact, you can implement your functions similarly to Microsoft's implementation of the heap functions: have your
Raising a software exception couldn't be easier. You simply call the RaiseException function:
VOIDRaiseException(DWORDdwExceptionCode, DWORDdwExceptionFlags, DWORDnNumberOfArguments, CONSTULONG_PTR*pArguments); |
The first parameter,
dwExceptionCode
, must be a value that identifies the raised exception. The
HeapAlloc
function
If you create your own exception code, fill out all four fields of the DWORD:
RaiseException
's second parameter,
dwExceptionFlags
, must be either 0 or EXCEPTION_NONCONTINUABLE. Basically, this flag indicates whether it is legal for an exception filter to return EXCEPTION_CONTINUE_EXECUTION in response to this raised exception. If you do not pass the EXCEPTION_NONCONTINUABLE flag to
RaiseException
, the filter can return EXCEPTION_CONTINUE_EXECUTION. Normally, this would cause the thread to re-execute the same CPU instruction that raised the software exception. However, Microsoft has done some
If you do pass the EXCEPTION_NONCONTINUABLE flag to
RaiseException
, you're telling the system that the type of exception you are raising can't be
If a filter ignores the EXCEPTION_NONCONTINUABLE flag and returns EXCEPTION_CONTINUE_EXECUTION anyway, the system raises a new exception: EXCEPTION_NONCONTINUABLE_EXCEPTION.
It is possible for an exception to be raised while the application is trying to process another exception. This makes sense, of course. While we're at it, let's note that it's also possible for an invalid memory access to occur inside a finally block, an exception filter, or an exception handler. When this happens, the system stacks exceptions. Remember the GetExceptionInformation function? This function returns the address of an EXCEPTION_POINTERS structure. The ExceptionRecord member of the EXCEPTION_POINTERS structure points to an EXCEPTION_RECORD structure that contains another ExceptionRecord member. This member is a pointer to another EXCEPTION_RECORD, which contains information about the previously raised exception.
Usually the system is processing only one exception at a time, and the
ExceptionRecord
member is NULL. However, if during the processing of one exception another exception is raised, the first EXCEPTION_RECORD structure contains information about the most recently raised exception and the
ExceptionRecord
member of this first EXCEPTION_RECORD structure points to the EXCEPTION_RECORD structure for the previously raised exception. If additional exceptions have not been
RaiseException 's third and fourth parameters, nNumberOfArguments and pArguments , are used to pass additional information about the raised exception. Usually, there is no need for additional arguments—you can simply pass NULL for the pArguments parameter, in which case RaiseException ignores the nNumberOfArguments parameter. If you do want to pass additional arguments, the nNumberOfArguments parameter must indicate the number of elements in the ULONG_PTR array pointed to by the pArguments parameter. This parameter cannot exceed EXCEPTION_MAXIMUM_PARAMETERS, which is defined in WinNT.h as 15.
During the processing of this exception, you can have an exception filter refer to the
NumberParameters
and
ExceptionInformation
You might want to generate your own software exceptions in your application for any of several reasons. For example, you might want to send informational messages to the system's event log. Whenever a function in your application sensed some