domingo, 19 de enero de 2014

El entorno Visual Basic VIII

Hay ocasiones en las cuales desde un programa de aplicación de Visual Basic es deseable abrir algún programa ejecutable o algunos de los programas accesorios que forman parte de los recursos adicionales que Windows trae consigo, y un ejemplo de ello sería el poder invocar y abrir la calculadora que viene incluída en Windows con el propósito de que el usuario pueda efectuar algunas operaciones aritméticas para poder obtener algún resultado intermedio necesario para poder continuar adelante con el programa de aplicación. Para cosas como ésta, Visual Basic incluye una función llamada Shell() cuya sintaxis es:

variable = Shell(programa , estilo)

en donde programa es la ruta completa que conduce hacia el programa ejecutable y estilo es un número entero con el que se especifica el estilo que será usado para la ventana con la que será abierto el programa, pudiendo ser una ventana maximizada. Si estilo tiene un valor de 1, 5 ó 9, el estilo de la ventana es el normal con enfoque. Si estilo tiene un valor de 2, la ventana del programa será minimizada manteniendo el enfoque; este es el valor predeterminado por Visual Basic en caso de que el programador no especifique valor alguno para estilo. Si estilo tiene un valor de 3, la ventana del programa es maximizada manteniendo el enfoque. Si estilo tiene un valor de 4 ó de 8, a la ventana del programa se le dá un tamaño normal pero sin darle el enfoque. Y si estilo tiene un valor de 6 ó 7, la ventana del programa es minimizada sin darle el enfoque.

En el siguiente ejemplo, meteremos dentro de una forma que será titulada “Selector de Programas” dos cajas de imagen y dos botones. Con la primera caja de imagen se invocará el procedimiento de evento Click() de dicha caja de imagen para abrir el Bloc de Notas que viene incluída con el sistema operativo Windows XP, con la segunda caja de imagen se invocará el procedimiento de evento Click() de dicha caja de imagen para abrir la calculadora que viene incluída también con el sistema operativo Windows XP, poniendo íconos de imagen representativos dentro de las cajas de imagen y fijando la propiedad BorderStyle de ambas cajas a “0-None” para remover el recuadro de borde trazado en torno a los íconos de imagen. Con el primer botón se invocará el procedimiento Click() de dicho botón para abrir el programa de trazados gráficos Paint que viene incluído con el sistema operativo Windows XP, y con el segundo botón se invocará el procedimiento Click() de dicho botón para abrir un programa titulado DEX para llevar a cabo el Diseño y Análisis de Experimentos, seguramente diseñado por algún programador avezado usando Visual Basic u otro entorno o lenguaje de programación. El código respectivo para los cuatro objetos metidos dentro de la forma es el siguiente:


   Sub Picture1_Click ()

      A = Shell("C:\WINDOWS\system32\notepad.exe", 1)

   End Sub


   Sub Picture2_Click ()

   B = Shell("C:\WINDOWS\system32\calc.exe")

   End Sub


   Sub Command1_Click ()

      C = Shell("C:\WINDOWS\system32\mspaint.exe", 1)

   End Sub


   Sub Command2_Click ()

      D = Shell("C:\WINDOWS\dex.exe", 1)

   End Sub


Obsérvese que en los cuatro casos en los que se usa la función Shell es necesario efectuar una asignación, la función no puede ser invocada por sí sola sin hacer la asignación.

Al ejecutar el programa, veremos una ventana como la siguiente:




Una vez que el programa se está ejecutando, si hacemos clic con el Mouse en la imagen que representa el Bloc de Notas se abrirá el Bloc de Notas; si hacemos clic con el Mouse en la imagen que representa a la calculadora Windows, se abrirá la calculadora. Y si hacemos clic con el Mouse en el botón que corresponde a Paint, se abrirá el programa Paint de Windows, mientras que si hacemos clic con el Mouse en el botón que corresponde a DEX, se abrirá un programa estadístico especializado llamado DEX que ciertamente no viene incluído en Windows y tuvo que haber sido instalado previamente en la máquina mediante algún procedimiento automatizado previo de instalación, un programa que seguramente trajo incluído el “Selector de Programas”.

Es posible que, además de abrir con Shell desde un programa de aplicación elaborado con Visual Basic otro programa ejecutable, queramos enviar unas “opresiones de teclas” al programa abierto con Shell, opresiones de teclas como las que llevaríamos a cabo al usarlo directamente, empezando de este modo el programa invocado de una forma predeterminada. Para este propósito, usamos el enunciado SendKeys. La sintaxis de este enunciado es:

SendKeys  textotecla  espera

en donde textotecla es la expresión de hilera enviada a la ventana activa, y espera es una expresión numérica lógica que puede ser True o False. Si espera es True, las opresiones programadas de teclas tienen que ser procesadas antes de que el control le sea regresado al procedimiento que llevó a cabo la invocación, si espera es False, el control es regresado inmediatamente antes de que las opresiones programadas de teclas sean enviadas.

