|
| Handling errors in Delphi |
| Whilst we all want to spend our time writing functional code, errors will and do occur in in code from time to time. Sometimes, these are outside of our control, such as a low memory situation on your PC. | |
| In serious code you should handle error situations so that at the very least, the user is informed about the error in your chosen way. | |
| Delphi uses the event handling approach to error handling. Errors are (mostly) treated as exceptions, which cause program operation to suspend and jump to the nearest exception handler. If you don't have one, this will be the Delphi default handler - it will report the error and terminate your program. | |
| Often, you will want to handle the error, and continue with your program. For example, you may be trying to display a picture on a page, but cannot find it. So you might display a placeholder instead. Much like Internet Explorer does. | |
| Try, except where there are problems |
| Delphi provides a simply construct for wrapping code with exception handling. When an exception occurs in the wrapped code (or anything it calls), the code will jump to the exception handling part of the wrapping code : | |
| begin Try ... The code we want to execute ... Except ... This code gets executed if an exception occurs in the above block ... end; end;
|
|
| We literally try to execute some code, which will run except when an error (exception) occurs. Then the except code will take over. | |
| Let us look at a simple example where we intentionally divide a number by zero : | |
| var number1, number0 : Integer; begin try number0 := 0; number1 := 1; number1 := number1 div number0; ShowMessage('1 / 0 = '+IntToStr(number1)); except on E : Exception do begin ShowMessage('Exception class name = '+E.ClassName); ShowMessage('Exception message = '+E.Message); end; end; end;
|
|
| When the division fails, the code jumps to the except block. The first ShowMessage statement therefore does not get executed. | |
| In our exception block, we can simpl place code to act regardless of the type of error. Or we can do different things depending on the error. Here, we use the On function to act on the exception type. | |
| The On clause checks against one of a number of Exception classes. The top dog is the Exception class, parent of all exception classes. This is guaranteed to be activated above. We can pick out of this class the name of the actual exception class name (EDivByZero) and the message (divide by zero). | |
| We could have multiple On clauses for specific errors : | |
| except // IO error On E : EInOutError do ShowMessage('IO error : '+E.Message); // Dibision by zero On E : EDivByZero do ShowMessage('Div by zero error : '+E.Message); // Catch other errors else ShowMessage('Unknown error'); end;
|
|
| What happens when debugging |
| Note that when you are debugging your code within Delphi, Delphi will trap exceptions even if you have exception handling. You must then click OK on the error dialogue, then hit F9 or the green arrow to continue to your except clause. You can avoid this by changing the debug options. | |
| And finally ... |
| Suppose that instead of trapping the error where it occurs, you may want to let a higher level exception handler in your code to do a more global trapping. But your code may have created objects or allocated memory that is now no longer referenced. It is dangerous to leave these allocations lying around. | |
| Delphi provides an alternative part to the exception wrapper the Finally clause. Instead of being called when an exception occurs, the finally clause is always called after part or all of the try clause is executed. It allows us to free up allocated memory, or other such activities. However, it does not trap the error - the next highest exception handling (try) block that we are nested in is located and executed. | |
| Raising exceptions |
| We can not only raise exceptions at our own choosing, but we can create Exception classes to manage them. This kind of processing is somewhat beyond the basics, being more appropriate to large applications, especially those using many large modules. These modules may generate their own exception types. Here are the most common exception types : | |
| Exception Base class EAbort Abort without dialog EAbstractError Abstract method error AssertionFailed Assert call failed EBitsError Boolean array error ECommonCalendarError Calendar calc error EDateTimeError DateTime calc error EMonthCalError Month calc error EConversionError Raised by Convert EConvertError Object convert error EDatabaseError Database error EExternal Hardware/Windows error EAccessViolation Access violation EControlC User abort occured EExternalException Other Internal error EIntError Integer calc error EDivByZero Integer Divide by zero EIntOverflow Integer overflow ERangeError Out of value range EMathError Floating point error EInvalidArgument Bad argument value EInvalidOp Inappropriate operation EOverflow Value too large EUnderflow Value too small EZeroDivide Floating Divide by zero EStackOverflow Severe Delphi problem EHeapException Dynamic memory problem EInvalidPointer Bad memory pointer EOutOfMemory Cannot allocate memory EInOutError IO error EInvalidCast Object casting error EInvalidOperation Bad component op EMenuError Menu item error EOSError Operating system error EParserError Parsing error EPrinter Printer error EPropertyError Class property error# EPropReadOnly Invalid property access EPropWriteOnly Invalid property access EThread Thread error EVariantError Variant problem
|
|
| | | | |