Visual Basic Simple
Eseguire operazioni di Shell sui files
Sincronizza Indice
Sincronizza Indice
Scarica il progetto
Scarica il progetto
Scarica il testo dell'articolo
Testo dell'articolo
Stampa l'articolo
Stampa l'articolo
Ricerca personalizzata

Difficoltà: 2 / 5

Quasi tutti i moderni programmi affidano alle funzioni di Shell il compito delle operazioni di copia, spostamento ed eliminazione dei files. In tal modo infatti il programmatore si scarica di alcuni compiti di analisi, in particolare la reiterazione per le sottocartelle. L'utente invece si trova a contatto con un'interfaccia grafica conosciuta ed apprezzata. Vedremo in questo progetto come richiamare le funzioni della shell per queste operazioni.

La classe clsFBIShellFileOperation sviluppata in questo progetto consentirà di eseguire le operazioni più comuni con estrema semplicità:

  1. Option Explicit
  2. Option Base 0
  3. Public Enum SHOperations
  4.     FO_MOVE = &H1
  5.     FO_COPY = &H2
  6.     FO_DELETE = &H3
  7.     FO_RENAME = &H4
  8. End Enum

L'enumerazione SHOperations si compone di 4 costanti definite dall'API che specificano il tipo di operazione da svolgere tra spostamento, copia, cancellazione e rinominazione. Sarà utilizzata più avanti dalla struttura SHFILEOPSTRUCT.

  1. Public Enum SHOperationFlags
  2.     FOF_MULTIDESTFILES = &H1
  3.     FOF_CONFIRMMOUSE = &H2
  4.     FOF_SILENT = &H4
  5.     FOF_RENAMEONCOLLISION = &H8
  6.     FOF_NOCONFIRMATION = &H10
  7.     FOF_WANTMAPPINGHANDLE = &H20
  8.     FOF_ALLOWUNDO = &H40
  9.     FOF_FILESONLY = &H80
  10.     FOF_SIMPLEPROGRESS = &H100
  11.     FOF_NOCONFIRMMKDIR = &H200
  12.     FOF_NOERRORUI = &H400
  13.     FOF_NOCOPYSECURITYATTRIBS = &H800
  14.     FOF_NORECURSION = &H1000
  15.     FOF_NO_CONNECTED_ELEMENTS = &H2000
  16.     FOF_WANTNUKEWARNING = &H4000
  17. End Enum

L'enumerazione SHOperationFlags consente di specificare uno o più comportamenti aggiuntivi durante l'operazione di Shell. I loro nomi dovrebbero da soli essere chiari ma merita una piccola citazione il flag FOF_ALLOWUNDO (riga 18) che consente di annullare l'ultima operazione eseguita, mediante la voce Annulla del menu popup in una qualunque cartella. Funziona regolarmente per le operazioni di copia e spostamento, ma nel caso dell'operazione di cancellazione, differenzia lo spostamento nel cestino dall'eliminazione vera e propria; la specifica del flag FOF_ALLOWUNDO nell'operazione di cancellazione comporta quindi lo spostamento nel cestino dei files.

  1. Private Type SHFILEOPSTRUCT
  2.     hwnd As Long
  3.     wFunc As Long
  4.     pFrom As String
  5.     pTo As String
  6.     fFlags As Long
  7.     fAnyOperationsAborted As Long
  8.     hNameMappings As Long
  9.     lpszProgressTitle As String
  10. End Type

La struttura SHFILEOPSTRUCT, riportata in maniera errata dalla maggior parte delle documentazioni, è stata trattata in un articolo della sezione Weird Things, è stata corretta per consentire un corretto funzionamento della funzione in tutte le situazioni. Il campo wFunc della struttura specifica il tipo di operazione da eseguire e determina l'uso degli altri campi; ad esempio durante la copia di files il campo pFrom indicherà l'origine dei files da copiare, mentre pTo conterrà la destinazione per i files; nel caso invece della cancellazione, il campo pTo non dovrà essere specificato. I valori ammessi per il campo wFunc sono quelli contenuti nell'enumerazione SHOperations, mentre per il campo fFlags sarà necessario specificare uno o più valori dell'enumerazione SHOperationFlags.

  1. Private Declare Function SHFileOperation Lib "SHELL32.DLL" Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
  2. Private udtOperation As SHFILEOPSTRUCT

