XL 2021 VBA - Comment transformer un classeur enregistré en classeur non enregistré

  • Initiateur de la discussion Initiateur de la discussion Dudu2
  • Date de début Date de début

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

Dudu2

XLDnaute Barbatruc
Bonjour,
J'aurais besoin de votre avis pour un code consistant à transformer un classeur enregistré (ayant pignon sur répertoire) en classeur non enregistré de même contenu.

Le contexte est le suivant:
Dans le cadre de la fusion des instances Excel, un classeur non encore enregistré et contenant des modifs appartient à une instance qui devra être fermée.
Il faut donc l'enregistrer en répertoire temporaire pour pouvoir le ré-ouvrir dans l'instance qui va survivre comme instance unique de fusion.
Lors de sa ré-ouverture à partir du répertoire temporaire, il faut lui restituer son statut initial de classeur non encore enregistré qu'il avait dans l'instance qui a été fermée.

Donc:
- création d'un nouveau classeur + copie du classeur temporaire + fermeture du classeur temporaire ?
- Autre solution ?
- Code ?

Merci par avance.
 
Solution
Bon, j'ai réglé le cas du code du ThisWorkbook en faisant un copier des lignes de code.
J'avais pas encore vu ton code là-dessus à cause des problèmes de TS à régler.

Cette fois c'est bon ? Finalement, c'est pas du gâteau que de dupliquer un classeur !
Les objets ne viennent hélas pas avec les feuilles.
Le code des feuilles oui.
Le code du Workbook non -> à modifier pour qu'il soit inclus (Thisworkbook.cls)
Les Shapes non -> j'ai ajouté la séquence de copie
Les Charts non -> Est-ce qu'un Chart est une Shape (?) auquel cas il vient dans la séquence Shape, sinon il faut le faire séparément.
 
re
le chart sur feuille tu le prends comme une shapes
les feuille graphique ce n'est pas pareille qu'une feulle (To work)
VB:
Option Explicit

'======================================================================================
'Requires the Reference "Microsoft for Visual Basic for Applications Exetnsibility 5.3"
'======================================================================================

Sub Test()
    Call CopyWorkbookToNewWorkbook(ThisWorkbook, IncludeVBAProject:=True)
End Sub

'------------------------------------
'Copy as Workbook into a new Workbook
'------------------------------------
Sub CopyWorkbookToNewWorkbook(SourceWorkbook As Workbook, Optional IncludeVBAProject As Boolean = False)
    Dim TargetWorkbook As Workbook
    Dim TabArray() As Variant
    Dim VBComponents As VBComponents
    Dim VBComponent As VBComponent
    Dim VBComponentExtension As String
    Dim VBComponentFileName As String
    Dim VBComponentsCollection As New Collection
    Dim ErrNumber As Long
    Dim S As String
    Dim i As Integer
    Dim k As Integer
    Dim p As Integer
    Dim Rep As VbMsgBoxResult
    Dim Rep2 As VbMsgBoxResult
    
    Application.ScreenUpdating = False
    
    On Error Resume Next
    If IncludeVBAProject Then
        Set VBComponents = SourceWorkbook.VBProject.VBComponents
        If Err Then
            Rep = MsgBox("En l'etat le niveau de sécurité dans les options d'Excel" & vbCrLf & _
                          "Ne permet pas la copie des modules" & vbCrLf & vbCrLf & _
                          "Vous devez cochez l'accès aprouvé à l'objet du modèle de projet vba" & vbCrLf & vbCrLf & _
                          "Voulez vous aller activer  cet accès approuvé " & vbCrLf & _
                          "Vous pourez réessayer apres l'export", vbYesNo + vbInformation)
            
            If Rep = vbYes Then
                Application.CommandBars.ExecuteMso "MacroSecurity"
                Exit Sub
            Else
                Rep2 = MsgBox("Très bien pas de modules exportés" & vbCrLf & _
                               "Voulez vous continuer la creation" & vbCrLf & "du clone de ce classeur Sans ces Macros !!!", vbYesNo, vbInformation)
                If Rep2 = vbNo Then Exit Sub
            End If
        End If
    End If
    
    '----------------------------------------------------------------------------------
    'Copy the source Workbook & Worksheets with their VBA code to a new target Workbook
    '----------------------------------------------------------------------------------
    With SourceWorkbook
        ReDim TabArray(1 To .Worksheets.Count)
        ReDim chartarray(1)
        For i = 1 To .Worksheets.Count
            TabArray(i) = i
        Next i
        
        'Creates a new target Workbook with the selected source Workbook Worksheets
        .Worksheets(TabArray).Select
        Worksheets.Copy
        Set TargetWorkbook = ActiveWorkbook
        '-------------------------------------
        'Ajout de la copie des feuilles graphiques(thisworkbook.charts)
        'exemple
        'un graphique dans une feuille  =        Worksheets("Feuil1").ChartObjects ("mongraphique")
        'une feuille graphique          =        ThisWorkbook.Charts("mongraphique")
        '-------------------------------------
        Dim C
        For Each C In ThisWorkbook.Charts
            C.Copy After:=ActiveWorkbook.Sheets(ActiveWorkbook.Sheets.Count)
        Next
        '--------------------------------------
        'Needed to "unlock" the all Worksheets Selection
        With SourceWorkbook
            .Activate
            .Worksheets(1).Select
        End With
        
        TargetWorkbook.Activate
        
        '---------------
        'Copy the Shapes
        '---------------
        For i = 1 To .Worksheets.Count
            For k = 1 To .Worksheets(i).Shapes.Count
                'Copy the Shape and its position
                .Worksheets(i).Shapes(k).Copy
                TargetWorkbook.Worksheets(i).Paste
                TargetWorkbook.Worksheets(i).Shapes(k).Left = .Worksheets(i).Shapes(k).Left
                TargetWorkbook.Worksheets(i).Shapes(k).Top = .Worksheets(i).Shapes(k).Top
                
                'Adapt the OnAction string
                S = .Worksheets(i).Shapes(k).OnAction
                If Not Len(S) = 0 Then
                    p = InStr(S, "!")
                    If p > 0 Then
                        If Replace(Left(S, p - 1), "'", "") = SourceWorkbook.Name Then
                            TargetWorkbook.Worksheets(i).Shapes(k).OnAction = "'" & TargetWorkbook.Name & "'!" & Mid(S, p + 1)
                        End If
                    End If
                End If
            Next k
            
            'Release the last Shape selected
            ActiveCell.Select
        Next i
    End With
    
    '------------------------------------------------------------
    'Include the VBA Project Modules, Class Modules and UserForms
    '------------------------------------------------------------
    If IncludeVBAProject Then
        If VBEOK Then
            Set VBComponents = SourceWorkbook.VBProject.VBComponents
            
            If Not VBComponents Is Nothing Then
                'Export VBComponents of the source Workbook
                For Each VBComponent In VBComponents
                    Select Case VBComponent.Type
                        Case vbext_ct_StdModule
                            VBComponentExtension = ".bas"
                        
                        Case vbext_ct_ClassModule
                            VBComponentExtension = ".cls"
                            
                        Case vbext_ct_MSForm
                            VBComponentExtension = ".frm"
                            
                        Case Else
                            VBComponentExtension = ""
                    End Select
                    
                    If Not Len(VBComponentExtension) = 0 Then
                        VBComponentFileName = Environ("TMP") & "\" & VBComponent.Name & VBComponentExtension
                        
                        If Not Len(Dir(VBComponentFileName)) = 0 Then
                            Kill VBComponentFileName
                        End If
                        
                        VBComponent.Export VBComponentFileName
                        VBComponentsCollection.Add VBComponentFileName
                    End If
                Next VBComponent
                
                'Import VBComponents to the new target Workbook
                Do While VBComponentsCollection.Count > 0
                    TargetWorkbook.VBProject.VBComponents.Import VBComponentsCollection(1)
                    Kill VBComponentsCollection(1)
                    VBComponentsCollection.Remove 1
                Loop
                
                'Copy the Reference list of the source Workbook into the target new Workbook
                With SourceWorkbook
                    On Error Resume Next
                    For i = 1 To .VBProject.References.Count
                        TargetWorkbook.VBProject.References.AddFromFile .VBProject.References.Item(i).FullPath
                    Next i
                    On Error GoTo 0
                End With
            End If
        End If
    End If
    
    Application.ScreenUpdating = True
    
    'Close the source Workbook
    SourceWorkbook.Close SaveChanges:=False
End Sub

