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

VBA Workbook_BeforeClose dans Excel — annuler la fermeture, proposer d'enregistrer, et où le code doit résider

|

VBA Workbook_BeforeClose dans Excel — annuler la fermeture, proposer d'enregistrer, et où le code doit résider

TL;DRWorkbook_BeforeClose est un événement qu'Excel déclenche à l'instant où quelqu'un tente de fermer le classeur — avant que la moindre fenêtre ne soit démantelée. Il vous remet un seul argument, Cancel, et c'est tout l'enjeu : mettez Cancel = True et la fermeture est annulée, le fichier reste ouvert. Ce n'est donc pas un mot d'adieu que vous exécutez sur le pas de la porte — c'est un point de contrôle capable de faire faire demi-tour à l'utilisateur sur le seuil. Le code doit résider dans ThisWorkbook, et si vous voulez exécuter votre propre invite d'enregistrement sans qu'Excel demande lui aussi, mettez ThisWorkbook.Saved = True pour faire taire sa boîte de dialogue intégrée.

' Réside dans ThisWorkbook — PAS un Module.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If ThisWorkbook.Sheets("Form").Range("Approved").Value <> "Yes" Then
        MsgBox "Set Approved = Yes before closing this file.", vbExclamation
        Cancel = True          ' <-- annule la fermeture ; le classeur reste ouvert
    End If
End Sub

La plupart des macros s'exécutent quand un utilisateur le demande — un bouton, un raccourci. Workbook_BeforeClose s'exécute quand un utilisateur tente de partir, et ce moment précis est ce qui la rend utile et dangereuse à parts égales. C'est l'événement derrière « vous avez des modifications non enregistrées », les validations obligatoires, le nettoyage à la sortie et « journaliser qui a fermé le fichier ». C'est aussi l'événement que l'on câble le plus souvent de travers — parce qu'on le traite comme une notification alors qu'Excel offre en réalité un droit de veto.

Ce que vous allez apprendre

  • Le modèle mental — un événement videur qui vous remet un droit de veto Cancel, pas un simple avertissement
  • Comment réellement empêcher une fermeture (et pourquoi une invite vbYesNo seule n'y suffit pas)
  • Le piège de la double invite — et le levier ThisWorkbook.Saved = True qui le corrige
  • Pourquoi BeforeClose ne doit jamais être votre filet de sécurité pour l'intégrité des données (les plantages l'ignorent)
  • Fermeture d'un classeur vs fermeture d'Excel entière — et où le code doit résider

Le modèle mental : un videur, pas un mot d'adieu

Workbook_BeforeClose se déclenche dès qu'une fermeture est demandée — le X de la fenêtre, Fichier ▸ Fermer, Application.Quit, ou une autre macro qui appelle .Close — et il se déclenche avant qu'Excel ne fasse quoi que ce soit d'irréversible. Point crucial : il passe un unique Boolean par référence, nommé Cancel. Vous n'appelez jamais ce Sub ; c'est Excel qui vous appelle, attend que vous ayez terminé, puis regarde la valeur de Cancel.

Ce seul argument recadre tout. Si vous laissez Cancel tel quel, la fermeture se déroule normalement. Si vous mettez Cancel = True, Excel abandonne la fermeture et le classeur reste ouvert exactement tel qu'il était. Le gestionnaire est donc un videur : il peut laisser passer l'utilisateur, ou l'arrêter et le renvoyer corriger quelque chose. Lisez-le comme « préviens-moi avant de fermer » et vous passerez à côté de toute la puissance de l'événement.

La signature est figée et l'emplacement n'est pas négociable : Private Sub Workbook_BeforeClose(Cancel As Boolean), dans le module de code ThisWorkbook — double-cliquez sur ThisWorkbook sous « Microsoft Excel Objets » dans l'Explorateur de projets. Placez-le dans un Module standard et il ne se déclenchera jamais, c'est la même règle du « où réside le code » que pour Workbook_Open.