L'intero codice è basato sull'uso della funzione SHFileOperation che richiede la specifica di una variabile di tipo SHFILEOPSTRUCT, definito in precedenza; tale valore è dichiarato alla riga 42, col nome udtOperation.

  1. Private Sub Class_Initialize()
  2.     udtOperation.fFlags = FOF_NOERRORUI
  3. End Sub

Il valore predefinito per il campo fFlags sarà FOF_NOERRORUI, che specifica di non mostrare le videate di errore della Shell, ma lasciare il compito al programma.

  1. Public Property Get AllowUndo() As Boolean
  2.     AllowUndo = CBool(udtOperation.fFlags And FOF_ALLOWUNDO)
  3. End Property
  4. Public Property Let AllowUndo(ByVal newValue As Boolean)
  5.     With udtOperation
  6.         .fFlags = IIf(newValue, .fFlags Or FOF_ALLOWUNDO, .fFlags And Not FOF_ALLOWUNDO)
  7.     End With
  8. End Property

La proprietà AllowUndo è utilizzata per recuperare ed assegnare con semplicità il flag FOF_ALLOWUNDO accennato in precedenza e consentire l'annullamento dell'ultima operazione eseguita.

  1. Public Property Get Confirm() As Boolean
  2.     Confirm = Not CBool(udtOperation.fFlags And FOF_NOCONFIRMATION)
  3. End Property
  4. Public Property Let Confirm(ByVal newValue As Boolean)
  5.     With udtOperation
  6.         .fFlags = IIf(newValue, .fFlags And Not FOF_NOCONFIRMATION, .fFlags Or FOF_NOCONFIRMATION)
  7.     End With
  8. End Property

La proprietà Confirm consente di richiedere conferma all'utente prima di eseguire certe operazioni di sovrascrittura o cancellazione. Si tratta in sostanza di recuperare o assegnare il valore del flag FOF_NOCONFIRMATION.

  1. Public Property Get Destination() As String
  2.     Destination = udtOperation.pTo
  3. End Property
  4. Public Property Let Destination(ByVal newValue As String)
  5.     udtOperation.pTo = newValue
  6. End Property
  7. Public Property Get Flags() As SHOperationFlags
  8.     Flags = udtOperation.fFlags
  9. End Property
  10. Public Property Let Flags(ByVal newValue As SHOperationFlags)
  11.     udtOperation.fFlags = newValue
  12. End Property
  13. Public Property Get Source() As String
  14.     Source = udtOperation.pFrom
  15. End Property
  16. Public Property Let Source(ByVal newValue As String)
  17.     udtOperation.pFrom = newValue
  18. End Property

Le tre proprietà Destination, Flags e Source consentono di recuperare o assegnare rispettivamente la destinazione (pTo), i flags (fFlags) e l'origine (pFrom) della variabile udtOperation che verrà utilizzata per eseguire l'operazione di Shell.

  1. Public Function Esegui(ByVal Operation As SHOperations) As Long
  2.     udtOperation.wFunc = Operation
  3.     Esegui = SHFileOperation(udtOperation)
  4. End Function

L'unico metodo della classe clsFBIShellFileOperation è Esegui e richiede la specifica del tipo di operazione da eseguire, corrispondente ad un valore dell'enumerazione SHOperations. Il valore sarà assegnato al membro wFunc della struttura udtOperation e quindi sarà richiamata la funzione SHFileOperation con la stessa struttura.


Figura 1Svilupperemo una semplice interfaccia per il nostro progetto, formata ad un controllo DirListBox di nome dirOrigine ed un controllo FileListBoxcollegato di nome filOrigine. In fondo a queste avremo tre pulsanti di nome cmdCopia, cmdSelezionaTutto e cmdDeselezionaTutto. Sul lato destro avremo invece un altro controllo FileListBox di nome filTemp che punterà sempre alla stessa cartella del programma; anche in fondo a questo esistono tre pulsanti di comando, di nome cmdAggiorna, cmdCestina e cmdElimina. Il controllo filOrigine avrà inoltre la proprietà MultiSelect impostata su 1 - Simple.