'-------------------------------------------------------------------------------------
'Return True if the "Trust Access to the VBA Project Object Model" checkbox is checked
'-------------------------------------------------------------------------------------
Function VBEOK() As Boolean
    Dim Version As String
    Dim ErrNumber As Long
    
    On Error Resume Next
    Version = ThisWorkbook.VBProject.VBE.Version
    ErrNumber = Err.Number
    On Error GoTo 0
    
    If ErrNumber = 0 Then
        'Return value
        VBEOK = True
    End If
End Function
 
et oui tu peux pas le thisworkbook
1par ce c'est le centre du fichier
2 par ce que c'est une classe et malheureusement c'est .cls donc exporté comme un module classe


donc pour le thisworkbook
VB:
Option Explicit

'======================================================================================
'Requires the Reference "Microsoft for Visual Basic for Applications Exetnsibility 5.3"
'======================================================================================

Sub Test()
    Call CopyWorkbookToNewWorkbook(ThisWorkbook, IncludeVBAProject:=True)
End Sub

'------------------------------------
'Copy as Workbook into a new Workbook
'------------------------------------
Sub CopyWorkbookToNewWorkbook(SourceWorkbook As Workbook, Optional IncludeVBAProject As Boolean = False)
    Dim TargetWorkbook As Workbook
    Dim TabArray() As Variant
    Dim VBComponents As VBComponents
    Dim VBComponent As VBComponent
    Dim VBComponentExtension As String
    Dim VBComponentFileName As String
    Dim VBComponentsCollection As New Collection
    Dim ErrNumber As Long
    Dim S As String
    Dim i As Integer
    Dim k As Integer
    Dim p As Integer
    Dim Rep As VbMsgBoxResult
    Dim Rep2 As VbMsgBoxResult
    
    Application.ScreenUpdating = False
    
    On Error Resume Next
    If IncludeVBAProject Then
        Set VBComponents = SourceWorkbook.VBProject.VBComponents
        If Err Then
            Rep = MsgBox("En l'etat le niveau de sécurité dans les options d'Excel" & vbCrLf & _
                          "Ne permet pas la copie des modules" & vbCrLf & vbCrLf & _
                          "Vous devez cochez l'accès aprouvé à l'objet du modèle de projet vba" & vbCrLf & vbCrLf & _
                          "Voulez vous aller activer  cet accès approuvé " & vbCrLf & _
                          "Vous pourez réessayer apres l'export", vbYesNo + vbInformation)
            
            If Rep = vbYes Then
                Application.CommandBars.ExecuteMso "MacroSecurity"
                Exit Sub
            Else
                Rep2 = MsgBox("Très bien pas de modules exportés" & vbCrLf & _
                               "Voulez vous continuer la creation" & vbCrLf & "du clone de ce classeur Sans ces Macros !!!", vbYesNo, vbInformation)
                If Rep2 = vbNo Then Exit Sub
            End If
        End If
    End If
    
    '----------------------------------------------------------------------------------
    'Copy the source Workbook & Worksheets with their VBA code to a new target Workbook
    '----------------------------------------------------------------------------------
    With SourceWorkbook
        ReDim TabArray(1 To .Worksheets.Count)
        ReDim chartarray(1)
        For i = 1 To .Worksheets.Count
            TabArray(i) = i
        Next i
        
        'Creates a new target Workbook with the selected source Workbook Worksheets
        .Worksheets(TabArray).Select
        Worksheets.Copy
        Set TargetWorkbook = ActiveWorkbook
        '-------------------------------------
        'Added by patricktoulon
        'Ajout de la copie des feuilles graphiques(thisworkbook.charts)
        'exemple
        'un graphique dans une feuille  =        Worksheets("Feuil1").ChartObjects ("mongraphique")
        'une feuille graphique          =        ThisWorkbook.Charts("mongraphique")
        '-------------------------------------
        Dim C
        For Each C In ThisWorkbook.Charts
            C.Copy After:=ActiveWorkbook.Sheets(ActiveWorkbook.Sheets.Count)
        Next
        '--------------------------------------
        'Added by patricktoulon
        'copie du code dans Thisworkbook
        Dim code$
        With ThisWorkbook.VBProject.VBComponents("Thisworkbook")
            code = .CodeModule.Lines(1, .CodeModule.CountOfLines)
        End With
        If Trim(code) <> "" Then
            With ActiveWorkbook.VBProject.VBComponents("Thisworkbook")
                .CodeModule.InsertLines 1, code
            End With
         End If
        
        
        'Needed to "unlock" the all Worksheets Selection
        With SourceWorkbook
            .Activate
            .Worksheets(1).Select
        End With
        
        TargetWorkbook.Activate
        
        '---------------
        'Copy the Shapes
        '---------------
        For i = 1 To .Worksheets.Count
            For k = 1 To .Worksheets(i).Shapes.Count
                'Copy the Shape and its position
                .Worksheets(i).Shapes(k).Copy
                TargetWorkbook.Worksheets(i).Paste
                TargetWorkbook.Worksheets(i).Shapes(k).Left = .Worksheets(i).Shapes(k).Left
                TargetWorkbook.Worksheets(i).Shapes(k).Top = .Worksheets(i).Shapes(k).Top
                
                'Adapt the OnAction string
                S = .Worksheets(i).Shapes(k).OnAction
                If Not Len(S) = 0 Then
                    p = InStr(S, "!")
                    If p > 0 Then
                        If Replace(Left(S, p - 1), "'", "") = SourceWorkbook.Name Then
                            TargetWorkbook.Worksheets(i).Shapes(k).OnAction = "'" & TargetWorkbook.Name & "'!" & Mid(S, p + 1)
                        End If
                    End If
                End If
            Next k
            
            'Release the last Shape selected
            ActiveCell.Select
        Next i
    End With
    
    '------------------------------------------------------------
    'Include the VBA Project Modules, Class Modules and UserForms
    '------------------------------------------------------------
    If IncludeVBAProject Then
        If VBEOK Then
            Set VBComponents = SourceWorkbook.VBProject.VBComponents
            
            If Not VBComponents Is Nothing Then
                'Export VBComponents of the source Workbook
                For Each VBComponent In VBComponents
                    Select Case VBComponent.Type
                        Case vbext_ct_StdModule
                            VBComponentExtension = ".bas"
                            
                        Case vbext_ct_ClassModule
                            VBComponentExtension = ".cls"
                            
                        Case vbext_ct_MSForm
                            VBComponentExtension = ".frm"
                            
                        Case Else
                            VBComponentExtension = ""
                    End Select
                    
                    If Not Len(VBComponentExtension) = 0 Then
                        VBComponentFileName = Environ("TMP") & "\" & VBComponent.Name & VBComponentExtension
                        
                        If Not Len(Dir(VBComponentFileName)) = 0 Then
                            Kill VBComponentFileName
                        End If
                        
                        VBComponent.Export VBComponentFileName
                        VBComponentsCollection.Add VBComponentFileName
                    End If
                Next VBComponent
                
                'Import VBComponents to the new target Workbook
                Do While VBComponentsCollection.Count > 0
                    TargetWorkbook.VBProject.VBComponents.Import VBComponentsCollection(1)
                    Kill VBComponentsCollection(1)
                    VBComponentsCollection.Remove 1
                Loop
                
                'Copy the Reference list of the source Workbook into the target new Workbook
                With SourceWorkbook
                    On Error Resume Next
                    For i = 1 To .VBProject.References.Count
                        TargetWorkbook.VBProject.References.AddFromFile .VBProject.References.Item(i).FullPath
                    Next i
                    On Error GoTo 0
                End With
            End If
        End If
    End If
    
    Application.ScreenUpdating = True
    
    'Close the source Workbook
    SourceWorkbook.Close SaveChanges:=False
