Premessa:
Il codice trattato in questo articolo è stato riscritto per renderlo
più intuitivo possibile e per utilizzarlo all'interno di un modulo
di classe, aumentando e semplificando quindi la sua riusabilità.
È stato studiato intorno a Windows 95/98/ME e solo in seguito
adattato per consentire un utilizzo in Windows NT/2000/XP.
Il giudizio di complessità massimo non deve spaventare perché
in gran parte dovuto alla lunghezza e completezza del modulo di classe
sviluppato ed in parte alla necessaria poca dettagliatezza che
altrimenti avrebbe portato via molto più spazio del dovuto.
Un problema comunissimo per tantissimi programmi è il salvataggio
ed il caricamento delle opzioni del programma sviluppato. Non è
molto sensato, infatti, obbligare ogni volta l'utente a regolarsi i parametri
del programma secondo le sue necessità; è molto più
agevole far sì che all'uscita del programma tali parametri ed impostazioni
vengano salvate da qualche parte e riprese al successivo ricaricamento
del programma.
Esistono due soluzioni fondamentali per il salvataggio ed il ripristino
delle impostazioni: la prima consiste nell'utilizzare i classici ed antiquati
files di impostazioni con estensione
INI, mentre la seconda sfrutta il registro
di Windows (chiamato talvolta semplicemente Registry), un particolare
file di Windows contenente molte impostazioni di quasi tutti i moderni
programmi per Windows.
All'interno del registro sono contenute tantissime informazioni e talvolta
è necessario accedervi per recuperare tali informazioni in mancanza
di una funzione API che li ricavi
direttamente. Si raccomanda quindi la manipolazione del registry soltanto
come ultima possibilità per il recupero dei dati, preferendo quindi,
l'utilizzo delle funzioni API specializzate.
In questo lungo tutorial svilupperemo una classe
per la lettura, la modifica, l'aggiunta e l'eliminazione di chiavi e valori
del registro. Sono state aggiunte in seguito due funzioni per l'esportazione
e l'importazione di parti del registro su file compatibili con Regedit.
Si suppone una minima conoscenza della struttura del Registry.
Tralasciamo le spiegazioni e vediamo subito il codice denso di API:
- Option Explicit
- Option Base 0
- Private Const STANDARD_RIGHTS_ALL As Long = &H1F0000
- Private Const STANDARD_RIGHTS_READ As Long = &H20000
- Private Const STANDARD_RIGHTS_WRITE As Long = &H20000
- Private Const SYNCHRONIZE As Long = &H100000
- Private Const KEY_QUERY_VALUE As Long = &H1
- Private Const KEY_SET_VALUE As Long = &H2
- Private Const KEY_CREATE_SUB_KEY As Long = &H4
- Private Const KEY_ENUMERATE_SUB_KEYS As Long = &H8
- Private Const KEY_NOTIFY As Long = &H10
- Private Const KEY_CREATE_LINK As Long = &H20
- Private Const REG_OPTION_NON_VOLATILE As Long = 0
Si apre il sipario con la presentazione di una serie di costanti
API utilizzate più avanti: sono suddivise in due tipologie: quelle
relative alla sicurezza e quella indicativa del tipo di dati da trattare
ovvero non volatili, i normali dati del registro opposti a quelli
volatili la cui esistenza si spegne al riavvio del computer. Vedremo le
altre costanti nelle enumerazioni
successive.
- Private Declare Function RegOpenKeyEx Lib "advapi32.dll"
Alias "RegOpenKeyExA" (ByVal hKey As Long, ByVal lpSubKey
As String, ByVal ulOptions As Long, ByVal samDesired As Long, phkResult
As Long) As Long
- Private Declare Function RegCreateKeyEx Lib "advapi32.dll"
Alias "RegCreateKeyExA" (ByVal hKey As Long, ByVal lpSubKey
As String, ByVal Reserved As Long, ByVal lpClass As String, ByVal dwOptions
As Long, ByVal samDesired As Long, ByVal lpSecurityAttributes As Long,
phkResult As Long, lpdwDisposition As Long) As Long
- Private Declare Function RegCloseKey Lib "advapi32.dll"
(ByVal hKey As Long) As Long
- Private Declare Function RegFlushKey Lib "advapi32.dll"
(ByVal hKey As Long) As Long
- Private Declare Function RegDeleteKey Lib "advapi32.dll"
Alias "RegDeleteKeyA" (ByVal hKey As Long, ByVal lpSubKey
As String) As Long
- Private Declare Function RegEnumKeyEx Lib "advapi32.dll"
Alias "RegEnumKeyExA" (ByVal hKey As Long, ByVal dwIndex As
Long, ByVal lpName As String, lpcbName As Long, lpReserved As Long,
ByVal lpClass As String, lpcbClass As Long, ByVal lpftLastWriteTime
As Long) As Long
- Private Declare Function RegQueryInfoKey Lib "advapi32.dll"
Alias "RegQueryInfoKeyA" (ByVal hKey As Long, ByVal lpClass
As String, lpcbClass As Long, lpReserved As Long, lpcSubKeys As Long,
lpcbMaxSubKeyLen As Long, lpcbMaxClassLen As Long, lpcValues As Long,
lpcbMaxValueNameLen As Long, lpcbMaxValueLen As Long, lpcbSecurityDescriptor
As Long, lpftLastWriteTime As Long) As Long
Segue un primo elenco di dichiarazioni di funzioni API relative alle
chiavi del registro. Non potendoci soffermare su ognuna accenneremo soltanto
qualcosa sul loro funzionamento generale:
- RegOpenKeyEx
Effettua l'apertura di una chiave o di una sua sottochiave.
- RegCreateKeyEx
Crea ed apre una nuova sottochiave della chiave indicata.
- RegCloseKey
Chiude una chiave precedentemente aperta liberando l'handle
assegnato.
- RegFlushKey
Aggiorna i dati di una chiave e forzando il sistema operativo a scrivere
tutte le modifiche non ancora scritte sul disco.
- RegDeleteKey
Elimina una chiave e tutte le sue sottochiavi ed i relativi valori.
- RegEnumKeyEx
Recupera i nomi di una o più sottochiavi della chiave indicata.
- RegQueryInfoKey
Ricava informazioni su una determinata chiave come il numero di sottochiavi
o di valori presenti.
- Private Declare Function RegQueryValueEx Lib "advapi32.dll"
Alias "RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName
As String, ByVal lpReserved As Long, lpType As Long, lpData As Any,
lpcbData As Long) As Long
- Private Declare Function RegSetValueEx Lib "advapi32.dll"
Alias "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName
As String, ByVal Reserved As Long, ByVal dwType As Long, lpData As Any,
ByVal cbData As Long) As Long
- Private Declare Function RegEnumValue Lib "advapi32.dll"
Alias "RegEnumValueA" (ByVal hKey As Long, ByVal dwIndex As
Long, ByVal lpValueName As String, lpcbValueName As Long, ByVal lpReserved
As Long, lpType As Long, lpData As Byte, lpcbData As Long) As Long
- Private Declare Function RegDeleteValue Lib "advapi32.dll"
Alias "RegDeleteValueA" (ByVal hKey As Long, ByVal lpValueName
As String) As Long
Dopo le funzioni relative alle chiavi segue l'elenco delle funzioni relative
ai valori contenuti nelle chiavi stesse:
- RegQueryValueEx
Interroga un valore di cui si conosce il nome ottenendo in risposta
il suo contenuto ed il suo tipo di dati.
- RegSetValueEx
Modifica il contenuto di un valore esistente e crea un nuovo valore
nel caso che esso non dovesse esistere, con il tipo di dati specificato.
- RegEnumValue
Interroga una chiave aperta per richiedere il nome di un valore in essa
contenuti e contestualmente consente di recuperare anche il loro contenuto
ed il tipo di dati.
- RegDeleteValue
Effettua semplicemente l'eliminazione del valore specificato. Se il
valore da eliminare è quello predefinito della chiave ne sarà
cancellato soltanto il suo contenuto.
Si sottolinea il fatto che tutte le funzioni che utilizzano stringhe
si riferiscono alla versione ANSI
piuttosto che alla versione Unicode
come indicato dalla A finale al nome della funzione dopo la parola chiave
"Alias"; la versione Unicode avrebbe il suffisso W.
Pertanto ogni qual volta viene passata una stringa sotto forma di array
di bytes è necessario fare la conversione di formato tramite la
funzione StrConv.
Seguono le enumerazioni
scritte per semplificare l'utilizzo delle varie costanti API e poter pertanto
usufruire del sistema Intellisense.
- Public Enum ChiaviPrincipali
- CHIAVE_APERTA = 0
- HKEY_CLASSES_ROOT = &H80000000
- HKEY_CURRENT_CONFIG = &H80000005
- HKEY_CURRENT_USER = &H80000001
- HKEY_DYN_DATA = &H80000006
- HKEY_LOCAL_MACHINE = &H80000002
- HKEY_PERF_ROOT = HKEY_LOCAL_MACHINE
- HKEY_PERFORMANCE_DATA = &H80000004
- HKEY_USERS = &H80000003
- End Enum
L'enumerazione ChiaviPrincipali verrà utilizzata
da molte funzioni della classe per determinare quale chiave utilizzare:
quella aperta dalla nostra istanza
(riga 30) oppure una delle chiavi di sistema (righe 31-38) sempre aperte.
In funzione della struttura della classe il programma potrà anche
fornire una chiave arbitraria, ovvero un handle ad una chiave già
aperta.
- Public Enum ChiaviSecurity
- KEY_UNKNOWN = 0
- KEY_READ = ((STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or
KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE))
- KEY_WRITE = ((STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or
KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE))
- KEY_ALL_ACCESS = ((STANDARD_RIGHTS_ALL Or KEY_QUERY_VALUE
Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY Or KEY_ENUMERATE_SUB_KEYS Or
KEY_NOTIFY Or KEY_CREATE_LINK) And (Not SYNCHRONIZE))
- End Enum
L'enumerazione ChiaviSecurity trova il suo vero significato
in Windows NT/2000/XP ed indica 4 permessi standard: da sconosciuto ad
accesso massimo.
- Public Enum TipoValoriRegistro
- REG_NONE = 0
- REG_SZ = 1
- REG_EXPAND_SZ = 2
- REG_BINARY = 3
- REG_DWORD = 4
- REG_DWORD_LITTLE_ENDIAN = 4
- REG_DWORD_BIG_ENDIAN = 5
- REG_LINK = 6
- REG_MULTI_SZ = 7
- REG_RESOURCE_LIST = 8
- End Enum
L'ultima enumerazione è TipoValoriRegistro e rappresenta
tutti i possibili tipi di dati presenti nel registro. Nel 90% dei casi
si utilizzano i tipi stringa (REG_SZ), binario (REG_BINARY)
e valore Double Word, un numero intero a 32 bit e senza segno (REG_DWORD).
Sono questi infatti i tipi di dati che è possibile inserire nel
Registry utilizzando il programma Regedit. Questa classe non implementa
i tipi di dati REG_LINK, REG_RESOURCE_LIST e REG_DWORD_BIG_ENDIAN.
- Private lngKeyValue As Long
- Private lngKeySecurity As Long
Gli unici due membri privati interni sono due valori di tipo Long: il
primo identifica l'handle alla
chiave aperta (vedi l'enumerazione ChiaviPrincipali) e verrà
utilizzato per la maggior parte delle operazioni. L'altro valore rappresenta
invece un indice di sicurezza come indicato dall'enumerazione ChiaviSecurity.
- Private Sub Class_Initialize()
- lngKeyValue = 0
- End Sub
- Private Sub Class_Terminate()
- Call RegCloseKey(lngKeyValue)
- End Sub
Giusto per sicurezza, all'istanza della classe la variabile lngKeyValue
viene posta uguale a 0 per indicare che nessuna chiave è stata
ancora aperta. Alla deallocazione
dell'istanza viene comunque effettuata la chiusura della chiave lngKeyValue.
È importante ricordarsi di chiudere le chiavi quando esse non sono
più necessarie e, come vedremo in seguito, non chiudere mai le
chiavi delle quali non è stata effettuata la diretta apertura.
|