TL;DR —
Workbook_BeforeSaveest un événement qu'Excel déclenche à l'instant où un enregistrement est demandé — Ctrl+S, le bouton Enregistrer, ou le.Saved'une macro — avant qu'il n'écrive sur le disque. Il vous remet deux arguments :SaveAsUI(la boîte de dialogue Enregistrer sous est-elle sur le point d'apparaître ?) etCancel(mettez-le àTruepour bloquer l'enregistrement). C'est donc un poste de contrôle qualité sur l'action d'enregistrer : inspectez le classeur, puis laissez passer l'écriture ou refusez-la. La seule chose qui piège tout le monde — si votre gestionnaire appelleThisWorkbook.Save, cet enregistrement redéclencheBeforeSave, et la boucle est infinie tant que vous ne l'encadrez pas avecApplication.EnableEvents.
' Réside dans ThisWorkbook — PAS 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 ' <-- bloque l'enregistrement ; rien n'est écrit
Exit Sub
End If
ThisWorkbook.Sheets("Invoice").Range("LastSaved").Value = Now ' estampille — aucun appel à .Save ici
End Sub
Enregistrer semble être la chose la plus sûre qu'un utilisateur puisse faire, et c'est
précisément pour cela que c'est le bon endroit pour imposer des règles.
Workbook_BeforeSave est l'événement derrière « impossible d'enregistrer avec un champ
obligatoire vide », les cellules « dernière modification » estampillées automatiquement,
les noms de fichiers imposés et les journaux d'audit à l'enregistrement. C'est aussi là
que se cachent deux pièges subtils : un enregistrement qui, en silence, ne fait rien, et
un gestionnaire qui s'enregistre lui-même dans une boucle infinie.
Ce que vous allez apprendre
- Le modèle mental — un poste de contrôle sur l'enregistrement, avec un droit de veto
Cancelet un signalSaveAsUI - Ce que
SaveAsUIsignifie réellement, et comment l'utiliser pour imposer un nom de fichier ou un dossier - Le motif d'estampillage automatique — inscrire « qui et quand » dans le fichier en cours d'enregistrement
- Le piège de la récursion — pourquoi
.Saveà l'intérieur deBeforeSaveboucle, et le correctifEnableEvents - Pourquoi un
Cancel = Truesilencieux est un bug, pas une fonctionnalité
Le modèle mental : un poste de contrôle sur l'enregistrement, pas un reçu
Workbook_BeforeSave se déclenche quand un enregistrement est demandé et s'exécute
avant qu'Excel n'écrive le fichier. Vous ne l'appelez pas — c'est Excel qui vous
appelle, attend, puis décide quoi faire selon ce que vous avez fait. Il passe deux
arguments par référence :
SaveAsUI As Boolean—Truequand Excel s'apprête à afficher la boîte de dialogue Enregistrer sous (l'utilisateur a choisi « Enregistrer sous », ou c'est un fichier tout neuf jamais enregistré),Falsepour un simple enregistrement par-dessus le fichier existant. C'est une information : de quel type d'enregistrement s'agit-il ?Cancel As Boolean— votre droit de veto. MettezCancel = Trueet Excel abandonne l'enregistrement ; rien n'est écrit.
Le gestionnaire est donc un poste de contrôle, pas un reçu. Un reçu confirmerait
qu'un enregistrement a déjà eu lieu ; celui-ci s'exécute en premier et peut dire
« non ». (Si vous voulez le reçu — savoir qu'un enregistrement a réussi — c'est
l'événement distinct Workbook_AfterSave, qui se déclenche après coup avec un
indicateur Success.)
La signature est figée et, comme tout événement de classeur, elle réside dans
ThisWorkbook :
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean). Dans un
Module standard, elle ne se déclenche jamais.
La règle qui le rend utile : Cancel bloque, SaveAsUI décide comment
Les deux arguments remplissent deux fonctions différentes, et les confondre, c'est là qu'on cale.
Utilisez Cancel pour imposer une condition préalable — refuser d'enregistrer tant
que les données ne sont pas valides :
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 ' l'enregistrement s'arrête ici
End If
End Sub
Utilisez SaveAsUI pour contrôler comment le fichier est enregistré — le plus
souvent pour empêcher les utilisateurs de disperser des copies aux noms aléatoires, ou
pour imposer une convention de nommage :
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 ' bloque « Enregistrer sous », autorise le simple « Enregistrer »
End If
End Sub
Ce gestionnaire laisse passer un Ctrl+S normal mais refuse « Enregistrer sous » — une
petite règle impossible à appliquer sans savoir quel type d'enregistrement est en cours.
La règle : SaveAsUI vous indique l'intention, Cancel décide de l'issue.
Le motif à mémoriser : estampiller le fichier avant son écriture
La chose la plus utile que fait BeforeSave, c'est d'écrire des métadonnées dans le
fichier au tout dernier moment, pour que la copie enregistrée les emporte. Comme votre
code s'exécute avant l'écriture sur le disque, tout ce que vous modifiez est capturé
par l'enregistrement sur le point de se produire :
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
' Aucun .Save ici — l'enregistrement qui a déclenché cet événement inclura les estampilles.
End Sub
Remarquez ce qui manque : il n'y a aucun appel ThisWorkbook.Save. Vous n'en avez pas
besoin — l'enregistrement est déjà en cours ; vous ne faites qu'éditer le classeur un
instant avant qu'il n'atterrisse sur le disque. Ajouter un .Save ici est non seulement
redondant, c'est aussi le décor planté pour le prochain piège.
Le piège qui fige Excel : appeler Save à l'intérieur de BeforeSave
Si votre gestionnaire appelle ThisWorkbook.Save (un instinct naturel — « estampille-le,
puis enregistre-le »), cet enregistrement redéclenche Workbook_BeforeSave, qui
enregistre à nouveau, qui le redéclenche encore — la même forme de boucle infinie que
Worksheet_Change écrivant dans une cellule. L'événement
n'a aucune protection intégrée contre le fait de réagir à sa propre action.
Quand vous devez vraiment déclencher un enregistrement depuis un gestionnaire d'enregistrement — ou depuis tout événement qui écrit ensuite — désactivez les événements autour de lui et rétablissez-les toujours dans un gestionnaire d'erreurs, pour qu'un plantage ne puisse pas les laisser bloqués à l'arrêt :
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
On Error GoTo CleanExit
Application.EnableEvents = False ' nos propres actions ne redéclencheront pas cet événement
' ... traitement susceptible d'enregistrer ou d'écrire lui-même ...
CleanExit:
Application.EnableEvents = True ' s'exécute que l'on ait réussi ou échoué
End Sub
Application.EnableEvents est un interrupteur unique, global à l'application, qu'Excel
ne rétablit pas pour vous. Si un gestionnaire le met à False et échoue avant de le
rétablir, chaque événement d'Excel devient muet jusqu'à ce que vous redémarriez ou
exécutiez Application.EnableEvents = True dans la fenêtre Exécution — le même mode de
défaillance décrit dans VBA On Error.
La règle qu'on oublie : ne pas annuler en silence
Un Cancel = True sans explication est un vrai bug. L'utilisateur appuie sur Ctrl+S, ne
voit rien, et repart en croyant le fichier enregistré — mais BeforeSave l'a bloqué en
douce et Workbook.Saved vaut toujours False. Des heures de travail peuvent
s'évaporer au prochain plantage. Chaque fois que vous mettez Cancel = True, dites à
l'utilisateur pourquoi avec un MsgBox, pour qu'un enregistrement bloqué soit une
décision visible, pas silencieuse. Un poste de contrôle que l'utilisateur ne peut pas
voir est un piège.
BeforeSave protège l'enregistrement ; son jumeau
Workbook_BeforeClose protège la fermeture avec le
même genre de droit de veto Cancel, et tous deux appartiennent à la famille des
événements de classeur aux côtés de Workbook_Open.
Comment ExcelMaster aide
Un poste de contrôle d'enregistrement comporte quantité de petits détails soit corrects
soit cassés : le gestionnaire dans ThisWorkbook, Cancel employé pour valider mais pas
en silence, SaveAsUI lu dans le bon sens, l'estampille écrite sans appel .Save, et
une protection EnableEvents si quoi que ce soit enregistre.
ExcelMaster
vous laisse énoncer la règle à la place. Dites « n'autorise pas l'enregistrement de ce
fichier si la cellule Total est vide, et estampille qui l'a enregistré et quand », et il
écrit un Workbook_BeforeSave qui bloque l'enregistrement avec un message clair,
estampille la feuille de journal avant l'écriture, et se prémunit contre la boucle
d'auto-déclenchement. Vous gardez le classeur et le code ; vous vous épargnez le blocage
que vous provoqueriez sinon en apprenant la règle par vous-même.
Questions fréquentes
Comment empêcher un classeur de s'enregistrer en VBA ?
Mettez l'argument Cancel à True dans Workbook_BeforeSave :
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) …
Cancel = True. Excel vérifie Cancel après l'exécution de votre gestionnaire ; True
abandonne l'enregistrement et n'écrit rien. Affichez toujours un message expliquant
pourquoi, pour que le blocage ne soit pas silencieux.
Que signifie le paramètre SaveAsUI ?
SaveAsUI vaut True quand Excel s'apprête à afficher la boîte de dialogue
Enregistrer sous — parce que l'utilisateur a choisi « Enregistrer sous » ou que le
fichier n'a jamais été enregistré — et False pour un simple enregistrement par-dessus
le fichier existant. Lisez-le pour traiter les deux cas différemment, par exemple
autoriser Ctrl+S mais bloquer « Enregistrer sous » afin que le fichier garde son nom.
Pourquoi ma macro BeforeSave provoque-t-elle une boucle infinie ?
Parce qu'elle appelle ThisWorkbook.Save (ou un autre enregistrement), et que cet
enregistrement redéclenche Workbook_BeforeSave, sans fin. En général, vous n'avez pas
besoin de .Save du tout — les modifications que vous faites dans le gestionnaire sont
capturées par l'enregistrement déjà en cours. Si vous devez vraiment enregistrer,
encadrez-le par Application.EnableEvents = False … = True et rétablissez les événements
dans un gestionnaire d'erreurs.
Comment ajouter automatiquement un horodatage « dernier enregistrement » ?
Dans Workbook_BeforeSave, écrivez la valeur dans une cellule sans appeler Save :
Sheets("Log").Range("LastSavedAt").Value = Now. Comme le gestionnaire s'exécute avant
qu'Excel n'écrive sur le disque, l'enregistrement qui a déclenché l'événement inclut
votre estampille. Ajoutez Environ("Username") pour savoir qui a enregistré.
Où placer le code Workbook_BeforeSave ?
Dans le module de code ThisWorkbook — double-cliquez sur ThisWorkbook sous
« Microsoft Excel Objets » dans l'Explorateur de projets et collez-y
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean). Il ne se
déclenche pas depuis un Module standard, et les macros doivent être activées.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — dernière vérification le 05/08/2026.
Guides associés : VBA Workbook_BeforeClose · VBA Worksheet_Activate et Deactivate · VBA Workbook_Open · VBA Worksheet_Change · VBA On Error
