🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Workbook_BeforeSave en Excel — valida o bloquea un guardado, y qué te dice de verdad SaveAsUI

|

VBA Workbook_BeforeSave en Excel — valida o bloquea un guardado, y qué te dice de verdad SaveAsUI

TL;DRWorkbook_BeforeSave es un evento que Excel dispara en el momento en que se solicita un guardado — Ctrl+S, el botón Guardar o el .Save de una macro — antes de escribir en disco. Te entrega dos argumentos: SaveAsUI (¿está a punto de aparecer el cuadro Guardar como?) y Cancel (ponlo en True para bloquear el guardado). Así que es un control de calidad sobre la acción de guardar: inspecciona el libro y, o bien dejas pasar la escritura, o bien la rechazas. Lo único que muerde a todo el mundo — si tu manejador llama a ThisWorkbook.Save, ese guardado dispara BeforeSave otra vez y entra en bucle infinito a menos que lo controles con Application.EnableEvents.

' Vive en ThisWorkbook, NO en un Module.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    If ThisWorkbook.Sheets("Invoice").Range("Total").Value = "" Then
        MsgBox "Enter a Total before saving.", vbExclamation
        Cancel = True                         ' <-- bloquea el guardado; no se escribe nada
        Exit Sub
    End If
    ThisWorkbook.Sheets("Invoice").Range("LastSaved").Value = Now   ' sella la hora — sin llamada a .Save aquí
End Sub

Guardar parece lo más seguro que puede hacer un usuario, y justo por eso es el lugar idóneo para imponer reglas. Workbook_BeforeSave es el evento detrás de «no puedes guardar con un campo obligatorio en blanco», las celdas de «última modificación» selladas automáticamente, los nombres de archivo obligatorios y los registros de auditoría en el momento de guardar. Es también donde viven dos trampas sutiles: un guardado que en silencio no hace nada, y un manejador que se guarda a sí mismo hasta caer en un bucle infinito.

Lo que aprenderás

  • El modelo mental — una compuerta sobre el guardado, con un veto Cancel y una señal SaveAsUI
  • Qué significa de verdad SaveAsUI, y cómo usarlo para forzar un nombre de archivo o una carpeta
  • El patrón de sellado automático — escribe «quién y cuándo» dentro del archivo que se guarda
  • La trampa de la recursión — por qué .Save dentro de BeforeSave entra en bucle, y el arreglo con EnableEvents
  • Por qué un Cancel = True silencioso es un bug, no una función

El modelo mental: una compuerta sobre el guardado, no un recibo

Workbook_BeforeSave se dispara cuando se solicita un guardado y se ejecuta antes de que Excel escriba el archivo. Tú no lo llamas — Excel te llama a ti, espera y luego decide qué hacer según lo que hiciste. Pasa dos argumentos por referencia:

  • SaveAsUI As BooleanTrue cuando Excel está a punto de mostrar el cuadro Guardar como (el usuario eligió «Guardar como», o es un archivo nuevo sin guardar), False para un guardado normal sobre el archivo existente. Es información: ¿qué tipo de guardado es este?
  • Cancel As Boolean — tu veto. Pon Cancel = True y Excel abandona el guardado; no se escribe nada.

Así que el manejador es una compuerta, no un recibo. Un recibo confirmaría que un guardado ya ocurrió; este se ejecuta primero y tiene la última palabra para decir «no». (Si quieres el recibo — saber que un guardado tuvo éxito — ese es el evento aparte Workbook_AfterSave, que se dispara después con un indicador Success.)

La firma es fija y, como todo evento de libro, vive en ThisWorkbook: Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean). En un Module estándar no se dispara nunca.

La regla que lo hace útil: Cancel bloquea, SaveAsUI decide cómo

Los dos argumentos hacen dos trabajos distintos, y confundirlos es donde la gente se atasca.

Usa Cancel para imponer una condición previa — niégate a guardar hasta que los datos sean válidos:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    If Sheets("Order").Range("CustomerID").Value = "" Then
        MsgBox "Can't save: Customer ID is required.", vbExclamation
        Cancel = True            ' el guardado se detiene aquí
    End If
End Sub

Usa SaveAsUI para controlar cómo se guarda el archivo — casi siempre para impedir que los usuarios desperdiguen copias con nombres aleatorios, o para forzar una convención de nombres:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    If SaveAsUI Then
        MsgBox "Use File > Save only. This file must keep its name.", vbCritical
        Cancel = True            ' bloquea "Save As", permite "Save" normal
    End If
End Sub

Ese manejador deja pasar un Ctrl+S normal pero rechaza «Guardar como» — una pequeña política imposible sin saber qué guardado está en curso. La regla: SaveAsUI te dice la intención, Cancel decide el resultado.

El patrón que vale la pena memorizar: sella el archivo antes de que se escriba

Lo más útil que hace BeforeSave es escribir metadatos dentro del archivo en el último momento posible, para que la copia guardada los lleve consigo. Como tu código se ejecuta antes de la escritura en disco, cualquier cosa que cambies queda capturada por el guardado que está a punto de suceder:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    With Sheets("Log")
        .Range("LastSavedBy").Value = Environ("Username")
        .Range("LastSavedAt").Value = Now
    End With
    ' Sin .Save aquí — el guardado que disparó este evento incluirá los sellos.
End Sub

