Trucos Manejo del registro de windows 32 bits

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 . Para dar valor, modificar o buscar este valor asociado especial debes usar las funciones del registro de 16 bits. Leer y escribir el registro en un entorno de 16 bits es mucho más sencillo que en uno de 32. Se sigue el mismo procedimiento básico : abrir una clave y obtener un handle y luego llamar a la función de modificación con ese handle pero sin las consideraciones necesarias para varios tipos de datos y varios valores por clave.

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

Download registro.zip  



Trucos Trucos

Visual Basic Página de Visual Basic

Página principal Página principal

www.jrubi.com