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

VBA Workbook_BeforeSave dans Excel — valider ou bloquer un enregistrement, et ce que SaveAsUI vous dit vraiment

|

VBA Workbook_BeforeSave dans Excel — valider ou bloquer un enregistrement, et ce que SaveAsUI vous dit vraiment

TL;DRWorkbook_BeforeSave est un événement qu'Excel déclenche à l'instant où un enregistrement est demandé — Ctrl+S, le bouton Enregistrer, ou le .Save d'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 ?) et Cancel (mettez-le à True pour 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 appelle ThisWorkbook.Save, cet enregistrement redéclenche BeforeSave, et la boucle est infinie tant que vous ne l'encadrez pas avec Application.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 Cancel et un signal SaveAsUI
  • Ce que SaveAsUI signifie 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 de BeforeSave boucle, et le correctif EnableEvents
  • Pourquoi un Cancel = True silencieux 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 BooleanTrue quand 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é), False pour 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. Mettez Cancel = True et 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