Hola, no se ustedes… pero yo siempre me pregunte como rayos se crean esas cosas llamadas dll ( dynamic-link library | biblioteca de enlace dinámico ) y mas cuando en tiempos aquellos de Windows 98 llegaba a faltar alguna para ejecutar un programa.
Bien, empecemos definiendo que es en si un archivo dll. A groso modo un archivo dll viene siendo un archivo donde se encuentran almacenadas funciones que pueden llegar a ser llamadas por uno o varios programas.
Por ejemplo (recalco que es un ejemplo ficticio) :
El archivo msnmsgr.exe hace uso de sus bibliotecas [msgsres.dll, rtmpltfm.dll, psmsong.dll] exclusivas para su funcionamiento, al igual que iexplorer.exe hace uso exclusivo de las suyas [jsdbgui.dll, , IEShims.dll, jsdebuggeride.dll] , pero los dos programas comparten la librería iexproxy.dll.
Los archivos dll además de ser compartidos por distintas aplicaciones, tienen la característica de que pueden ser llamados en runtime (en ejecución).
Que ventajas nos trae que los programas compartan bibliotecas (*.dll) , la ventaja principal es el reducir el tamaño del programa ejecutable ( *.exe), pero al igual que existen ventajas, existen desventajas; la mas común y odiada por todos es que un programa que desinstalamos desinstale una dll que era necesaria para otro programa.
Después de esta introducción, hablemos sobre el por que crear dll para nuestros programas. Siempre será mucho mas sencillo gestionar nuestra aplicación por módulos, donde se encuentren distintas funciones y sean fácilmente localizables, muy al estilo de las bibliotecas estáticas (*.h) a diferencia de las bibliotecas estáticas que se encuentran embebidas en el archivo exe, las bibliotecas de enlace dinámico (*.dll) se encuentran, como archivos independiente reduciendo considerablemente el tamaño de nuestro archivo ejecutable, facilitando la actualización del mismo o bien de alguno de sus componentes.
Basta de hacerla de emoción, empecemos a escribir código.
1.- Abrimos DevC++ (mi versión es 4.9.9.2), Archivo –> Nuevo –> Proyecto
Elegimos “DLL”, de nombre colocamos “dll” y en tipo colocamos “En C”
Guardamos nuestro proyecto como dll.dev
2.- Se abran creado 2 archivos automáticamente [ dllmain.c y dll.h ]
dll.h
#ifndef _DLL_H_ #define _DLL_H_ #if BUILDING_DLL # define DLLIMPORT __declspec (dllexport) #else /* Not BUILDING_DLL */ # define DLLIMPORT __declspec (dllimport) #endif /* Not BUILDING_DLL */ DLLIMPORT void HelloWorld (void); #endif /* _DLL_H_ */
dllMain.c
/* Replace "dll.h" with the name of your header */ #include "dll.h" #include <windows.h> #include <stdio.h> #include <stdlib.h> DLLIMPORT void HelloWorld () { MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION); } BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ , DWORD reason /* Reason this function is being called. */ , LPVOID reserved /* Not used. */ ) { switch (reason) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } /* Returns TRUE on success, FALSE on failure */ return TRUE; }
3.-En realidad con eso tenemos creado nuestra DLL, no hace falta mas que compilar el archivo.
Una vez compilado el archivo veremos que se crea una dll en el directorio donde tengamos guardado el proyecto.
Antes de continuar, expliquemos algunas líneas de código.
Esencialmente en el archivo dll.h se declaran las funciones que serán exportables por el archivo dll, para ello tenemos las líneas siguientes:
1: #ifndef _DLL_H_
2: #define _DLL_H_
3:
4: #if BUILDING_DLL
5: # define DLLIMPORT __declspec (dllexport) //Export de la DLL
6: #else
7: # define DLLIMPORT __declspec (dllimport) //Import de la DLL
8: #endif
9: DLLIMPORT void HelloWorld (void); //Prototipo de la función HelloWord
10: #endif /* _DLL_H_ */
Mientras que en el archivo dllmain.c tenemos:
Declaración de librerías.
1: #include "dll.h" // Nombre de la libreria donde se declaran los prototipos
2: #include <windows.h> // biblioteca Windows.h para el uso de dll
3: #include <stdio.h> //Biblioteca de funciones estandar
4: #include <stdlib.h>
Definición de la función HelloWord
1: DLLIMPORT void HelloWorld ()
2: {
3: //En la definicion colocamos un MessageBox con el texto Hello World
4: //Sintaxis de MessageBox
5: // MessageBox( 0, "Mensaje de Salida","Titulo de Ventana",Tipo); Tipos: MB_YESNOCANCEL | MB_ICONQUESTION | MB_SYSTEMMODAL | MB_OK | MB_ICONEXCLAMATION | MB_YESNO
6: MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION);
7: }
Declaración/prototipo de función DllMain:
1: BOOL APIENTRY DllMain (HINSTANCE hInst/* Library instance handle. */ ,
2: DWORD reason /* Reason this function is being called. */ ,
3: LPVOID reserved /* Not used. */ )
Cuando Windows se vincula a una DLL de un programa, Windows llama a la función de la biblioteca DllMain. Esto significa que cada DLL debe tener una función DllMain. La función DllMain debe ser definido como tal. Las palabras clave «BOOL», «APIENTRY», «HINSTANCE», etc, están todos definidos en <windows.h>.Por lo tanto, debe incluir ese archivo, incluso si no se usa ninguna API Win32 en su biblioteca
Esta función va a ser llamada automáticamente por cualquier programa que cargue automáticamente la librería.
Definiendo la función DllMain :
1: {
2: switch (reason)
3: {
4: case DLL_PROCESS_ATTACH:
5: break;
6:
7: case DLL_PROCESS_DETACH:
8: break;
9:
10: case DLL_THREAD_ATTACH:
11: break;
12:
13: case DLL_THREAD_DETACH:
14: break;
15: }
16:
17: /* Returns TRUE on success, FALSE on failure */
18: return TRUE;
19: }
APIENTRY es sólo una palabra clave que Windows utiliza internamente.Por lo tanto, no es necesario que te preocupes por eso.
La variable «hInstance» es el identificador de HINSTANCE para la biblioteca, y puede utilizar, o bien puede borrarlo.
Dentro de la definición de la función DllMain podemos encontrar la razón por la cual la biblioteca fue llamada, esto se controla con un switch siendo los siguientes casos:
DLL_PROCESS_ATTACH
En caso de que un programa se ha vinculado a la biblioteca por primera vez.
DLL_PROCESS_DETACH
En caso de que un programa se ha desvinculado de la biblioteca.
DLL_THREAD_ATTACH
En caso de que un hilo de un programa se vinculado a la biblioteca.
DLL_THREAD_DETACH
En caso de que un hilo de un programa ha desvinculado de la biblioteca.
La función DllMain no necesita hacer nada especial para estos casos, aunque para algunas bibliotecas, podría resultar útil para asignar el almacenamiento de cada subproceso o un proceso nuevo que se está utilizando con la biblioteca.
La función DllMain debe devolver TRUE si la librería cargada con éxito, o FALSE si en la biblioteca había un error y no se pudo cargar. Si se devuelve FALSE, el programa mostrará un mensaje de advertencia y se cerrara.
La llamada de la biblioteca podrá producirse en dos ocasiones, una en la carga de la librería, siendo entonces el parámetro reason = DLL_PROCESS_ATTACH y otra cuando se descarga la librería, en este caso, con el parámetro reason = DLL_PROCESS_DETACH.
Sin embargo, si no estamos interesados en saber alguna de las causas por la cual la biblioteca fue llamada por un programa, entonces podemos eliminar la sentencia switch y simplemente devolver un TRUE (return TRUE) .
Quedando de la siguiente forma:
1: BOOL APIENTRY DllMain (HINSTANCE hInst
2: DWORD reason
3: LPVOID reserved
4: {
5: /* Returns TRUE on success, FALSE on failure */
6: return TRUE;
7: }
Llamando funciones del DLL desde un EXE
Si nos pregunta si deseamos añadir el nuevo archivo al proyecto contestamos que No
El contenido de nuestro archivo será el siguiente:
// usar librería dinámica con enlazado dinámico #include <windows.h> #include <stdlib.h> #include <iostream> #include "dll.h" //Puntero enlace typedef void __stdcall (* FPTR)(); int main(int argc, char *argv[]) { FreeConsole();// Liberamos al programa de la consola HMODULE dllHandle = LoadLibrary("dll.dll"); // cargar librería if (!dllHandle) { std::cout << "Error en la carga de dll.dll\n"; } else { FPTR llamada = (FPTR) GetProcAddress(dllHandle, "HelloWorld"); //Use GetProcAddress para devolver un puntero de función a una función en la biblioteca. if (!llamada) std::cout << "Error al obtener direccion de HelloWord()\n"; else llamada(); FreeLibrary(dllHandle); // descargar librería //Una vez que haya terminado con un archivo DLL, y desea eliminarlo de la memoria, //podemos llamar a la función FreeLibrary con identificador de módulo de la DLL. } // system("PAUSE"); return EXIT_SUCCESS; }
Guardamos el archivo como Llama_dll.cpp en el mismo directorio donde tenemos nuestro archivo dll.dll.
Cerramos DevC++ para cerrar nuestro proyecto dll.dev. y abrimos el archivo Llama_dll.cpp
Compilamos y ejecutamos
Y Wala! tenemos nuestro mensaje que definimos en la función HelloWord de la biblioteca 🙂 .
Es muy importante mencionar que si el archivo dll.dll no se encuentra en el mismo directorio donde ejecutamos Llama_dll.exe este no desplegaría el mensaje en pantalla.
Espero como siempre, les sea de utilidad 🙂 … dejo los archivos en el siguiente link:
Fuentes:
Un muy buen articulo que explica algunos conceptos
Wiki que explica a detalle la sintaxis
Documento Word que explica en muy resumidas cuentas como crear una dll
http://www.svetlian.com/dll/articulos_descripcion_dll.htm
Gran articulo, me ha ayudado mucho, felicitaciones!
http://ayudaveloz.blogspot.com <- Codigos Dev C++
gracia por tu aporte
muchisimas gracias amigo
eres grande
por compartirnos tus conocimientos y por usar dev c++
saludos y felisidades compa
El enlace a la descarga está roto…