Come già detto, i due controlli dirOrigine e filOrigine saranno collegati, per cui al cambio della cartella sul controllo superiore corrisponderà il cambio della cartella nel secondo. Vediamo il semplice codice che gestisce tutti gli eventi del form:

  1. Option Explicit
  2. Private fbiShellOperation As clsFBIShellFileOperation

Alla riga 3 è dichiarata un'istanza della classe clsFBIShellFileOperation, che verrà dichiarata in occasione del caricamento del form.

  1. Private Function LastBSlash(ByVal Path As String) As String
  2.     If Right$(Path, 1) <> "\" Then Path = Path & "\"
  3.     LastBSlash = Path
  4. End Function
  5. Private Sub Form_Load()
  6.     Set fbiShellOperation = New clsFBIShellFileOperation
  7.     filTemp.Path = LastBSlash(App.Path) & "TEMP"
  8. End Sub
  9. Private Sub Form_Unload(Cancel As Integer)
  10.     Set fbiShellOperation = Nothing
  11. End Sub

La funzione LastBSlash, trattata anche in altri articoli del sito, è utilizzata per assicurare che il percorso fornito termini con una barra rovesciata ( \ ) e poterlo quindi concatenare ad un nome di file ed avere quindi la sicurezza che il percorso fornito sia valido. Prendiamo ad esempio il percorso C:\ da concatenare ad un nome di file quale "file1.txt"; nel caso del percorso "C:\" non sarà necessario aggiungere la barra rovesciata ("C:\" & "file1.txt"), ma nel caso di un altro percorso quale "C:\Cartella", la stessa sarà mancante e dovrà essere specificata prima del nome del file. La funzione LastBSlash restituisce sempre e comunque un percorso che termini con la barra rovesciata, da concatenare quindi al nome di un file.

La funzione sarà utilizzata alla riga 12, al caricamento del form, per inizializzare il controllo filTemp e farlo puntare alla cartella TEMP contenuta nella cartella del nostro programma; in occasione dell'operazione, sarà anche istanziata la variabile fbiShellOperation, che verrà quindi deallocata alla chiusura del form.

  1. Private Sub dirOrigine_Change()
  2.     filOrigine.Path = dirOrigine.Path
  3. End Sub
  4. Private Sub cmdAggiorna_Click()
  5.     filTemp.Refresh
  6. End Sub

Come già detto, al cambio della cartella nel controllo dirOrigine corrisponderà il cambio della cartella del controllo filOrigine e ciò è gestito alle righe 19-21.
La pressione del pulsante cmdAggiorna invece causerà l'aggiornamento dell'altro elenco di files, di nome filTemp.

  1. Private Sub cmdSelezionaTutto_Click()
  2.     Dim intLoop As Integer
  3.     For intLoop = 0 To filOrigine.ListCount - 1
  4.         filOrigine.Selected(intLoop) = True
  5.     Next intLoop
  6. End Sub
  7. Private Sub cmdDeselezionaTutto_Click()
  8.     Dim intLoop As Integer
  9.     For intLoop = 0 To filOrigine.ListCount - 1
  10.         filOrigine.Selected(intLoop) = False
  11.     Next intLoop
  12. End Sub

Le due routine legate al click dei pulsanti cmdSelezionaTutto e cmdDeselezionaTutto sono molto simili e comprendono un semplice ciclo per ogni elemento dell'elenco filOrigine. La prima routine assegnerà lo stato di selezionato ad ogni elemento, mentre la seconda deselezionerà tale stato.

  1. Private Sub cmdCopia_Click()
  2.     Dim intLoop As Integer
  3.     Dim strFiles As String
  4.     With filOrigine
  5.         For intLoop = 0 To .ListCount - 1
  6.             If .Selected(intLoop) Then strFiles = strFiles & LastBSlash(filOrigine.Path) & .List(intLoop) & vbNullChar
  7.         Next intLoop
  8.         If Len(strFiles) > 0 Then
  9.             strFiles = strFiles & vbNullChar
  10.             With fbiShellOperation
  11.                 .Confirm = True
  12.                 .AllowUndo = False
  13.                 .Source = strFiles
  14.                 .Destination = filTemp.Path
  15.                 Call .Esegui(FO_COPY)
  16.             End With
  17.             cmdAggiorna_Click
  18.         End If
  19.     End With
  20. End Sub

