lunes, 13 de enero de 2014

Control de errores en VBA para Excel


Cualquier usuario que se haya adentrado en el mundo de las macros o del VBA (Visual Basic for Applications) habrá comprobado como es necesario convivir con los errores que se producen al ejecutar determinado código.
A veces, que ocurra un error es comprensible, natural y en ocasiones inevitable. Lo que sí debemos evitar es que nuestra macro o procedimiento se bloquee, apareciendo el típico mensaje de error:



Pero comencemos desde el principio. En el ámbito del VBA, hay tres tipos de error:

  • Los errores de compilación (sintaxis inadecuada). Estos errores de compilación son detectados por el editor de VBA al compilar el código, antes de comenzar a ejecutarse el procedimiento:
    • Por escribir inadecuadamente una expresión. Es decir, escribir una palabra inexistente en VBA
    • Por omitir una expresión donde debería estar escrita
    • Por escribir una expresión en un lugar que no corresponde
  • Los errores lógicos. Estos errores son más bien de planteamiento del código, no de sintaxis. El código está bien escrito y no se producen errores que bloqueen la ejecución. Aunque el programa funciona, no realiza las funciones para las que se diseñó o las realiza de forma errónea.
  • Los errores en tiempo de ejecución. Estos son detectados por Excel cuando ya se está ejecutando el código y pueden ser motivados por múltiples causas. En cualquier caso, siempre hay algo en común: Excel no puede ejecutar la acción que nosotros pretendemos con el código porque se produce una incoherencia (el resultado es un error, una condición que nunca se cumple, un valor que es imposible de asignar, un límite sobrepasado, etc.)



En la imagen anterior, vemos un error en tiempo de ejecución. Concretamente, Excel no ha podido encontrar el archivo que el código solicitaba abrir. En adelante, en este post, nos referiremos a este último tipo de errores (los errores en tiempo de ejecución).

¿Qué podemos hacer ante la posibilidad de que se produzca un error en la ejecución de nuestro código?

En Visual Basic tenemos la instrucción "On Error" para decidir lo que queremos que ocurra si se produjera un error en nuestro código. Tenemos 3 opciones para complementar la instrucción "On Error":
  • On error Resume Next (traducido sería: si hay un error, reanudar el código en la siguiente línea). Con esta opción, cuando se detecta el error, no aparece ningún cuadro de diálogo para "Finalizar" o "Depurar". La ejecución continua en la siguiente línea de código. Podemos ver un ejemplo aquí:
  • On Error GoTo MiEtiqueta (traducido sería: si hay un error, ir a MiEtiqueta). Con esta opción, al detectarse un error, obligamos a que la ejecución de código continúe en una línea marcada por nosotros con una etiqueta*. De esta forma y a continuación de esa etiqueta, podemos escribir un código que se ejecute en el caso de existencia de error:

Vemos en el ejemplo anterior que, en caso de error (al no encontrar el archivo Libro2.xlsm), enviamos la ejecución a la etiqueta ControlErrores para que se ejecute el código a partir de ahí (un MsgBox).

(*) Las etiquetas pueden ser textos (sin espacios), pero también pueden ser números (excepto el 0 (cero)). En el siguiente punto de este artículo quedará explicado por qué no se debe poner un cero como etiqueta..
Cuando nombramos una etiqueta después de las instrucciones "On Error GoTo ...." , la etiqueta no debe llevar dos puntos al final, pero al etiquetar la linea (a la que enviamos la ejecución del código), la etiqueta SÍ debe llevar dos puntos al final (ver imagen anterior).

Es conveniente utilizar una instrucción Exit Sub antes del control de errores (que se suele colocar al final del procedimiento) para evitar que sea leído el código si no es necesario (si no existe error). Por ejemplo:


  • On Error Goto 0 (traducido sería: si hay un error, deshabilitamos el control de errores). Con esta opción, si habíamos utilizado en el procedimiento la instrucción "On Error..." quedará deshabilitada y los errores de nuevo bloquearán Excel si se producen. 

         En la imagen de arriba vemos como se produce un error, puesto que "On Error GoTo 0" deshabilita el anterior "On Error GoTo ControlErrores"

          Es importante resaltar que "On Error.." habilita el control de errores sólo para un ámbito de procedimiento. En otras palabras:
    • Cuando se termina de ejecutar un procedimiento, termina el efecto de "On Error"
    • "On Error..." utilizado en un procedimiento x , no afecta a ningún otro procedimiento.
  • On Error Goto -1 (traducido sería: si hay un error, se reinicia la posibilidad de detectar y controlar un error)**. Es necesario saber que si en un momento dado hay una instrucción "On Error.." controlando un error (está en pleno trabajo)... si ocurriera otro error en ese instante, no podría ser controlado. Para restablecer "On Error..."  y que pueda volver a detectar errores (quede libre de trabajo), se utiliza On Error GoTo -1.
