Creazione automatica del backup di un modello
Mi pervengono le richieste più strane e inattese. L’ultima, espressa nel titolo e esternata da un tal Nonricordo Chisia , è la possibilità di effettuare tramite macro VBA un archivio Excel che sia la copia precedente di quello che di volta in volta viene aperto e, il più delle volte, aggiornato. Si tratta d’una pignoleria? Giudichi ognuno, di fatto l’esigenza nasce laddove è prevista una notevole attività di data entry ad esempio nelle righe di una tabella. La responsabilità dell’utente resta sempre malgrado opportune tecniche di convalida e persino con il rimedio che vado subito a suggerire.
Sia come sia ecco la ricetta, che comunque ritengo curiosa e interessante.
Nota. In quel che segue, per fissare le idee, si supporrà che il file da curare e la sua versione... postuma siano ModelloBase.xlsm e, rispettivamente, ModelloBaseBackup.xlsm. I perfezionisti se hanno voglia e tempo potranno sostituirli con generici parametri.
Primi tentativi, uno problematico l’altro... illusorio
Come sarà subito venuto in mente a molti, incluso il succitato Nonricordo Chisia (ignobile nomignolo che verrà perdonato, spero), si potrebbe ricorrere all’evento Open del modulo ThisWorkbook del nostro ModelloBase. Ne descrivo a parole le operazioni manuali:
- Salvare (subito) ModelloBase in ModelloBaseBackup;
- Chiudere ModelloBase! (infatti dopo il passo 1 è aperto solo ModelloBaseBackup);
- Aprire nuovamente ModelloBase.
Così facendo però se affidiamo tali operazioni all’evento di apertura di ModelloBase, perché il passo 3 implica la ripresa del passo 1, creando un loop infinito (o no?). Chi ne ha voglia può studiare una qualche variabile booleana del tipo switch di primo giro, ma il tutto appare macchinoso, poco chiaro e fonte di rischi più o meno (in)attesi.
Un uccellino (di quelli che frullano nella testa nottetempo o in tram) mi ha allora detto: perché non ricorrere all’istruzione FileCopy? Detto fatto:
Nota. L’ipotesi, direi scontata, è che ModelloBase e ModelloBaseBackup risiedano nella stessa cartella di file.
Private Sub Workbook_Open() ' Evento del file ModelloBase
ChDir Me.Path ' Fissa la directory di ModelloBase
FileCopy "ModelloBase.xlsm", "ModelloBaseBackup
End Sub
Giusto? Ahimè no, perché Excel rigetta l’istruzione FileCopy applicata a un ModelloBase.xlsm attualmente aperto. L’illusione nacque dall’idea che i file Excel risiedono su RAM. Vero, ma l’applicativo mantiene un contatto con l’archivio su disco (tra l’altro vitale e non virtuale nel caso di swapping con modelli enormi e/o con sovraccarico di RAM per altri motivi).
La ricetta, un ripiego comunque interessante
Prima di cedere le armi, ho infine escogitato il ricorso a un archivio ausiliario, diciamo Menu.xlsm, il cui scopo primario (o addirittura unico) sia quello di lanciare a sua volta ModelloBase.Xlsm. Si può pensare a qualcosa del genere, che suggerisce un Menu relativo a più modelli che a volte fanno parte di un’applicazione:
|
|
A |
B |
C |
D |
|
1 |
ModelloBase.xlsm |
<= legame ipertestuale |
|
|
|
2 |
QuestAltroModello |
" |
|
|
|
3 |
QuellAltroModello |
" |
|
|
|
4 |
ecc. |
" |
|
|
Nota. I legami ipertestuali costituiscono una variante rispetto a dei pulsanti di comando di cui non tutti si ricordano.
Insomma Menu.xlsm conterrà nel modulo ThisWorkbook la macro d’apertura seguente:
Private Sub Workbook_Open()
ChDir Me.Path
FileCopy "ModelloBase.xlsm", "ModelloBaseBackup.xlsm"
End Sub
L’utente dovrà poi cliccare sul link predetto. Stavolta Excel non protesta, ovviamente a patto che l’utente non abbia già aperto il fatidico ModelloBase (v. più avanti il rimedio a questo caso estremo).
Infine ho supposto che Menu.xlsm sia semplicemente un archivio “di lancio” relativo al ModelloBase, nel qual caso sarà meglio chiamarlo, piuttosto, ModelloBaseLancio.xlsm. esso potrebbe non contenere nulla, tranne il seguente codice nel solito ThisWorkbook:
Function ModelloAperto(NomeWrk As String) As Boolean
Dim Wrk As Workbook
ModelloAperto = False
For Each Wrk In Workbooks
If Wrk.Name = NomeWrk Then
ModelloAperto = True
Exit For
End If
Next
End Function
Private Sub Workbook_Open()
Dim ModBase As String, ModBackup As String
ChDir Me.Path
ModBase = "ModelloBase.xlsm"
ModBackup = "ModelloBaseBackup.xlsm"
Dim Msg As String, Titolo As String
If Not ModelloAperto("ModelloBase.xlsm") Then
FileCopy ModBase, ModBackup
Workbooks.Open ModBase
Else
Msg = "Non ho creato il backup " & ModBackup & _
vbLf & "perché " & ModBase & " era già aperto..."
Titolo = ModBase & " non va aperto prima di " & Me.Name
MsgBox Msg, vbCritical, Titolo
End If
Application.DisplayAlerts = False
If MsgBox("Chiudo il Menu?", vbYesNo, "") = vbYes Then Me.Close
End Sub
Commenti? Nisba, li affido all’esegesi fai-da-te del visitatore, cui dico solo che la funzione ModelloAperto esplora tutti gli oggetti dell’insieme Workbooks (cartelle di lavoro aperte) restituendo True se e solo se della combriccola fa parte la cartella di lavoro chiamata “NomeWrk” – che poi sarà la nostra ModelloBase.xlsm come passatale dalla macro Workbook_Open. E spero sia chiaro al proverbiale duo Chicche & Sia (*) il messaggio che uscirebbe se l’incauto utilizzatore aprisse per primo ModelloBase.xlsm.
(*) Di decurtisiana memoria, se ben ricordo.