•»Sin pelos en la Lengua ► C++

Crear dll con DevC++

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.

 

image

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

image

Elegimos “DLL”, de nombre colocamos “dll” y en tipo colocamos “En C”

 image

Guardamos nuestro proyecto como dll.dev

image

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.

image

Una vez compilado el archivo veremos que se crea una dll en el directorio donde tengamos guardado el proyecto.

image

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: }

 
Con eso tenemos una explicación de la sintaxis de nuestros dos archivos, el siguiente paso…. llamar la función  HelloWorld que se encuentra dentro de nuestra dll ( dll.dll ).
 

Llamando funciones del DLL desde un EXE

 
Para poder llamar nuestra función crearemos un nuevo “Código Fuente”.

image

Si nos pregunta si deseamos añadir el nuevo archivo al proyecto contestamos que No

image

 

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.

image

 

Cerramos DevC++ para cerrar nuestro proyecto dll.dev. y abrimos el archivo Llama_dll.cpp

image

Compilamos y ejecutamos

image

 

Y Wala! tenemos nuestro mensaje que definimos en la función HelloWord de la biblioteca  🙂 .

image

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:

Archivo_zipDescargar

 

Fuentes:

Un muy buen articulo que explica algunos conceptos

Wiki que explica a detalle la sintaxis

Ventanas Modales en DevC++

Documento Word que explica en muy resumidas cuentas como crear una dll

http://www.svetlian.com/dll/articulos_descripcion_dll.htm

http://www.zator.com/Cpp/E1_4_4b2b.htm#[2]

http://elblogroboticodepedro.weebercorp.com/2009/02/03/labview-31-crear-dll-en-c-con-dev-c-y-llamada-en-labview/

Video: http://www.youtube.com/watch?v=fzO9L6tlXDI

8 comentarios

  1. Pingback: Dll | TagHall

Deja un comentario