Cada envío de opresión de tecla es representado por uno o más caracteres. Para especificar un solo caracter del teclado, úsese el caracter encerrado entre dobles comillas y en caso de ser neceario enciérrese entre corchetes. Si se va a representar la tecla A, úsese "A" para textotecla. Si se va a representar más de un caracter, se anexa cada caracter adicional al que lo precede. Para representar las letras A, B y C, usamos "ABC" para textotecla.

El signo de más (+), el carete (^), el signo de porcentaje (%), la tilde (~) y los paréntesis tienen significados especiales para el enunciado SendKeys. Para especificar uno de estos caracteres en particular, se les encierra entre corchetes. Por ejemplo, para usar el signo de más, se le encierra entre dos corchetes. Los paréntesis rectangulares ([]) no tienen ningún significado especial para SendKeys, pero de cualquier modo también tienen que ser encerrados entre corchetes porque en otras aplicaciones para Microsoft Windows los paréntesis rectangulares sí tienen un significado especial que puede ser importante cuando ocurre en algunos programas (obsoletos) lo que se conoce como Intercambio Dinámico de Datos DDE (Dynamic Data Exchange).

Para especificar caracteres que no se muestran en la pantalla cuando se opresiona una tecla (como la tecla de Introducción ENTER o la tecla del tabulador TAB) se recurre a los códigos que se muestran en la siguiente tabla:


Tecla Código Tecla Código
 Backspace
 (Atrás)
 {BACKSPACE} ó
 {BS} ó {BKSP}
 Break  {BREAK}
 Caps Lock  {CAPSLOCK}  Clear  {CLEAR}
 Del  {DELETE} ó
 {DEL}
 Down arrow
 (flecha abajo)
 {DOWN}
 End  {END}  Enter   {ENTER} ó ~ 
 Esc  {ESCAPE} ó
 {ESC}
 Help  {HELP}
 Home  {HOME}  Ins  {INSERT}
 Left Arrow
 (flecha izq)
 {LEFT}  Num Lock  {NUMLOCK} 
 Page Down   {PGDN}  Page Up  {PGUP}
 Print Screen   {PRTSC}  Right arrow
 (flecha der.)
 {RIGHT}
 Scroll Lock   {SCROLLLOCK}  Tab  {TAB}
 Up Arrow  {UP}  F1  {F1}
 F2  {F2}  F3  {F3}
 F4  {F4}  F5  {F5}
 F6  {F6}  F7  {F7}
 F8  {F8}  F9  {F9}
 F10  {F10}  F11  {F11}
 F12  {F12}  F13  {F13}
 F14  {F14}  F15  {15}
 F16  {F16}  


Para especificar opresiones de teclas combinadas con cualquier combinación (valga la redundancia) de teclas SHIFT, CTRL, y ALT, se debe preceder el código regular con uno o más de los siguientes códigos:


Tecla  Código
 SHIFT +
 CONTROL ^
 ALT %


A continuación se muestra el siguiente ejemplo del uso del enunciado SendKeys:


   Sub Form_Click ()

      Dim I, X

      X = Shell("Calc.exe", 1)

      For I = 1 To 100
   
         SendKeys I & "{+}", True

      Next I

      SendKeys "=", True

      AppActivate "Microsoft Visual Basic"

      Msg = "Oprime OK para cerrar la calculadora"

      MsgBox Msg

      AppActivate "Calculator"

      SendKeys "%{F4}", True

   End Sub


El programa invoca la calculadora de Microsoft Windows para llevar a cabo la evaluación de la serie aritmética:

1 + 2 + 3 + 4 + 5 + 6 + 7 + ...

de modo tal que el usuario pueda “ver en vivo” la suma cumulativa conforme se está llevando a cabo. En primer lugar, con la instrucción:

X = Shell("Calc.exe", 1)

se hace la invocación de la calculadora de Microsoft Windows. A continuación, mediante el bucle:

      For I = 1 To 100
   
         SendKeys I & "{+}", True

      Next I

se envía primero una opresión de la tecla 1 de la calculadora seguida de una opresión (obsérvese el uso del signo de concatenación de hileras &) de la tecla de suma de la calculadora. Al repetirse el bucle con I igual a 2, se hace una opresión de la tecla 2 de la calculadora seguida de una opresión de la tecla de suma de la calculadora, con lo cual se suma el 2 al 1 que había antes obteniéndose en la calculadora la suma cumulativa 3. El proceso es repetido hasta que I toma el valor de 100 que es el último en ser usado en el bucle para la suma cumulativa. Tras esto, la instrucción:

SendKeys "=", True

