VBA
Erreurs d'exécution VBA
Recherche…
Introduction
Le code qui compile peut encore présenter des erreurs lors de l'exécution. Cette rubrique répertorie les plus courantes, leurs causes et comment les éviter.
Erreur d'exécution '3': Retour sans GoSub
Code incorrect
Sub DoSomething()
GoSub DoThis
DoThis:
Debug.Print "Hi!"
Return
End Sub
Pourquoi cela ne marche pas?
L'exécution entre dans la procédure DoSomething
, passe à l'étiquette DoThis
, imprime "Hi!" à la sortie de débogage, retourne à l'instruction immédiatement après l'appel GoSub
, imprime "Hi!" encore une fois, et rencontre ensuite une déclaration de Return
, mais il n'y a nulle part où revenir maintenant, car nous ne sommes pas GoSub
ici avec une déclaration GoSub
.
Code correct
Sub DoSomething()
GoSub DoThis
Exit Sub
DoThis:
Debug.Print "Hi!"
Return
End Sub
Pourquoi ça marche?
En introduisant une instruction Exit Sub
avant le DoThis
ligne DoThis
, nous avons séparé la sous-routine DoThis
du reste du corps de la procédure. La seule manière d'exécuter la sous-routine DoThis
est le saut GoSub
.
Autres notes
GoSub
/ Return
est obsolète et devrait être évité en faveur des appels de procédure réels. Une procédure ne doit pas contenir de sous-routines autres que les gestionnaires d'erreurs.
Ceci est très similaire à l' erreur d'exécution '20': reprendre sans erreur ; dans les deux cas, la solution consiste à s'assurer que le chemin d'exécution normal ne peut pas entrer dans une sous-routine (identifiée par une étiquette de ligne) sans saut explicite (en supposant que On Error GoTo
soit considéré comme un saut explicite ).
Erreur d'exécution '6': débordement
code incorrect
Sub DoSomething()
Dim row As Integer
For row = 1 To 100000
'do stuff
Next
End Sub
Pourquoi cela ne marche pas?
Le type de données Integer
est un entier signé 16 bits avec une valeur maximale de 32 767; l'affecter à quelque chose de plus grand que celui qui débordera le type et provoquera cette erreur.
Code correct
Sub DoSomething()
Dim row As Long
For row = 1 To 100000
'do stuff
Next
End Sub
Pourquoi ça marche?
En utilisant un entier Long
(32 bits) à la place, on peut maintenant faire une boucle qui itère plus de 32 767 fois sans déborder le type de la variable du compteur.
Autres notes
Voir Types de données et limites pour plus d'informations.
Erreur d'exécution '9': indice hors limites
code incorrect
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = 1 To 100
foo(i) = i
Next
End Sub
Pourquoi cela ne marche pas?
foo
est un tableau qui contient 10 éléments. Lorsque le compteur de boucles i
atteint la valeur 11, foo(i)
est hors limites . Cette erreur se produit chaque fois qu'un tableau ou une collection est accessible avec un index qui n'existe pas dans ce tableau ou cette collection.
Code correct
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = LBound(foo) To UBound(foo)
foo(i) = i
Next
End Sub
Pourquoi ça marche?
Utilisez les fonctions LBound
et UBound
pour déterminer respectivement les limites inférieure et supérieure d'un tableau.
Autres notes
Lorsque l'index est une chaîne, par exemple ThisWorkbook.Worksheets("I don't exist")
, cette erreur signifie que le nom fourni n'existe pas dans la collection interrogée.
L'erreur réelle est spécifique à l'implémentation bien que; Collection
déclenchera l'erreur d'exécution 5 "Appel ou argument de procédure non valide" à la place:
Sub RaisesRunTimeError5()
Dim foo As New Collection
foo.Add "foo", "foo"
Debug.Print foo("bar")
End Sub
Erreur d'exécution '13': incompatibilité de type
code incorrect
Public Sub DoSomething()
DoSomethingElse "42?"
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Pourquoi cela ne marche pas?
VBA essaie vraiment de convertir le "42?"
argument dans une valeur de Date
. En cas d'échec, l'appel de DoSomethingElse
ne peut pas être exécuté, car VBA ne sait pas quelle date doit être transmise, ce qui provoque une incompatibilité de type erreur d'exécution 13, car le type de l'argument ne correspond pas au type attendu (et peut ne soit pas implicitement converti non plus).
Code correct
Public Sub DoSomething()
DoSomethingElse Now
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Pourquoi ça marche?
En transmettant un argument Date
à une procédure qui attend un paramètre Date
, l'appel peut aboutir.
Erreur d'exécution '91': variable d'objet ou variable de bloc With non définie
code incorrect
Sub DoSomething()
Dim foo As Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Pourquoi cela ne marche pas?
Les variables d'objet contiennent une référence et les références doivent être définies à l'aide du mot-clé Set
. Cette erreur se produit chaque fois qu'un appel de membre est effectué sur un objet dont la référence est Nothing
. Dans ce cas, foo
est une référence de Collection
, mais elle n'est pas initialisée. La référence contient donc Nothing
- et nous ne pouvons pas appeler .Add
sur Nothing
.
Code correct
Sub DoSomething()
Dim foo As Collection
Set foo = New Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Pourquoi ça marche?
En attribuant à la variable d'objet une référence valide à l'aide du mot clé Set
, les appels .Add
réussissent.
Autres notes
Souvent, une fonction ou une propriété peut renvoyer une référence d'objet - un exemple courant est la méthode Range.Find
d'Excel, qui renvoie un objet Range
:
Dim resultRow As Long
resultRow = SomeSheet.Cells.Find("Something").Row
Cependant, la fonction peut très bien retourner Nothing
(si le terme de recherche n'est pas trouvé), il est donc probable que l'appel de membre chaîné .Row
échoue.
Avant d'appeler des membres d'objet, vérifiez que la référence est définie avec la condition If Not xxxx Is Nothing
:
Dim result As Range
Set result = SomeSheet.Cells.Find("Something")
Dim resultRow As Long
If Not result Is Nothing Then resultRow = result.Row
Erreur d'exécution '20': reprendre sans erreur
code incorrect
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Pourquoi cela ne marche pas?
Si la procédure DoSomethingElse
une erreur, l'exécution passe à l' CleanFail
ligne CleanFail
, imprime le numéro d'erreur et l'instruction Resume Next
retourne à l'instruction qui suit immédiatement la ligne où l'erreur s'est produite, à savoir Debug.Print
instruction: le sous-programme de traitement des erreurs s'exécute sans contexte d'erreur et lorsque l'instruction Resume Next
est atteinte, l'erreur d'exécution 20 est déclenchée car il n'y a aucun endroit où reprendre.
Code correct
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
Exit Sub
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Pourquoi ça marche?
En introduisant une instruction Exit Sub
avant le CleanFail
ligne CleanFail
, nous avons séparé le CleanFail
-programme de gestion des erreurs CleanFail
du reste du corps de la procédure. Le seul moyen d'exécuter le sous-programme de traitement des erreurs est un saut d' On Error
; par conséquent, aucun chemin d'exécution n'atteint l'instruction Resume
dehors d'un contexte d'erreur, ce qui évite l'erreur d'exécution 20.
Autres notes
Ceci est très similaire à l' erreur d'exécution "3": Retour sans GoSub ; dans les deux cas, la solution consiste à s'assurer que le chemin d'exécution normal ne peut pas entrer dans une sous-routine (identifiée par une étiquette de ligne) sans saut explicite (en supposant que On Error GoTo
soit considéré comme un saut explicite ).