Fíjate en lo que falta: no hay ninguna llamada a ThisWorkbook.Save. No necesitas una — el guardado ya está ocurriendo; solo estás editando el libro un instante antes de que aterrice en el disco. Añadir un .Save aquí no solo es redundante, sino que prepara el terreno para la siguiente trampa.

La trampa que congela Excel: llamar a Save dentro de BeforeSave

Si tu manejador llama a ThisWorkbook.Save (un instinto natural — «séllalo y luego guárdalo»), ese guardado dispara Workbook_BeforeSave otra vez, que guarda de nuevo, que lo dispara de nuevo — la misma forma de bucle infinito que Worksheet_Change escribiendo en una celda. El evento no tiene ninguna protección incorporada contra reaccionar a su propia acción.

Cuando de verdad tengas que provocar un guardado desde dentro de un manejador de guardado — o desde cualquier evento que luego escriba — apaga los eventos a su alrededor y restáuralos siempre en un manejador de errores para que un fallo no pueda dejarlos atascados en apagado:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    On Error GoTo CleanExit
    Application.EnableEvents = False        ' nuestras propias acciones no volverán a disparar este evento
    ' ... trabajo que podría a su vez guardar o escribir ...
CleanExit:
    Application.EnableEvents = True         ' se ejecuta tanto si tuvimos éxito como si falló
End Sub

Application.EnableEvents es un único interruptor global de la aplicación que Excel no restaura por ti. Si un manejador lo pone en False y falla antes de restaurarlo, todos los eventos de Excel se quedan callados hasta que reinicies o ejecutes Application.EnableEvents = True en la ventana Inmediato — el mismo modo de fallo descrito en VBA On Error.

La regla que la gente olvida: no canceles en silencio

Un Cancel = True sin explicación es un bug de verdad. El usuario pulsa Ctrl+S, no ve nada y se marcha creyendo que el archivo está guardado — pero BeforeSave lo bloqueó en silencio y Workbook.Saved sigue siendo False. Horas de trabajo pueden evaporarse en el siguiente cuelgue. Siempre que pongas Cancel = True, dile al usuario por qué con un MsgBox, para que un guardado bloqueado sea una decisión visible, no una silenciosa. Una compuerta que el usuario no puede ver es una trampa.

BeforeSave protege el guardado; su hermano Workbook_BeforeClose protege el cierre con la misma clase de veto Cancel, y ambos pertenecen a la familia de eventos de libro junto a Workbook_Open.

Cómo ayuda ExcelMaster

Una compuerta de guardado tiene un montón de pequeños detalles de correcto-o-roto: el manejador en ThisWorkbook, Cancel usado para validar pero no en silencio, SaveAsUI leído en el sentido correcto, el sello escrito sin una llamada a .Save, y una protección con EnableEvents si algo llega a guardar.

ExcelMaster te deja enunciar la regla en su lugar. Di «no dejes que este archivo se guarde si la celda Total está vacía, y sella quién lo guardó y cuándo», y escribe un Workbook_BeforeSave que bloquea el guardado con un mensaje claro, sella la hoja de registro antes de la escritura y protege contra el bucle de autodisparo. Te quedas con el libro y el código; te ahorras el congelón que provocarías, si no, enseñándote la regla a ti mismo.

Preguntas frecuentes

¿Cómo impido que un libro se guarde en VBA?

Pon el argumento Cancel en True dentro de Workbook_BeforeSave: Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)Cancel = True. Excel comprueba Cancel después de que se ejecute tu manejador; True abandona el guardado y no escribe nada. Muestra siempre un mensaje que explique por qué, para que el bloqueo no sea silencioso.

¿Qué significa el parámetro SaveAsUI?

SaveAsUI es True cuando Excel está a punto de mostrar el cuadro Guardar como — porque el usuario eligió «Guardar como» o el archivo nunca se ha guardado — y False para un guardado normal sobre el archivo existente. Léelo para tratar los dos casos de forma distinta, por ejemplo para permitir Ctrl+S pero bloquear «Guardar como» de modo que el archivo conserve su nombre.

¿Por qué mi macro BeforeSave provoca un bucle infinito?

Porque llama a ThisWorkbook.Save (u otro guardado), y ese guardado dispara Workbook_BeforeSave de nuevo, sin fin. Normalmente no necesitas ningún .Save — las ediciones que haces en el manejador quedan capturadas por el guardado que ya está en curso. Si de verdad tienes que guardar, envuélvelo en Application.EnableEvents = False … = True y restaura los eventos en un manejador de errores.

¿Cómo añado una marca de tiempo de «última vez guardado» automáticamente?

En Workbook_BeforeSave, escribe el valor en una celda sin llamar a Save: Sheets("Log").Range("LastSavedAt").Value = Now. Como el manejador se ejecuta antes de que Excel escriba en disco, el guardado que disparó el evento incluye tu sello. Añade Environ("Username") para saber quién lo guardó.

¿Dónde va el código de Workbook_BeforeSave?

En el módulo de código de ThisWorkbook — haz doble clic en ThisWorkbook bajo «Objetos de Microsoft Excel» en el Explorador de proyectos y pega Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean). No se dispara desde un Module estándar, y las macros deben estar habilitadas.

Probado en

Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 05/08/2026.

Guías relacionadas: VBA Workbook_BeforeClose · VBA Worksheet_Activate y Deactivate · VBA Workbook_Open · VBA Worksheet_Change · VBA On Error