End Sub

'-------------------------------------------------------------------------------------
'Return True if the "Trust Access to the VBA Project Object Model" checkbox is checked
'-------------------------------------------------------------------------------------
Function VBEOK() As Boolean
    Dim Version As String
    Dim ErrNumber As Long
    
    On Error Resume Next
    Version = ThisWorkbook.VBProject.VBE.Version
    ErrNumber = Err.Number
    On Error GoTo 0
    
    If ErrNumber = 0 Then
        'Return value
        VBEOK = True
    End If
End Function
Terminé tu a tout 😉
 
J'ai intégré ton code du Prompt de la sécurité des macros dans la fonction VBEOK (sur option).

J'ai aussi adapté la formule des Charts copiés pour faire référence à leur source de données locale au nouveau classeur après copie.
Je ne connais pas bien les Charts et ne sais pas s'il faut aussi adapter d'autres propriétés pour les rendre locales au nouveau classeur.

2 points encore à résoudre:
  1. Copie du code du Workbook (voir le code):
    L'export fonctionne mais l'Import ne fonctionne pas (le Remove de l'existant avant Import non plus)
    La classe ThisWorkbook.cls vient s'insérer dans les Classes en ThisWorkbook1.cls.

  2. Les feuilles graphiques je ne connaissais pas leur existence !
    Es-tu sûr qu'elles ne sont pas copiées / collées dans la sélection de toutes les feuilles ?
    Faudrait que tu me rajoutes une feuille graphique dans le classeur ci-joint qui contient le dernier code pour valider.
 
Dernière édition:
Plus grave (Excel fait suer !)
Si j'ajoute un tableau structuré dans une feuille voila le résultat !

1748807271470.png


Si on ne peut plus utiliser la technique de sélection de toutes les feuilles, ça fiche par terre la réplication exacte avec code des feuilles.
Et on ne peut pas dé-structurer et re-structurer les tableaux car les formules y faisant référence vont partir en live.
 
Dernière édition:
Concernant le problème du tableau structuré, en fait il n'est pas nécessaire de sélectionner les feuilles pour les copier / coller dans un nouveau classeur.
VB:
ActiveWorkbook.Worksheets.Copy
Ça suffit, et les TS passent. Ouf !
 
Dernière édition:
Bon, j'ai réglé le cas du code du ThisWorkbook en faisant un copier des lignes de code.
J'avais pas encore vu ton code là-dessus à cause des problèmes de TS à régler.

Cette fois c'est bon ? Finalement, c'est pas du gâteau que de dupliquer un classeur !
 

Pièces jointes

Dernière édition:
re
il faudra m'expliquer comment un classeur qui vient d’être créé par un copy des sheets peut avoir du code dans le thisworkbook
LOL

VB:
 Set CodePaste = TargetWorkbook.VBProject.VBComponents(ThisWorkbook.CodeName).CodeModule
            If CodePaste.CountOfLines > 0 Then CodePaste.DeleteLines 1, CodePaste.CountOfLines
            If CodeCopy.CountOfLines > 0 Then CodePaste.AddFromString CodeCopy.Lines(1, CodeCopy.CountOfLines)
je dis ca moi je dis rien 🤣 🤣 🙃
 
Bonjour @patricktoulon,
il faudra m'expliquer comment un classeur qui vient d’être créé par un copy des sheets peut avoir du code dans le thisworkbook
Tu devrais te coucher plus tôt.
1748835108527.gif

Ici le but est de créer un nouveau classeur identique (non enregistré) à un classeur source existant (supposé enregistré).
Ceci dans le cadre de la fusion des instances mais peut être généralisé.

Et c'est le classeur source existant qui a:
1 - des feuilles et leur code potentiel qui viennent par copy des sheets
2 - un ThisWorkbook avec son code potentiel
3 - des Shapes dont des Charts et des OnAction
4 - des References spécifiques potentielles
qu'il faut reproduire dans le nouveau classeur. Et je pense qu'on n'a pas tout mais c'est déjà pas mal.

Sinon un classeur qui vient d'être créé par un copy des sheets (Workbook.Worksheets.Copy) ne peut pas avoir les 2, 3 et 4 identiques au classeur source. C'est pour ça qu'on a fait mouliner les neurones.
1748835015624.gif
 
Je supprime le code dans le classeur nouvellement créé car il peut y avoir une ligne de type:
Option Explicit si l'option est cochée.
Et si je rajoute directement comme tu l'as fait dans ton code, le code du classeur source, on se retrouve avec 2 fois Option Explicit et ça s'appelle un bug.
Je me couche tard et me réveille tôt, et tu peux constater que j'ai toute ma tête !
1748841750273.gif


1748841906213.png


Edit: La preuve en image
1748842346640.png
 
Dernière édition:
La leçon du jour est un peu foireurse.
VB:
Option Explicit

Private Sub Workbook_Open()

End Sub
Option Explicit
allez va y teste tu va comprendre tout seul 😉

La VRAIE leçon du jour:
Tester avant d'affirmer péremptoirement !
 
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD
Retour