hace que se envíe una opresión de la tecla de igual de la calculadora, para producir el resultado final de la suma cumulativa, tal y como lo haríamos nosotros mismos si estuviésemos usando la calculadora de Microsoft Windows.

Hecho lo anterior, regresamos el enfoque al entorno de Visual Basic con la instrucción:

AppActivate "Microsoft Visual Basic"

Esta instrucción utiliza el enunciado AppActivate, el cual en una situación en la cual están abiertos varios programas activa la ventana de aplicación que tenga por título la hilera de texto puesta entre las dobles comillas. La sintaxis de AppActivate es obviamente:

AppActivate  títuloventana

El título de la ventana es precisamente el mismo título que le damos a una forma con la propiedad Caption y es además el título que se le dá a los programas ejecutables que se corren en un sistema operativo Windows. Así pues, tenemos aquí un nuevo uso del título de los programas.

La razón por la cual devolvemos el enfoque al entorno Visual Basic con AppActivate es para que se pueda imprimir la caja de mensajes especificada por las instrucciones:

      Msg = "Oprime OK para cerrar la calculadora"

      MsgBox Msg

Una vez que el usuario (o en este caso y mejor dicho, el programador) cierra la caja de mensajes oprimiendo el botón OK, el enfoque de las ejecuciones es devuelto a la calculadora con la instrucción:

SendKeys "%{F4}", True

Obsérvese que, de acuerdo con las tablas y las indicaciones que se han dado arriba, esto simula la opresión simultánea de la tecla ALT y la tecla de función F4, que es precisamente la combinación de teclas con las cuales se cierra la calculadora de Microsoft Windows. No se requiere de ninguna otra instrucción, porque una vez cerrada la calculadora el enfoque es regresado automáticamente por el sistema operativo Windows al entorno Visual Basic.

Con el entorno Visual Basic aparentemente podemos construír una gran variedad de programas que pueden hacer prácticamente cualquier cosa. Y en efecto, podemos construír muchas aplicaciones prácticas. Sin embargo, Visual Basic tiene sus limitaciones, y una de ellas es que carece de la suficiente penetración como para poder inquirir en detalle sobre lo que sucede al nivel del hardware, al nivel de la electrónica de la máquina.

En las versiones de BASIC que aparecieron en las computadoras que precedieron a las computadoras personales basadas en arquitecturas como las que introdujo la empresa IBM en sus modelos IBM PC XT e IBM PC AT, había enunciados disponibles como PEEK y POKE que permitían echar un “vistazo” a lo que había en cualquier parte de la memoria activa RAM de la computadora, e inclusive se podía meter algo directamente en cualquier localidad de la memoria de la computadora. Pero cualquiera que haya tenido en sus manos los manuales de alguna versión de Visual Basic tal vez se haya dado cuenta de que en Visual Basic no existe nada equiparable a los comandos PEEK y POKE. No se trata de una omisión deliberada de parte de los creadores de Visual Basic. Después de todo, poner un recurso como éste en manos de un programador inexperto que no sabe bien lo que está haciendo puede mandar abajo la máquina e inclusive puede dañar partes importantes en las rutinas del sistema operativo a grado tal que se requiera instalar de nueva cuenta el sistema operativo en el disco duro de la máquina perdiéndose lo que ya se tenía almacenado previamente.

Supongamos, por ejemplo, que queremos elaborar un programa para saber cuánta memoria hay disponible para ejecutar programas. En un principio, al encender la máquina, su memoria RAM no tiene absolutamente nada en ninguno de sus domicilios, todo está vacío con una distribución aleatoria de unos y ceros que resultan del encendido eléctrio. Después de que el hardware de la máquina, bajo la dirección del firmware (memoria de lectura únicamente ROM) verifica que todos los espacios de bits de la memoria RAM almacenan correctamente los “unos” y “ceros” (esto es lo que se conoce como la prueba de la memoria), las rutinas esenciales del sistema operativo son cargadas en la memoria RAM. Si la memoria RAM del hardware es de 256K bytes, al cargarse un sistema operativo como Windows XP o Linux posiblemente queden únicamente 180K bytes disponibles para ejecución de programas. Abriendo un programa, lo cual requerirá que se le adjudique parte de la memoria RAM, tal vez queden unos 100K bytes disponibles. Abriendo un segundo programa sin cerrar el primero, también requerirá que se le adjudique otra porción de la memoria RAM disponible, lo cual hará que tal vez queden ya unos 80K bytes disponibles. Eventualmente, al ir abriendo más programas, el sistema operativo tal vez se quejará enviándole un mensaje de protesta al usuario diciéndole que no hay suficiente memoria RAM para la ejecución de algún programa, indicándole que se tiene que cerrar algunos de los programas abiertos para que haya espacio suficiente en la máquina para poder correr el programa que se desea. Obviamente, hay ocasiones en las cuales resulta de interés saber cuánta memoria RAM queda disponible.

