Vous êtes sur la page 1sur 8

Visual Basic 6.

0 y el Puerto Paralelo

PRECAUCION: Conectar dispositivos al puerto paralelo implica el riesgo de daños


permanentes a la tarjeta madre de la PC, tenga siempre presente que aún los
profesionales cometen errores, por lo tanto no está de más recomendarle extremo
cuidado al trabajar en el puerto paralelo. Lea el contenido total de éste artículo y
asegúrese de comprenderlo cabalmente. Se recomiendan conocimientos sólidos en
electrónica y programación para manipular el puerto paralelo. Éste artículo tiene el
carácter de informar exclusivamente, si bién el material presentado refleja fielmente
las prácticas y resultados obtenidos en mi computadora, Yo, Jaime Virgilio Gómez
Negrete no asumo responsabilidad alguna por el uso ó mal uso que se le dé a lo
descrito en éste artículo.

En el articulo Conversión Digital/Analógico se presentaron los conceptos básicos


para implementar un convertidor D/A conectado al puerto paralelo de la PC y además
un programa para Windows 9x. escrito en C que permite operaciones básicas de
escritura de datos al puerto. A juzgar por los mensajes que amablemente me hacen
llegar a mi e-buzón :-) se aprecia la inquietud que existe por implementar un
programa similar pero utilizando Visual Basic de Microsoft, este artículo lo escribo en
respuesta a todas aquellas personas que me han manifestado su interés esperando sea
de utilidad.

Es conocido de todos la habilidad de C para acceder al hardware de la computadora


en forma directa, por otra parte también es conocida la inhabilidad de Visual Basic, al
contrario de BASIC, para realizar tareas similares. Aparentemente lo que se necesita
para acceder al puerto paralelo de la PC utilizando Visual Basic es un mecanismo que
nos permita "traducir" algunas habilidades de C y así aprovechar la facilidad de VB
para crear interfaces de usuario fácil y rápidamente. Dicho mecanismo toma la forma
de una DLL, misma que habrá que programar en otro lenguaje diferente de VB, una
vez que se cuenta con dicha librería se utiliza como cualquier otra disponible en
Windows, por lo tanto es hora de entrar en materia. Antes conviene aclarar unos
puntos. En este artículo describiré cómo escribir una librería de enlace dinámico (DLL)
en C++, para ésta utilicé el compilador de Symantec versión 7.2 por su habilidad para
incorporar funciones de C que no están disponibles en Visual C++. Por otra parte, la
DLL se probó en un pequeño programa escrito en Visual Basic versión 6.0, confío en
que los códigos aquí presentados sean portables a versiones anteriores de Visual Basic,
particularmente la 5.0 y la 4.0, además si Usted no cuenta con un compilador de C++
capaz de crear DLL para Windows 9x, Usted dispone de la DLL debidamente compilada
en un archivo comprimido que puede descargar al final de este artículo. Se incluye
también todo el código fuente, tanto en C++ como en Visual Basic.

Conceptos básicos de la DLL


Las librerías de enlace dinámico son uno de los elementos principales del sistema
operativo Windows 9x. En su concepto básico, se tratan de archivos ejecutables
independientes que contienen funciones y recursos que pueden ser llamados por los
programas y por otras DLL para realizar ciertos trabajos. Una DLL no puede ser
ejecutada en forma independiente, entra en acción hasta que un programa ú otra DLL
llama a una de las funciones de la librería. El término "enlace dinámico" se refiere al
hecho de que el código que contiene la DLL se incorpora al programa ejecutable que la
llama sólo hasta el momento en que es requerido, en tiempo de ejecución, al contrario
del enlace estático que es el que se lleva a cabo durante el proceso de enlazado para
crear un programa Windows 9x.

En otro artículo escribiré a fondo sobre el tema de las DLL, aquí se necesitan
soluciones prácticas para quienes desean experimentar con el puerto paralelo desde
Visual Basic, por lo tanto abordemos algunas sorpresas que seguramente nos esperan
en el camino.

El objetivo es crear un par de funciones que nos permitan realizar operaciones de


lectura y escritura en el puerto paralelo, como Usted sabe podemos hechar mano de la
biblioteca C para acceder al puerto paralelo, en C++ dichas funciones son éstas:

unsigned char _outp(unsigned direccion_de_puerto, char valor);

int _inp(unsigned direccion_de_puerto);

Naturalmente, dependiendo del compilador que Usted utilice puede cambiar


ligeramente el nombre de las funciones similares que ejecutan el trabajo de escritura y
lectura al puerto respectivamente, consulte la documentación de su compilador. Se
aprecia que necesitamos para realizar operaciones de escritura dos parámetros, uno es
la dirección del puerto paralelo y el otro es el valor que deseamos escribir en el puerto.
Para operaciones de lectura basta especificar la dirección del puerto. Respecto al valor
que podemos escribir ó leer no hay mucho problema pues se trata de cualquier valor
comprendido entre 0 y 255, por esta razón se utiliza un tipo char en el segundo
parámetro de la función _outp(). La gran incógnita es la dirección del puerto y para
ésto viene en nuestro rescate el programa det.c que utilizamos en el artículo
Conversión Digital/Analógico que para comodidad repito en este espacio:

/**********************************************************
* det.c *
* Genera un archivo de información de puertos *
* (c)1999, Virgilio Gómez Negrete *
**********************************************************/

#include <stdio.h>

int main()
{
unsigned int __far *direccion;
int i;
FILE *puertos;

direccion = (unsigned int __far *) 0x00000408;


puertos = fopen("Puertos.ini", "w");
for (i=0; i<3; i++)
{
fprintf(puertos, "%d ", *direccion);
direccion++;
}
fclose(puertos);
return 0;
}

Este programa nos muestra que por lo general la dirección del puerto paralelo LPT1
es 0x378h, que en números decimales equivale al valor de 888, sin embargo conviene
que primero determine con seguridad la dirección correcta del puerto paralelo en su PC
y así evitar conflictos, en este artículo se asume que dicha dirección es en efecto 888
decimal, o sea 0x378h. Es importante el valor decimal porque Visual Basic entiende
poco de conversión de bases numéricas, así que habrá que facilitarle las cosas.

Tomando en cuenta las funciones descritas, el código fuente para la DLL es el


siguiente:

//*********************************************************
// puerto.cpp
// Una DLL para manejo de puerto paralelo
// ©2000, Jaime Virgilio Gómez Negrete
//*********************************************************

#include <windows.h>
#include <dos.h>
#include "puerto.h"

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)


{
return TRUE;
}

EXPORT BOOL Escritura(int direccion, int valor)


{
int test;

test = outp(direccion, valor);


if(test != valor)
return FALSE;

return TRUE;
}

EXPORT int Lectura(int direccion)


{
int numero;

numero = inp(direccion);

return numero;
}
Su respectivo archivo de cabecera es:

//*********************************************************
// puerto.h
// ©2000, Jaime Virgilio Gómez Negrete
//*********************************************************

#define EXPORT extern "C" __declspec(dllexport)

//*********************************************************
// Uso: Escritura(int direccion_puerto_LPT1, int valor)
//*********************************************************
EXPORT BOOL Escritura(int, int);

//*********************************************************
// Uso: Lectura(int direccion_puerto_LPT1)
//*********************************************************
EXPORT int Lectura(int);

Se aprecia en el archivo de cabecera puerto.h que disponemos de dos funciones,


una llamada Escritura() que acepta dos parámetros, el primero es para la dirección
del puerto paralelo, el segundo parámetro es el valor que deseamos escribir en el
puerto. La segunda función se llama Lectura() y su único parámetro es para
especificar la dirección del puerto. Como puede ver, trabajé arduamente para
determinar el nombre de éstas funciones. A continuación vienen los problemas...

Como mencioné al principio, la DLL la escribí en C++ y la compilé utilizando


Symantec C++ versión 7.2, utilizar un entorno de desarrollo integrado (IDE, por sus
siglas en inglés) es muy conveniente en casos como el que nos ocupa, sencillamente
basta con crear un proyecto especificando que el resultado final esperado es una DLL
para la plataforma Windows 95 y que los archivos a incluir son el llamado puerto.cpp y
el archivo puerto.h arriba presentados. Con otros compiladores la labor no debe ser
muy diferente, es cosa que Usted consulte la documentación respectiva. Observe en el
código puerto.h la declaración de una macro:

#define EXPORT extern "C" __declspec(dllexport)

Aquí, la palabra clave EXPORT indica que las funciones están disponibles para otros
programas externos a la DLL, además se utiliza la palabra clave __declspec con el
atributo dllexport para garantizar que las funciones sean exportables a otros
programas que así las requieran, con ésto al compilar la DLL se crea un archivo de
definición en donde queda especificado cuales son las funciones disponibles para otros
programas en una DLL, en otras palabras, se trata del punto de entrada a las funciones
de la DLL.

Otro punto importante a considerar es la convención de llamadas a función.


Lenguajes como C/C++ utilizan la convención __cdecl que se caracteriza por incluir
un código que sirve para realizar labores de limpieza previa (inicialización con valor
igual a cero) en el stack. En comparación, las funciones de la API de Windows utilizan
la convención __stdcall la cual realiza un decorado de los nombres de función
utilizando un símbolo de subrayado seguido de @#nn donde #nn representa el
número total de bytes que se requieren en los parámetros de la función. Tanto en la
convención __cdecl como en __stdcall los argumentos de las funciones se pasan al
stack de derecha a izquierda. Se estará Usted preguntando ¿Y qué importancia tiene
todo ésto? Pues bién, resulta que en Windows se declara a las convenciones de
llamadas a función WINAPI, PASCAL y CALLBACK como de tipo __stdcall y resulta
que Visual Basic utiliza la convención de tipo PASCAL la cual no distingue entre letras
mayúsculas y minúsculas, al contrario de la convención utilizada por C/C++ que es
sensible al tamaño de caja de las letras, por lo tanto los argumentos utilizados en
nuestras funciones entran en conflicto al tratar de utilizarlas desde Visual Basic. Para
resolver este inconveniente se requiere establecer una equivalencia de exportación, es
decir, especificamos que el nombre de función LECTURA sea asociado con la función
llamada Lectura() y que ésta requiere 1 parámetro. Para el caso de la función
Escritura se sigue un proceso similar pero especificando que ésta función requiere dos
parámetros, de ésta manera se definen los valores de exportación así:

EXPORTS
LECTURA=Lectura @1
ESCRITURA=Escritura @2

Al momento de utilizar la DLL desde Visual Basic, naturalmente que debemos


especificar el nombre de las funciones, luego Visual Basic hará una conversión, por
ejemplo para la función Lectura(direccion) Visual Basic la convertirá en una llamda
similar a esta: LECTURA(DIRECCION) lo cual obviamente no será reconocido por la
DLL, pero como especificamos los valores de exportación adecuados, la llamada a
función solicitada por Visual Basic será interpretada correctamente.

Compile los archivos llamados Puerto.cpp y Puerto.h para obtener la DLL llamada
Puerto.dll y veamos a continuación cómo utilizarla desde Visual Basic.

Volver al principio

Usando la DLL desde Visual Basic 6.0


La disposicón de los elementos que
componen la interfaz gráfica de usuario
se aprecia en la imagen a la derecha de
éste párrafo. A la izquierda están una
serie de casillas de verificación
marcadas como D0 hasta D7 que sirven
para establecer el valor binario a
escribir en el puerto, una marca en la
casilla equivale a un valor lógico de 1 en
tanto que dejando la casilla sin marca el
valor correspondiente será de nivel
lógico bajo, de esta manera, si
marcamos todas las casillas de
verificación y luego presionamos el
botón Escribir Valor en LPT1 la totalidad
de las líneas de salida del puerto
paralelo tendrán un valor lógico de 1. Para leer datos presentes en el puerto basta con
presionar el respectivo botón y el equivalente decimal aparece en la ventana de texto
marcada como Valor Leído al Puerto LPT1. La dirección del puerto LPT1 se especifica en
la ventana superior derecha, este valor lo puede Usted obtener corriendo el programa
det.c y luego consultando el archivo generado por éste llamado Puertos.ini. Ahora que
tiene una idea de cómo se vé el programa pasemos a los detalles de programación.

Lo primero que necesitamos conocer es la ruta completa para acceder a la DLL


