VBA-Erreurs

La gestion des Erreurs

La gestion des erreurs est autre chose que ce qui a été vu sur la page débogage, je considère que cette phase de débogage est terminée et que les erreurs de logique, de syntaxe, de variables sont éliminées.
Le but de la gestion des erreurs dans un projet VBA consiste se prémunir (autant que possible) de l’apparition d’erreurs lors de l’exécution et (ou) faire en sorte que des explications sur les raisons de ces erreurs soient fournies aux utilisateurs.


Au sujet de GoTo

l’instruction "Goto" est un héritage du langage "Basic" que le langage VBA a conservé, ce n'est pas une des meilleures choses à utiliser, à mes yeux, bien qu'on la trouve en maints endroits dans les vieux programmes. Toutefois, pour la gestion des erreurs, elle a un certain côté "pratique".
Dans les projets VBA, il est recommandé d’éviter l’usage de cette instruction "Goto" en lui préférant des instructions plus structurées (For..Next ; Select Case ; Do Until…Loop ; …) mais aussi d’organiser les projets en procédures et  sous-procédures.
Ne pas perdre de vue que le langage « VB.Net » (lui-aussi lointain héritier de « Basic ») a introduit l’instruction "Try…Catch…Finally" permettant de se passer de l’instruction « On Error Goto ».

"On Error Goto…"est un exemple de GoTo dont je parle tout de suite pour la mise en place d’une gestion des erreurs.

On Error Goto…

Cette instruction permet d’indiquer une étiquette pour que le code VBA se déclenche en cas d’erreur. C’est une instruction de base à utiliser pour la gestion des erreurs.

Dans le cas où une erreur se produit dans la procédure, le programme exécutera la séquence de code située après l’étiquette indiquée dans l’instruction en ignorant tout code situé entre l’instruction ayant provoqué l’erreur et l’étiquette.

Dans cet exemple à la ligne 8 il y a une étiquette Gest_Erreur: qui va afficher une MsgBox si une des entités trouvée se trouve sur un calque qui est verrouillé, cette étiquette est branchée par la ligne 3.
Vous notez que la SUB Change_color se termine par "Exit Sub" à la fin de la boucle, car si cette instruction n'était pas envoyée en fin de traitement, la ligne suivante (gestion d'erreur) serait lue et le message d'erreur serait envoyé (par erreur, si je peux me permettre) :

Sub Change_Color() Dim Entity As Object On Error GoTo Gest_Erreur For Each Entity In ThisDrawing.ModelSpace Entity.color = acRed Next Entity Exit Sub ' Important : Exit à la fin pour sortir proprement s'il n'y a pas d'erreur Gest_Erreur: MsgBox Entity.EntityName + " est sur un calque verrouillé." Resume Next End Sub

Le langage VBA ne peut traiter qu’une seule séquence de gestion d’erreurs à un instant donné.
Si une sous-procédure appelée ne possède pas sa propre séquence de gestion d’erreurs et qu’une erreur s’y produit, c’est la gestion d’erreurs de la procédure appelante qui sera appelée.


On Error GoTo 0

Cette forme particulière de l’instruction "On Error Goto" permet d’annihiler l’effet de la dernière instruction "On Error".
Après cette instruction, si une erreur d’exécution se produit, VBA affiche les messages et la boîte de dialogue système par défaut.
L’utilisation de l’instruction "On error Goto 0" est de mettre fin à l’effet d’une instruction
"On Error Resume Next", dont il est question plus tard dans cette page.

L'objet Err

L’objet "Err" est utilisé par le langage VBA pour fournir des détails sur l’erreur rencontrée au cours de l’exécution.

Par exemple, si elle n’est pas gérée, comme vu ci-dessus, la division par 0 provoque le message suivant :

L'objet "Err" a des propriétés et des méthodes (c'est bel et bien un "objet"), dans le gestionnaire d'erreurs, on peut comparer la propriété Number de l'erreur à une valeur attendue. Cela aidera à déterminer la nature de l'erreur qui s'est produite.
Les principales propriétés et méthodes utilisées sont celles-ci :

Propriétés :
Err.Number = Contient le code d'erreur unique associé à l'erreur (exemple précédent : "11")
Err.Description = Contient le message d'erreur qui donne une description courte de l’erreur (par exemple : "Division par zéro")
Err.Source = Nom du projet d’origine dans lequel l’erreur s’est produite (non affiché dans la boîte de dialogue par défaut)

Méthodes :
Err.Clear = efface le numéro et la description de la dernière erreur d’exécution rencontrée.
Err.Raise = permet d’affecter une erreur propre à notre traitement en lui donnant un numéro et éventuellement une description, une origine.

Les numéros d’erreurs de 0 à 512 sont réservés aux erreurs VBA.
Les numéros d’erreurs 513 à 65535 sont pour affecter les erreurs propres à votre traitement.


L'instruction RESUME

Cette instruction reprend l’exécution après la fin du traitement par une routine de gestion d’erreur.

Dans l'exemple qui suit il va falloir entrer une valeur numérique dans une InputBox, gérer les erreurs consiste à vérifier que la saisie est bien un chiffre (ou un nombre), il faut aussi penser à vérifier que la saisie n'est pas vide, c'est donc ça "gérer les erreurs".

Définitions de deux constantes "Err0" et "Err1" avec des nombres en dehors des bornes réservées par le VBA. Ensuite une étiquette "Saisie:" pour commencer l'opération de saisie de la valeur.
Quand la fenêtre est lancée et que l'utilisateur a répondu, on revient dans VBA et on analyse, Si la saisie est vide par Err.Raise Err0, la propriété de Err est le contenu de la constante Err0, lancement de la GestionErreur et analyse du contenu de Err pour renvoyer le message qui correspond (saisie vie ou non numérique), comme GestionErreur se termine par Resume Saisie, VBA retourne à l'étiquette Saisie: et ce tant que les valeurs ne correspondent pas. Vous êtes tous OK ?
Dans cet exemple, je fais appel à des concepts pas encore explicités sur da-code (If, Then, Select Case, etc.) ne vous en occupez pas trop pour l'instant et les explications viendront rapidement.

Const Err0 = 1000
Const Err1 = 1001
Sub Exemple_Erreur()
     On Error GoTo GestionErreur
Saisie:
     Valeur = InputBox("Entrez un chiffre", "Test Erreur", 10)
     If Len(valeur) = 0 Then
          Err.Raise Err0
     End If
     If Not IsNumeric(valeur) Then
          Err.Raise Err1
     End If
     MsgBox "saisie correcte", vbOKOnly, "Test réussi"
     Exit Sub
GestionErreur:
     Select Case Err
          Case Err0
               MsgBox "Vous n'avez rien saisi", vbExclamation, "Saisie Vide"
               Resume Saisie
     Case Err1
              MsgBox "La valeur n'est pas un nombre", vbExclamation, "Avertissement"
              Resume Saisie
     End Select
End Sub

Voici en animation pas à pas ce qui se passe en fonction de ce qui est entré dans la "InputBox" :


L'instruction On Error Resume Next

L’instruction "On Error Resume next" permet de demander à VBA d’ignorer les erreurs à partir de la ligne où elle est écrite. À utiliser avec parcimonie et toujours en connaissance de cause, car ça peut être une fausse bonne idée puisque qu'elle va faire ignorer les messages d'erreurs rencontrées.
Il est conseillé de mettre un On Error Goto étiquette ou 0 dès que possible pour "reprendre la main" sur les erreurs. Ce n'est pas en décidant de ne pas prendre de parapluie que le soleil est assuré.