Pero si queremos elaborar un programa Visual Basic para poder estar checando cuánta memoria RAM queda disponible en cierto momento, veremos que no hay enunciado alguno que nos permita acceder directamente a estos recursos del hardware. En este sentido, Visual Basic hace un buen trabajo en “blindar” los detalles internos de la máquina tanto del usuario como del mismo programador. Un buen lenguaje de alto nivel como FORTRAN, COBOL, PL/1 y Pascal es portátil en el sentido de que, si está escrito correctamente, puede ser ejecutado en distintos tipos de máquinas con distintos tipos de arquitecturas de hardware sin problema alguno, ya el compilador usado para cada máquina (y en este sentido, cada compilador será distintO) se encargará de convertir el código fuente en el código binario ejecutable adecuado para cada tipo de máquina y procesador CPU. La portabilidad de los lenguajes de alto nivel es, en principio, universal. Pero precisamente por lo mismo, y a diferencia de lo que ocurre con los lenguajes ensambladores, no es posible tener ni siquiera la más remota idea del tipo de arquitectura de la máquina en la que se está ejecutando un programa cuando todo se lleva a cabo desde un lenguaje de alto nivel como FORTRAN o COBOL.

Podemos construír un programa en Visual Basic que nos permita saber cuánta memoria RAM hay disponible en una máquina en cierto momento. Pero para ello nos vemos obligados a echar mano de otros recursos que no forma parte de Visual Basic en sí, se trata de recursos que le pertenecen al sistema operativo Windows, recursos que en un principio fueron agrupados en lo que se dió en llamar Interfaz de Programación de Aplicaciones que en el caso de Windows era el API de Windows o Windows API, también conocida simplemente como Win API.

Se trata de una colección masiva de funciones, accesibles todas ellas en alguna de las bibliotecas de enlazado dinámico del sistema operativo Windows, que permiten tomar un control directo de la máquina, inclusive al nivel del hardware.

Es muy importante resaltar que la enorme colección de funciones del Windows API ya estaba disponible desde antes de que Windows se constituyera en todo un sistema operativo con Windows 95. En efecto, ese enorme arsenal de funciones archivado bajo bibliotecas de enlazado dinámico DLL formaba parte de lo que era únicamente una interfaz visual, la interfaz visual Windows invocable desde el sistema operativo MS-DOS, alcanzando un alto grado de perfeccionamiento con Windows 3.1 (la última versión de Windows que era únicamente una interfaz visual y no un sistema operativo), y ya para ese entonces Visual Basic también estaba desarrollado y disponible para elaborar programas ejecutables bajo la interfaz visual Windows, de modo tal que la promoción de Windows de interfaz visual a sistema operativo (con la introducción de Windows 95) en realidad se trató de una oficialización de algo que ya casi era en los hechos un sistema operativo; lo único que permitía distinguir que antes de la promoción Windows era una mera interfaz visual es que después de arrancar la marcha e instalarse en la memoria RAM el sistema operativo MS-DOS (o equivalentemente, el sistema operativo PC-DOS, ambos elaborados por Microsoft), la interfaz visual Windows tenía que ser invocada desde la línea de comandos con una instrucción como:

 C:> win                            

Para poder construír con Visual Basic un programa para poder determinar la cantidad de memoria RAM libre que hay en cierto momento, tenemos que echar mano de una función Function y una subrutina Sub que forman parte del Windows API:

GetFreeSpace()

MessageBox()

Tanto la función como la subrutina tienen que ser declaradas usando una palabra reservada de Visual Basic, Declare, y las dos declaraciones tienen que ser puestas en un módulo independiente como MODULE1.BAS, de la siguiente manera (obsérvese que en el segundo caso estamos recurriendo a la convención de Visual Basic que permite con fines de legibilidad que una instrucción muy larga se pueda separar en varias líneas siempre y cuando al final de cada línea intermedia se ponga al fina de la línea un espacio en blanco y un signo de subrayado):

   Declare Function GetFreeSpace Lib "Kernel" (ByVal n As Integer) _
      As Long

   Declare Sub MessageBox Lib "User" (ByVal h As Integer, _
      ByVal Hilera1 As String, ByVal Hilera2 As String, _
      ByVal n As Integer)

Una vez declaradas las dos funciones del Windows API, en la forma tenemos que meter el siguiente código:

   Sub Form_Load ()

      Dim S As String
      Dim M As Long
      Dim MS As String

      M = GetFreeSpace(0)

      MS = Str$(M)

      S = "La memoria RAM disponible es: " & MS

      MessageBox hWnd, S, "MEMORIA RAM DISPONIBLE", 0

   End Sub

Si corremos lo anterior, obtendremos una ventana como la siguiente (esto se llevó a cabo en una máquina con 512 Mb de RAM total y un sistema operativo Windows XP instalado en ella):




