6/24/2010

Este artículo muestra cómo capturar errores genéricos (de todo tipo), tratamiento de excepciones, en Delphi y mostrar (o no) mensajes a medida.

Explica la diferencia entre las cláusulas "except" y "finally". También muestra un listado de las clases de excepción (class exception) y la descripción.

En primer lugar explicamos las dos estructuras básicas para la captura de errores:

1ª En la estructura que mostramos a continuación sólo se ejecutará el código que va entre el "except" y el "end" si se produce un error:

...

begin

... //código que estará fuera de la captura de errores, normalmente
//se colocará fuera el código que sepamos que no puede dar errror

try

// Aquí irá el código susceptible de provocar errores

except

//colocaremos aquí el código que se ejecutará si se produce un error,
//sólo se ejecutará si se produce un error

end;

end;
2ª En la siguiente estructura el código que va entre el "finally" y el "end" se ejecutará siempre (tanto si se produce error como si no):
...

begin

... //código que estará fuera de la captura de errores, normalmente
//se colocará fuera el código que sepamos que no puede dar errror

try

// Aquí irá el código susceptible de provocar errores

finally

//colocaremos aquí el código que se ejecutará tanto si
//se produce un error como si no

end;

end;
Por ejemplo podemos acotar un código susceptible de que se produzca una división por cero con un "try" y un "except" de la siguiente forma:
... 
var
numero1, numero2, numero3 : integer;
begin
numero1 := 0;
numero2 := 1;
try
numero3 := numero1 div numero2;
ShowMessage ('Esta línea no se ejecutará pues se producirá el error.');
except
on e : exception do
begin
ShowMessage ('Clase de error: ' + e.ClassName + chr(13) + chr(13) +
'Mensaje del error: ' + e.Message);
end;
end;
end;
En este ejemplo hemos utilizado el objeto "exception" que es la clase padre. Si queremos mostrar un mensaje personalizado por cada tipo de error utilizaremos el siguiente código:
... 
var
numero1, numero2, numero3 : integer;
begin
numero1 := 0;
numero2 := 1;
try
numero3 := numero1 div numero2;
ShowMessage ('Esta línea no se ejecutará pues se producirá el error.');
except
on e : EDivByZero do
begin
ShowMessage ('Ha intentado dividir un número por cero.');
end;
else
ShowMessage ('Se ha producido un error: ' + chr(13) + chr(13) +
'Clase de error: ' + e.ClassName + chr(13) + chr(13) +
'Mensaje del error: ' + e.Message);
end;
end;
Un ejemplo utilizando "finally" (código que siempre se ejecutará tanto si hay error como si no):
procedure TformMenuPrincipal.actCuentasEmailExecute(Sender: TObject);
var
formulario : TformCuentas;
begin
formulario := TformCuentas.Create(Application);
try
formulario.ShowModal;
finally
formulario.Free;
end;
end;
En este caso hemos utilizado un ejemplo que crea un formulario y lo muestra modal, si la línea "formualario.ShowModal" da un error (por cualquier causa) se ejecutará lo que haya en el "finally" y si no da error también, con lo cual, en este caso, nos aseguramos de que el formulario modal se libera tras su ejecución.

Con lo cual utilizaremos "finally" siempre que nos interese que se ejecute código tanto si se produce un error como si no se produce, por ejemplo cuando creamos un objeto y queramos que este se libere sea cual sea el resultado de la creación. Y utilizaremos "except" en los demás casos, cuando queramos que el código de error sólo se ejecute cuando éste se produzca.

Otro ejemplo de utilización de "try ... except":

  try
md.tcSpam.Open;
except
on e : exception do
begin
insertarLog (now, 'Error', E.Classname + ' : ' + E.Message);
md.tcSpam.Close;
end;
end;
En este caso "md.tcSpam.Open" es un TQuery con una consulta SQL asociada, si se produce algún error se ejecutará lo que haya dentro del "except", en este caso un procedimiento llamado "insertarLog" que, a su vez, inserta un registro en una base de datos para guardar los posibles errores de la aplicación. A continuación os mostramos el código del procedimiento "insertarLog":
procedure insertarLog (fecha : TDateTime; tipo : string; mensaje : string);
begin
md.tLog.Open;
md.tLog.Insert;
md.tLogFECHA.Value := fecha;
md.tLogTIPO.Value := tipo;
md.tLogTEXTO.Value := mensaje;
md.tLog.Post;
md.tLog.Close;
end;
Donde md es el nombre del módulo de datos (TDataModule) en el que está el TTable "tLog" que apunta a una tabla de la base de datos con la siguiente estructura (MySQL):
CREATE TABLE `log` (
`ID` int(10) NOT NULL auto_increment,
`FECHA` datetime default NULL,
`TEXTO` varchar(255) default NULL,
`TIPO` varchar(20) default NULL,
PRIMARY KEY  (`ID`)
)
Aunque hemos de reconocer que no es conveniente utilizar funciones/procedimientos/código que pueda generar errores dentro de las cláusulas "except" ó "finally".


A continuación os mostramos un listado de clases de excepciones:

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


No hay comentarios: