Workbook_BeforeClose récalcitrant ! [Résolu]

Messages postés
377
Date d'inscription
lundi 3 avril 2006
Dernière intervention
22 août 2018
- - Dernière réponse : CerberusPau
Messages postés
377
Date d'inscription
lundi 3 avril 2006
Dernière intervention
22 août 2018
- 28 sept. 2010 à 01:01
Bonjour à tous,

Mais où est donc mon erreur ???

Dans mon exemple :

1) J'ai 2 claseurs ouverts : Prog.xls et Toto.xls, avec Toto.xls actif.
2) Je ferme EXCEL (avec la croix de l'application)
3) J'ai le message "Voulez-vous enregistrer Toto ?"
4) Je réponds et en principe Toto devrait se fermer après ma réponse, puis Prog.xls se sauver, se fermer, et enfin Excel se fermer dans la foulée...

Eh bien NON!
Il faut que je reclique sur la croix de l'application, et ce autant de fois qu'il y a de classeurs ouverts...

Même avec DoEvents, ça marche pas...

Grand merci pour toute aide!

Code dans Thisworkbook de Prog.xls
Private Sub Workbook_BeforeClose(Cancel As Boolean)

    For Each w In Workbooks
        If w.Name <> ThisWorkbook.Name Then
            Dim Ms, Ss, Ts, Rs                              'définition
            Ms = "Voulez_vous enregistrer " & w.Name & " ?" 'définit le message.
            Ss = vbYesNo + vbExclamation + vbDefaultButton1 'définit les boutons.
            Ts = "Enegistrer avant de quitter"              'définit le titre.
            Rs = MsgBox(Ms, Ss, Ts)                         'demande une réponse
            If Rs = vbYes Then w.Close savechanges:=True    'Réponse OUI... Enregistre et ferme
            If Rs = vbNo Then w.Close savechanges:=False    'Réponse NON... Ferme sans enregistrer
            End If
            DoEvents
    Next w
    
    Workbooks("Prog.xls").Save                              'Sauvegarde seulement le fichier
    Application.Quit                                        'Ferme Excel
    DoEvents

Cordialement
Rataxes64
Afficher la suite 

Votre réponse

9 réponses

Meilleure réponse
Messages postés
1839
Date d'inscription
vendredi 13 mai 2005
Dernière intervention
20 novembre 2013
3
Merci
Salut,

je pense qu'il y a plus simple:

Workbook_BeforeClose est un evenement de fermeture de classeur et qui sera déclenché à chaque fermeture de classeur.
Ta boucle "For Each w In Workbooks" va donc declencher cet evenement pour chaque fichier ouvert et que tu fermes avec les lignes:
            If Rs = vbYes Then w.Close savechanges:=True    'Réponse OUI... Enregistre et ferme
            If Rs = vbNo Then w.Close savechanges:=False    'Réponse NON... Ferme sans enregistrer


La solution est donc de désactiver cet évenement en temps voulu:

Private Sub Workbook_BeforeClose(Cancel As Boolean)

    Application.EnableEvents = False 'on desavtive les évenements
    For Each w In Workbooks
        If w.Name <> ThisWorkbook.Name Then
            Dim Ms, Ss, Ts, Rs                              'définition
            Ms = "Voulez_vous enregistrer " & w.Name & " ?" 'définit le message.
            Ss = vbYesNo + vbExclamation + vbDefaultButton1 'définit les boutons.
            Ts = "Enegistrer avant de quitter"              'définit le titre.
            Rs = MsgBox(Ms, Ss, Ts)                         'demande une réponse
            If Rs = vbYes Then w.Close savechanges:=True    'Réponse OUI... Enregistre et ferme
            If Rs = vbNo Then w.Close savechanges:=False    'Réponse NON... Ferme sans enregistrer
            End If
            DoEvents
    Next w
    
    Workbooks("Prog.xls").Save         'Sauvegarde seulement le fichier
    Application.EnableEvents = true    'il est toujours préférable de réactiver les évenements même si on ferme l'application
    Application.Quit                   'Ferme Excel
    DoEvents
End sub


A+

Merci bigfish_le vrai 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources a aidé 103 internautes ce mois-ci

Commenter la réponse de bigfish_le vrai
Messages postés
14010
Date d'inscription
samedi 29 décembre 2001
Dernière intervention
28 août 2015
0
Merci
Salut

Quand tu fais un .Close, l'évènement Workbook_BeforeClose doit se relancer, d'où, peut-être, ces soucis.
Je te propose de mémoriser que tu as déjà tenu compte du premier évènement pour encadrer le code.
Vois si cela change qqchose :
Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Static bIsClosing As Boolean
    If Not bIsClosing Then
        bIsClosing = True
        For Each w In Workbooks
            If w.Name <> ThisWorkbook.Name Then
                Dim Ms, Ss, Ts, Rs                              'définition
                Ms = "Voulez_vous enregistrer " & w.Name & " ?" 'définit le message.
                Ss = vbYesNo + vbExclamation + vbDefaultButton1 'définit les boutons.
                Ts = "Enegistrer avant de quitter"              'définit le titre.
                Rs = MsgBox(Ms, Ss, Ts)                         'demande une réponse
                If Rs = vbYes Then w.Close SaveChanges:=True    'Réponse OUI... Enregistre et ferme
                If Rs = vbNo Then w.Close SaveChanges:=False    'Réponse NON... Ferme sans enregistrer
            End If
            DoEvents
        Next w

        Workbooks("Prog.xls").Save                              'Sauvegarde seulement le fichier
        Application.Quit                                        'Ferme Excel
        DoEvents
        bIsClosing = False
    End If
End Sub

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
Commenter la réponse de cs_Jack
Messages postés
14010
Date d'inscription
samedi 29 décembre 2001
Dernière intervention
28 août 2015
0
Merci
Au fait, si Toto.xls est actif au moment où tu cliques sur la croix, ThisWorkbook.Name sera "Toto", donc problème.
Il vaudrait mieux tester le nom réel plutôt que ThisWorkbook.Name
            If w.Name <> "Prog.xls" Then
Commenter la réponse de cs_Jack
Messages postés
423
Date d'inscription
vendredi 17 novembre 2006
Dernière intervention
15 juillet 2014
0
Merci
Bonjour,

Essayez ceci :

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Dim w As Workbook
    
    For Each w In Workbooks
        If w.Name <> ThisWorkbook.Name Then
            Dim Ms, Ss, Ts, Rs                              'définition
            Ms = "Voulez_vous enregistrer " & w.Name & " ?" 'définit le message.
            Ss = vbYesNo + vbExclamation + vbDefaultButton1 'définit les boutons.
            Ts = "Enegistrer avant de quitter"              'définit le titre.
            Rs = MsgBox(Ms, Ss, Ts)                         'demande une réponse
            If Rs = vbYes Then w.Save  'Réponse OUI... Enregistre et ferme
            w.Saved = True
        End If
    Next w
    
    ThisWorkbook.Save
    ThisWorkbook.Saved = True

End Sub


Il ne faut pas appeler la fonction close des classeur car elle est appelée autmatiquement si vous cliquez sur la croix de l'application excel. De meme pour le application.quit. En réalité c'est même application.quit qui entraine l'exécution de votre Workbook_BeforeClose.

Donc il suffit tout simplement de sauvegarder ou non vos classeurs et le tour est joué.
Commenter la réponse de foliv57
Messages postés
423
Date d'inscription
vendredi 17 novembre 2006
Dernière intervention
15 juillet 2014
0
Merci
Par contre petite précision, si tous les classeurs doivents êtres fermés par le fermeture d'Excel (croix de l'application Excel) ET par la fermeture de prog.xls (croix du classeur), il faudra plutot faire comme ceci :

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Dim w As Workbook
    
    For Each w In Workbooks
        If w.Name <> ThisWorkbook.Name Then
            Dim Ms, Ss, Ts, Rs                              'définition
            Ms = "Voulez_vous enregistrer " & w.Name & " ?" 'définit le message.
            Ss = vbYesNo + vbExclamation + vbDefaultButton1 'définit les boutons.
            Ts = "Enegistrer avant de quitter"              'définit le titre.
            Rs = MsgBox(Ms, Ss, Ts)                         'demande une réponse
            If Rs = vbYes Then w.Save   'Réponse OUI... Enregistre et ferme
            w.Saved = True
        End If
    Next w
    
    ThisWorkbook.Save
    ThisWorkbook.Saved = True
    
    Application.Quit

End Sub


Dans tous les cas c'est toujours application.quit qui ferme tous les classeurs.

Voila, avec tous ces exemples vous devriez trouver votre bonheur.

@Jack > Il me semble que ThisWorkbook.Name revoie bien le nom du classeur qui exécute la macro et que c'est ActiveWorkbook.Name qui renvoie le nom du classeur actif.
Commenter la réponse de foliv57
Messages postés
377
Date d'inscription
lundi 3 avril 2006
Dernière intervention
22 août 2018
0
Merci
Bonjour,