La prima routine che utilizza l'istanza fbiShellOperation è quella legata all'operazione di copia selezionati nell'elenco filOrigine. Sarà pertanto lanciato un ciclo per tutti gli elementi dell'elenco (riga 46) ed il nome (completo di percorso) di ciascun file selezionato sarà concatenato alla variabile strFiles. I nomi saranno tra loro separati da un carattere NULL.

Se almeno un file sarà stato accodato alla variabile strFiles, sarà quindi aggiunto un ulteriore carattere terminatore (riga 49) e quindi invocata la procedura di copia dei files selezionati. Saranno impostate le proprietà Confirm su True, AllowUndo su False, Source sull'elenco di files da copiare e Destination sul percorso della cartella temporanea (indicato dalla proprietà Path del controllo filTemp, inizializzato all'avvio del programma). Sarà quindi lanciata la procedura di copia mediante metodo Esegui.

Al termine dell'operazione sarà forzato l'aggiornamento dell'elenco filTemp, richiamando la routine cmdAggiorna_Click.

  1. Private Sub cmdCestina_Click()
  2.     fbiShellOperation.AllowUndo = True
  3.     EliminaFiles
  4. End Sub
  5. Private Sub cmdElimina_Click()
  6.     fbiShellOperation.AllowUndo = False
  7.     EliminaFiles
  8. End Sub

Le due routine di eliminazione definitiva o provvisoria, si differenziano soltanto per l'assegnazione della proprietà AllowUndo dell'istanza fbiShellOperation. Entrambe affidano l'operazione alla routine EliminaFiles che vediamo qui di seguito:

  1. Private Sub EliminaFiles()
  2.     With fbiShellOperation
  3.         .Source = LastBSlash(filTemp.Path) & "*.*"
  4.         .Destination = ""
  5.         .Confirm = True
  6.         .Esegui FO_DELETE
  7.     End With
  8.     cmdAggiorna_Click
  9. End Sub

La routine assegna come origine dei files da eliminare il percorso della cartella TEMP, concatenato con i caratteri jolly *.*; la destinazione dovrà essere nulla, sarà attivata la conferma (riga 76) e lanciata quindi l'operazione alla riga successiva. Al termine dell'operazione sarà richiesto l'aggiornamento dell'elenco filTemp mediante richiamo della routine cmdAggiorna_Click.


Figura 2
Figura 2
Figura 3
Figura 3
Figura 4
Figura 4

Durante le operazioni di copia, spostamento nel cestino ed eliminazione dei files saranno mostrate le finestre di dialogo standard in ambiente Windows, analoghe a quelle mostrate a fianco.

Resta tuttavia impossibile modificare il titolo mostrato sulla barra delle suddette finestre di dialogo ed il testo in esso contenuto.

Ad esempio durante l'operazione di spostamento nel cestino di uno o più files sarà mostrato il testo "Spostare i file selezionati elementi nel Cestino?", mentre nel caso di eliminazione diretta apparirà il testo "Eliminare tutti gli elementi presenti nel Cestino?", entrambi per nulla chiari, anzi fuorvianti con le azioni da svolgere.

 

La classe clsFBIShellFileOperation consente una minima gestione delle operazioni sui files con estrema semplicità e dovrebbe essere preferita alla copia manuale di uno o più files, in modo da rendere l'ambiente in cui si opera quanto più familiare possibile con il look dei vari Windows in cui il programma viene eseguito.

Fibia FBI
3 Giugno 2003

Scarica il progetto
Scarica il progetto
Scarica il testo dell'articolo
Scarica il testo dell'articolo
Stampa l'articolo
Stampa l'articolo
Torna all'indice degli HowTo