Repasemos lo anterior en mayor detalle.

El programa invoca dos funciones del     WinAPI , GetFreeSpace y MessageBox para presentarnos la memoria RAM disponible, dándonos el resultado en una caja de mensajes titulada "MEMORIA RAM DISPONIBLE".

Una diferencia sutil pero importante es que la caja de mensajes no fue producida mediante la función definida dentro de Visual Basic para producir cajas de mensajes. En efecto, el nombre de la rutina Visual Basic para producir una caja de mensajes es MsgBox, mientras que el nombre de la rutina del Windows API para producir cajas de mensajes es MessageBox, lo cual dicho sea de paso permite evitar confundirlas dentro de un programa Visual Basic. Esta es la razón por la cual las rutinas en Visual Basic tienen designaciones similares pero diferentes a sus equivalentes en el Windows API.

Haremos ahora una afirmación categórica: Todas las rutinas del Windows API son accesibles desde Visual Basic, siempre y cuando cada rutina utilizada dentro de un programa de Visual Basic sea declarada en la manera como se muestra arriba.

La sintaxis de las declaraciones de las funciones del Windows API es rígida y no admite omisiones ni alteraciones. Y basta ver la sintaxis completa de las declaraciones de las funciones GetFreeSpace() y MessageBox() dadas arriba para darse cuenta de que dichas funciones pueden contener una gran variedad de detalles, sobre todo en los argumentos. Para un programa tan sencillo como el determinar la cantidad de memoria RAM libre, solo usamos dos funciones del Windows API. Pero en un programa Visual Basic que invoque unas 200 ó 400 rutinas del Windows API, el colectivo conjunto de cada declaración individual puede constituirse fácilmente en una pesada carga de trabajo para el programador. Esta es una de las razones por las cuales podía ser preferible recurrir a otro lenguaje de programación, el lenguaje C, que dicho sea de paso era ya el lenguaje sobre el cual estaban definidas las funciones del Windows API. Todo lo que hemos hecho con Visual Basic se podía lograr igualmente con otro entorno como Visual C++ como el entorno Borland C++, pero requiriendo una mayor destreza en la elaboración de programas ejecutables de calidad profesional.

Observando lo siguiente en las declaraciones dadas a Visual Basic:

   Declare Function GetFreeSpace Lib "Kernel" (ByVal n As Integer) _
      As Long

   Declare Sub MessageBox Lib "User" (ByVal h As Integer, _
      ByVal Hilera1 As String, ByVal Hilera2 As String, _
      ByVal n As Integer)

podemos ver que al declarar dentro de Visual Basic una rutina del Windows API hay que especificar la biblioteca en la cual se encuentra la rutina. En el caso de GetFreeSpace dicha función se encuentra especificada bajo la biblioteca "Kernel", como podemos leerlo en la declaración dada arriba, mientras que en el caso de la función MessageBox dicha función se encuentra especificada bajo la biblioteca "User" (hay muchas otras funciones especificadas dentro de estas bibliotecas). De hecho, lo anterior es aplicable a Windows 3.1, la interfaz visual que contenía los siguientes archivos:

        KERNEL.EXE

        USER.EXE

        GDI.EXE

Estos “programas ejecutables” en realidad no son simples programas ejecutables como erróneamente nos lo sugiere su extensión .EXE (haciendo clic con el Mouse en cualquiera de ellos no se pone en marcha nada que pueda interactuar con el usuario). Son verdaderas bibliotecas de rutinas del Windows API, posteriormente conocidas como bibliotecas de enlazado dinámico DLL. En un principio, todas las funciones del Windows API se encontraban en una de esas tres bibliotecas a espera de ser invocadas. Y ya cuando Windows se solidificó como sistema operativo, aumentó en forma considerable el número de funciones disponibles. Al llegar a los sistemas operativos de 32 bits, con Windows XP, en la siguiente ruta:

C:\WINDOWS\system32

podemos encontrar bibliotecas de enlazado dinámico DLL como las siguientes:

comdlg32.dll

gdi32.dll

kernel32.dll

iesetup.dll

user32.dll

vbscript.dll

winfax.dll

Por los nombres usados, el lector puede intuír el propósito de estas bibliotecas de enlazado dinámico bajo Windows XP. En el caso de “comdlg32.dll”, esta biblioteca es usada para proveer varias funciones necesarias para producir cajas de diálogo común. En el caso de “gdi32.dll”, se trata de la versión de GDI.EXE usada en la interfaz visual Windows 3.1 pero actualizada para el procesamiento en 32-bits de Windows XP. En el caso de “iesetup.dll”, podemos intuír que se trata de una biblioteca usada para funciones de actualización del navegador Internet Explorer. En el caso de “user32.dll”, se trata de la versión de USER.EXE usada en la interfaz visual Windows 3.1 pero actualizada para el procesamiento en 32-bits de Windows XP. En el caso de “vbscript.dll” podemos intuir que se trata de una biblioteca usada para proporcionar el procesamiento de funciones propias del lenguaje VBScript usado en el navegador Internet Explorer. Y en el caso de “winfax.dll”, podemos intuír que se trata de una biblioteca usada para proporcionar funciones para el manejo de máquinas de fax conectadas a la computadora. Dentro de cada biblioteca puede haber decenas, o inclusive cientos de funciones.

