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

Quella che segue è la parte più complessa dell'intero articolo: saranno trattati i metodi pubblici e privati della nostra classe clsFBIRegistry.

  1. Public Function ApriChiave(ByVal ChiavePrincipale As ChiaviPrincipali, ByVal SottoChiave As String) As Long
  2.   Dim oldKey As Long
  3.   oldKey = lngKeyValue
  4.   If ChiavePrincipale = CHIAVE_APERTA Then ChiavePrincipale = lngKeyValue
  5.   lngKeyValue = 0
  6.   Call RegOpenKeyEx(ChiavePrincipale, SottoChiave, ByVal 0&, lngKeySecurity, lngKeyValue)
  7.   ApriChiave = lngKeyValue
  8.   Call RegCloseKey(oldKey)
  9. End Function
  10. Public Sub ChiudiChiave()
  11.   Call RegCloseKey(lngKeyValue)
  12.   lngKeyValue = 0
  13. End Sub

Le prime due funzioni sono le più scontate: ApriChiave effettua l'apertura di una chiave o di una sottochiave, mentre ChiudiChiave chiude la chiave aperta. Per la prima funzione potrà essere fornito l'handle ad una qualsiasi chiave aperta (da un'altra istanza o processo) oppure una chiave di sistema (come definito dall'enumerazione ChiaviPrincipali). Nel caso venisse utilizzato il valore CHIAVE_APERTA sarà utilizzato l'handle della chiave aperta dall'istanza della nostra classe. Il parametro sottochiave invece identicherà la sottochiave da apire rispetto alla chiave specificata.

La funzione ChiudiChiave invece effettua semplicemente la chiusura della chiave e l'azzeramento dell'handle lngKeyValue.

  1. Public Function CreaChiave(ByVal ChiavePrincipale As ChiaviPrincipali, ByVal SottoChiave As String, Optional ByVal NonCambiare As Boolean = False) As Long
  2.   Dim newKeyValue As Long
  3.   If ChiavePrincipale = CHIAVE_APERTA Then ChiavePrincipale = lngKeyValue
  4.   Call RegCreateKeyEx(ChiavePrincipale, SottoChiave, ByVal 0&, vbNullChar, REG_OPTION_NON_VOLATILE, lngKeySecurity, ByVal 0&, newKeyValue, ByVal 0&)
  5.   If NonCambiare = False Then
  6.     Call RegCloseKey(lngKeyValue)
  7.     lngKeyValue = newKeyValue
  8.   End If
  9.   CreaChiave = newKeyValue
  10. End Function

In maniera analoga alla funzione vista in precedenza, la funzione CreaChiave consente la creazione e l'apertura di una sottochiave. Se la sottochiave richiesta non esiste essa verrà creata ed aperta. Il funzionamento è analogo alla funzione ApriChiave ma il parametro aggiuntivo NonCambiare consente di effettuare le due succitate operazioni senza tuttavia chiudere e cambiare la chiave utilizzata dall'istanza, ed indicata dalla proprietà Chiave.

Questa possibilità si rivela utile quando si desidera creare una nuova sottochiave, ottenerne l'handle (come valore di ritorno della funzione) senza però chiudere la chiave sulla quale l'istanza sta lavorando.

  1. Public Function ElencaChiave(ByVal ChiavePrincipale As ChiaviPrincipali, ByVal Indice As Long) As String
  2.   Dim Buffer As String
  3.   Dim Lunghezza As Long
  4.   If ChiavePrincipale = CHIAVE_APERTA Then ChiavePrincipale = lngKeyValue
  5.   Buffer = String$(255, 0)
  6.   Lunghezza = 255
  7.   Call RegEnumKeyEx(ChiavePrincipale, Indice, Buffer, Lunghezza, ByVal 0&, vbNullString, ByVal 0&, ByVal 0&)
  8.   ElencaChiave = Left$(Buffer, Lunghezza)
  9. End Function

La funzione ElencaChiave consente di recuperare il nome di una sottochiave in base al suo ordine, ad esempio la prima, la seconda o la terza sottochiave della chiave aperta. Viene utilizzata a tale scopo la funzione API RegEnumKeyEx.

  1. Public Function ElencaChiavi(ByVal ChiavePrincipale As ChiaviPrincipali) As Variant
  2.   Dim Elenco() As String
  3.   Dim Conta As Long
  4.   Dim Buffer As String
  5.   If ChiavePrincipale = CHIAVE_APERTA Then ChiavePrincipale = lngKeyValue
  6.   Buffer = String$(1024, 0)
  7.   Call RegQueryInfoKey(ChiavePrincipale, Buffer, Len(Buffer), ByVal 0&, Conta, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&)
  8.   If Conta > 0 Then
  9.     ReDim Elenco(Conta - 1) As String
  10.     For Conta = 0 To Conta - 1
  11.       Buffer = String$(255, 0)
  12.       Call RegEnumKeyEx(ChiavePrincipale, Conta, Buffer, Len(Buffer), ByVal 0&, vbNullString, ByVal 0&, ByVal 0&)
  13.       Elenco(Conta) = Left$(Buffer, InStr(1, Buffer, Chr$(0), vbBinaryCompare) - 1)
  14.     Next Conta
  15.     ElencaChiavi = Elenco
  16.   Else
  17.     ElencaChiavi = Null
  18.   End If
  19. End Function

