[C con Clase] carga retrasada de una dll

Programante programante en gmail.com
Lun Abr 9 21:43:14 CEST 2007


AntonioFrancisco Gimenez escribió:
> a ver eso ya lo he probao y todo lo que sea sin referenciar en el 
> linker el .lib no funciona entonces el tema es sin referenciarlo 
> siguiendo un metodo parecido a ese pero al hacer GetProcAddress me 
> retornaba siempre nulo eso usando simplemente punteros a una funcion 
> declarada de la forma:
>  
> float __declspec(dllexport) suma(float a,float b) ;
>  
> a continuación incluyo el código de la carga dinamica de la dll:
>  
>                  hlibrary=LoadLibrary("dll.dll") ;
>                 if (!hlibrary)MessageBox(hwnd,"error cargar","error 
> cargar",MB_OK);
>                 ptrfnsuma=(PFNSUMA) GetProcAddress(hlibrary,"suma") ;
>                 if (ptrfnsuma==NULL) 
> MessageBox(hwnd,"error","error",MB_OK);
>                 ptrfnsuma(2,3);
>                 FreeLibrary(hlibrary);
>  
> el tipo PFNSUMA lo declaro como:
>  
> typedef float __stdcall (WINAPI* PFNSUMA)(float,float) ;
En principio el código parece correcto. Tras los MessageBox deberías 
salir de la función y te olvidas de que tu función retorne el valor de 
ptrfnsuma (que supongo estará declarado como PFNSUMA).

> al ejecutar el código de la carga dinamica todo va bien hasta que 
> llamo a GetProcAddress que compruebo si me devuelve el puntero nulo y 
> asi es
Preveo que la función que exportas no se llama suma. No es sólo 
diferenciar suma de Suma y SUMA, sino que probablemente sea suma en 8 Esto 
es así para diferenciar el tipo de convención de llamada y que no se 
pueda enlazar sin querer con otra. En stdcall es nombre@<tamaño 
parámetros>, en la convención C se les antepone un prefijo, etc.

Si la librería está compilada como C++ la cosa puede ser aún peor, 
puesto que el nombre se decora (name mangling) para que contenga 
información sobre los parámetros, y para colmo el decorado es diferente 
para cada compilador. Así que podrías tener wqapsuma en 8

Normalmente nos interesará que se exporte como suma, pero por defecto 
los compiladores adornarán el nombre exportado. ¿Cómo saber el nombre 
*real* de la función?
Mencionas que tienes Visual C++, entre las utilidades hay una que es 
dumpbin que nos permite saber precisamente eso:
dumpbin /exports retrasada.dll
nos dará todas las funciones que exporta. Y ahora sí, con el nombre de 
verdad.

Si el problema es ese, tienes dos formas de solucionarlo:
-El fácil: Cambiar tu código de GetProcAddress, para que llame a 
"wqapsuma en 8"
-El más complicado: Compilar la biblioteca para que la función se 
exporte como 'suma'. Normalmente tendremos que realizar un archivo .dep 
donde indicaremos el nombre real, el deseado, y el ordinal a indicarle. 
Aunque algunos compiladores tienen opciones más rápidas, como 
--add-stdcall-alias en los GNU (pasárselo de parámetro al linker), que 
produce las funciones también sin el @...

> ya ab urrido de dar vueltas buscando el porque sin saber porque me 
> fallaba lei que existia una forma de carga de dlls llamada carga 
> retrasada o delay load que se le expecifica al linker y el programa 
> carga la dll solo si se accede a un recurso que asi lo requiera que es 
> justo lo que quiero hacer venia un ejemplo para ms visual c++ decia 
> que se supone que todos los linker tienen opciones parecidas, he 
> encontrado tb indicaciones de esto en el msdn on line y por eso he 
> hecho tal pregunta en este foro, que es donde me nutro de información 
> acerca del compilador mingw(devcpp), aunque si me explicas porque no 
> me funciona lo del GetProcAddress perfecto pues tambien me sirve.
>  
> Saludos
Miraré sobre el delay load.

Saludos




Más información sobre la lista de distribución Cconclase