La declaración de funciones del Windows API dentro de programas de Visual Basic es más elaborada de lo que el lector pudiera suponer. Por principio de cuentas, se tiene que consultar la declaración del prototipo de las rutinas en algún archivo de cabecera (esto se estudia en mayor detalle al aprender el lenguaje C). A modo de ejemplo, las rutinas GetFreeSpace y MessageBox aparecen declaradas en el archivo de cabecera WINDOWS.H como sigue:

   DWORD WINAPI GetFreeSpace (UINT)

   int WINAPI MessageBox (HWND, LPCSTR, LPCSTR, UINT)

De estas declaraciones se sabe que la función GetFreeSpace regresa una palabra binaria de tamaño DWORD, y se le tiene que proporcionar como argumento un número entero sin signo (UINT, Unsigned Integer) como sigue:

GetFreeSpace(0)

mientras que a MessageBox hay que proporcionarle un argumento del tipo HWND, dos argumentos de hilera del tipo LPCSTR, y un argumento del tipo UINT como sigue:

MessageBox hWnd, S, "MEMORIA RAM DISPONIBLE", 0

Obtenidas las declaraciones de las dos funciones del archivo de cabecera WINDOWS.H, consultando tablas o mediante operaciones de copiado y empastado hay que hacer la conversión de tipos para poner las funciones del Windows API en la sintaxis que requiere Visual Basic para poder “entenderlas” (estamos usando aquí la convención de poner un espacio seguido de un guión bajo para continuar una instrucción muy larga hacia otras líneas de texto, convención que desafortunadamente no es reconocida por todas las versiones de Visual Basic):

   Declare Function GetFreeSpace Lib "Kernel" (ByVal n As Integer) _
      As Long

   Declare Sub MessageBox Lib "User" (ByVal h As Integer, _
      ByVal Hilera1 As String, ByVal Hilera2 As String, _
      ByVal n As Integer)

y usamos para esto el declarador interno ByVal. Dentro de Visual Basic, los cuatro argumentos proporcionados a la función MessageBox son, respectivamente, un entero, dos hileras, y otro entero:

   ByVal h As Integer

   ByVal Hilera1 As String

   ByVal Hilera2 As String

   ByVal n As Integer

Se sobreentiende también que se tiene que determinar la biblioteca a la cual pertenece una función del Windows API para que pueda ser declarada dentro de Visual Basic (“KERNEL”, “USER”, “GDI”, “KERNEL32”, etc.). En el caso de GetFreeSpace y MessageBox, esto se sabe consultando también el archivo de cabecera WINDOWS.H.

Obsérvese que al invocar la rutina MessageBox del Windows API desde Visual Basic, utilizamos como primer parámetro la palabra hWnd. En relación a esto, hWnd y hDC son palabras reservadas en Visual Basic, no se pueden usar para otra cosa más que aquello para lo que son  usadas.

El programa Visual Basic que se dió arriba en realidad no tiene mucho chiste. Con el evento Load() de la forma Form se usa la función GetFreeSpace para determinar la memoria RAM libre disponible, y una vez obtenida como número entero de tipo Long se le asigna a la variable M declarada también como de tipo Long. Con la función de conversión a hilera tomamos Str$(M) y obtenemos una hilera de texto que asignamos a la variable MS (declarada como hilera) que representa al número entero M de tipo Long. Tras esto se forma una hilera combinada concatenando el texto "La memoria RAM disponible es: " con MS, e imprimimos una caja de mensajes titulada "MEMORIA RAM DISPONIBLE" que nos produce el resulado mostrado arriba.

Se repite que no existió ningún evento, método, propiedad, enunciado o función dentro de Visual Basic como la función GetFreeSpace del Windows API que nos diera la memoria RAM residual libre, y de hecho esta función quedó obsoleta al ser subtituída por la función GlobalMemoryStatus. Lo mismo ocurrió con muchas otras funciones del Windows API capaces de hacer cosas fuera del ámbito de Visual Basic. Aunque la programación en otro entorno basada en un lenguaje como el lenguaje C o una variante ampliada del mismo lenguaje C (que dicho sea de paso, es el lenguaje en el cual está basada la sintaxis de la declaración de los prototipos y funciones del Windows API) siempre se ha antojado intimidante, fue necesario aceptar la realidad de que Visual Basic no reemplazó la necesidad de tener que recurrir a otros entornos de alto nivel como (Borland C++) capaz de interactuar directamente con el hardware de la máquina y capaz de complementar las carencias de Visual Basic. Es por esto que Visual Basic recibió su ayuda externa al ser integrado en lo que se conoció como Visual Studio, lo cual evolucionó a Visual .NET al tomarse conciencia de que la computadora personal casera desconectada del resto del mundo dejó de serlo al empezar a conectarse a Internet para pasar a formar parte de la red de redes.

