Cette page est consultable pour des raisons historiques : elle n'est maheureusement plus maintenue faute de temps.
Le traitement des exceptions
Une exception est un événement qui survient lors d'une erreur à l'éxécution du programme. La VCL fournit un ensemble de classes dérivant toutes de la classe Exception dans l'unité SysUtils qui represente les exceptions prédéfinies.
La classe Exception
Les exceptions sont des classes qui ne comportent que quelques champs qui permettent d'identifier l'exception. Certaines exceptions possèdent des champs supplémentaires qui permettent de connaitre avec plus de précision l'origine de l'erreur.
La propriété Message contient le message qui est affiché quand l'exception est levée.
La propriété HelpContext permet de faire la liaison entre l'exception et une rubrique du fichier d'aide.
La classe Exception propose plusieurs constructeurs :
- le constructeur Create permet de créer l'exception et de lui associer le message passer en paramètre
- le constructeur CreateFmt permet de créer l'exception et de formater le message passé en paramètre avec la chaine de formatage et le tableau darguments
- le constructeur CreateRes permet de créer l'exception et de lui associer le message contenu dans le tableau de ressources à lindice indiqué
Les autres constructeurs ont les mêmes fonctionnalités mais permettent en plus de préciser la propriété HelpContext.
Il n'est pas nécessaire de se préoccuper de la destruction des objets exceptions car ils seront détruits par le gestionnaire d'exception.
Les principes d'héritage permettent de gérer plusieurs exceptions en même temps si celles ci dérivent d'une même classe parent voir de la classe mère de toutes les exceptions : la classe Exception.
Il est aussi possible de créer ces propres exceptions en dérivant une classe de la classe Exception ou d'une de ces classes filles.
Exemple :
type
Emon_erreur = class(Exception)
end;
Il est possible de rajouter des propriétés (pour détailler lexception) et des méthodes à ces nouvelles classes (par exemple de nouveaux contructeurs pour alimenter les nouvelles propriétés).
Les routines de traitements des erreurs
Le pascal objet définit trois opérateurs pour gérer la capture des exceptions : try, except et finally.
Ils sont regroupés en deux structures : try ... except ... end et try ... finally ... end .
Le mot try est suivi des traitements qui doivent être protégés car ils sont susceptibles de soulever une exception. Si une exception est levée dans ces traitements, le programme execute les instructions incluses après le mot except ou finally.
Dans le bloc except il faut tester la ou les exceptions concernées et leur associer les traitements qui conviennent.
Dans le bloc except, les mots clés on .. do permettent de tester le type d'exception qui est levée et d'y associer les traitements. La syntaxe de on .. do ressemble à celle de l'instruction case. Il est possible de traiter plusieurs exceptions de la même façon en les séparant par des ;. Il peut y avoir plusieurs instructions on avec des exceptions differentes : elles seront evaluées dans un ordre séquentiel. Il est donc important de préciser les exceptions dans l'ordre inverse de la hiérarchie de classe Exception : les classes filles avant les classes mères.
A la fin du bloc except, il est possible de définir un branchement else qui englobe toutes les autres exceptions non capturées dans le bloc.
try
...
except
on e1 : type_exception1 do instruction ou bloc_d'instructions
on e2 : type_exception2 do instruction ou bloc_d'instructions
...
else instruction ou bloc_d'instructions
end;
Exemple :
try
...
except
on EInOutError do ...
else ...
end;
Il est possible de fournir un nom à l'exception pour accéder à l'instance de celle ci.
Exemple :
try
...
Except
on e : Emon_erreur do begin
...
end;
end;
Il est alors possible d'accéder aux champs et aux méthodes de cette instance.
Pour accéder à l'instance de l'exception, il est aussi possible d'appeler la fonction ExceptObject définie dans l'unité SysUtils qui renvoie l'instance de l'exception courante. Cette instance est référencée sous la forme d'un objet TObject qu'il faut convertir à l'aide de l'instruction as.
Le bloc inclus après finally est toujours executé qu'une exception soit levée ou non : il permet notamment de libérer des ressources qui ont été allouées.
Il n'est pas possible de faire suivre un bloc try par une instruction except et finally. Il faut emboiter deux blocs try, l'un contenant except et l'autre contenant finally.
le bloc try ... finally ne gère pas l'exception donc elle ne libère pas les ressources qui lui sont allouées. L'exception continue de se propager jusqu'à ce qu'elle rencontre un bloc de type try ... except ou le gestionnaire d'exception par défaut qui contient un tel bloc.
Les blocs except et finally sont facultatifs.
Dès qu'une exception est levée, le programme recherche dans la pile de fonction en cours une fonction qui contient un gestionnaire d'exception.Une exception levée est propagée dans les procedures et fonctions en remontant les différents appels jusqu'à ce qu'elle soit capturée dans un bloc except. A ce moment, la propagation de l'exception s'arrete. Le reste du code de chaque fonction est ignoré.
Une fois l'exception traitée, le programme se poursuit après le bloc de gestion d'exception et non après l'instruction qui a provoqué l'exception.
Si l'exception n'est pas capturée en remontant la hiérarchie des procédures, elle est traitée par la méthode HandeException de l'objet Application qui définit un comportement par défaut. Il est possible de rédéfinir cette méthode pour en modifier le comportement : par exemple ajouter un message dans un fichier log qui contiendra les exceptions levées.
Lever une exception
Le mot clé raise permet de lever une exception : cette instruction doit etre suivie d'une instance d'une classe exception
Exemple :
raise Emon_erreur.Create('Problème lors de l''execution');
Raise permet aussi de relever une exception qui vient d'etre capturée pour poursuivre sa propagation. Pour cela il suffit d'invoquer raise dans le bloc except
Exemple :
try
...
Except
on EInOutError do
begin
... //traitement de l'exception
raise; // l'exception est relever et donc passée à la procedure appelante
end;
end;
Il est possible de préciser au moment de l'appel à raise l'adresse qui est à l'origine de l'exception
Exemple :
raise OutOfMemory at ReturnAddr;
Les exceptions dans lenvironnement déxécution
Par défaut, lors de l'execution d'un programme, dès qu'une exception est levée, le programme est interrompu à la ligne de l'instruction qui a levé l'exception et le message de l'exception est affiché. Il est alors possible de poursuivre directement ou pas à pas l'execution. Cette option peut être désactivée en décochant l'option "arret sur les exceptions" dans la boite de dialogue options d'environnement.
L'objet application généré dans tous projets Delphi possède un mécanisme de gestion des exceptions par défaut : cet objet déclenche l'événement OnException dès qu'une exception lui arrive. Si aucun gestionnaire d'exception ne capture l'exception, l'objet application execute sa méthode HandleException qui appelle elle même la fonction précisée par la propriété OnException. Cette propriété doit recevoir une méthode qui respecte le type TExceptionEvent
TExceptionEvent = procedure(Sender : TObject ; E : Exception) of Object;
Exemple :
procedure TForm1.gestion_erreur(Sender : TObject ; E : Exception);
begin
MessageDlg(E.message,mtInformation,[mrOk],0);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// affectation du gestionnaire d'exception
Application.OnException:=gestion_erreur;
end;
Les exceptions silencieuses
Ce sont des exceptions qui dérivent de la classe EAbort. La différence avec une exception normale est qu'elles ne remontent pas les differents niveaux de la pile et ne dépassent pas le premier niveau. Si une telle exception n'est pas traitée à ce moment la, elle est détruite.