Visual Basic Simple
Utilizzare il registro di Windows
(quinta 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 4

Concludiamo questo lungo articolo con le ultime due funzioni della classe: SeparaValore e Importa: la prima servirà per estrarre da un file di testo il corretto nome e contenuto di un valore; la seconda si occuperà di leggere i dati da un file di testo compatibile con Regedit ed inserirli nel registro nella corretta posizione.

  1. Private Function SeparaValore(ByVal Dati As String, ByRef NomeValore As String) As String
  2.   Dim Conta As Integer
  3.   Conta = InStr(2, Dati, """")
  4.   Do While Conta > 0
  5.     If Mid$(Dati, Conta - 1, 2) <> "\""" Then Exit Do
  6.     Conta = InStr(Conta + 1, Dati, """")
  7.   Loop
  8.   If Left$(Dati, 1) = "@" Then Conta = 1
  9.   NomeValore = Left$(Dati, Conta)
  10.   NomeValore = Replace(NomeValore, "\\", "\")
  11.   NomeValore = Replace(NomeValore, "\r", vbCr)
  12.   NomeValore = Replace(NomeValore, "\n", vbLf)
  13.   NomeValore = Replace(NomeValore, "\""", """")
  14.   SeparaValore = Mid$(Dati, Conta + 2)
  15.   SeparaValore = Replace(SeparaValore, "\\", "\")
  16.   SeparaValore = Replace(SeparaValore, "\r", vbCr)
  17.   SeparaValore = Replace(SeparaValore, "\n", vbLf)
  18.   SeparaValore = Replace(SeparaValore, "\""", """")
  19. End Function

Semplice quanto banale, la funzione SeparaValore ricostruisce il corretto nome e contenuto di un valore dal formato proveniente da file (ovvero alterato dalla procedura di esportazione o dal programma Regedit). La ricostruzione terrà conto che all'interno del nome di un valore possono esserci anche quei simboli particolari quali le virgolette o il segno di uguaglianza e pertanto la separazione tra nome e contenuto del valore deve tenerne conto prima (righe 446-450), ed eliminare quelle alterazioni (righe 451-461).

  1. Public Function Importa(ByVal NomeFile As String) As Boolean
  2.   Dim FileNR As Integer
  3.   Dim LineBuffer As String
  4.   Dim Buffer As Variant
  5.   Dim oldKey As Long
  6.   Dim newKey As Long
  7.   Dim Conta As Integer
  8.   Dim Buffer2() As Byte
  9.   Dim TipoDati As TipoValoriRegistro
  10.   FileNR = FreeFile
  11.   On Error Resume Next
  12.   Open NomeFile For Input As FileNR
  13.   If Err.Number <> 0 Then
  14.     MsgBox "Errore durante la preparazione all'importazione!", vbCritical + vbOKOnly, "FBIRegistry"
  15.     Importa = False
  16.     Close FileNR
  17.     Exit Function
  18.   End If
  19.   Line Input #FileNR, LineBuffer
  20.   If UCase$(LineBuffer) <> "REGEDIT4" Then
  21.     MsgBox "Il formato del file da importare non è corretto!", vbCritical + vbOKOnly, "FBIRegistry"
  22.     Importa = False
  23.     Exit Function
  24.   End If

Prima di iniziare l'elaborazione vera e propria saranno effettuati quei controlli d'obbligo quale l'accessibilità al file ed il controllo della sua intestazione (REGEDIT4). Nella mancanza di uno di questi due requisiti l'elaborazione verrà interrotta con un messaggio di errore (righe 476-487).

  1.   oldKey = lngKeyValue
  2.   lngKeyValue = 0
  3.   Do While Not EOF(FileNR)
  4.     Line Input #FileNR, LineBuffer
  5.     LineBuffer = Trim$(LineBuffer)
  6.     Buffer = ""
  7.     Do While Right$(LineBuffer, 1) = "\"
  8.       Buffer = Buffer & Left$(LineBuffer, Len(LineBuffer) - 1)
  9.       Line Input #FileNR, LineBuffer
  10.       LineBuffer = Trim$(LineBuffer)
  11.     Loop

Verrà quindi letto il contenuto del file linea per linea (riga 491). Se i dati letti dal file termineranno sulla destra con un "\" sarà segno di un dato binario spezzato su più righe e pertanto sarà necessario ricostruire l'intero valore (righe 494-498) leggendo una per una le righe successive.

  1.     If LineBuffer <> "" Then
  2.       Buffer = Buffer & LineBuffer
  3.       If Left$(Buffer, 1) = "[" Then
  4.         Buffer = Mid$(Buffer, 2, Len(Buffer) - 2)
  5.         Conta = InStr(1, Buffer, "\")
  6.         LineBuffer = Buffer
  7.         If Conta > 0 Then LineBuffer = UCase$(Left$(Buffer, Conta - 1))
  8.         Select Case LineBuffer
  9.           Case "HKEY_CLASSES_ROOT": newKey = HKEY_CLASSES_ROOT
  10.           Case "HKEY_CURRENT_CONFIG": newKey = HKEY_CURRENT_CONFIG
  11.           Case "HKEY_CURRENT_USER": newKey = HKEY_CURRENT_USER
  12.           Case "HKEY_DYN_DATA": newKey = HKEY_DYN_DATA
  13.           Case "HKEY_LOCAL_MACHINE": newKey = HKEY_LOCAL_MACHINE
  14.           Case "HKEY_PERF_ROOT": newKey = HKEY_PERF_ROOT
  15.           Case "HKEY_PERFORMANCE_DATA": newKey = HKEY_PERFORMANCE_DATA
  16.           Case "HKEY_USERS": newKey = HKEY_USERS
  17.           Case Else
  18.             MsgBox "La chiave principale non è una chiave di sistema.", vbCritical + vbOKOnly, "FBIRegistry"
  19.             Importa = False
  20.             Close FileNR
  21.             Exit Function
  22.         End Select

Ottenuta quindi una riga completa di dati dal file sarà necessario innanzitutto verificare se si tratti di una chiave oppure di un valore. Le chiavi sono identificate da una coppia di parentesi quadre agli estremi nella forma "[chiave]". Pertanto i dati che iniziano per "[" identificano una chiave e come tale deve essere trattata.

Verranno quindi estratte la chiave di sistema e la sottochiave rispetto a questa e salvata nella variabile newKey (righe 502-520).

  1.         Call RegCloseKey(lngKeyValue)
  2.         lngKeyValue = 0
  3.         Call RegCreateKeyEx(newKey, Mid$(Buffer, Len(LineBuffer) + 2), ByVal 0&, vbNullChar, REG_OPTION_NON_VOLATILE, lngKeySecurity, ByVal 0&, lngKeyValue, ByVal 0&)

Sarà adesso necessario aprire o creare la nuova chiave ottenuta. La funzione RegCreateKeyEx crea la chiave se non esiste ma provvede anche la sua apertura nel caso essa esista. Prima di aprire la chiave però, verrà chiusa la chiave eventualmente aperta in precedenza tramite RegCloseKey.

  1.       Else
  2.         Conta = InStr(1, Buffer, "=")
  3.         If Conta > 0 Then
  4.           Buffer = SeparaValore(Buffer, LineBuffer)
  5.           If LineBuffer = "@" Then LineBuffer = ""
  6.           LineBuffer = DeQuote(LineBuffer)
  7.           If Left$(Buffer, 1) = """" Then
  8.             TipoDati = REG_SZ
  9.             Buffer = DeQuote(Buffer)
  10.             Buffer2 = StrConv(Buffer, vbFromUnicode) & vbNullChar

Se invece il dato estratto dal file non è una chiave, con grossissima probabilità si tratterà di un valore dell'ultima chiave aperta. Alla riga 527 vengono estratti nome (nella variabile LineBuffer) e contenuto (nella variabile di ritorno Buffer) del valore recuperato da file.
Saranno in seguito fatti quei minimi aggiustamenti (righe 528-529) per ricostruire il nome valore nella maniera corretta.

Soltanto adesso potrà essere fatta l'analisi dei dati recuperati per determinare il tipo di dati trattati. Se il contenuto di tale valore dovesse iniziare con le virgolette ci troveremmo in presenza di un valore di tipo REG_SZ la cui conversione in array di bytes risulta molto semplice (righe 531-533).

  1.           ElseIf UCase$(Left$(Buffer, 3)) = "HEX" Then
  2.             TipoDati = REG_BINARY
  3.             If UCase$(Left$(Buffer, 4)) = "HEX(" Then
  4.               TipoDati = CByte(Mid$(Buffer, 5, 1))
  5.             End If
  6.             Conta = InStr(1, Buffer, ":")
  7.             Buffer = Mid$(Buffer, Conta + 1)
  8.             ReDim Buffer2(Ceil(Len(Buffer) / 3)) As Byte
  9.             For Conta = 0 To UBound(Buffer2) - 1
  10.               Buffer2(Conta) = CByte("&H" & Mid$(Buffer, Conta * 3 + 1, 2))
  11.             Next Conta

Diversamente se il contenuto di tali dati inizia con la stringa "Hex" ci troveremmo in presenza di dati binari (righe 534-535). Un'eventuale parentesi successiva alla stringa "Hex" indicherà il tipo di dati binari (righe 536-538).

Sarà quindi allocato un buffer di bytes in base all'ampiezza dei dati binari recuperati. L'ampiezza è calcolata come arrotondamento per eccesso (Ceil) della lunghezza del buffer diviso per 3. Il numero tre sta ad indicare 2 bytes per ogni cifra binaria ed un byte per la virgola separatrice. Tali bytes saranno poi riconvertiti in numeri decimali ed inseriti nel buffer binario.

  1.           ElseIf UCase$(Left$(Buffer, 5)) = "DWORD" Then
  2.             TipoDati = REG_DWORD
  3.             Buffer = Mid$(Buffer, 7)
  4.             ReDim Buffer2(Ceil(Len(Buffer) / 2)) As Byte
  5.             For Conta = 1 To Len(Buffer) Step 2
  6.               Buffer2(Conta \ 2) = CByte("&H" & Mid$(Buffer, Len(Buffer) - Conta, 2))
  7.             Next Conta
  8.           Else
  9.             MsgBox "Errore nell'importazione del valore """ & LineBuffer & "=" & Buffer, vbCritical + vbOKOnly, "FBIRegistry"
  10.             Importa = False
  11.             Exit Function
  12.           End If

Se invece il tipo di dati estratto non è neanche quello binari si tratterà necessariamente del tipo di dati DWORD oppure di un caso di errore. Sarà quindi controllata la presenza della stringa "DWORD" e nel caso positivo verrà ricostruito il valore DWORD (righe 545-551).

Come ultimissima ipotesi, se non si tratta né di stringhe, né di dati binari e né tantomeno di valori DWORD abbiamo dinanzi un caso di errore che non può essere gestito. Sarà generato un avviso e la procedura di importazione verrà interrotta (righe 552-555).

  1.           Call RegSetValueEx(lngKeyValue, LineBuffer, ByVal 0&, TipoDati, Buffer2(0), UBound(Buffer2))
  2.         Else
  3.           MsgBox "Il valore presenta una forma anomala.", vbCritical + vbOKOnly, "FBIRegistry"
  4.           Importa = False
  5.           Exit Function
  6.         End If
  7.       End If
  8.     End If
  9.   Loop
  10.   Call RegCloseKey(lngKeyValue)
  11.   Close FileNR
  12.   lngKeyValue = oldKey
  13.   Importa = True
  14. End Function

Il raggiungimento della riga 557 dovrebbe indicare nessuna interruzione e quindi un buffer caricato con i dati corretti e nella forma desiderata. La variabile TipoDati dovrebbe invece contenere il tipo di dati desiderato. Saranno quindi salvati tali dati sul registro tramite RegSetValueEx.

Alla riga 526 abbiamo verificato la presenza di un simbolo "=" ad indicare la separazione tra nome del valore e suo contenuto. Se tale simbolo non dovesse essere affatto presente avremmo dinanzi un altro emblematico caso di errore; sarà generato un avviso e l'esecuzione verrà interrotta (righe 559-561).

Al termine dell'importazione di tutti i valori sarà chiusa la chiave aperta e si potrà quindi procedere all'importazione della chiave successiva, fino alla fine del file, segnata anche dalla sua chiusura.

Questo lunghissimo articolo si conclude qui. Ci sarebbe molto altro da dire ma risulterebbe troppo pesante. La classe sviluppata si presenta parecchio complessa e lunga ma altrettanto semplice e ben fatta.

Nel progetto da scaricare è presente anche un semplicissimo esempio a scopo dimostrativo delle principali funzioni della classe clsFBIRegistry, tutta da scoprire.
La classe è stata testata su Windows 98 e Windows 2000 utilizzando un file di registro fino a 18 MB e svolge egregiamente il suo compito, tanto da riprodurre gli stessi risultati del programma Regedit (esclusa la velocità, ovviamente, limite invalicabile di Visual Basic).

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