Documente Academic
Documente Profesional
Documente Cultură
Dado que este libro tiene lógicamente un alcance limitado, y el tema de APIs es enorme, se
recomienda recurrir a un libro específico de APIs. Este no puede ser otro que el siguiente :
Nota introducida en el 2001 - Aparte de este libro, existe un recurso en Internet que incluso
le supera, y que tiene la gran ventaja de que se trata de un sistema informático donde puede
copiar y pegar código. Puede encontrarlo en http://www.allapi.net/
Desde que lo he descubierto he dejado el Libro de Appleman un poco aparcado. Sin
embargo las explicaciones aportadas en ese libro son difícilmente sustituibles.
Para usar una función API lo primeros que tenemos que hacer es declararla en nuestra
aplicación. La declaración debe hacerse en la sección de declaraciones de un formulario o
módulo. Si la declaramos en un formulario, necesariamente debemos declararla como privada.
Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
Public Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
Private Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
En esta declaración lo que le estamos diciendo es que, en la librería kernel32 está escrita una
función llamada Sleep (Es el nombre que figura entre comillas en la declaración) y que le
tenemos que pasar un parámetro, el tiempo que queremos que se pare la ejecución de la
aplicación, expresado en milisegundos. Nos dice la declaración que el parámetro se le pasa
Por Valor (ByVal) y que ese dato debe ser un Long, es decir, si se lo pasamos como una
variable, esa variable debe ser del tipo Long. Una vez declarada esta función, en la sección de
declaraciones de un módulo o de un formulario, podremos acceder a ella en cualquier parte de
la aplicación (las partes de la aplicación donde se puede usar dependerá del ámbito de la
declaración, que es idéntica que para las variables) usando una línea de código como esta :
Sleep (500) y la aplicación se detendrá medio segundo cuando llegue a esa línea
ó Sleep (tiempo) donde tiempo es una variable tipo Long que contiene el tiempo (en
milisegundos) que queremos detener el programa.
Aquí ya se ha complicado un poco la cosa. Pero tras un análisis detenido veremos que esa
complicación es sólo aparente.
En primer lugar vemos que la librería donde está esta función es, como en la función Sleep, el
kernel32 . Esto quiere decir que la librería kernel32 contiene varias funciones. Pero ¿qué es la
librería kernel32 ? Ni mas ni menos que una DLL llamada kernel32.dll que puede encontrar en
el directorio C :\WINDOWS\SYSTEM, y que es el alma de Windows. (Kernell significa, como
muy bien sabrá, núcleo)
En segundo lugar, vemos que el nombre de esta función dentro de la DLL kernel32.dll es
GetVolumeInformationA, que es lo que figura entre comillas en la declaración. El nombre
GetVolumeInformation que figura como nombre de la función, al principio de la declaración,
es el nombre por el que nos vamos a referir a la función en nuestra aplicación. Ese nombre
puede cambiarse, cambiando también el nombre con el que vamos a llamar a esta función a lo
largo de nuestra aplicación. Esto se lo digo solamente a nivel informativo. No lo haga. Su
aplicación no podría ser interpretada por otra persona. No es profesional y quien mas
perderá por ello es Vd. Le hago especial hincapié en esto, porque es una forma de proteger
sus programas por parte de algunos programadores. Pero un analista experto encuentra
enseguida el truco. Y algunos no perdonan. Seamos profesionales
En tercer lugar, vemos que la declaración de esta función termina con la expresión As Long.
Esto significa que esta función devuelve un dato, y es concretamente, un Long. Por lo tanto, si
ese dato nos sirve para algo, podemos obtenerlo. Verá que no es necesario, pero en muchas
ocasiones, ese dato nos va a indicar si la función se ejecutó correctamente. Concretamente,
esta función devuelve un 0 si ha existido algún problema para obtener el número del disco, o un
número distinto de 0 si lo ha obtenido. Las demás constantes deberemos declararlas en el
procedimiento donde vamos a usar la función (o en otro lugar, si así lo exige el ámbito que les
queramos dar, pero generalmente, en el mismo procedimiento), e invocar la función pasándole
los parámetros correctos.
La sintaxis de las Apis va a ser distinta si deseamos obtener el valor que devuelve o no. Por
ejemplo, para la función anterior podemos poner perfectamente estas dos expresiones
En el ejercicio realizado para hacer estos apuntes, este código se metió en el procedimiento
click de un botón de comando.
‘Declaramos las variables. Observe que no tienen por qué tener el mismo nombre que en la
‘declaración de la función.
Estas variables son las que se van a pasar como parámetros a la función. La correspondencia
entre el nombre del parámetro y cada una de las variables es la siguiente :
Función GetVolumeInformation
Declare Function GetVolumeInformation Lib "kernel32" Alias "GetVolumeInformationA" (ByVal
lpRootPathName As String, ByVal lpVolumeNameBuffer As String, ByVal nVolumeNameSize As
Long, lpVolumeSerialNumber As Long, lpMaximumComponentLength As Long,
lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String, ByVal
nFileSystemNameSize As Long) As Long
lpRootPathName
Es un string que contiene el directorio raíz del disco a analizar. Si es te parámetro es Null, se
toma el directorio raíz del directorio actual. Esta parámetro puede indicar el disco de un
servidor, en cuyo caso debe indicarse con dos backslash. (\\Servidor\Disco)
lpVolumeNameBuffer
Apunta a una variable que va a recibir el nombre del Label del disco. Hay que declararla con un
tamaño predeterminado, siempre mayor que el que va a tener el dato
p.e. Dim VolBuf As String * 255
nVolumeNameSize
Especifica la longitud de la variable anterior. No importa que la hayamos declarado ya con
determinado tamaño. Hay que poner aquí otra vez ese tamaño, que será el mismo que tenía
declarado la variable.
lpVolumeSerialNumber
Apunta a una variable tipo Long, donde se va a meter el número del disco.
lpFileSystemFlags
Apunta a una variable tipo Long, (Igual que la anterior, concatenación de dos bytes) que
especifican los Flags asociados al sistema de ficheros. Puede ser la combinación de dos de los
siguientes parámetros (Excepción: FS_FILE_COMPRESSION y FS_VOL_IS_COMPRESSED
son mutuamente excluyentes).
FS_CASE_IS_PRESERVED
If this flag is set, the file system preserves the case of filenames when it places a name on disk.
FS_CASE_SENSITIVE
El sistema de ficheros diferencia mayúsculas y minúsculas.
FS_UNICODE_STORED_ON_DISK
FS_PERSISTENT_ACLS
FS_FILE_COMPRESSION
FS_VOL_IS_COMPRESSED
El disco especificado se trata de un disco comprimido. Por ejemplo, es un disco al que se le ha
aplicado DoubleSpace.
lpFileSystemNameBuffer
Apunta a una variable tipo string, donde se mete el sistema de ficheros soportado (FAT or
NTFS). Esta variable debe declararse con un número prefijado de caracteres, siempre superior
al que vaya a tener realmente (p.e. Dim SysName As String * 255)
nFileSystemNameSize
Especifica el número de caracteres de la variable anterior. Debe introducirse el mismo número
con el que se ha declarado la longitud de esa variable. (255 en el ejemplo).
Ya vamos viendo que las APIs no son tan difíciles de entender. Vamos a ver otra, la inversa de
la anterior, que pone el valor al parámetro Label del disco. Observe que el resto de los
parámetros no pueden variarse ya que vienen marcados en el disco (número) o implícitos en el
sistema operativo.
Función SetVolumeLabel
Private Declare Function SetVolumeLabel Lib "kernel32" Alias "SetVolumeLabelA" (ByVal
lpRootPathName As String, ByVal lpVolumeName As String) As Long
lpRootPathName
Variable tipo string donde se introduce el directorio raíz del disco al que se le va a poner o
cambiar el Label. Si este parámetro es Null, se entiende que es el raíz del directorio actual.
lpVolumeName
Variable tipo string que contienen el Label a poner. Si es Null, borra el Label actual.
Esta chuleta no es otro que el Visor de Texto API (API Text Wiever en Inglés). Este es un
programa que se distribuye con Visual Basic y que se instala al tiempo que este, formando
parte del mismo grupo de programas. Haciendo clic en su icono aparece esta ventana :
Haciendo Click sobre la palabra Archivo de la Barra de Menú, aparecen unos ficheros que
contienen las declaraciones de las funciones API :
Win32Api.txt
Winmmsys.txt
Estos dos ficheros son los que suministra Microsoft con VB6. El primero contiene las
declaraciones de las funciones API no relacionadas con el tema multimedia. El segundo
contiene las declaraciones de las API relacionadas con este tema de multimedia.
Si ha adquirido el libro de Appleman puede tener otro fichero : Api32.txt. El autor de este libro
asegura que es mucho mas completo que el fichero que entrega Microsoft. De hecho contiene
bastantes mas declaraciones.
API-Guide presenta también la declaración del API para ser copiada directamente en el
portapapeles y pegada en nuestra aplicación. Últimamente es la única que uso, ya que al
tiempo, se obtienen una explicación de cada uno de los parámetros.
Para obtener una o varias declaraciones, seleccione las funciones en la ventana de arriba del
visor, haga click en Agregar y esa función le pasará para la ventana de abajo. Una vez que
tenga en esa ventana todas las funciones que necesita, haga click en el botón Copiar y las
declaraciones completas le pasarán al portapapeles.
Una vez que ya sabemos donde se pueden copiar las declaraciones de las APIs, veamos una
que nos permitirá obtener la hora desde el sistema operativo :
Ahora nos surge una duda ¿Qué es SYSTEMTIME ? Es una variable que hay que declararla
con la instrucción Type, igual que hacíamos con las variables con varios campos en los ficheros
tipo Random. Repase este capítulo si no lo tiene claro.
Para poder declarar esta variable, podemos obtener su declaración del mismo Visor de Texto
API
Para ello, en la ventana Tipo API en vez de figurar Declaraciones debe poner Tipos. Busque
esta opción desplegando la ventana con la flecha que tiene a la derecha. Busque ahora la
variable cuya declaración quiere conocer. Repitiendo el proceso anterior, se llevará en el
portapapeles la declaración de la variable :
Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Haga un pequeño ejercicio para obtener la fecha y hora usando un API :
Para ello debemos introducir un módulo donde definiremos la variable SYSTEMTIME y donde
podemos declarar la función GetSystemTime :
Módulo 1 Declaraciones
Option Explicit
Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Este programa nos mostrará la hora (hasta milésimas de segundo), la fecha y el día de la
semana.
Cuando necesite un API nuevo para su programa no se conforme con salir del paso. Eso se
logra con el libro de Appelman o con el API-Guide. Por experiencia propia, le recomiendo que
haga una pequeña aplicación para emplear esa o esas APIS que necesita. Estúdielas,
documéntelas y guárdelas donde guarda sus tesoros más preciados. Hágalo, pues al cabo de
una año sin volver a usarlas se le van a olvidar, y tendrá que ponerse nuevamente al día. Hay
APIs caprichosas, declaraciones que tienen que ser así, sin ninguna razón ni criterio para ello.
No duplique su trabajo. Créese una libreta de APIs y con el tiempo, llegará a dominarlas como
el mismísimo Appleman. Por mi parte, dejo como botón de muestra las que presento a
continuación.
La zona de acceso rápido de la barra de tareas es la parte derecha de esta barra en la que se
encuentra el reloj. En el inglés original se denomina System Tray, y no encuentro en español
una palabra del argot informático que la defina.
Es muy cómodo, sobre todo para los programas que se deben estar ejecutando continuamente,
poner su icono en esta parte de la barra de tareas, ya que ocupan menos espacio que un
programa minimizado normalmente. Solamente se ve el icono representativo del programa.
Por ello es necesario elegir un icono que defina de forma sencilla e inequívoca la aplicación.
Generalmente se le pone un PopUp menú que muestra las opciones de restaurar (Muestra la
aplicación en su tamaño normal) y Salir. También se suele poner un TextToolTip para mostrar
de forma literal el nombre del programa minimizado en ese icono.
Fig. 1 - Icono del programa Wsk colocado en el System Tray con su ToolTipText y PopupMenú
Este sistema permite comunicar la aplicación con el icono creado en el System Tray.
Lógicamente, primero debe crearse el icono (Se crea normalmente en el Load del formulario
inicial de la aplicación), y permanece ahí mientras dura la ejecución de la aplicación. Si se
minimiza la aplicación, no aparece su icono en la barra de tareas. Por lo tanto se necesitará
algún artilugio para poder poner otra vez la aplicación en su estado normal. Esto se hace
mediante una comunicación entre el icono del System Tray y la aplicación. Esa comunicación
es lo que llamaremos mensaje de retorno. Al recibir ese mensaje de retorno, el formulario va a
tratarlo en uno de sus procedimientos. El procedimiento donde lo va a tratar se le especifica en
la llamada a la API como se verá mas adelante. El mensaje de retorno va a depender de lo que
se haga sobre el icono del System Tray, (Tecnología Windows) y es en principio un poco
complicado, pero verá también más adelante una breve explicación sobre este valor devuelto.
Para que el icono no siga en el System Tray una vez hayamos salido de la aplicación, es
necesario eliminarlo en el procedimiento Unload del formulario inicial.
El icono puede cambiarse en tiempo de ejecución, y es una de las aplicaciones más vistosas
de este sistema. Puede, por ejemplo, cambiar el color del icono para indicar que se ha recibido
un mensaje, que se está conectado, etc.
Vemos que la declaración incluye una variable definida por el usuario: NOTIFYCONDATA. Se
define de esta forma
El segundo parámetro (pnid) es una variable tipo NOTIFYICONDATA tal como se definió más
atrás. Vemos a continuación cada componente de esta variable:
UId Es el identificador del icono del System Tray. Puede ser cualquier
número Long. Solamente será necesario usar un número si hace falta
identificar ese icono para una operación posterior. Si no se va hacer ninguna
operación con él, caso más habitual, basta con poner vbNull como valor de esta
parte.
Uflags puede contener los tres valores, validando de esta forma las tres condiciones anteriores.
Es muy tipico ver que UFlags toma el valor:
Resumiendo: Uflags es en realidad un conjunto de tres banderas, que puede tomar el valor 1,
3 ó 7, según se haya aplicado NIF_MESSAGE (Pesa 1), NIF_ICON (Pesa 2) y NIF_TIP
(Pesa 4)
HIcon Icono que presentará en el System Tray. Es muy normal poner el icono
del formulario inicial de la aplicación. Si el código de creación del icono
está es ese formulario (cosa muy normal) basta con poner aquí,
Me.Icon
SzTip Aquí debe poner el ToolTipText que quiere que aparezca cuando
mantiene el cursor del ratón unos instantes sobre el icono del System
Tray.
EJERCICIO PRACTICO
En el mismo módulo introducimos las constantes que va a requerir, tanto la llamada a la función
Shell_NotifyIcon como las que vamos a necesitar para analizar el mensaje de retorno:
Declaramos otra API, con la que podemos hacer que un formulario tome el foco, y se coloque
en primer plano: SetForegroundWindow
Public Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long
Ahora declaramos una variable llamada Nid, que será del tipo NOTIFYICONDATA
Ya hemos terminado con el código del módulo. Vayamos ahora al procedimiento Load del
formulario inicial. Además de todo lo que debamos hacer en ese procedimiento, le añadiremos
esta parte, correspondiente a la creación del icono en el System Tray
Con estas dos líneas garantizamos que se va a presentar el formulario, si se hubiese abierto
con la instrucción Load
Me.Show
Me.Refresh
‘Damos los valores apropiados a cada una de las partes de la variable Nid
With Nid
.cbSize = Len(Nid)
.hwnd = Me.hwnd
.uId = vbNull
.uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE
.uCallBackMessage = WM_MOUSEMOVE
.hIcon = Me.Icon
.szTip = "SEAE - Conexión vía IP" & vbNullChar
End With
Llamamos a la función para crear el icono (Parámetro NIM_ADD) y le pasamos la variable Nid
con las características del icono
cbSize = Len(Nid) Tal como se dijo más atrás, cbSize contiene un Long con el tamaño de
la variable tipo NOTIFYICONDATA. Al poner cbSize = Len(Nid) se lo estamos pasando
mediante el cálculo que realiza la función Len.
hwnd = Me.hwnd Le pasa el .hwnd del formulario. Así Windows ya sabe a qué formulario
debe enviar el mensaje de retorno.
NIF_ICON es una constante que vale 2, NIF_TIP es otra constante que vale 4 y
NIF_MESSAGE es otra que vale 1. Por lo tanto, esta línea es exactamente igual a otra que
pusiese
uFlags = 7
La razón de poner una constante en vez del valor es solamente a efectos didácticos durante la
programación. Es más sencillo acordarse de un neumónico que de un número. Es costumbre
de programación solamente. Y recuerde que esas constantes deben estar declaradas, cosa
que hicimos en el módulo, cuya declaración se repite aquí por facilidad de comprensión:
hIcon = Me.Icon Con esta línea le decimos que el icono que debe presentar en el
System Tray es precisamente el icono de este formulario. Podríamos indicarle otro icono,
pasándole la propiedad Icon de otro objeto, o la propiedad picture de un picture box o control
image, siempre y cuando en esa propiedad hayamos puesto un icono.
szTip = "SEAE - Conexión vía IP" & vbNullChar Este es el ToolTipText que va a
aparecer cuando dejemos unos instantes el puntero del ratón encima del icono. Esta variable
tiene 64 caracteres, pues así se declaró – y no funciona si se declara de otro tamaño – en la
definición de la variable tipo NOTIFYICONDATA. Para evitar que aparezcan como espacios los
caracteres no usados, cosa que deja muy fea la presentación del ToolTipText, basta con poner
& vbNullChar tras el texto deseado.
Este procedimiento espera recibir 4 parámetros, sin embargo solamente va a recibir 3. Por lo
tanto, el valor de Y será siempre nulo a lo largo de este procedimiento.
El mensaje recibido del icono contiene un número. Si la propiedad ScaleMode del formulario
estuviese en Pixels, ese número coincidiría con el que genera el icono. Si ScaleMode no está
en Pixels, el valor generado lo multiplica por el valor de la propiedad TwipsPerPixelX. Las
líneas anteriores detectan el valor de la propiedad ScaleMode y actúan en consecuencia. Al
final tenemos un número que es el que metemos en la variable msg. Hacemos un Select Case
para obtener un resultado distinto en función del valor de msg
End Select
End Sub
Solamente nos queda ver que números genera el icono para el mensaje de retorno. Son unos
valores que Windows ya tiene predispuestos, y que para mayor facilidad de programación ya
hemos introducido en unas constantes. Repetimos aquí el código de declaración de esas
constantes:
(Recuerde que estos valores están en Hexadecimal). Por ejemplo, cuando hacemos clic en el
icono con el botón derecho (R), en el instante de bajar el botón (ButtonDown) se genera como
mensaje de retorno el número 204 en hexadecimal. Ese valor, que no depende de la
programación, sino que es un valor que Windows tiene prefijado, se lo asociamos a una
constante llamada WM_RBUTTONDOWN (La podríamos haber llamado de otra forma, pero
Microsoft la llama así, y si todos la llamamos así existirá cierta semejanza entre el código de
todos los programadores). Luego, en el procedimiento MouseMove del formulario, en vez de
preguntar si el mensaje de retorno vale &H204, preguntamos si vale WM_RBUTTONDOWN
Podemos hacer que el icono del System Tray cambie en determinadas circunstancias. Por
ejemplo, si el programa minimizado es un correo electrónico, podemos hacer que cambie de
color intermitentemente cuando se ha recibido un mensaje nuevo. Esto podemos hacerlo con
un control Timer, donde pondríamos un código parecido a esto:
Picture1 es un array de Pictures con Index del 0 al 3, y cada uno con una imagen del icono
distinta, para producir un efecto agradable. El código siguiente cambia el icono con 4 imágenes
distintas.
Va a encontrar en este capítulo una palabra muy repetida: Clave del registro. (Key) Una
clave del registro es una de las muchas informaciones que existen en el registro. Por
ejemplo:
Esta clave contiene el color de fondo del formulario de la aplicación AgendaTel, y debe
contener un valor, concretamente el número que expresa el color de fondo citado. En el caso
del ejemplo, mi PC contenía el valor “8454016”, (contiene la cadena de caracteres 8454016,
no el número 8.454.016, por eso va entre comillas). Por eso, al tratar ese dato, debe hacerse
pensando que es un string.
Las claves se expresan con una estructura similar a la de las carpetas (directorios) del
explorador de Windows. No es que sea así, ya que el registro es un fichero único, pero su
estructura jerárquica es similar. Por eso, hablaremos de Claves y Subclaves, lo mismo que
hablamos de directorios y subdirectorios (Carpetas y Subcarpetas). Una clave tendrá
subclaves si hay más claves por debajo de su nivel jerárquico. En el ejemplo anterior, la clave
tiene la subclave Colores y esta a su vez tiene la subclave Fondo. La clave Fondo no tiene
subclaves.
Podríamos clasificarlas en dos grupos, uno la de aquellas que sirven para leer y guardar
valores, y otro, con aquellas Apis que sirven para mantenimiento del registro.
La primera operación que debemos hacer para trabajar sobre una clave es abrirla
(Exceptuando lógicamente la operación de crearla). Para abrir una clave se usa el API
RegOpenKeyEx. Al final, una vez realizadas todas las operaciones deseadas, hay que
cerrarla. Se cierra mediante el API RegCloseKey
Handle = Manejador en español, pero esta es una de estas palabras que es mejor no
traducirlas. Utilizaremos la expresión Handle durante todo este capítulo.
Función RegOpenKeyEx
Abre la clave especificada. Es la primera operación que hay que hacer para trabajar con una
clave. (Es similar, en ficheros, a Open NombreFichero For xxx As #n)
Declaración:
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
HKey es el Handle de la clave de nivel superior. Hkey acepta cualquiera de los valores
predefinidos:
Función RegCloseKey
Cierra el Handle de la clave que estamos utilizando. Es la operación que finaliza cualquier
operación de lectura o escritura en el registro. Si hacemos un símil con los ficheros
secuenciales, sería el Close #n
Declaración
Declare Function RegCloseKey Lib "advapi32.dll" Alias "RegCloseKey" (ByVal hKey As Long)
As Long
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
(Estos valores son las constantes citadas en la función anterior.)
Función RegCreateKeyEx
Crea la clave especificada. Si existe ya esa clave, la abre.
LpSubKey es una variable tipo string que contiene el nombre de la subclave a crear.
La subclave no debe empezar por el carácter \. Este parámetro no puede ser nulo.
LpClass Variable tipo string que especifica el tipo de esta clave. Puede poner una
cadena vacía y el tipo de la clave se especificará cuando le introduzca el valor. Este
parámetro se ignora si la clave ya existe.
dwOptions Especifica las opciones especiales de la clave. Puede ser uno de los
siguientes valores:
PhkResult Apunta a una variable que devuelve un Long con el Handle de la clave
creada o abierta, en caso de que ya existiera.
lpdwDisposition Apunta a una variable que devuelve un Long con uno de los
siguientes valores:
Función RegDeleteKey
Borra una clave del registro de Windows. Funciona de forma distinta en W95 que en WNT. En
W95 borra esa clave y todas sus subclaves. En WNT no permite borrar una clave que tenga
subclaves.
HKey Es el Handle de una clave abierta. Puede ser también una de las siguientes
constantes:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
Para crear una clave, primero hay que abrir todas las claves jerárquicamente superiores a esa
clave a crear. En este ejemplo vamos a crear una clave de la siguiente forma:
HKEY_CURRENT_USER/Software/GuiadelEstudiante/Colores
La clave HKEY_CURRENT_USER existe, ya que es una de las de más alto nivel. La clave
Software también existe, ya que vienen predeterminada. La que posiblemente no existe es la
de GuiadelEstudiante, y tampoco la de Colores dentro de ella. Estas claves no existirán en
principio, pero una vez que las hayamos creado, ya pueden existir. Por lo tanto deberemos
Para eliminar una clave debemos utilizar la función RegDeleteKey. La clave inmediatamente
superior a la clave a borrar debe abrirse previamente con RegOpenKey. Y para abrir una clave,
debemos abrir previamente todas las claves jerárquicamente superiores. Para borrar una clave
con subclaves, borramos primero las subclaves. Deberemos ir borrando en orden ascendente.
Una vez borradas las claves, cerramos las claves superiores a la borrada. En el siguiente
ejemplo se borra la clave GuiadelEstudiante y su subclave, Colores
Para que todas estas funciones puedan trabajar es necesario haberlas declarado previamente.
La declaración puede hacerse, o bien en la sección de declaraciones de un módulo, donde las
declararemos como Públicas, o en la sección de declaraciones de un formulario, donde deben
declararse como privadas. Las constantes también se declararán en el mismo sitio que las
funciones. En este caso, se declararon en el formulario:
Option Explicit
Const HKEY_CLASSES_ROOT = &H80000000
Const HKEY_CURRENT_USER = &H80000001
Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_USERS = &H80000003
Const HKEY_CURRENT_CONFIG = &H80000005
Const ERROR_NO_MORE_ITEMS = 259&
Const REG_OPTION_NON_VOLATILE = 0
Const KEY_SET_VALUE = &H2
Const REG_OPTION_BACKUP_RESTORE = 4
Const REG_OPTION_VOLATILE = 1
Const STANDARD_RIGHTS_ALL = &H1F0000
Const SYNCHRONIZE = &H100000
Const READ_CONTROL = &H20000
Const STANDARD_RIGHTS_READ = (READ_CONTROL)
Const STANDARD_RIGHTS_WRITE = (READ_CONTROL)
Const KEY_CREATE_LINK = &H20
Const KEY_CREATE_SUB_KEY = &H4
Const KEY_ENUMERATE_SUB_KEYS = &H8
Const KEY_NOTIFY = &H10
Const KEY_QUERY_VALUE = &H1
Const KEY_READ = ((STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or _
KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE))
Const KEY_WRITE = ((STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or _
KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE))
Const KEY_EXECUTE = (KEY_READ)
Const 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))
Función RegSetValueEx
Guarda un dato en una clave previamente abierta. Con esta función, puede también modificar
el valor y el tipo de información que almacena ese dato.
Declaración
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
(Si declara el parámetro lpData como String, debe pasarlo por valor - By Val lpData As String)
Función RegQueryValueEx
Devuelve el tipo y el valor de un dato almacenado en una clave abierta.
Declaración
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
(Si se declara el parámetro lpData como String, debe pasarse por Valor -By Val).
lpType Apunta a una variable que va a recibir el tipo de dato que contiene. Es un Long,
y devolverá uno de los valores descritos para el valor dwType de la función
RegQueryValueEx. Este valor debe ponerse a Null si no se necesita conocer el tipo de
dato.
lpData Apunta a una variable que recibirá el valor del dato. Esta variable, cuando es
tipo string, hay que declararla con un tamaño prefijado, siempre mayor que el tamaño
del dato que va a recibir (Por ejemplo, Dim MiVariable as String * 100 Se entiende que
el dato que se va a meter en MiVariable nunca será superior a 100 caracteres) También
puede declararse como String sin tamaño, y ponerle posteriormente el tamaño igual a
lpcbData. Vea la explicación de esto en el ejemplo. Si no se necesita conocer el valor
del dato, debe ponerse Null
lpcbData Apunta a una variable que guardará el tamaño del copiado en lpData.
Si la variable lpData no tienen tamaño suficiente para almacenar el valor del dato,
lpcbData devolverá el valor ERROR_MORE_DATA ( = 234)
Sigamos con el ejemplo práctico. Vamos a introducir y leer valores en una clave.
Para poner el valor a un dato de una clave, esa clave debe estar abierta. Se irán abriendo las
claves de forma jerárquica hasta llegar a la clave deseada. Una vez abierta esa clave, se
utilizará la función RegSetValueEx. Luego se cierran todas las claves en orden inverso a la
apertura.
RegCloseKey Manejador3
RegCloseKey Manejador2
RegCloseKey Manejador1
End Sub
Para leer un dato hay que proceder de forma similar, abriendo jerárquicamente las claves hasta
llegar a la clave a leer, y una vez abierta, proceder con la función RegQueryValueEx.
Recuerde que esta función hay que ejecutarla 2 veces para conseguir el valor del dato.
RegCloseKey Manejador3
RegCloseKey Manejador2
RegCloseKey Manejador1
LValorClaveRet = Trim(Var_lpData)
LTamanoValor = Var_lpcbData
End Sub
Podemos aprovechar la primera ejecución de la función para leer el dato lpcbData que nos
indica el tamaño de lpData. A continuación hacemos que la variable Var_lpData tenga ese
tamaño, rellenando tantos caracteres con espacios. Es otra forma de hacer lo mismo.
Declaración
Declare Function RegDeleteValue Lib "advapi32.dll" Alias "RegDeleteValueA" (ByVal hKey As
Long, ByVal lpValueName As String) As Long
RegEnumValue
Esta función devuelve el nombre y el valor de cada uno de los datos contenidos dentro de una
clave previamente abierta. Esta función devuelve el nombre y valor de uno solo de los datos,
por lo que será necesario recurrir a una serie de llamadas en un bucle para obtenerlos todos.
Declaración
Declare Function RegEnumValue Lib "advapi32.dll" Alias "RegEnumValueA" (ByVal hKey As
Long, ByVal dwIndex As Long, ByVal lpValueName As String, lpcbValueName As Long,
lpReserved As Long, lpType As Long, lpData As Any, lpcbData As Long) As Long
lpValueName Apunta a una variable que recibe el nombre del dato, incluido el
carácter nulo de terminación.
Do While Resp = 0
Var_lpValueName = Space(255)
Var_lpData = Space(255)
Var_lpcbValueName = 255
Var_lpcbData = 255
Resp = RegEnumValue(Manejador3, I, Var_lpValueName, Var_lpcbValueName, 0, Var_lpType,
ByVal Var_lpData, Var_lpcbData)
Var_lpValueName = Left(Var_lpValueName, Var_lpcbValueName)
Var_lpData = Left(Var_lpData, Var_lpcbData)
List1.AddItem I & " - " & Trim(Var_lpValueName) & " - " & Trim(Var_lpData)
I=I+1
Loop
RegCloseKey Manejador3
RegCloseKey Manejador2
RegCloseKey Manejador1
End Sub
Función RegEnumKeyEx
Devuelve los nombres de las subclaves de una clave del registro previamente abierta. Esta
función obtiene el nombre de una única subclave cada vez que se le llama, por lo que para
leerlos todos, es necesario recurrir a llamadas en bucle.
Declaración
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, lpftLastWriteTime As FILETIME) As Long
LpcbClass Es el buffer que contiene el tamaño (en caracteres) previsto para LpClas.
Una vez ejecutada la función, contiene el tamaño exacto de LpClas sin contar el
carácter nulo de terminación. Este parámetro debe ser Null solamente cuando
LpClass sea Null
El uso de Apis en una aplicación la hace generalmente más rápida ya que aprovecha recursos
ya existentes en Windows y además compilados. Tiene un pequeño inconveniente cuando se
hace un desarrollo que va a funcionar sobre distintas versiones de Windows. No es normal que
ocurra, pero hay que comprobar que un programa diseñado en W95 corre perfectamente en
W2000. Y es que algunas Apis no son exactamente iguales.
Función EnumPrinters
Declaración
Declare Function EnumPrinters Lib "winspool.drv" Alias "EnumPrintersA" (ByVal flags As Long,
ByVal name As String, ByVal Level As Long, pPrinterEnum As Long, ByVal cdBuf As Long,
pcbNeeded As Long, pcReturned As Long) As Long
Next C
' Presenta el nombre de las impresoras
For C = 0 To NumPrinters - 1
LbPrinters.AddItem PrintInfo(C).pName
Next C
End Sub
De las APIs queda mucho por estudiar. Pero ya debe ser el alumno quien ahonde en ello según
sus propias necesidades. Creo que con lo expuesto hay suficiente para empezar.