SUMARIO
Aunque Visual Basic incluye las funciones SaveSetting y GetSetting para guardar y recuperar información del registro, estas funciones operan sólo en una sección específica del mismo: la sección "VB and VBA Program Settings" de la clave raíz HKEY_CURRENT_USER.
En este artículo veremos como emplear las funciones del API de windows de 32 bits para guardar y recuperar información de cualquier parte del registro.
Se incluyen un módulo y una clase (cada uno que emplee el que más le guste) en Visual Basic 5 listos para su uso. En ambos se han añadido las funciones / métodos EnumKey y EnumValue que devuelven todas las subclaves / valores de una clave dada. El empleo de las mismas no está comentado en este artículo por lo que se recomienda descargar dichos módulos.
INFORMACION GENERAL DEL REGISTRO
El registro es usado por windows y por las aplicaciones para guardar datos de configuración. Es el sustituto para el gran número de ficheros .ini que proliferan por las máquinas con windows 3.x, y es muy usado por el OLE.
El registro está organizado usando una serie jerárquica de claves y valores, formando un arbol. Cada clave, empezando por las seis claves raíz predefinidas, puede tener subclaves y valores asociados con ella.
Las claves son unidades para la organización y aparecen en el editor del registro como carpetas. Los valores son datos y aparecen en el panel derecho del editor. Las claves pueden tener o nó valores asociados. Cada valor tiene un tipo de dato asociado. Los más usados son REG_SZ, cadena terminada en null, y REG_DWORD, un número de 32 bits.
El proceso básico empleado para escribir o leer del registro es el mismo. Para referenciar una clave o valor determinado debes tener un handle ("manejador") a la clave. Una vez que has obtenido este handle puedes leer, escribir o listar (enumerar) los valores y subclaves que dependen de la clave referenciada por él.
Para obtener un hadle a una clave debes comenzar por una de las seis claves raíz predefinidas (HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS,
HKEY_CURRENT_CONFIG y HKEY_DYN_DATA) y recorrer el árbol hasta encontrar la clave deseada. Los programas de ususario suelen leer y escribir en HKEY_CURRENT_USER y HKEY_LOCAL_MACHINE. Si las claves ya existen puedes usar una serie de llamadas a las funciones RegOpenKey o RegOpenKeyEx. Si tienes que crear la clave necesitarás emplear las funciones RegCreateKey y RegCreateKeyEx.
Las funciones que tiene el sufijo "Ex" sólo están disponibles para 32 bits. Las funciones que no lo tienen pueden trabajar en 16 y 32 bits. Recuerda que no todas las funciones del registro que no tienen el sufijo "Ex" son funciones creadas por compatibilidad con las plataformas de 16 bits. El sufijo "Ex" se añadió sólo a las funciones que añadían capacidades a las de 16 bits. Las funciones totalmente nuevas y específicas para 32 bits no poseen dicho sufijo.
Las funciones RegSetValue y RegSetValueEx permiten modificar el contenido de los valores, mientras que RegQueryValue y RegQueryValueEx permiten recuperar el contenido actual. Las limitaciones de la versión de 16 bits es evidente. Cuando empleamos la función RegSetValue de 16 bits no podemos usar parámetros con nombre por lo que no prodremos asociar más de un valor con cada clave. Además todos los valores deben ser del tipo REG_SZ. Estas limitaciones son inherentes al registro de 16 bits. La función RegSetValueEx permite crear múltiples valores de cualquiera de los tipos disponibles.
COMO ESCRIBIR EN EL REGISTRO
Esta sección del artículo muestra el uso de esas funciones del registro. Después de determinar qué funciones necesitas usar, copia las declaraciones del código que hay al final de este artículo en un módulo. Los dos procedimientos de Visual Basic incluídos (SetValueEx y QueryValueEx) son "atajos" para emplear las funciones del API RegSetValueEx y RegQueryValueEx de una forma más sencilla. Las notas que vienen a continuación hacen uso de esas funciones de VB pero por supuesto que puedes hacer llamadas directamente al API si quieres.
Crear y modificar claves y valores
Crear una nueva clave
Crear una nueva clave es tan simple como usar el siguiente procedimiento. CreateNewKey necesita el nombre de la clave a crear y la constante que representa la clave predefinida bajo la cual crearemos nuestra nueva clave. La llamada a RegCreateKeyEx no está usando las ventajas de los mecanismos de seguridad, pero se puede modificar para hacerlo. Una discusión sobre la seguridad del registro está fuera del alcance de este artículo.
Private Sub CreateNewKey (sNewKeyName As String, lPredefinedKey As Long)
Dim hNewKey As Long 'handle a la nueva clave
Dim lRetVal As Long 'resultado de la funcion RegCreateKeyEx
lRetVal = RegCreateKeyEx(lPredefinedKey, sNewKeyName, 0&, _
vbNullString, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, _
0&, hNewKey, lRetVal)
RegCloseKey (hNewKey)
End Sub
Con este procedimiento, una llamada a :
CreateNewKey "TestKey", HKEY_CURRENT_USER
creará una clave llamada "TestKey" inmediatamente debajo de HKEY_CURRENT_USER.
Llamando al procedimiento de esta manera :
CreateNewKey "TestKey\SubKey1\SubKey2", HKEY_LOCAL_MACHINE
se crearán tres claves indentadas comenzando por TestKey inmediatamente debajo de HKEY_LOCAL_MACHINE, SubKey1 dependiendo de TestKey, y SubKey3 bajo SubKey2.
Crear y modificar un valor
Crear y modificar un valor de una clave específica puede hacerse mediante este pequeño procedimiento. SetValue necesita la clave con la que estará asociado el valor, el nombre del valor, el contenido y el tipo de dato (la función SetValueEx sólo soporta REG_SZ y REG_DWORD, pero puede ser modificada si es necesario). Especificando un nuevo contenido para un valor (sValueName) existente modificaremos el contenido actual del valor.
Private Sub SetValue (sKeyName As String, sValueName As String, _
vValueSetting As Variant, lValueType As Long)
Dim lRetVal As Long 'resultado de la funcion SetValueEx
Dim hKey As Long 'handle de la clave abierta
'abrir la clave especificada
lRetVal = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyName, 0, _
KEY_ALL_ACCESS, hKey)
lRetVal = SetValueEx(hKey, sValueName, lValueType, vValueSetting)
RegCloseKey (hKey)
End Sub
Una llamada a :
SetValue "TestKey\SubKey1", "StringValue", "Hello", REG_SZ
creará un valor de tipo REG_SZ llamado "StringValue" con el contenido "Hello". Este valor está asociado a la clave SubKey1 de la clave TestKey.
En este caso, "TestKey" es una subclave de HKEY_CURRENT_USER, pero esto puede ser modificado cambiando la llamada a RegOpenKeyEx. Esta llamada falla si "TestKey\SubKey1" no existe. Para evitar este problema podemos emplear RegCreateKeyEx en vez de RegOpenKeyEx. RegCreateKeyEx abre la clave especificada si ya existe.
Buscar un valor
El siguiente procedimiento puede ser usado para conocer el contenido de un valor existente. QueryValue necesita el nombre de la clave y el nombre del valor y saca un message box con el contenido del valor. Emplea una llamada a la función "atajo" QueryValueEx definida más abajo, la cual sólo soporta los tipos de datos REG_SZ y REG_DWORD :
Private Sub QueryValue (sKeyName As String, sValueName As String)
Dim lRetVal As Long 'resultado de las llamadas a funciones dell API
Dim hKey As Long 'handle de la clave abierta
Dim vValue As Variant 'contenido del valor buscado
lRetVal = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyName, 0, _
KEY_ALL_ACCESS, hKey)
lRetVal = QueryValueEx(hKey, sValueName, vValue)
MsgBox vValue
RegCloseKey (hKey)
End Sub
Con este procedimiento, una llamada a :
QueryValue "TestKey\SubKey1", "StringValue"
scará un message box con el contenido actual del valor "StringValue", y asumimos que "StringValue" existe en la clave "TestKey\SubKey1".
Si el valor buscado no existe, la función QueryValue devolverá un código de error 2 - 'ERROR_BADKEY'.
Notas adicionales
Los ejemplos anteriores usan las versiones extendidas de 32 bits de las funciones del registro. Estas funciones permiten tener más de un valor asociado a cada clave. Como se comentó anteriormente, las funciones RegSetValue y RegQueryValue de 16 bits actúan con un único valor asociado a cada clave (siempre de tipo REG_SZ). Esas funciones aparecen en el editor de registro de 32 bits con el nombre
En algunos casos, algunos valores no necesitan estar relacionados cun una clave. Una aplicación puede necesitar sólo saber si cierta clave o cierto valor existen. Para ello podemos emplear las funciones RegEnumKey, RegEnumKeyEx y RegEnumValue. Para más información sobre esas funciones buscar en el visor del API (API Text Viewer).
Declaración de Funciones y Constantes del API
Option Explicit
Global Const REG_SZ As Long = 1
Global Const REG_DWORD As Long = 4
Global Const HKEY_CLASSES_ROOT = &H80000000
Global Const HKEY_CURRENT_USER = &H80000001
Global Const HKEY_LOCAL_MACHINE = &H80000002
Global Const HKEY_USERS = &H80000003
Global Const ERROR_NONE = 0
Global Const ERROR_BADDB = 1
Global Const ERROR_BADKEY = 2
Global Const ERROR_CANTOPEN = 3
Global Const ERROR_CANTREAD = 4
Global Const ERROR_CANTWRITE = 5
Global Const ERROR_OUTOFMEMORY = 6
Global Const ERROR_INVALID_PARAMETER = 7
Global Const ERROR_ACCESS_DENIED = 8
Global Const ERROR_INVALID_PARAMETERS = 87
Global Const ERROR_NO_MORE_ITEMS = 259
Global Const KEY_ALL_ACCESS = &H3F
Global Const REG_OPTION_NON_VOLATILE = 0
Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
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
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
Declare Function RegQueryValueExString Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
String, ByVal lpReserved As Long, lpType As Long, ByVal lpData _
As String, lpcbData As Long) As Long
Declare Function RegQueryValueExLong Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
String, ByVal lpReserved As Long, lpType As Long, lpData As _
Long, lpcbData As Long) As Long
Declare Function RegQueryValueExNULL Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
String, ByVal lpReserved As Long, lpType As Long, ByVal lpData _
As Long, lpcbData As Long) As Long
Declare Function RegSetValueExString Lib "advapi32.dll" Alias _
"RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, _
ByVal Reserved As Long, ByVal dwType As Long, ByVal lpValue As _
String, ByVal cbData As Long) As Long
Declare Function RegSetValueExLong Lib "advapi32.dll" Alias _
"RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, _
ByVal Reserved As Long, ByVal dwType As Long, lpValue As Long, _
ByVal cbData As Long) As Long
Funciones "atajo" SetValueEx y QueryValueEx
Public Function SetValueEx(ByVal hKey As Long, sValueName As String, _
lType As Long, vValue As Variant) As Long
Dim lValue As Long
Dim sValue As String
Select Case lType
Case REG_SZ
sValue = vValue & Chr$(0)
SetValueEx = RegSetValueExString(hKey, sValueName, 0&, _
lType, sValue, Len(sValue))
Case REG_DWORD
lValue = vValue
SetValueEx = RegSetValueExLong(hKey, sValueName, 0&, _
lType, lValue, 4)
End Select
End Function
Function QueryValueEx(ByVal lhKey As Long, ByVal szValueName As _
String, vValue As Variant) As Long
Dim cch As Long
Dim lrc As Long
Dim lType As Long
Dim lValue As Long
Dim sValue As String
On Error GoTo QueryValueExError
' Determinar tl tamaño y tipo de datos a leer
lrc = RegQueryValueExNULL(lhKey, szValueName, 0&, lType, 0&, cch)
If lrc <> ERROR_NONE Then Error 5
Select Case lType
' Para strings
Case REG_SZ:
sValue = String(cch, 0)
lrc = RegQueryValueExString(lhKey, szValueName, 0&, lType, _
sValue, cch)
If lrc = ERROR_NONE Then
vValue = Left$(sValue, cch-1)
Else
vValue = Empty
End If
' Para DWORDS
Case REG_DWORD:
lrc = RegQueryValueExLong(lhKey, szValueName, 0&, lType, _
lValue, cch)
If lrc = ERROR_NONE Then vValue = lValue
Case Else
'los demás tipos de datos no están soportados
lrc = -1
End Select
QueryValueExExit:
QueryValueEx = lrc
Exit Function
QueryValueExError:
Resume QueryValueExExit
End Function
Trucos