In maniera analoga alla funzione precedente, la funzione ElencaChiavi restituisce un array contenente i nomi di tutte le sottochiavi presenti all'interno della chiave specificata. Se nessuna sottochiave è presente, restituirà valore Null. Utilizza la funzione RegQueryInfoKey allo stesso modo della proprietà NumeroSottochiavi per recuperare il numero complessivo delle sottochiavi ed allocare così il buffer necessario e poi ne estrae uno per uno i nomi utilizzando la funzione RegEnumKeyEx nella stessa maniera della funzione ElencaChiave.

  1. Public Function ElencaValore(ByVal ChiavePrincipale As ChiaviPrincipali, ByVal Indice As Long) As String
  2.   Dim Buffer As String
  3.   Dim Lunghezza As Long
  4.   If ChiavePrincipale = CHIAVE_APERTA Then ChiavePrincipale = lngKeyValue
  5.   Buffer = String$(255, 0)
  6.   Lunghezza = 255
  7.   Call RegEnumValue(ChiavePrincipale, Indice, Buffer, Lunghezza, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&)
  8.   ElencaValore = Left$(Buffer, Lunghezza)
  9. End Function

La funzione ElencaValore consente di recuperare il nome di un valore specifico, di cui si possiede l'indice, all'interno della chiave indicata. Il funzionamento è molto simile a quello della funzione ElencaChiave con l'unica differenza che utilizza la funzione RegEnumValue per recuperare l'informazione dal registro.

  1. Public Function ElencaValori(ByVal ChiavePrincipale As ChiaviPrincipali) As Variant
  2.   Dim Elenco() As String
  3.   Dim Conta As Long
  4.   Dim Buffer As String
  5.   If ChiavePrincipale = CHIAVE_APERTA Then ChiavePrincipale = lngKeyValue
  6.   Buffer = String$(255, 0)
  7.   Call RegQueryInfoKey(lngKeyValue, Buffer, Len(Buffer), ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&, Conta, ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&)
  8.   If Conta > 0 Then
  9.     ReDim Elenco(Conta - 1)
  10.     Buffer = String$(255, 0)
  11.     Conta = 0
  12.     Do While RegEnumValue(ChiavePrincipale, Conta, Buffer, Len(Buffer), ByVal 0&, ByVal 0&, ByVal 0&, ByVal 0&) = 0
  13.       Elenco(Conta) = Left$(Buffer, InStr(1, Buffer, Chr$(0), vbBinaryCompare) - 1)
  14.       Conta = Conta + 1
  15.       Buffer = String$(255, 0)
  16.     Loop
  17.     ElencaValori = Elenco
  18.   Else
  19.     ElencaValori = Null
  20.   End If
  21. End Function

E come la sua parente, la funzione ElencaValori restituisce un array contenente i nomi di tutti i valori presenti all'interno della chiave specificata. Restituisce invece Null in assenza di valori all'interno della chiave.

  1. Public Function EliminaChiave(ByVal ChiavePrincipale As ChiaviPrincipali, Optional ByVal SottoChiave As String) As Boolean
  2.   If ChiavePrincipale = CHIAVE_APERTA Then ChiavePrincipale = lngKeyValue
  3.   EliminaChiave = (RegDeleteKey(ChiavePrincipale, SottoChiave) = 0)
  4. End Function
  5. Public Function EliminaValore(Optional ByVal NomeValore As String = "") As Boolean
  6.   EliminaValore = (RegDeleteValue(lngKeyValue, NomeValore) = 0)
  7. End Function

Le due funzioni di eliminazione: EliminaChiave ed EliminaValore consentono l'eliminazione rispettivamente di una chiave e di un valore.

Tralasciamo per il momento l'ordine alfabetico e, saltando la funzione Esporta, passiamo direttamente alla funzione ForzaAggiornamentoChiave. Vista la loro complessità, le due funzioni di esportazione ed importazione saranno trattate nella prossima parte.

  1. Public Sub ForzaAggiornamentoChiave()
  2.   Call RegFlushKey(lngKeyValue)
  3. End Sub

