Visual Basic Simple
Utilizzare il registro di Windows
(quarta parte)
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à: 5 / 5

<< Continua dalla parte 3

Ci avviciniamo alla fine di questo lungo tutorial. Saranno trattate le ultime quattro funzioni della nostra classe FBIRegistry relative ai processi di esportazione ed importazione dei dati del registro in file.

  1. Public Function Esporta(ByVal ChiavePrincipale As ChiaviPrincipali, ByVal SottoChiave As String, ByVal NomeFile As String, ByVal SottoChiavi As Boolean, ByVal Aggiunge As Boolean) As Boolean
  2.   Dim FileNR As Integer
  3.   Dim oldKey As Long
  4.   Dim NomeChiave As String
  5.   If ChiavePrincipale = CHIAVE_APERTA Then ChiavePrincipale = lngKeyValue
  6.   Select Case ChiavePrincipale
  7.     Case HKEY_CLASSES_ROOT: NomeChiave = "HKEY_CLASSES_ROOT"
  8.     Case HKEY_CURRENT_CONFIG: NomeChiave = "HKEY_CURRENT_CONFIG"
  9.     Case HKEY_CURRENT_USER: NomeChiave = "HKEY_CURRENT_USER"
  10.     Case HKEY_DYN_DATA: NomeChiave = "HKEY_DYN_DATA"
  11.     Case HKEY_LOCAL_MACHINE: NomeChiave = "HKEY_LOCAL_MACHINE"
  12.     Case HKEY_PERF_ROOT: NomeChiave = "HKEY_PERF_ROOT"
  13.     Case HKEY_PERFORMANCE_DATA: NomeChiave = "HKEY_PERFORMANCE_DATA"
  14.     Case HKEY_USERS: NomeChiave = "HKEY_USERS"
  15.     Case Else
  16.       MsgBox "Per salvare una chiave è necessario che la chiave principale sia una chiave di sistema.", vbCritical + vbOKOnly, "FBIRegistry"
  17.       Esporta = False
  18.       Exit Function
  19.   End Select

La funzione Esporta consente il salvataggio di una chiave, delle sue sottochiavi e dei loro valori in un file di testo compatibile con Regedit. La funzione richiede tre argomenti fondamentali: la chiave di sistema in cui si trova la sottochiave, il percorso logico della sottochiave rispetto alla chiave di sistema ed il nome del file in cui salvare tali dati.

Gli altri due argomenti consentono di salvare soltanto la chiave specificata o anche tutte le sue sottochiavi. L'ultimo argomento specifica se creare un nuovo file di testo oppure aggiungere i dati a quelli già esistenti nel file.

Il controllo alle righe 329-342 assicura che la chiave specificata sia una chiave di sistema nell'enumerazione ChiavePrincipali ed in tal caso ne registra il nome nella variabile NomeChiave. Se la chiave specificata non è una chiave di sistema verrà generato un avviso e l'esportazione verrà interrotta.

  1.   FileNR = FreeFile
  2.   If Aggiunge Then
  3.     Open NomeFile For Append As FileNR
  4.   Else
  5.     Open NomeFile For Output As FileNR
  6.   End If
  7.   If LOF(FileNR) = 0 Then Print #FileNR, "REGEDIT4" & vbNewLine
  8.   oldKey = lngKeyValue
  9.   lngKeyValue = 0
  10.   Call RegOpenKeyEx(ChiavePrincipale, SottoChiave, ByVal 0&, lngKeySecurity, lngKeyValue)
  11.   If Left$(SottoChiave, 1) <> "\" Then SottoChiave = "\" & SottoChiave
  12.   If SottoChiave = "\" Then SottoChiave = ""
  13.   SalvaRamo CHIAVE_APERTA, NomeChiave & SottoChiave, FileNR, SottoChiavi
  14.   Print #FileNR, vbNullString
  15.   Close FileNR
  16.   FileNR = 0
  17.   Call RegCloseKey(lngKeyValue)
  18.   lngKeyValue = oldKey
  19.   Esporta = True
  20. End Function

In funzione dell'argomento Aggiungi verrà creato un nuovo file di testo sovrascrivendo i dati precedenti oppure il file sarà aperto in modalità di Append per inserire nuovi dati (righe 344-348). Inoltre se la dimensione del file aperto è di zero bytes (ovvero il file è nuovo oppure vengono aggiunti dati su un file vuoto) verrà inserita una breve intestazione per rendere il file riconoscibile da Regedit (riga 349).

Solo in seguito a questi necessari controlli verrà aperta la chiave richiesta per l'esportazione e passata con altri dati alla funzione SalvaRamo che vedremo tra poco. In sostanza la funzione SalvaRamo effettua l'operazione di esportazione dei dati vera e propria utilizzando l'handle di file passatole come argomento della funzione.