D'abord, merci à tous pour vos réponses.

Ensuite, avant de vous répondre, j'ai testé vos propsitions, mais je n'ai pas encore pu finaliser un code qui convienne pleinement.

Il faut que je précise que j'ai volontairement pris un exemple simplifié ; en effet mon code complet (lourd) fait appel a un grand nombre de macros qui, selon des résultats de boucles IF ou FOR doivent pouvoir fermer le classeur (et s'il est seul ouvert, l'application), en le sauvegardant ou non, via 2 Sub : FermeSave et FermeNoSave.

Le soucis, c'est qu'un utilisateur peut à tout moment cliquer sur la croix de fermeture de l'application... surtout s'il a un autre classeur ouvert actif , donc j'ai besoin d'un Workbook_BeforeClose pour la gestion de cette fermeture "sauvage", mais UNIQUEMENT dans ce cas.

Dans une telle éventualité, je veux que mon classeur se ferme, directement s'il n'a pas été modifié, ou sinon après sauvegarde au préalable, puis passer les messages "Sauvegarder OUI/NON ?" pour les autres.

La solution de Bigfish est donc extrêmement intéressante (je ne connaissais pas Application.EnableEvents appliqué à Close).

C'est la bonne piste, mais après diverses tentatives, il y a un problème :

Application.EnableEvents<gras>True est placé AVANT Application.Quit, donc Workbook_Before Close est rappelé... (c'est d'ailleurs pareil en le plaçant après): J'ai donc dû supprimer Application.EnableEvents</gras>True ...

Mais après avoir fermé mon fichier, quelles seront les conséquences à l'ouverture d'autres classeurs qui comportent des macros ?

Cordialement
Rataxes64
Commenter la réponse de CerberusPau
Messages postés
1839
Date d'inscription
vendredi 13 mai 2005
Dernière intervention
20 novembre 2013
0
Merci
Salut,

aucune conséquence ! car à la prochaine ouverture tout sera rentré dans l'ordre.

le seul truc est de vérifier que l'utilisateur n'a pas moyen, volontairement ou involontairement, de stopper la macro entre le moment de la désactivation des événements et la fermeture d'excel. Si il le peut tes macros ne fonctionnerons plus correctement.

Mais pourquoi la macro "Workbook_Before Close" est t'elle rappelée ? est-ce du au fichier qui contient les macros lui même ?

A+
Commenter la réponse de bigfish_le vrai
Messages postés
423
Date d'inscription
vendredi 17 novembre 2006
Dernière intervention
15 juillet 2014
0
Merci
Workbook_BeforeClose est un evenement de fermeture de classeur et qui sera déclenché à chaque fermeture de classeur.
Ta boucle "For Each w In Workbooks" va donc declencher cet evenement pour chaque fichier ouvert et que tu fermes avec les lignes


Si "Workbook_BeforeClose" est placé uniquement dans "ThisWorkbook" de Prog.xls, il n'est appelé qu'à la fermeture de Prog.xls et pas des autres classeurs.
Commenter la réponse de foliv57
Messages postés
377
Date d'inscription
lundi 3 avril 2006
Dernière intervention
22 août 2018
0
Merci
Bonsoir,

Bigfish, ta réponse a attiré mon attention... sur mon fichier d'appel du programme.

J'explique :

Chaque utilisateur autorisé dispose dans son PC d'un Classeur Start.xls pour appeler Prog.xls sur le réseau.

Start.xls renvoie l'information que Prog.xls est déjà ouvert par quelqu'un (nom et contact); et l'ouvre s'il est libre d'accès (Le mode partagé sous Excel étant une catastrophe, on ne partage pas! Alors, chacun son tour...).

La mise à jour nécessaire de Start.xls est assurée par Prog.xls

Si Prog.xls reste ouvert et inutilisé, il est automatiquement fermé (et sauvegardé) après une alarme sonore sur le PC de l'utilisateur "distrait".

... ça fait pas mal de "bouclages" à gérer en réseau (recours à des "pauses" via Application.wait...).

Le redéclenchement venait d'un rappel inopiné de la fermeture de Start.xls à la fermeture de Prog.xls.

On ne se méfie jamais assez des On error Resume Next (que je n'utilse pourtant que TRES rarement sur les Application.Wait)

Une fois ce point corrigé, tout est rentré dans l'ordre :

Le code de Bigfish tourne parfaitement(seul le dernier DoEvents est finalement utile).

1000 Merci à tous

Rataxes64
Commenter la réponse de CerberusPau

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.