main
por:
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }Cada vez que un proceso quiera usar la DLL que vamos a crear, se hará automáticamente una llamada a
DllMain
.
La diferencia estará en el parámetro
ul_reason_for_call
. Cuando hagamos
LoadLibrary
,
valdrá DLL_PROCESS_ATTACH
.
Cuando hagamos FreeLibrary
, valdrá
DLL_PROCESS_DETACH
. Si se crea o muere un hilo
entre ambos instantes, se llamará con los valores
DLL_THREAD_ATTACH
y DLL_THREAD_DETACH
respectivamente. Esta llamada nos servirá
para poder hacer tareas de reserva inicial o limpieza de la DLL.
fnBibliot
,
¿por qué dice que la función exportada se llama
?fnBibliot@@YAHXZ
? La razón está en el
enlazador de C++. Las funciones de C++ cuando se guardan
en los módulos objeto cambian (o revisten) su nombre en
parte debido a que en C++ dos funciones diferentes pueden
tener el mismo nombre en el código fuente. Esto hace que
usar la función así exportada
sea un verdadero infierno.
Para volver a sentir las piernas, es necesario incluir
la opción de enlazado literal de C. Sustituid en el fichero
de cabecera el prototipo de la función exportada por:
extern "C" BIBLIOT_API int fnBibliot(void);El nombre de la funcióni cambiará en vuestro caso. Ahora ya podéis comprobar en la vista rápida de la DLL (una vez recompilada) que el nombre que aparece es el correcto. La macro
BIBLIOT_API
está definida como
__declspec(dllexport) y lo podéis usar mejor.
Si queréis exportar variables o funciones de la DLL, con
estos ejemplos deberíais poder hacerlo.
HINSTANCE LoadLibrary( LPCTSTR lpLibFileName);En
lpLibFileName
indicaremos el
camino completo de la DLL. Se nos devolverá un
manejador de la DLL o NULL
,
si la llamada fracasó.
Además, la llamada hará
que se invoque la función
DllMain
de la DLL con el parámetro
ul_reason_for_call
igualado a la macro
DLL_PROCESS_ATTACH
.
FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName);En
hModule
va el handle de la DLL y, como
segundo parámetro, el nombre de la función.i
En nuestro caso, hemos hecho:
FARPROC funciOn; [...] funciOn=GetProcAddress(hbiblio,"fnBibliot"); if (funciOn==NULL) { PERROR("GetProcAddress"); return 1; } printf("El valor de la función es %d.\n",funciOn());
FreeLibrary
.
HANDLE GetStdHandle( DWORD nStdHandle); Puede ser el parámetro: STD_INPUT_HANDLE, STD_OUTPUT_HANDLE o STD_ERROR_HANDLE. BOOL SetStdHandle( DWORD nStdHandle, HANDLE hHandle);¿Sois capaces de manejarlas sin nada más y escribir algo en la pantalla dentro de una DLL? Si es así, habéis aprovechado el curso.
VOID Poner_a_cero(VOID); VOID Incrementa(VOID); y LONG Mostrar(VOID).La DLL mantendrá un contador interno que será puesto a cero, incrementado o devuelto su valor con las funciones que exporta. Para probar la DLL, haced un programa de nombre
carrera
. Este programa creará cuatro
hilos y pondrá sus identificadores por la pantalla.
Los hilos se quedarán esperando por un objeto de
tipo evento.
El hilo principal pondrá el contador de la DLL a cero.
A continuación,
señalará el evento para que todos comiencen. Cada
hilo incrementará sin pausas el contador de la DLL
un millón de veces. Mientras, el hilo primero esperará
a que vayan acabando los hilos corredores e imprimirá
sus identificadores según vayan llegando.
Cuando hayan llegado todos, imprimirá el valor del
contador de la DLL y acabará con limpieza.