Implementación de Try-Catch-Finally en VBA

Generalmente, el manejo de errores se realiza mínimamente en cada función y luego se lanza al llamador. Sin embargo, en VBA no es fácil implementar esto.

Si se crea un controlador de errores, se suprime el error y, al intentar lanzar Err.Raise nuevamente, se captura el error dentro de la misma función, creando un bucle infinito.

Por ejemplo,

  • Después de abrir un archivo con la función Open, incluso si ocurre un error, se debe ejecutar Close.
  • Además, se debe transmitir el error al llamador.
On Error GoTo 0
Call Err.Raise(Err.Number)

Para resolver esto, se utiliza el código anterior. A continuación se presenta una explicación y ejemplos.

On Error GoTo 0

Al usar On Error GoTo 0, se anula cualquier On Error definido anteriormente.

Normalmente, al escribir Err.Raise en un controlador de errores,

  1. Se captura el error
  2. Se salta al controlador de errores
  3. Se lanza el error
  4. Se vuelve al paso 1

Esto crea un bucle, pero al incluir On Error GoTo 0,

  1. Se captura el error
  2. Se salta al controlador de errores
  3. Se anula el controlador de errores
  4. Se lanza el error al llamador

Esto permite recrear Try-Catch-Finally, similar a otros lenguajes de programación.

Ejemplo de código

Solo manejo de errores y lanzamiento

Public sub Caller()
    On Error GoTo ERROR_HANDLER
    Call Called

ERROR_HANDLER:
    Debug.Print(Err.Number)
End Sub
Public sub Called()

    On Error GoTo ERROR_HANDLER
    Dim errNumber as Long

    ' Escribir el código que puede causar errores

    Exit Sub

ERROR_HANDLER:
    errNumber = Err.Number
    On Error GoTo 0

    ' Escribir el código que se ejecuta después de un error

    ' Transmitir el error al llamador
    Call Err.Raise(errNumber)

End Sub

Recrear Try-Catch-Finally

Requiere una escritura bastante larga.

Public sub Caller()

    On Error GoTo ERROR_HANDLER

    Call Called

ERROR_HANDLER:
    Debug.Print(Err.Number)
End Sub

Public sub Called()

    On Error GoTo ERROR_HANDLER
    Dim errNumber as Long

    ' Escribir el código que puede causar errores

FINALLY:

    If errNumber <> 0 then
        Err.Raise(errNumber)
    End if

    Exit Sub
ERROR_HANDLER:
    errNumber = Err.Number
    On Error GoTo 0

    ' Escribir el código que se ejecuta después de un error

     Resume FINALLY
End Sub

Ejemplo práctico

Solo Try-Catch

'------------------------------------------------
'
' Función que llama a otra función
'
'------------------------------------------------
Public Sub Caller()
    On Error GoTo ERROR_HANDLER
    Call Called

ERROR_HANDLER:

    Debug.Print "Llamador : Catch"

End Sub
'------------------------------------------------
'
' Función llamada (que lanza el error)
'
'------------------------------------------------
Public Sub Called()

    On Error GoTo ERROR_HANDLER
    Dim errNumber as Long

    Dim n As Long: n = 1 / 0

    Exit Sub

ERROR_HANDLER:
    errNumber = Err.Number
    On Error GoTo 0

    Debug.Print "Llamado : Catch"

    ' Transmitir el error al llamador
    Call Err.Raise(errNumber)

End Sub

Resultado de ejecución

Llamado : Catch
Llamador : Catch

Recrear Try-Catch-Finally

'------------------------------------------------
'
' Función que llama a otra función
'
'------------------------------------------------
Public sub Caller()

    On Error GoTo ERROR_HANDLER

    Call Called

ERROR_HANDLER:

    Debug.Print "Llamador : Catch"

End Sub

'------------------------------------------------
'
' Función llamada (que lanza el error)
'
'------------------------------------------------
Public sub Called()

    On Error GoTo ERROR_HANDLER

    Dim errNumber as long

    Dim n as long: n = 1 / 0

FINALLY:

    Debug.Print "Llamado : Finally"

    If errNumber <> 0 then
        Err.Raise(errNumber)
    End if

    Exit Sub
ERROR_HANDLER:
    errNumber = Err.Number
    On Error GoTo 0

    Debug.Print "Llamado : Catch"

     Resume FINALLY
End Sub

Resultado de ejecución

Llamado : Catch
Llamado : Finally
Llamador : Catch
#Excel #VBA