** Es importante tener en cuenta la diferencia entre "On Error GoTo 0" y "On Error GoTo -1":
  • "On Error GoTo 0", se utiliza para dejar de detectar errores
  • "On Error GoTo -1", se utiliza para volver a detectar errores, durante el control de un error
¿Cómo puedo comprobar si hay un error en algún rango o expresión y decidir lo que ocurrirá después?

También podemos controlar el comportamiento de Visual Basic en el caso de que se produzca un error, de otra forma distinta a las ya conocidas. Es el caso de la función de comprobación IsError. La forma de utilizarla es:
IsError(expresión)

Veamos un ejemplo en este fragmento de código:


Podemos apreciar como, después de declarar la variable "Edad" y de asignarle como valor lo introducido en un cuadro de entrada de datos (InputBox), el código comprueba...:
  1. Con una estructura condicional If...Then...Else, si la edad es < 18
  2. Con la función de comprobación IsError, si la variable contiene un error (este se podría producir si el usuario no introduce un número, pues la variable se declaró como numérica)


Si desea llevar a la práctica todo lo que le hemos ofrecido en este artículo, puede asistir a nuestros cursos prácticos de Excel o puede solicitarlos in company:







6 comentarios:

  1. Gracias miles yo pense que andaba algo mal con mi office y a cambiar de versiones y cd's jejeje habia que cambiar al programador (yo) gracias gracias

    ResponderEliminar
  2. Buenas! Necesito ayuda. Quise abrir un formulario de VBA desde una imagen en un Excel a través de la cual se abría normalmente. Ayer quise abrirlo y me saltó el siguiente error: "No se puede ejecutar la macro 'LibroX'. Puede que la macro no esté disponible en este libro o que hayan deshabilitado todas las macros" y sólo el botón de Aceptar... Qué está pasando? Cómo se soluciona?

    ResponderEliminar
    Respuestas
    1. Pues está pasando justo lo que dice el cuadro de diálogo. Que la macro que estaba asignada al botón ya no está: o bien porque se ha eliminado, o bien porque la macro no se grabó para este libro y por lo tanto no está alojada en este libro.
      También podría haber alguna que otra razón más extraña...pero posible.

      Eliminar
  3. Hola, necesito ayuda. Busco como hacer una macro para que cierre Word o la aplicación de Office que corresponda cuando al abrir el archivo lo detecte como corrupto o dañado. He conseguido hacer una macro que cierra la aplicación si aparace algún error en el código de la macro, pero no me sirve del todo ya que si no acepto las ventanas de aviso de archivo dañado la macro no se ejecuta. Saludos y gracias.

    ResponderEliminar
  4. Prueba con Application.DisplayAlerts = False

    Saludos

    ResponderEliminar
  5. MIRA MI CÓDIGO ES EL SIGUIENTE:
    Private Sub CommandButton1_Click()
    On Error GoTo ERROR
    Dim Myconm As New Connection
    Dim rm As String
    Dim X As Integer
    X = 0
    Myconm.Open "ConexionMantenimiento"
    Set rsrc = New Recordset
    rm = "Select CODIGO, APELLIDO, NOMBRE FROM FAM_OFI"
    rsrc.Open rm, Myconm
    listfo.Clear
    Do While rsrc.EOF = False
    listfo.AddItem
    listfo.List(X, 0) = rsrc!CODIGO
    listfo.List(X, 1) = rsrc!APELLIDO
    listfo.List(X, 2) = rsrc!NOMBRE
    X = X + 1
    rsrc.MoveNext
    Loop

    ERROR:
    MsgBox "ALGO INESPERADO SUCEDIO"
    End Sub

    cuando lo ejecuto así no exista algún error igual me muestra el mensaje, cosa que no debería ser ya que no existe ningún error.

    ResponderEliminar