Declarar un proceso de DLL.Aunque Visual Basic proporciona un amplio conjunto de declaraciones predefinidas en el archivo Win32api.txt, tarde o temprano querrá saber cómo puede crearlas por sí mismo. Por ejemplo, es posible que desee tener acceso a procedimientos de DLL creados en otros lenguajes o volver a escribir declaraciones predefinidas de Visual Basic para adaptarlas a sus necesidades.
Para declarar un procedimiento de DLL, agregue una instrucción
Declare a la sección Declaraciones de la ventana del código. Si el procedimiento devuelve un valor, escriba la declaración como
Function:
Declare Function nombrePúblico Lib "nombreBiblioteca" [Alias "alias"] [([[ByVal] variable [As tipo] [,[ByVal] variable [As tipo]]...])] As TypeSi el procedimiento no devuelve ningún valor, escriba la declaración como Sub:
Declare Sub nombrePúblico Lib "nombreBiblioteca" [Alias "alias"] [([[ByVal] [/i]variable[/i]
[As tipo] [,[ByVal] variable [As tipo]]...])]De forma predeterminada, los procedimientos de DLL declarados en módulos estándar son públicos y se pueden llamar desde cualquier parte de la aplicación. En cambio, los procedimientos de DLL declarados en otro tipo de módulo son privados para ese módulo y debe identificarlos como tales, precediendo la declaración con la palabra clave
Private.
Los nombres de los procedimientos distinguen mayúsculas y minúsculas en las versiones de 32 bits de Visual Basic. En las versiones anteriores, de 16 bits, no las distinguían.
Especificar la biblioteca.La cláusula
Lib de la instrucción
Declare indica a Visual Basic dónde puede encontrar el archivo .dll que contiene el procedimiento. Si hace referencia a una de las bibliotecas comunes de Windows (User32, Kernel32 o GDI32), no necesita incluir la extensión del archivo:
Declare Function GetTickCount Lib "kernel32" Alias _
"GetTickCount" () As Long
Para otras DLL, la cláusula
Lib es la especificación de un archivo que puede incluir una ruta de acceso:
Declare Function lzCopy Lib "c:\windows\lzexpand.dll" _
(ByVal S As Integer, ByVal D As Integer) As Long
Si no especifica una ruta de acceso para
nombreBiblioteca, Visual Basic buscará el archivo en el orden siguiente:
* Directorio que contiene el archivo .exe
* Directorio actual
* Directorio del sistema de Windows (a menudo, pero no necesariamente, \Windows\System)
* Directorio de Windows (no necesariamente \Windows)
* Variable de entorno de la ruta de acceso.
En la tabla siguiente se muestran los archivos de bibliotecas comunes del entorno operativo:
Biblioteca de vínculo
dinámico -----------------> Descripción.
Advapi32.dll ---> Biblioteca de servicios avanzados de la API que admite múltiples API, incluidas muchas llamadas de seguridad y del Registro.
Comdlg32.dll ---> Biblioteca de la API de diálogos comunes.
Gdi32.dll ---> Biblioteca de la API para dispositivos gráficos.
Kernel32.dll ---> Soporte común de la API base de 32 bits de Windows.
Lz32.dll ---> Rutinas de compresión de 32 bits.
Mpr.dll ---> Biblioteca de enrutadores de múltiples proveedores.
Netapi32.dll ---> Biblioteca de la API para redes de 32 bits.
Shell32.dll ---> Biblioteca de la API para Shell de 32 bits.
User32.dll ---> Biblioteca de rutinas para interfaces de usuario.
Version.dll ---> Biblioteca de versiones.
Winmm.dll ---> Biblioteca multimedia de Windows.
Winspool.drv ---> Interfaz de cola de impresión que contiene las llamadas de la API a la cola de impresión.
Trabajar con procedimientos de la API de Windows que utilizan cadenas.Si trabaja con procedimientos de la API de Windows que utilizan cadenas, debe agregar una cláusula
Alias a las instrucciones
Declare para especificar el juego de caracteres correcto. En realidad, las funciones de la API de Windows que contienen cadenas pueden tener dos formatos: ANSI y Unicode. Por tanto, en los archivos de encabezado de Windows podrá ver las versiones ANSI y Unicode de cada función que contiene una cadena.
Por ejemplo, a continuación se muestran las dos descripciones del lenguaje C para la función
SetWindowText. Observe que la primera descripción define la función como SetWindowTextA, donde la "A" final la identifica como una función ANSI:
WINUSERAPI
BOOL
WINAPI
SetWindowTextA(
HWND hWnd,
LPCSTR lpString);[/b]
La segunda descripción define la función como
SetWindowTextW, donde la "W" final la identifica como una función amplia (wide) o Unicode:
WINUSERAPI
BOOL
WINAPI
SetWindowTextW(
HWND hWnd,
LPCWSTR lpString);
Puesto que ninguna de las funciones se llama en realidad "SetWindowText," debe agregar una cláusula
Alias a la declaración para indicar la función a la que desea hacer referencia:
Private Declare Function SetWindowText Lib "user32" _
Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal _
lpString As String) As Long
Observe que la cadena que sigue a la cláusula Alias debe ser el nombre verdadero del procedimiento (con minúsculas y mayúsculas).
Importante: Para las funciones de la API que utiliza en Visual Basic, debe especificar la versión ANSI de una función, ya que las versiones Unicode sólo son compatibles con Windows NT, no con Windows 95. Utilice las versiones Unicode sólo si sabe con seguridad que las aplicaciones se van a ejecutar sólo en sistemas basados en Windows NT.
Pasar argumentos por valor o por referencia.De forma predeterminada, Visual Basic pasa todos los argumentos por referencia. Esto significa que, en lugar de pasar el valor real del argumento, Visual Basic pasa una dirección de 32 bits donde se almacena el valor. Aunque no necesita incluir la palabra clave
ByRef en las instrucciones
Declare, puede que desee hacerlo para documentar cómo se pasan los datos.
Muchos procedimientos de DLL esperan que se pasen los argumentos por valor. Esto implica que esperan el valor real, en lugar de su ubicación en la memoria. Si pasa un argumento por referencia a un procedimiento que espera un argumento por valor, el procedimiento recibirá datos incorrectos y no funcionará correctamente.
Para pasar un argumento por valor, coloque la palabra clave
ByVal delante de la declaración del argumento en la instrucción
Declare. Por ejemplo, el procedimiento
InvertRect acepta el primer argumento por valor y el segundo por referencia:
Declare Function InvertRect Lib "user32" Alias _
"InvertRectA" (ByVal hdc As Long, _
lpRect As RECT) As Long
También puede usar la palabra clave
ByVal al llamar al procedimiento.
Nota: Si consulta la documentación sobre procedimientos de DLL que utilizan la sintaxis del lenguaje C, recuerde que C pasa todos los argumentos, excepto las matrices, por valor.
Los argumentos de cadena son un caso especial. Pasar una cadena por valor significa que está pasando la dirección del primer byte de datos de la cadena. En cambio, si pasa una cadena por referencia, lo que está haciendo es pasar la dirección de la memoria donde está almacenada otra dirección; la segunda dirección es la que hace referencia realmente al primer byte de datos de la cadena. Para determinar qué enfoque debe usar, vea el tema "Pasar cadenas a un procedimiento de DLL", más adelante en este capítulo.
Nombres no estándar.Ocasionalmente, los procedimientos de DLL tienen un nombre que no es un identificador válido. Puede que el nombre tenga un carácter que no es válido (por ejemplo, un guión) o puede que coincida con una palabra clave de Visual Basic (por ejemplo,
GetObject). En este caso, utilice la palabra clave
Alias para especificar el nombre del procedimiento no válido.
Por ejemplo, algunos procedimientos de los archivos DLL del entorno operativo comienzan con un carácter de subrayado. Aunque puede emplear este carácter en identificadores de Visual Basic, no puede comenzarlos con él. Para usar uno de estos procedimientos, primero debe declarar la función con un nombre válido y después usar la cláusula Alias para hacer referencia al nombre real del procedimiento:
Declare Function lopen Lib "kernel32" Alias "_lopen" _
(ByVal lpPathName As String, ByVal iReadWrite _
As Long) As Long
En este ejemplo, lopen es el nombre del procedimiento al que se hace referencia en los procedimientos de Visual Basic. El nombre _lopen es el nombre reconocido en el archivo DLL.
También puede usar la cláusula
Alias para cambiar el nombre de un procedimiento siempre que sea conveniente. Si escribe otros nombres para los procedimientos (por ejemplo, utiliza WinDir para GetWindowsDirectoryA), asegúrese de que documenta en detalle los cambios para poder actualizar posteriormente el código.
Usar números ordinales para identificar procedimientos de DLL.Además de un nombre, todos los procedimientos de DLL se pueden identificar por un número ordinal que especifica el procedimiento. Algunas DLL no incluyen los nombres de sus procedimientos y requieren la utilización de números ordinales para declarar los procedimientos que contienen. Emplear números ordinales consume menos memoria en la aplicación terminada y es más rápido que identificar los procedimientos de DLL por el nombre.
Importante: El número ordinal de una API específica será diferente con distintos sistemas operativos. Por ejemplo, el valor ordinal para
GetWindowsDirectory es 432 bajo Win95, pero cambia a 338 bajo Windows NT 4.0. En definitiva, si espera ejecutar sus aplicaciones bajo distintos sistemas operativos, no utilice números ordinales para identificar los procedimientos de la API. Este enfoque puede ser también útil en el caso de procedimientos que no pertenecen a la API o en aplicaciones con una distribución muy controlada.
Para declarar un procedimiento de DLL por número ordinal, utilice la cláusula
Alias con una cadena que contenga el carácter de signo numérico (#) y el número ordinal del procedimiento. Por ejemplo, el número ordinal de la función
GetWindowsDirectory tiene el valor 432 en el núcleo de Windows; puede declarar el procedimiento del archivo DLL de la manera siguiente:
Declare Function GetWindowsDirectory Lib "kernel32" _
Alias "#432" (ByVal lpBuffer As String, _
ByVal nSize As Long) As Long
Observe que puede especificar cualquier nombre válido para el procedimiento en este caso, ya que Visual Basic emplea el número ordinal para buscar el procedimiento en el archivo DLL.
Para obtener el número ordinal de un procedimiento que desea declarar, puede usar una herramienta, como Dumpbin.exe, para examinar el archivo .dll. (Dumpbin.exe es una herramienta incluida en Microsoft Visual C++.) Mediante la ejecución de Dumpbin en un archivo .dll, puede extraer información como listas de funciones incluidas en el archivo DLL, sus números ordinales y otros datos sobre el código.
Tipos de argumentos flexibles.Algunos procedimientos de DLL pueden aceptar más de un tipo de datos para el mismo argumento. Si necesita pasar más de un tipo de datos, declare el argumento con la cláusula
As Any para quitar restricciones de tipos.
Por ejemplo, puede pasar el tercer argumento de la siguiente declaración (lppt As Any) como una matriz de estructuras POINT o como una estructura RECT, según sus necesidades:
Declare Function MapWindowPoints Lib "user32" Alias _
"MapWindowPoints" (ByVal hwndFrom As Long, _
ByVal hwndTo As Long, lppt As Any, _
ByVal cPoints As Long) As Long
Aunque la cláusula
As Any ofrece flexibilidad, también presenta riesgos ya que desactiva toda la comprobación de tipos. Sin esta comprobación, es probable que llame al procedimiento con el tipo equivocado, lo que puede tener como resultado varios problemas, entre ellos un error de la aplicación. Asegúrese de comprobar detenidamente los tipos de todos los argumentos si utiliza la cláusula
As Any.
Si quita las restricciones de tipos, Visual Basic supondrá que el argumento se pasa por referencia. Incluya
ByVal en la llamada real al procedimiento para pasar los argumentos por valor. Las cadenas se pasan por valor, por lo que se pasa un puntero a la cadena, en lugar de pasar un puntero a otro puntero. Para obtener más información al respecto, vea la sección "Pasar cadenas a un procedimiento de DLL".