Estamos en condiciones de poder asentar a continuación la sintaxis del enunciado Declare. Lo haremos primero para las rutinas Sub:

   Declare Sub  nombreglobal  Lib  biblioteca _
        (ByVal variable As Type, ...)

En el caso de las rutinas Function la sintaxis es:

   Declare Function  nombreglobal  Lib  biblioteca _
        (ByVal variable As Type, ...) As Type

Usamos el enunciado Declare para declarar procedimientos externos a Visual Basic, esto es, procedimientos contenidos en una biblioteca de enlazado dinámico. Un enunciado Declare para un procedimiento externo puede aparecer una sola vez en la sección de declaraciones de una forma o módulo. Los procedimientos DLL declarados en cualquier módulo están disponibles a todos los procedimientos en todas las formas y en todos los módulos, pero los procedimientos DLL declarados en una forma solo están disponibles a los procedimientos en la forma.

Los paréntesis vacíos indican que un procedimiento Sub o Function no tiene argumentos. y los argumentos deben ser cotejados para asegurarse de que no se pase ninguno. En el siguiente ejemplo, Ajedrez no toma argumentos, y si se usan argumentos en una invocación a Ajedrez ocurrirá un error:

Declare Sub Ajedrez Lib "MiAjedrez" ( )

Cuando aparece una lista de argumentos, el número y el tipo de argumentos son checados cada vez que el procedimiento es invocado. En el siguiente ejemplo, Ajedrez toma un argumento de tipo Long (evidenciado por el sufijo & colocado después de la variable):

Declare Sub Ajedrez Lib "MiAjedrez" (A&)

