Versión 3.0

800x600 mínimo
En esta lección:

Conceptos básicos de la DLL
-----
Usando la DLL desde Visual Basic
-----
Descargas
-----


Otras secciones:

Conceptos básicos
-----
Programando en C
-----
Programando en C++
-----
Programando Windows 9x.
-----
Teoría electrónica
-----
Circuitos electrónicos
-----
Actividades adicionales
-----
Hipervínculos
-----


Contácteme:

Dudas y comentarios
-----


Visual Basic 6.0 y el Puerto Paralelo

Hola mundo

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.

Hola mundo

     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.

Hola mundo

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

Hola mundo

Usando la DLL desde Visual Basic 6.0 

Usando Visual Basic 6.0 para acceder la puerto paralelo

     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

Hola mundo

Descargas 

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

Volver al principio

Hola mundo
© 1998, 1999, 2000 Virgilio Gómez Negrete, Derechos Reservados