La règle qui compte le plus : une invite sans Cancel n'est que du théâtre

Voici l'erreur que presque tout le monde commet en premier. Vous voulez confirmer avant de fermer, alors vous écrivez :

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    MsgBox "Are you sure you want to close?", vbYesNo   ' pose la question... et ignore la réponse
End Sub

La boîte de dialogue s'affiche, l'utilisateur clique sur Non — et le classeur se ferme quand même. Rien dans ce code ne touche à Cancel, donc Excel poursuit. L'invite n'était que du théâtre. La règle : une décision que vous voulez imposer doit être réécrite dans Cancel. Récupérez la réponse et agissez en conséquence :

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If MsgBox("Close without exporting the report?", vbYesNo + vbQuestion) = vbNo Then
        Cancel = True          ' l'utilisateur a dit Non -> annuler la fermeture
    End If
End Sub

Désormais, « Non » garde réellement le fichier ouvert. C'est toute la différence entre un événement qui informe et un événement qui protège : la protection n'est réelle que si Cancel = True peut être atteint.

Le piège qui agace les utilisateurs : Excel demande deux fois d'enregistrer

Le second bug classique surgit dès que votre gestionnaire enregistre. Vous ajoutez une étape « enregistrer avant de partir », et voilà que fermer un classeur modifié produit deux boîtes de dialogue : la vôtre, puis celle d'Excel, « Voulez-vous enregistrer les modifications ? ». La raison : vous et Excel tentez tous deux de gérer le même état non enregistré.

Le levier, c'est la propriété Saved du classeur. Saved est l'indicateur qu'Excel utilise pour « il n'y a aucune modification non enregistrée ». Quand vous la mettez à True, vous dites à Excel que le fichier est propre — il se ferme donc sans afficher sa propre invite d'enregistrement, même s'il existe réellement des modifications. Gérez l'enregistrement vous-même, puis basculez Saved :

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Dim answer As VbMsgBoxResult
    answer = MsgBox("Save changes before closing?", vbYesNoCancel + vbQuestion)

    If answer = vbCancel Then
        Cancel = True                 ' ne pas fermer du tout
    ElseIf answer = vbYes Then
        ThisWorkbook.Save             ' enregistrer, puis laisser la fermeture se poursuivre
    Else ' vbNo
        ThisWorkbook.Saved = True     ' abandonner : dire à Excel qu'il est propre pour qu'il ne redemande pas
    End If
End Sub

Mettre Saved = True n'enregistre rien — cela supprime l'invite en prétendant que le classeur est déjà enregistré. Utilisez-le à dessein : c'est l'interrupteur qui fait de votre propre logique d'enregistrement la seule que l'utilisateur voit.

La règle qui protège vos données : BeforeClose n'est pas un filet de sécurité

Workbook_BeforeClose se déclenche à chaque fermeture ordonnée — le X, Fichier ▸ Fermer, .Close, Application.Quit. Il ne se déclenche pas quand Excel plante, quand le processus est tué, ou lors d'une coupure de courant. D'où une tentation dangereuse : ne faites jamais de BeforeClose le seul mécanisme qui enregistre vos données. Si la logique « enregistrer l'unique copie » réside ici et qu'Excel meurt, la copie est perdue. Traitez BeforeClose comme une courtoisie (inviter, ranger, journaliser), et gardez la vraie persistance sur un enregistrement explicite ou une sauvegarde automatique minutée, pas sur le chemin de sortie.

Un dernier cas limite à connaître : quand l'utilisateur quitte Excel lui-même avec plusieurs classeurs ouverts, chaque classeur reçoit son propre BeforeClose. Mettre Cancel = True dans l'un d'eux empêche ce classeur de se fermer, mais les autres qui ont déjà exécuté leur gestionnaire peuvent se retrouver dans un état à moitié fermé. Si vous voulez du « tout ou rien » à la fermeture, coordonnez depuis Workbook_BeforeClose avec parcimonie et testez le cas multi-fichiers.