El siguiente ejemplo usa el enunciado Declare para declarar una referencia a la función externa GetProfileString (usada para obtener el perfil internacional de la máquina) almacenada en la biblioteca KERNEL del sistema operativo Windows (pondremos todo el código dentro de la forma, el enunciado Declare en la sección de declaraciones de la forma, y el código dentro del procedimiento de evento Load():


   Declare Function GetProfileString Lib "Kernel" _
        (ByVal SNombre$, ByVal KNombre$, ByVal Def$, _
         ByVal Ret$, ByVal Tamano%) As Integer


   Sub Form_Load ()

      Dim Msg
      Dim KNombre$, Ret$, SNombre$
      SNombre$ = "Intl"
      KNombre$ = "sCountry"
      Ret$ = String$(255, 0)

      Exito = GetProfileString(SNombre$, KNombre$, "", Ret$, Len(Ret$))

      If Exito Then

         Msg = "El codigo de tu pais es: " & Ret$

      Else

         Msg = "No hay codigo de tu pais en tu archivo WIN.INI."

      End If

      MsgBox Msg

   End Sub

Los resultados obtenidos con la ejecución del programa dependen de lo que esté consignado en el archivo WIN.INI para la máquina que está siendo usada con el sistema operativo propio del país en el que se esté usando. Un resultado podría ser una caja de mensajes que dice:

El codigo de tu pais es: United States

Así como lo que se conoce como la programación Windows empezó con bibliotecas de enlazado dinámico usadas para invocar funciones propias de la interfaz visual Windows, antes de que Windows hiciera su aparición también se usaban funciones accesibles en paquetes como COMMAND.COM del sistema operativo DOS con las cuales se podían efectuar manipulaciones cercanas al nivel del hardware de la máquina.

Hay otra manera de poner en marcha las funciones del Windows API, y esta consiste en usar el enunciado Call, el cual puede transferir el control de un programa a un procedimiento Sub de Visual Basic, o lo que más nos interesa, a un procedimiento de una biblioteca de enlazado dinámico.  El programador no necesariamente tiene que usar la palabra reservada Call para poner en marcha un procedimiento, aunque puede hacerlo si quiere presumir de elegancia y formalidad.

En el siguiente ejemplo usaremos una rutina disponible en la biblioteca de enlazado dinámico USER.EXE, la rutina MessageBeep que activa la bocina de las computadoras personales, para producir un tono audible. Se mostrarán dos maneras de hacer un llamado a dicha rutina, una usando Call y la otra no usándolo.


   Declare Sub MessageBeep Lib "User" (ByVal N As Integer)


   Sub Form_Click ()

      Dim I

      Call MessageBeep(0)

      For I = 1 To 1000
      Next I

      MessageBeep 0

   End Sub

Si se corre el programa, cada vez que se haga clic en la computadora sonará un tono. Pero si se borran las líneas que contienen MessageBeep el tono no se escuchará. Aquí es importante observar que en Visual Basic también hay un enunciado para producir un tono audible, el enunciado Visual Basic Beep, el cual no requiere que se haga una declaración invocando con Declare la función MessageBeep del Windows API. Para una cosa así, es preferible usar el enunciado Visual Basic que invocar una función de la interfaz Windows API. Después de todo, se trata de cosas diferentes que logran lo mismo. Pero si logran lo mismo al nivel del hardware, ¿realmente son diferentes? Aquí es donde el lector puede empezar a sospechar que el entorno Visual Basic en realidad actúa como una concha que esconde los detalles desagradables y complejos requeridos ultimadamente para hacer uso de lo que Windows, ya sea como mera interfaz visual (Windows 3.1) o como sistema operativo (Windows 98, Windows XP, etc.), tiene que ofrecer.

El siguiente programa hace uso de la rutina FloodFill del Windows API que está archivada en la biblioteca de enlazado dinámico GDI:


   Declare Sub FloodFill Lib "GDI" (ByVal hDC As Integer, _
      ByVal X As Integer, ByVal Y As Integer, _
      ByVal Color As Long)


   Sub Form_Click ()

      ScaleMode = 3
      ForeColor = 0
      Line (100, 50)-(300, 50)
      Line -(200, 200)
      Line -(100, 50)
      FillStyle = 0
      FillColor = RGB(128, 128, 255)
      FloodFill hDC, 200, 100, ForeColor

   End Sub


El programa anterior, recurriendo a los métodos Line, traza primero un triángulo, y especificándose un color de llenado con FillColor se llena dicho triángulo con el color especificado, produciendo algo como lo que se muestra a continuación:




Se ha mencionado arriba el archivo de cabecera WINDOWS.H. Este es el archivo de cabecera no para ser usado por el entorno Visual Basic sino para proporcionar en una sintaxis apropiada al lenguaje C los prototipos y declaraciones de funciones necesarias para llevar a cabo una verdadera programación Windows en lenguaje C. Mucho antes de que Windows hiciera su aparición, cuando en las primeras computadoras personales caseras todo se llevaba a cabo en una interfaz basada en líneas de comandos al estilo PC-DOS y MS-DOS, y de hecho antes que esto cuando se usaba el sistema operativo UNIX en los grandes centros académicos en ausencia de computadoras personales, el lenguaje C era el medio universal para producir programas ejecutables capaces de poder interactuar directamente con el hardware de las máquinas. En los sistemas operativos PC-DOS y MS-DOS, para producir programas ejecutables escritos en lenguaje C el archivo de cabecera que precedió a WINDOWS.H fue el archivo DOS.H, el cual se tiene que invocar en el lenguaje C para poder obtener programas ejecutables capaces de ejecutar instrucciones propias de un sistema operativo basado en líneas de comandos. Después del Win16 que solo era usado en las versiones de 16 bits de Windows llegó el Win32 para ser usado en las versiones de 32 bits de Windows, y esto a su vez empezó a entrar en obsolescencia con la llegada del Win64, la extensión a 64 bits de la versión Windows de 32 bits, lo cual entraña el uso de procesadores CPU cada vez más complejos con un conjunto cada vez mayor de instrucciones. Pudiera suponerse que los siguientes pasos naturales serían Win128, Win256 y así sucesivamente, de no ser por el hecho de que no es posible seguir aumentando indefinidamente la integración de circuitos electrónicos más allá de lo que permita el mismo tamaño del átomo. Por otro lado, la utilidad de procesadores CPU cada vez más complejos, conocidos como CISC (Complex Instruction Set Computer) está siendo cuestionada por una cantidad creciente de expertos que apoyan el uso de una cantidad limitada de instrucciones en procesadores conocidos como RISC (Reduced Instruction Set Computer). Por otro lado, el advenimiento de las tabletas electrónicas construídas con procesadores tipo RISC está demostrando que el verdadero recurso para lograr hacer algo está más bien en la cantidad de memoria RAM disponible que en la complejidad del procesador CPU. Lo que ha posibilitado el advenimiento de las tabletas ha sido la disponibilidad creciente de memorias RAM de estado sólido en el orden de los gigabytes, y no tanto el uso de microprocesadores cada vez más complejos. De cualquier modo, el punto de partida para la programación de estas máquinas es y seguirá siendo el lenguaje C, del cual derivó en buena medida el lenguaje Java que es lo que se usa para la programación de las aplicaciones app en las tabletas, y en sus varias versiones como C# (C sostenido) es lo que se seguirá usando en el futuro previsible para apoyar entornos de programación como lo que ha sido Visual Basic. Sazonado, desde luego, con programación-orientada-a-objetos.