La nostra funzione Esporta infatti si occuperà soltanto dei controlli iniziali, dell'apertura del file, del richiamo della funzione SalvaRamo e della chiusura di file e chiave. Questo per dare completa flessibilità alla funzione SalvaRamo che non dovrà occuparsi di tutti questi noiosi compiti.

  1. Private Sub SalvaRamo(ByVal Chiave As ChiaviPrincipali, ByVal Percorso As String, ByVal FileNR As Integer, ByVal SottoChiavi As Boolean)
  2.   Dim Conta As Integer
  3.   Dim Conta2 As Long
  4.   Dim Elementi As Variant
  5.   Dim ValoreElemento As Variant
  6.   Dim TipoDati As TipoValoriRegistro
  7.   Dim Buffer As String
  8.   Dim Buffer2 As String
  9.   If Chiave = CHIAVE_APERTA Then Chiave = lngKeyValue
  10.   Print #FileNR, "[" & Percorso & "]"
  11.   Elementi = Me.ElencaValori(CHIAVE_APERTA)
  12.   If Not IsNull(Elementi) Then
  13.     For Conta = LBound(Elementi) To UBound(Elementi)
  14.       ValoreElemento = Me.Valore(Elementi(Conta), TipoDati)
  15.       Buffer2 = ""
  16.       Elementi(Conta) = Replace(Elementi(Conta), "\", "\\")
  17.       Elementi(Conta) = Replace(Elementi(Conta), vbCr, "\r")
  18.       Elementi(Conta) = Replace(Elementi(Conta), vbLf, "\n")
  19.       Elementi(Conta) = Replace(Elementi(Conta), """", "\""")
  20.       Buffer = """" & Elementi(Conta) & """"
  21.       If Elementi(Conta) = "" Then Buffer = "@"

La funzione SalvaRamo, la più complessa dell'intero progetto, effettua il salvataggio del contenuto di una chiave su un file già aperto, mantenendo naturalmente il formato dei dati originali. La funzione richiede quattro parametri: Chiave è la chiave che si intende salvare, Percorso è il percorso logico della chiave nella struttura ad albero, FileNR è l'handle del file già aperto in cui scrivere i dati ed infine Sottochiavi determina se effettuare il salvataggio anche delle sottochiavi e dei valori in esse contenuti.

La funzione si apre con il salvataggio su file del percoso (riga 373) ed il recupero di tutti i valori presenti nella chiave specificata (riga 374). Per ogni valore recuperato sarà ottenuto anche il suo contenuto (riga 377) ed effettuate alcune semplici conversioni per rendere l'esportazione coerente con il formato REGEDIT4 (righe 379-384). Il valore predefinito della chiave deve essere salvato come "@".

  1.       Select Case TipoDati
  2.         Case REG_SZ
  3.           ValoreElemento = Replace(ValoreElemento, "\", "\\")
  4.           ValoreElemento = Replace(ValoreElemento, vbCr, "\r")
  5.           ValoreElemento = Replace(ValoreElemento, vbLf, "\n")
  6.           ValoreElemento = Replace(ValoreElemento, """", "\""")
  7.           Buffer2 = Buffer & "=""" & ValoreElemento & """"

Per fortuna o purtroppo il registro contiene una varietà di tipologie di dati presenti e soprattutto non tutti questi dati sono scritti nella maniera corretta. Per ogni tipo di dato trattato sarà necessario effettuare alcuni aggiustamenti in esportazione.

L'esempio più semplice è il formato stringa REG_SZ che richiede soltanto la sostituzione di alcuni caratteri speciali ("\", Enter, a capo, virgolette) nelle corrispondenti sequenze escape e ciò viene effettuato utilizzando la funzione Replace.

Purtroppo il caso degli altri tipi di dati non è altrettanto semplice. Esistono infatti alcuni dati che, pur essendo ad esempio valori REG_DWORD non contengono un valore corretto ma soltanto una matrice di bytes, quasi che si trattasse di dati REG_BINARY.

  1.         Case REG_BINARY, REG_NONE, REG_EXPAND_SZ, _
  2.              REG_DWORD_LITTLE_ENDIAN, REG_DWORD, _
  3.              REG_MULTI_SZ
  4.           If IsArray(ValoreElemento) Then
  5.             Buffer = Buffer & "=hex"
  6.             If TipoDati = REG_NONE Then Buffer = Buffer & "(0)"
  7.             If TipoDati = REG_EXPAND_SZ Then Buffer = Buffer & "(2)"
  8.             If TipoDati = REG_DWORD Then Buffer = Buffer & "(4)"
  9.             If TipoDati = REG_MULTI_SZ Then Buffer = Buffer & "(7)"
  10.             Buffer = Buffer & ":"
  11.             If Not IsNull(ValoreElemento) Then
  12.               For Conta2 = LBound(ValoreElemento) To UBound(ValoreElemento)
  13.                 Buffer = Buffer & Right$("00" & LCase$(Hex$(ValoreElemento(Conta2))), 2)
  14.                 If Conta2 < UBound(ValoreElemento) Then Buffer = Buffer & ","
  15.                 If (Len(Buffer) > 76) And (Conta2 < UBound(ValoreElemento)) Then
  16.                   Buffer2 = Buffer2 & Buffer & "\" & vbNewLine
  17.                   Buffer = " "
  18.                 End If
  19.               Next Conta2
  20.             End If
  21.             Buffer2 = Buffer2 & Buffer

Nel caso del tipo di dati binario o DWORD dovrà quindi esser fatta un'investigazione più profonda. Il primo di questi controlli consiste nel verificare se i dati sono in forma di array ed in tal caso dovranno essere trattati come dati binari, pur manentendo il formato di dati originale. Tutti i dati binari devono essere salvati nel formato "hex(x): XX, YY". dove x indica il tipo di dati e XX, YY sono i dati in forma binaria esadecimale. L'unica eccezione sta nel caso dei dati REG_BINARY, che non richiedono le parentesi che racchiudono il tipo di dati. Tale formattazione di dati è fatta alle righe 396-401.

Soltanto adesso sarà possibile convertire i singoli bytes della matrice in stringhe esadecimali utilizzando l'istruzione Hex$. Ma, ahinoi, non ancora finito qui: ogni riga da salvare che superi la lunghezza di 76 caratteri dovrà essere spezzata in altre righe (righe 406-409).

  1.           ElseIf TipoDati = REG_DWORD Then
  2.             Buffer = Buffer & "=dword:"
  3.             Buffer2 = Buffer & LCase$(HexDouble(ValoreElemento, 8))
  4.           Else
  5.             Buffer = Buffer & "=hex"
  6.             If TipoDati <> REG_BINARY Then Buffer = Buffer & "(" & CStr(TipoDati) & ")"
  7.             Buffer = Buffer & ":"
  8.             If Not IsNull(ValoreElemento) Then Buffer = Buffer & CStr(ValoreElemento)
  9.             Buffer2 = Buffer
  10.           End If
  11.         Case REG_DWORD_BIG_ENDIAN, REG_LINK, _
  12.              REG_RESOURCE_LIST
  13.           MsgBox "Tipo di dati non implementato!", vbCritical + vbOKOnly, "FBIRegistry"
  14.       End Select
  15.       Print #FileNR, Buffer2
  16.     Next Conta
  17.   End If

Se invece i dati recuperati non sono in forma di matrice, sarà verificato che il tipo di dati sia DWORD perché anche questo tipo richiede una sua particolare formattazione come "dword: XX" dove XX è il valore DWORD convertito in stringa esadecimale (righe 413-415).

Se i dati non sono né una matrice di bytes né un valore DWORD allora saranno semplicemente scritti come numero decimale (se i dati esistono) oppure non verranno scritti affatto. Sarà cioè scritto soltanto il tipo di dati trattato come "hex(x):" ma non il loro contenuto. Non si tratta infatti di una possibilità remota ma di una consuetudine nell'universo del registro di Windows.

I tipi di dati REG_DWORD_BIG_ENDIAN, REG_LINK e REG_RESOURCE_LIST non saranno affatto trattati e quindi esclusi dal processo di esportazione.

Alla riga 427 verrà infine scritto il buffer di dati preparato mediante i controlli e le conversioni appena fatti.

  1.   If (SottoChiavi = True) And (Me.NumeroSottoChiavi > 0) Then
  2.     Elementi = ElencaChiavi(CHIAVE_APERTA)
  3.     If IsNull(Elementi) Then Exit Sub
  4.     For Conta = LBound(Elementi) To UBound(Elementi)
  5.       Print #FileNR, vbNullString
  6.       Conta2 = lngKeyValue
  7.       Call RegOpenKeyEx(Chiave, Elementi(Conta), ByVal 0&, lngKeySecurity, lngKeyValue)
  8.       SalvaRamo CHIAVE_APERTA, Percorso & "\" & Elementi(Conta), FileNR, SottoChiavi
  9.       Call RegCloseKey(lngKeyValue)
  10.       lngKeyValue = Conta2
  11.     Next Conta
  12.   End If
  13. End Sub

Un'intera chiave è stata salvata su file. Resta pertanto l'ultima possibilità ovvero quella di dover salvare ogni singola sottochiave della nostra chiave e così le sottochiavi delle sottochiavi, etc... Quest'operazione è svolta nel ciclo descritto alle righe 433-440.

Sarà quindi aperta una sottochiave per volta, ricreato il percorso e richiamata ricorsivamente la funzione SalvaRamo con i nuovi dati. La ricorsività assicurerà il salvataggio di tutti i valori presenti in ogni sottochiave di ogni sottochiave della prima chiave.

Questa è la ragione principale per cui abbiamo preferito separare la routine Esporta da quella SalvaRamo.

Segue parte 5 >>

Fibia FBI
1 Aprile 2002
Corretto il 20 Settembre 2002
Rivisitato il 24 Maggio 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