VBA
Errores en tiempo de ejecución de VBA
Buscar..
Introducción
El código que se compila todavía puede tener errores, en tiempo de ejecución. Este tema enumera los más comunes, sus causas y cómo evitarlos.
Error en tiempo de ejecución '3': Devolución sin GoSub
Código incorrecto
Sub DoSomething()
GoSub DoThis
DoThis:
Debug.Print "Hi!"
Return
End Sub
¿Por qué no funciona esto?
La ejecución ingresa al procedimiento DoSomething
, salta a la etiqueta DoThis
, imprime "¡Hola!" a la salida de depuración, vuelve a las instrucciones inmediatamente después de la llamada GoSub
, imprime "¡Hola!" de nuevo, y luego encuentra una declaración de Return
, pero no hay a dónde regresar ahora, porque no llegamos aquí con una declaración de GoSub
.
Código correcto
Sub DoSomething()
GoSub DoThis
Exit Sub
DoThis:
Debug.Print "Hi!"
Return
End Sub
¿Por qué funciona esto?
Al introducir una instrucción Exit Sub
antes de la DoThis
línea DoThis
, hemos separado la subrutina DoThis
del resto del cuerpo del procedimiento: la única forma de ejecutar la subrutina DoThis
es a través del salto GoSub
.
Otras notas
GoSub
/ Return
está en desuso, y debe evitarse en favor de las llamadas a procedimientos reales. Un procedimiento no debe contener subrutinas, excepto los controladores de errores.
Esto es muy similar al error en tiempo de ejecución '20': Reanudar sin error ; en ambas situaciones, la solución es garantizar que la ruta de ejecución normal no pueda ingresar a una subrutina (identificada por una etiqueta de línea) sin un salto explícito (asumiendo que On Error GoTo
se considera un salto explícito ).
Error en tiempo de ejecución '6': Desbordamiento
código incorrecto
Sub DoSomething()
Dim row As Integer
For row = 1 To 100000
'do stuff
Next
End Sub
¿Por qué no funciona esto?
El tipo de datos Integer
es un entero con signo de 16 bits con un valor máximo de 32,767; asignarlo a algo más grande que eso desbordará el tipo y generará este error.
Código correcto
Sub DoSomething()
Dim row As Long
For row = 1 To 100000
'do stuff
Next
End Sub
¿Por qué funciona esto?
Al usar un entero Long
(32 bits) en su lugar, ahora podemos hacer un bucle que itere más de 32,767 veces sin desbordar el tipo de variable del contador.
Otras notas
Consulte Tipos de datos y límites para obtener más información.
Error en tiempo de ejecución '9': Subíndice fuera de rango
código incorrecto
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = 1 To 100
foo(i) = i
Next
End Sub
¿Por qué no funciona esto?
foo
es una matriz que contiene 10 elementos. Cuando el contador de bucle i
alcanza un valor de 11, foo(i)
está fuera de rango . Este error se produce siempre que se accede a una matriz o colección con un índice que no existe en esa matriz o colección.
Código correcto
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = LBound(foo) To UBound(foo)
foo(i) = i
Next
End Sub
¿Por qué funciona esto?
Use las funciones LBound
y UBound
para determinar los límites inferior y superior de una matriz, respectivamente.
Otras notas
Cuando el índice es una cadena, por ejemplo, ThisWorkbook.Worksheets("I don't exist")
, este error significa que el nombre proporcionado no existe en la colección consultada.
Sin embargo, el error real es específico de la implementación; Collection
generará el error de tiempo de ejecución 5 "Llamada o argumento de procedimiento no válido" en su lugar:
Sub RaisesRunTimeError5()
Dim foo As New Collection
foo.Add "foo", "foo"
Debug.Print foo("bar")
End Sub
Error en tiempo de ejecución '13': No coincide el tipo
código incorrecto
Public Sub DoSomething()
DoSomethingElse "42?"
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
¿Por qué no funciona esto?
VBA está realmente tratando de convertir el "42?"
argumento en un valor de Date
. Cuando falla, la llamada a DoSomethingElse
no se puede ejecutar, porque VBA no sabe qué fecha pasar, por lo que aumenta el tipo de error de tiempo de ejecución 13, porque el tipo de argumento no coincide con el tipo esperado (y puede Tampoco se convertirá implícitamente).
Código correcto
Public Sub DoSomething()
DoSomethingElse Now
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
¿Por qué funciona esto?
Al pasar un argumento de Date
a un procedimiento que espera un parámetro de Date
, la llamada puede tener éxito.
Error en tiempo de ejecución '91': variable de objeto o variable de bloque no establecida
código incorrecto
Sub DoSomething()
Dim foo As Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
¿Por qué no funciona esto?
Las variables de objeto contienen una referencia y las referencias deben establecerse con la palabra clave Set
. Este error se produce cuando se realiza una llamada de miembro en un objeto cuya referencia es Nothing
. En este caso, foo
es una referencia de Collection
, pero no está inicializada, por lo que la referencia no contiene Nothing
, y no podemos llamar a .Add
en Nothing
.
Código correcto
Sub DoSomething()
Dim foo As Collection
Set foo = New Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
¿Por qué funciona esto?
Al asignar a la variable de objeto una referencia válida utilizando la palabra clave Set
, las llamadas .Add
se .Add
correctamente.
Otras notas
A menudo, una función o propiedad puede devolver una referencia de objeto; un ejemplo común es el método Range.Find
de Excel, que devuelve un objeto Range
:
Dim resultRow As Long
resultRow = SomeSheet.Cells.Find("Something").Row
Sin embargo, la función puede devolver Nothing
(si no se encuentra el término de búsqueda), por lo que es probable que la llamada al miembro .Row
encadenado falle.
Antes de llamar a los miembros del objeto, verifique que la referencia esté establecida con una condición 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
Error en tiempo de ejecución '20': Reanudar sin error
código incorrecto
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
¿Por qué no funciona esto?
Si el procedimiento DoSomethingElse
genera un error, la ejecución salta a la CleanFail
línea CleanFail
, imprime el número de error y la instrucción Resume Next
vuelve a la instrucción que sigue inmediatamente a la línea donde ocurrió el error, que en este caso es Debug.Print
instrucción: la subrutina de manejo de errores se ejecuta sin un contexto de error, y cuando se alcanza la instrucción Resume Next
, se genera el error 20 en tiempo de ejecución porque no hay ningún lugar para reanudar.
Código correcto
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
Exit Sub
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
¿Por qué funciona esto?
Al introducir una instrucción Exit Sub
antes de la CleanFail
línea CleanFail
, hemos segregado la subrutina de manejo de errores CleanFail
del resto del cuerpo del procedimiento: la única forma de ejecutar la subrutina de manejo de errores es a través de un salto On Error
; por lo tanto, ninguna ruta de ejecución llega a la instrucción Resume
fuera de un contexto de error, lo que evita el error 20 en tiempo de ejecución.
Otras notas
Esto es muy similar al error en tiempo de ejecución '3': Devolución sin GoSub ; en ambas situaciones, la solución es garantizar que la ruta de ejecución normal no pueda ingresar a una subrutina (identificada por una etiqueta de línea) sin un salto explícito (asumiendo que On Error GoTo
se considera un salto explícito ).