Some information on setting up error handling in Delphi program code. Solution: Delphi Error Handling Techniques ================================ The best way to catch exceptions is by defensive programming. For example, all code sections which allow for input from a user should be wrapped in a "try" block. This piece of code takes the form : tryexcept on do begin end; end; finally do begin . end; Execution begins in the try section. If no exceptions are raised, the except section is skipped and the finally block (if one exists) is executed. If an exception is raised, code execution immediately goes to the exception section. The except section is searched. If there is an "on" block, an attempt will be made to look for a matching exception condition. If a matching exception type is found, the code in that exception block is executed. If no matching exception type is found, the default behavior of the class will be executed (usually displaying an error message). If no "on" block exists, the code in the except section will be executed for all error conditions. After any exception code is executed, the program will continue on to the "finally" block, or if no finally block is provided, execution will continue on the next statement after the exception block. An example (provided from the classes.pas file in Delphi 4 source) is shown below. This example shows the general layout and the use of a finally clause. Note: the "exception" clause is not used. function GetClass(const AClassName: string): TPersistentClass; var I: Integer; begin with ClassList.LockList do try // ClassAliasList protected by ClassList lock for I := 0 to Count - 1 do begin Result := Items[I]; if Result.ClassNameIs(AClassName) then Exit; end; I := ClassAliasList.IndexOf(AClassName); if I >= 0 then begin Result := TPersistentClass(ClassAliasList.Objects[I]); Exit; end; Result := nil; finally ClassList.UnlockList; end; end; This function (GetClass), attempts to select a class from a list of classes from the classes.pas file. The ClassList is first locked. Then a search is done for the class name or an alias. If the class is found, the class name is assigned to the parameter "Result" then the function exits. If the class name is not found, the value "nil" is assigned to the parameter "Result". In either case, the finally clause is executed which unlocks the ClassList. Another example (from "Learning Delphi 4 in 21 Days - pg 583) shows some exception handling. if OpenPictureDialog.Execute then begin Child := TChild.Create(Self); with Child.Image.Picture do begin try LoadFromFile(OpenPictureDialog.Filename); Child.ClientWidth := Width; Child.ClientHeight := Height; except Child.Close; Application.MessageBox( `This file is not a Windows image file.', `Picture Viewer Error', MB_ICONHAND or MB_OK); Exit; end; end; Child.Caption := ExtractFileName(OpenPictureDialog.FileName); Child.Show; end; In this case, the user has supplied a file name which should contain a picture file to display. If there is an error in attempting to load the file (wrong file type in this case), the Child.Close routine error exception will be raised. The exception code displays a message and exits from the display routine. The finally clause, is not used in this example. If this error does not occur (Child.close), the code after the exception handler gets executed (Child.Caption := . . .). These examples display one requirement, and one weakness to error handling code. The requirement is that you should know what exceptions can be raised by a routine before you use it (to make sure that you can perform the proper recovery if the exceptions occur). If you do not trap a specific exception, the code following the try block will attempt to execute. Routines may have several specific error conditions trapped and a few general error conditions. It is good programming practice to trap the specific errors first, and then after, trap the more general ones. Error routines can either be found in the documentation for a component, or in the source code. Delphi 4 VCL source code, for example is, by default, located at "Program FilesBorlandDelphi 4SourceVCL" Look for the key word "raise" which is used to raise an exception. An example procedure from classes.pas (Delphi 4 VCL source) with the use of the "raise" exception is shown below. In this case, the name of the raised exception is "EFilerError". procedure RegisterClass(AClass: TPersistentClass); var AClassName: string; begin with ClassList.LockList do try while IndexOf(AClass) = -1 do begin AClassName := AClass.ClassName; if GetClass(AClassName) <> nil then raise EFilerError.CreateFmt(SDuplicateClass, [AClassName]); Add(AClass); if AClass = TPersistent then Break; AClass := TPersistentClass(AClass.ClassParent); end; finally ClassList.UnlockList; end; end;
Last Modified: 23-OCT-00