La sua utilità è dubbia e potrebbe generare sospetti sul corretto funzionamento della classe. Nel momento in cui viene richiesta la modifica di un valore nel registro i dati sono effettivamente alterati ma non immediatamente scritti su disco. Se ipoteticamente, un secondo dopo un'operazione di scrittura sul registro, andasse via la luce, al riavvio del computer il valore potrebbe non essere stato ancora scritto.

Questo perché Windows utilizza un sistema di cache e di scrittura ritardata (lazy write) che non impegna troppo il computer in lente operazioni di scrittura. Essa seguirà infatti nei momenti più liberi del computer.

La funzione ForzaAggiornamentoChiave e quindi RegFlushKey obbligano il sistema operativo a scrivere su disco tutte le modifiche relative alla chiave specificata, garantendo l'immediata scrittura su disco ma rallentando pericolosamente la velocità del sistema. In linea generale questa funzione non è necessaria ma in rarissimi casi può richiedersi utile. La funzione RegFlushKey viene chiamata dal sistema operativo sulle chiavi di sistema al momento dello spegnimento della macchina per assicurare la corretta scrittura dei dati su disco.


Prima di vedere le ultime due funzioni pubbliche relative all'esportazione ed all'importazione dei dati, diamo un rapido sguardo ad alcune funzioni private utilizzate in altre parti del codice.

  1. Private Function DeQuote(ByVal Stringa As String) As String
  2.   If Left$(Stringa, 1) = """" Then Stringa = Mid$(Stringa, 2)
  3.   If Right$(Stringa, 1) = """" Then Stringa = Left$(Stringa, Len(Stringa) - 1)
  4.   DeQuote = Stringa
  5. End Function
  6. Private Function Ceil(ByVal Numero As Double) As Double
  7. Ceil = Fix(Numero)
  8. If Numero > Fix(Numero) Then Ceil = Ceil + 1
  9. End Function

La funzione DeQuote consente di rimuovere l'eventuali virgolette ( " ) alla sinistra ed alla destra di una stringa. Non rimuovono tutte le virgolette ma soltanto un singolo paio. Viene utilizzata per recuperare il nome reale dei valori durante la fase di importazione da file.

La funzione Ceil prende il nome dalla funzione analoga del linguaggio JavaScript e restituisce il numero arrotodonato sempre per eccesso. È utilizzata per determinare l'ampiezza del buffer durante il processo di importazione.

  1. Private Function HexDouble(ByVal Numero As Double, Optional Padding As Integer) As String
  2.   Dim HighPart As Double
  3.   Numero = Fix(Numero)
  4.   HighPart = Fix(Numero / 65536)
  5.   Numero = Numero - HighPart * 65536
  6.   HexDouble = Hex$(HighPart) & Right$("0000" & Hex$(Numero), 4)
  7.   If Padding > 0 Then HexDouble = Right$(String$(Padding, "0") & HexDouble, Padding)
  8. End Function

Una funzione un po' unusuale è la HexDouble ed in un linguaggio quale il C non avrebbe probabilmente senso di esistere. Viene utilizzata durante il processo di esportazione per convertire un numero Double ovvero il valore DWORD (visto che in VB non è possibile definire Long senza segno) in una stringa esadecimale. L'istruzione Hex arriva infatti soltanto al 31° bit ed al superamento di questo, genera Overflow.

La funzione scompone il numero Double in due parti: la parte alta è mantenuta nella variabile HighPart mentre la parte bassa rimane nel parametro Numero. I due valori sono poi convertiti separatamente e le due stringhe unite solo in seguito alla conversione.

Il parametro Padding è utile per assicurare una lunghezza minima di quella specificata in tale argomento; eventuali cifre mancanti saranno riempite con zeri alla sinistra.

  1. Private Function Replace(ByVal Stringa As String, ByVal Trova As String, ByVal Rimpiazza As String) As String
  2.   Dim Pos As Integer
  3.   Dim Buffer As String
  4.   Pos = InStr(1, Stringa, Trova)
  5.   Buffer = ""
  6.   Do While Pos > 0
  7.     Buffer = Buffer & Left$(Stringa, Pos - 1) & Rimpiazza
  8.     Stringa = Mid$(Stringa, Pos + Len(Trova))
  9.     Pos = InStr(1, Stringa, Trova)
  10.   Loop
  11.   Replace = Buffer & Stringa
  12. End Function

La funzione Replace è del tutto inutile ai programmatori VB6 ma per chi usufruisce (come me) della versione 5 di VB essa è indispensabile. Com'è ovvio, consente di sostuire tutte le occorrenze di una data stringa con un'altra e presenta alcune marginali differenze rispetto alla funzione Replace nativa in VB6.

Segue parte 4 >>

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