llamada Puerto.dll. Usted puede colocar la DLL en el mismo directorio del proyecto
Visual Basic donde Usted esté trabajando, por ejemplo, en mi caso dicha ruta es
C:\dll\Puerto\. Para llamar a las funciones incluidas en la DLL utilizamos la siguiente
instrucción dentro de la sección de declaraciones generales:

Private Declare Function Escritura Lib _


"C:\dll\Puerto\Puerto.dll" _
(ByVal direccion As Long, _
ByVal Valor As Long) As Boolean

Private Declare Function Lectura Lib _


"C:\dll\Puerto\Puerto.dll" _
(ByVal dir2 As Long) As Long

Observe que se debe incluir la ruta completa de acceso a la DLL, o sea


C:\dll\Puerto\Puerto.dll. Cambie este valor para que refleje la ruta de su directorio
de trabajo, muy importante. Observe además que los parámetros de las funciones son
declarados como de tipo Long al igual que el valor que devuelve la función Lectura(),
esto también es importante pues Visual Basic hace una interpretación diferente de los
tipos de datos en C, para que Usted tenga una referencia completa de la interpretación
de los tipos de datos, aquí está la lista:

API de Windows Visual Basic


int, INT ByVal Long
UINT ByVal Long
BOOL ByVal Long
WORD ByVal Integer
DWORD ByVal Long
WPARAM ByVal Long
LPARAM, LRESULT ByVal Long
COLORREF ByVal Long
ATOM ByVal Integer
HANDLE ByVal Long
BYTE ByVal Byte
char ByVal Byte
El código fuente en Visual Basic es el siguiente, recuerde que Usted puede
descargar los códigos de ejemplo al final.

Option Explicit

Private Declare Function Escritura Lib _


"C:\dll\Puerto\Puerto.dll" _
(ByVal direccion As Long, _
ByVal Valor As Long) As Boolean

Private Declare Function Lectura Lib _


"C:\dll\Puerto\Puerto.dll" _
(ByVal dir2 As Long) As Long

Private Sub cmdEscribir_Click()


Dim Valor1 As Integer
Dim Result As Boolean

Valor1 = 0
If chkD0.Value = 1 Then
Valor1 = Valor1 + 1
End If
If chkD1.Value = 1 Then
Valor1 = Valor1 + 2
End If
If chkD2.Value = 1 Then
Valor1 = Valor1 + 4
End If
If chkD3.Value = 1 Then
Valor1 = Valor1 + 8
End If
If chkD4.Value = 1 Then
Valor1 = Valor1 + 16
End If
If chkD5.Value = 1 Then
Valor1 = Valor1 + 32
End If
If chkD6.Value = 1 Then
Valor1 = Valor1 + 64
End If
If chkD7.Value = 1 Then
Valor1 = Valor1 + 128
End If

txtEscritura.Text = Valor1
Result = Escritura(txtDireccion.Text, Valor1)
txtLectura.Text = Lectura(txtDireccion.Text)

End Sub

Private Sub cmdLeer_Click()


Dim Valor As Long

Valor = Lectura(txtDireccion.Text)
txtLectura.Text = Valor
End Sub

Private Sub cmdSalir_Click()


Dim Result2 As Boolean

Result2 = Escritura(txtDireccion.Text, 0)
End

End Sub

Finalmente, si Usted lo desea puede colocar la DLL en el directorio System de


Windows y entonces bastará con especificar el nombre de la DLL en la declaración de
las respectivas funciones, sin embargo recomiendo mantener separados los archivos de
trabajo y no tocar nada que tenga que ver con el sistema operativo, digamos que se
trata de una norma elemental de seguridad que puede evitarnos algunos dolores de
cabeza.

Ahora ya dispone Usted de una herramienta básica para trabajar con el puerto
paralelo desde Visual Basic, puede incluso agregar nuevas funciones a la DLL y así
agregar funcionalidad a VB a través de llamadas a función de la biblioteca C, Usted
tiene la palabra...

Volver al principio

Descargas
El código fuente tanto en C++ como en Visual Basic 6.0 lo puede descargar haciendo
clic aquí

Vous aimerez peut-être aussi