martes, 11 de octubre de 2022

VBA: Erl-Controlando los errores en VBA

Son muchos años ya los que llevo publicando artículos sobre esta herramienta, pero siempre hay un paso más, siempre aprendo algo nuevo.. y me fascina.
Hace unos siete años, por el 2015, publiqué un post sobre el objeto Err que nos aportaba información sobre el error generado.
Veíamos como con Err.Number o Err.Description determinabamos más o menos de qué error se trataba... una gran ayuda para depurar nuestras macros.
Puedes estudiar el listado completo de errores que pueden aparecer en este link:
https://learn.microsoft.com/es-es/office/vba/language/reference/user-interface-help/trappable-errors

En el artículo de hoy vamos a ir un paso más allá... vamos a emplear la función de VBA Erl, la cual nos indicará en qué línea del código se está produciendo el fallo!!.
MUY ÚTIL cuando ejecutamos UDF y el depurador salta sin detenerse en ningún sitio en concreto ;-)

Si bien, lo primero que tenemos que saber y hacer es numerar cada línea o bloque de código en nuestra macro.
Sin esta numeración, la función Erl siempre devolverá el valor 0 (y no nos servirá de nada).

Pongamos un ejemplo sencillo, donde recorremos, con un bucle For each, el rango A1:A10 que contiene diferentes valores entre 200 y 300.
En nuestra macro, definimos un 'cálculo' con un tipo de dato Byte, lo que significa que solo admitirá valores entre 0 y 255...
Esto es, fallará para valores superiores a ese 255.
En un módulo estándar de nuestro libro de trabajo tenemos la siguiente macro:
Sub Gestionando_Errores()
On Error GoTo trato_error

10 Dim dato As Byte    'valores entre 0 y 255
20 For Each celda In Range("A1:A10")
30    dato = celda.Value
40    Debug.Print dato
50 Next celda

Exit Sub
trato_error:
    
    Debug.Print Err.Number & " - " & Err.Description & " - línea - " & Erl()
End Sub

Fíjate como he comenzado a escribir cada línea de código con un número, que será el número de línea asociado y que la función Erl leerá.

Al ejecutar el proceso en la ventana de Inmediato veremos..
VBA: Erl-Controlando los errores en VBA


:OOO
Al saltar el controlador 'On Error GoTo trato_error', se interpreta el número y descripción del error generado... y con Erl junto al detalle de líneas añadido, idetificamos en qué momento exacto de la macro ha ocurrido!!.

Mágico!.

Claro, para este código sencillo es fácil añadir un número de línea por fila de código...
Pero si nuestro código en VBA tuviera cientos y cientos de líneas, se haría inviable este trabajo...

Aunque he leído que hay programas de terceros que incorporan automáticamente esta numeración de línea, o incluso con algunas macros dentro del mismo Excel se podrían autogenerar, creo que hay una salida más simple y práctica.
Numerar por bloques de código dentro de nuestra macro.

No creo ser el único que al programar vaya secuenciando diferentes acciones, por distintos bloques... lo que reduciría, en principio la cantidad de números de líneas a añadir... en un paso siguiente, si procede, añadiríamos la numeración por líneas, pero solo de ese bloque!!.

Pongamos un segundo ejemplo. Tenemos el siguiente código:
Sub Gestionando_Errores()
On Error GoTo trato_error

Dim arrValores As Variant   'definición de una matriz
Dim dato As Byte    'valores entre 0 y 255

x = 0
10 For Each celda In Range("A1:A10")
  dato = celda.Value
  ReDim Preserve arrValores(x) As Variant
  arrValores(x) = dato
  x = x + 1
Next celda

100 For i = LBound(arrValores) To UBound(arrValores)
    Cells(1, "B").Value = arrValores(i)/2
Next i

Exit Sub
trato_error:
    
    Debug.Print Err.Number & " - " & Err.Description & " - línea - " & Erl()
End Sub

Observa que solo he numerado el inicio de mis dos bloques de programación.
Con el número de línea 10 al bucle For each que recorre el rango A1:A10 e intenta cargas dichos valores a la matriz.
Y con el número de línea 100 el bucle For que trasladaría a la columna B la operación dada (dividir el dato cargado entre dos)

Nuestra macro contiene un primer error de compilación a la hora de definir la matriz arrValores.
Debería ser:
Dim arrValores() As Variant
en lugar de
Dim arrValores As Variant
Al ejecutar la macro, veríamos en la ventana de Inmediato el siguiente mensaje:
13 - No coinciden los tipos - línea - 10
VBA: Erl-Controlando los errores en VBA

Una vez identificado el bloque, en una segunda etapa, podemos renumerar las demás líneas para ganar en precisión.. así:
Sub Gestionando_Errores()
On Error GoTo trato_error

Dim arrValores As Variant   'definición de una matriz
Dim dato As Byte    'valores entre 0 y 255

x = 0
10 For Each celda In Range("A1:A10")
11  dato = celda.Value
12  ReDim Preserve arrValores(x) As Variant
13  arrValores(x) = dato
14  x = x + 1
15 Next celda

100 For i = LBound(arrValores) To UBound(arrValores)
    Cells(1, "B").Value = arrValores(i) / 2
Next i

Exit Sub
trato_error:
    
    Debug.Print Err.Number & " - " & Err.Description & " - línea - " & Erl()
End Sub

Que al ejecutar en esta segunda ocasión nos lanza el mensaje:
13 - No coinciden los tipos - línea - 12
Esto es, precisando que el error procede más concretamente de la línea 12...

Depurando así, poco a poco, línea a línea, nuestros códigos de VBA.

Una recomendación general leída en diferente documentación es que el añadir estas numeraciones de línea ralentiza los tiempos de ejecución de las macros, personalmente no he verificado estos retrasos, pero tiene sentido ya que hay más 'código' que leer ;-)

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.