La distinction qui fait trébucher : BeforeClose vs BeforeSave

BeforeClose protège la sortie ; son jumeau Workbook_BeforeSave protège l'enregistrement et vous remet le même genre de droit de veto Cancel (plus un indicateur SaveAsUI). Ils forment une paire naturelle — valider à l'enregistrement, confirmer à la fermeture — et tous deux partagent la règle d'or de la famille d'événements : si un gestionnaire écrit dans des cellules ou enregistre, encadrez cette action par Application.EnableEvents = False … = True et rétablissez-la dans un gestionnaire d'erreurs, exactement comme le fait Worksheet_Change, afin que votre propre écriture ne puisse pas redéclencher la mécanique.

Comment ExcelMaster aide

Un garde-fou de fermeture, ce sont quatre petites décisions faciles à rater subtilement : le code dans ThisWorkbook (pas un Module), l'écriture de Cancel qui arrête réellement la fermeture, le basculement Saved = True qui évite la double invite, et le jugement sur ce qu'il ne faut pas confier au chemin de sortie.

ExcelMaster vous laisse décrire le comportement à la place. Dites « avant que ce fichier ne se ferme, si la cellule Approved n'est pas à Yes, arrête la fermeture et préviens l'utilisateur », et il écrit un Workbook_BeforeClose dans ThisWorkbook qui règle Cancel correctement, gère l'invite d'enregistrement sans la dédoubler, et protège toute écriture. Vous gardez le classeur et le code ; vous vous épargnez les tâtonnements pour apprendre quel levier fait quoi.

Questions fréquentes

Comment empêcher un classeur de se fermer en VBA ?

Mettez l'argument Cancel à True dans Workbook_BeforeClose : Private Sub Workbook_BeforeClose(Cancel As Boolean)Cancel = True. Excel passe Cancel par référence et le vérifie après l'exécution de votre gestionnaire ; True annule la fermeture et le fichier reste ouvert. Un MsgBox seul ne fait rien — vous devez réécrire la décision dans Cancel.

Pourquoi Excel me demande-t-il deux fois d'enregistrer à la fermeture ?

Parce que votre gestionnaire BeforeClose propose d'enregistrer et qu'Excel pense encore qu'il y a des modifications non enregistrées, il affiche donc lui aussi sa propre boîte de dialogue. Gérez l'enregistrement vous-même, puis mettez ThisWorkbook.Saved = True pour dire à Excel que le classeur est propre — cela supprime son invite intégrée « Voulez-vous enregistrer ? ».

Où placer le code Workbook_BeforeClose ?

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_BeforeClose(Cancel As Boolean). Il ne se déclenche pas depuis un Module standard, et les macros doivent être activées.

Workbook_BeforeClose s'exécute-t-il si Excel plante ?

Non. Il ne se déclenche que lors d'une fermeture ordonnée — le X de la fenêtre, Fichier ▸ Fermer, .Close ou Application.Quit. Un plantage, un processus tué ou une coupure de courant l'ignorent complètement. Ne comptez jamais sur BeforeClose comme seul mécanisme d'enregistrement de vos données.

En quoi BeforeClose diffère-t-il de Workbook_BeforeSave ?

BeforeClose se déclenche quand le fichier se ferme et vous laisse annuler la fermeture ; Workbook_BeforeSave se déclenche quand le fichier est en cours d'enregistrement et vous laisse annuler l'enregistrement. Fermer un fichier modifié déclenche généralement une invite d'enregistrement, si bien que les deux apparaissent souvent ensemble, mais ce sont des événements distincts avec des indicateurs Cancel distincts.

Testé dans

Testé dans : Excel 365 (Windows 11), VBA 7.1 — dernière vérification le 05/08/2026.

Guides associés : VBA Workbook_BeforeSave · VBA Worksheet_Activate et Deactivate · VBA Workbook_Open · VBA Worksheet_Change · VBA On Error