Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

martes, 25 de junio de 2024

Tutorial viejito: Creando una dll en Borland C++ para luego usarla en Visual Basic 6

 Otro tutorial de los viejitos, de hace casi 20 años! Enjoy!

Visual Basic es un lenguaje de programación con claras ventajas: Es fácil y rápido de programar, cuenta con abundante documentación, recursos y herramientas gratuitos botados por toda la Internet, permite redimensionar arrays, jalar datos desde archivos en Office, se lleva bien con las Apis, etc, etc. 

Pero también tiene sus desventajas: sus aplicaciones tienden a ser un tanto más lentas y pesadas que las programadas en otros lenguajes, depende de librerías que no todo el mundo tiene, es un compilador propietario de Microsoft, no maneja sentencias en asm, no permite declarar variables binarias tipo word o byte y manipularlas bit por bit, etc, etc.  

Es decir: todas esas cosas que tiene el lenguaje C++ pero que le faltan al Visual Basic. No digo que uno sea mejor que el otro, sino que uno tiene lo que al otro le falta. Si tuviera que elegir, haría las GUIs de mis programas en Visual, pero la parte del manejo de arrays, bucles, cálculo matemático, lectura/escritura en el puerto paralelo, entre otras cosas más, se lo dejaría al C++. Al Visual Basic le dejaría las Apis y el puerto serial, además de intercambiar datos con archivos de Office o leer imágenes desde el disco duro. 

En realidad, existe una manera de combinar las bondades de ambos lenguajes: hacer las GUIs del programa en Visual Basic y ordenarle que jale las funciones que necesita desde Dlls hechas y compiladas en C++. El uso de Dlls tiene claras ventajas: si todo el código está metido en un exe éste será más pesado y, a la hora de ejecutarlo, se cargará todo en la memoria RAM. Pero si hace llamadas a Dlls, éstas sólo se cargarán en la RAM en el momento de ser usadas, lo cual liberará espacio en memoria y hará que el programa corra más rápido.  

1. Cómo hacer la Dll:

Primero hay que bajar el compilador gratuito que ofrece Borland.  Incluye un ide, pero este tutorial está hecho para la versión original sin ide. La carpeta Borland se debe copiar a la partición C:, por lo que la ruta del ejecutable que realiza la compilación (el bcc32.exe) queda en C:\Borland\BCC55\Bin\.

Luego se debe ir a la carpeta C:\Borland\BCC55\Lib\ y copiar todos los archivos (excepto la carpeta PSDK) a la carpeta Bin, donde está bcc32.exe. Esto es porque a la hora de compilar, el compilador busca los archivos obj de la carpeta Lib, si no los copiamos a la misma carpeta donde está bcc32.exe nos botará error. 

En la misma carpeta Bin, desde el block de notas, se debe crear el archivo que será nuestra Dll, debe tener extensión cpp y el nombre que llevará la dll. Yo la llamaré inicio.cpp. El código es:

// inicio.cpp

#include <windows.h>
#include "inicio.h"


BOOL WINAPI DllEntryPoint(HINSTANCE, DWORD, LPVOID)
{
return TRUE;
}

extern "C"
int __declspec (dllexport) WINAPI suma (int a, int b) {
return a+ b;
}

La primera función WINAPI es "el puntero de entrada" que necesita Visual Basic para poder usar la Dll. Borland C++ permite declarar esta función como "BOOL WINAPI dllMain(HINSTANCE, DWORD, LPVOID)", pero en este caso Visual Basic generará error al no hallar el puntero de entrada. (Hay que notar que no existe una función main o winMain en la dll)

De la forma que sea, esta función DllEntryPoint deberá retornar siempre el valor de TRUE o se generará error.  

La siguiente función es la que programé y hace una simple sumatoria de dos enteros. La sintaxis en general es:

extern "C"
tipo __declspec (dllexport) WINAPI nombre_funcion (argumentos) { ... }

Hay que observar que antes de "declspec" pueden ir uno o dos guiones largos. 

Se debe notar que el archivo "inicio.cpp" también llama a un archivo "inicio.h", para crear la dll ambos son necesarios. El código de "inicio.h" es:

#ifndef _INICIO_H
#define _INICIO_H

#ifdef BUILD_DLL // en la construcción de la librería
#define EXPORT __declspec(dllexport)
#else // en la construcción del ejecutable
#define EXPORT __declspec(dllimport)
#endif

#ifdef __cplusplus /* if in a C++ program */
extern "C"
#endif

int __declspec(dllexport) WINAPI suma(int a, int b);

#endif 

Lo importante aquí está en la penúltima línea de código: la declaración de la función que se "exporta" desde la dll y que devolverá los valores al programa principal. 

La Compilación:

Ambos archivos, "inicio.cpp" e "inicio.h" deberán estar en la misma carpeta donde está el ejecutable compilador, la carpeta deberá tener estos archivos:


Luego se va a Inicio->Ejecutar->cmd (para windows 2000 hacia arriba, para windows 98 es Inicio->Ejecutar->Command), nos situamos en la carpeta del compilador y se ingresa el siguiente comando (va todo seguido):


El compilador necesita varios parámetros para hacer lo que queremos, ahora los voy a explicar:

"-einicio": todo lo que va después de "-e" y sin espacios, será el nombre de la dll.

-Q: Es para que nos dé la información de la compilación y si se generó algún error.

-I: este comando, seguido de una ruta o varias rutas separadas por punto y coma sin espacios, le indica al compilador dónde buscar las cabeceras que se están usando. Como "windows.h" está en la carpeta Include, debemos decirle que busque allí o botará error. 

-WD: es el comando para generar una dll y no un exe. 

Después de todo esto, le decimos qué archivo se quiere compilar.

Para más información, recomiendo revisar el archivo de ayuda que viene con el compilador y que está en la carpeta Help.

Si todo sale bien, deberá aparecer:


Después de esto, la dll deberá aparecer en la carpeta donde tenemos los archivos "inicio¡.cpp" e "inicio.h" con el nombre de "inicio.dll". Esta dll ya podemos copiarla a donde la necesitemos para poder usarla (se recomienda ponerla en la carpeta system32).

 

Probando la dll:

Abrimos el visual con un proyecto Exe Estándar. Le añadimos un módulo .bas nuevo y le ponemos este código:

Public Declare Function suma Lib "inicio.dll" (ByVal a As Integer, ByVal b As Integer) As Integer

Dentro de la Dll está la función "suma" (pueden ser varias funciones, entonces tenemos que jalarlas una por una), con los dos argumentos tipo Entero. La función devuelve un entero, por ello se la declara "As Integer". Si la función en C++ fuera del tipo "void" no se pone al final el tipo de dato pues no devuelve ningún valor (incluso en algunas webs vi que las funciones tipo "void" de C++ eran llamadas como "Sub" en lugar de "Function" desde Visual Basic, pero esto no lo he probado).

En el formulario, el único código que puse para probar si devolvía un valor correcto fue:

Private Sub Form_Load()
    Dim c As Integer
    c = suma(8, 4)
    Form1.Caption = c
End Sub

Y lo que salió fue:

Ya funciona :)

Y ahora, una web donde explican un poco más esto de las Dlls generadas con el Borland C++:

http://www.zator.com/Cpp/E1_4_4b2a.htm

No hay comentarios: