Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Dll linkée statiquement et vérification de n° de version

3 réponses
Avatar
Jean-Yves
Bonjour,

Mon application MFC utilise une DLL linkée statiquement. Au démarrage de
l'application, est-il possible de vérifier la version de la DLL avant que
soit vérifié automatiquement que dans la DLL il y a bien tous les points
d'entrées qui sont requis par l'application ?

En fait le but c'est d'afficher un message plus "propre" pour l'utilisateur
que "le point d'entrée XXX@YYYY n'a pas été trouvé dans la bibliothèque
dynamique....".

Bien sur vous allez me dire que je n'ai qu'à utiliser la DLL en link
dynamique et de vérifier la version avant de charger les points d'entrée par
un "GetProcAddress". Le problème c'est que c'est franchement "lourd".

Merci pour vos idées.

Jean-Yves

3 réponses

Avatar
Thierry
Bonjour,

Jean-Yves a écrit :

Bien sur vous allez me dire que je n'ai qu'à utiliser la DLL en link
dynamique et de vérifier la version avant de charger les points
d'entrée par un "GetProcAddress". Le problème c'est que c'est
franchement "lourd".

Merci pour vos idées.



delay load ?

--
« Le travail est probablement ce qu'il y a sur cette terre de plus bas et
de plus ignoble. Il n'est pas possible de regarder un travailleur sans
maudire ce qui a fait que cet homme travaille, alors qu'il pourrait nager,
dormir dans l'herbe ou simplement lire ou faire l'amour avec sa femme. »
Boris VIAN
Mon blog RSS : http://yarglah.free.fr/monblog_rss.php <<




Avatar
Patrick Philippot
Jean-Yves wrote:
Bien sur vous allez me dire que je n'ai qu'à utiliser la DLL en link
dynamique et de vérifier la version avant de charger les points
d'entrée par un "GetProcAddress". Le problème c'est que c'est
franchement "lourd".



Bonjour,

Une petite correction tout d'abord: une DLL est toujours chargée
dynamiquement (Dynamic Link Library). Elle peut être chargée
implicitement (édition de liens avec la bibliothèque d'import) ou
explicitement (LoadLibrary).

Une solution consiste à faire du Delay Loading (à préciser au moment du
link). La DLL ne sera chargée qu'au moment de l'utilisation, ce qui vous
laisse éventuellement le temps (c'est selon) de vérifier la version
avant l'utilisation de la première fonction dans la DLL. Le Delay
Loading

Une autre solution est de faire du chargement implicite quand même mais
sans se fatiguer à faire des GetProcAddress. Mais comment est-ce
possible me direz vous? En utilisant la capacité des DLLs Win32 à
exporter des données. Prenons un petit exemple issu d'un des TPs que
j'utilise pendant mes cours.

Supposons une DLL qui exporte les fonctions suivantes:

int APIENTRY _StartSelection (HWND, POINT, LPRECT, int);
int APIENTRY _UpdateSelection (HWND, POINT, LPRECT, int);
int APIENTRY _EndSelection (POINT, LPRECT);
int APIENTRY _ClearSelection (HWND, LPRECT, int);

Je déclare dans mon fichier .H la structure suivante:

typedef int (* APIENTRY STARTSELECTION) (HWND, POINT, LPRECT, int);
typedef int (* APIENTRY UPDATESELECTION) (HWND, POINT, LPRECT, int);
typedef int (* APIENTRY ENDSELECTION) (MPOINT, LPRECT);
typedef int (* APIENTRY CLEARSELECTION) (HWND, LPRECT, int);

typedef struct tagFunctionTable {
STARTSELECTION StartSelection;
UPDATESELECTION UpdateSelection;
ENDSELECTION EndSelection;
CLEARSELECTION ClearSelection;
} FUNCTION_TABLE;

et une variable globale dans ma DLL de type FUNCTION_TABLE :

FUNCTION_TABLE Function_Table;

Dans le DllMain, je renseigne la table avec les adresses effectives
(cela sera fait à chaque chargement de la DLL puisque l'adresse de la
fonction peut varier d'un process client à l'autre):

BOOL APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID
lpReserved)
{
UNREFERENCED_PARAMETER(hInst);
UNREFERENCED_PARAMETER(lpReserved);

if (ul_reason_being_called == DLL_PROCESS_ATTACH)
{


Function_Table.StartSelection = (STARTSELECTION)
_StartSelection;
Function_Table.UpdateSelection = (UPDATESELECTION)
_UpdateSelection;
Function_Table.EndSelection = (ENDSELECTION) _EndSelection;
Function_Table.ClearSelection = (CLEARSELECTION)
_ClearSelection;
}
return 1;
}

Dans mon .DEF, je ne fais un export que de Function_table, pas des
fonctions:

EXPORTS Function_Table CONSTANT

-----------------------------


Dans le programme client, j'inclus le fichier .H de la DLL et je déclare
ma table de fonctions:

FUNCTION_TABLE *Functions;

Ensuite, pendant l'initialisation du programme (ou plus tard - après
avoir vérifié la présence et la version de la DLL), je charge ma table:

hDLL = LoadLibrary("MADLL.DLL");
if (hDLL != NULL)
{
// Recherche un point d'entrée unique pour les fonctions appelées
// Cette méthode n'est pas obligatoire et ne sera pas mise en oeuvre
// dans le cas de la mixité 16-32 bits
Functions = (FUNCTION_TABLE*) GetProcAddress (hDLL,
"Function_Table");
if (Functions == NULL)
{
FreeLibrary(hDLL);
return (0);
}
}
else
return (0);

Et voilà, en une seule passe, j'ai chargé toutes mes adresses. Il ne me
reste plus pour appeler les fonctions qu'à référencer ma table. Par
exemple:

Functions->UpdateSelection(hWnd, Point, &Rect, Shape);

Avantages de cette technique très simple à mettre en oeuvre:

- Un seul GetProcAddress
- Les noms des fonctions ne sont pas exportés (sécurité)
- Les noms des fonctions dans la table peuvent être différents des noms
réels des fonctions

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Jean-Yves
Merci beaucoup pour votre aide, cela répond parfaitement à mon problème.

"Patrick Philippot" a écrit dans le
message de news:d1uoe3$2fu1$
Jean-Yves wrote:
> Bien sur vous allez me dire que je n'ai qu'à utiliser la DLL en link
> dynamique et de vérifier la version avant de charger les points
> d'entrée par un "GetProcAddress". Le problème c'est que c'est
> franchement "lourd".

Bonjour,

Une petite correction tout d'abord: une DLL est toujours chargée
dynamiquement (Dynamic Link Library). Elle peut être chargée
implicitement (édition de liens avec la bibliothèque d'import) ou
explicitement (LoadLibrary).

Une solution consiste à faire du Delay Loading (à préciser au moment du
link). La DLL ne sera chargée qu'au moment de l'utilisation, ce qui vous
laisse éventuellement le temps (c'est selon) de vérifier la version
avant l'utilisation de la première fonction dans la DLL. Le Delay
Loading

Une autre solution est de faire du chargement implicite quand même mais
sans se fatiguer à faire des GetProcAddress. Mais comment est-ce
possible me direz vous? En utilisant la capacité des DLLs Win32 à
exporter des données. Prenons un petit exemple issu d'un des TPs que
j'utilise pendant mes cours.

Supposons une DLL qui exporte les fonctions suivantes:

int APIENTRY _StartSelection (HWND, POINT, LPRECT, int);
int APIENTRY _UpdateSelection (HWND, POINT, LPRECT, int);
int APIENTRY _EndSelection (POINT, LPRECT);
int APIENTRY _ClearSelection (HWND, LPRECT, int);

Je déclare dans mon fichier .H la structure suivante:

typedef int (* APIENTRY STARTSELECTION) (HWND, POINT, LPRECT, int);
typedef int (* APIENTRY UPDATESELECTION) (HWND, POINT, LPRECT, int);
typedef int (* APIENTRY ENDSELECTION) (MPOINT, LPRECT);
typedef int (* APIENTRY CLEARSELECTION) (HWND, LPRECT, int);

typedef struct tagFunctionTable {
STARTSELECTION StartSelection;
UPDATESELECTION UpdateSelection;
ENDSELECTION EndSelection;
CLEARSELECTION ClearSelection;
} FUNCTION_TABLE;

et une variable globale dans ma DLL de type FUNCTION_TABLE :

FUNCTION_TABLE Function_Table;

Dans le DllMain, je renseigne la table avec les adresses effectives
(cela sera fait à chaque chargement de la DLL puisque l'adresse de la
fonction peut varier d'un process client à l'autre):

BOOL APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID
lpReserved)
{
UNREFERENCED_PARAMETER(hInst);
UNREFERENCED_PARAMETER(lpReserved);

if (ul_reason_being_called == DLL_PROCESS_ATTACH)
{


Function_Table.StartSelection = (STARTSELECTION)
_StartSelection;
Function_Table.UpdateSelection = (UPDATESELECTION)
_UpdateSelection;
Function_Table.EndSelection = (ENDSELECTION) _EndSelection;
Function_Table.ClearSelection = (CLEARSELECTION)
_ClearSelection;
}
return 1;
}

Dans mon .DEF, je ne fais un export que de Function_table, pas des
fonctions:

EXPORTS Function_Table CONSTANT

-----------------------------


Dans le programme client, j'inclus le fichier .H de la DLL et je déclare
ma table de fonctions:

FUNCTION_TABLE *Functions;

Ensuite, pendant l'initialisation du programme (ou plus tard - après
avoir vérifié la présence et la version de la DLL), je charge ma table:

hDLL = LoadLibrary("MADLL.DLL");
if (hDLL != NULL)
{
// Recherche un point d'entrée unique pour les fonctions appelées
// Cette méthode n'est pas obligatoire et ne sera pas mise en oeuvre
// dans le cas de la mixité 16-32 bits
Functions = (FUNCTION_TABLE*) GetProcAddress (hDLL,
"Function_Table");
if (Functions == NULL)
{
FreeLibrary(hDLL);
return (0);
}
}
else
return (0);

Et voilà, en une seule passe, j'ai chargé toutes mes adresses. Il ne me
reste plus pour appeler les fonctions qu'à référencer ma table. Par
exemple:

Functions->UpdateSelection(hWnd, Point, &Rect, Shape);

Avantages de cette technique très simple à mettre en oeuvre:

- Un seul GetProcAddress
- Les noms des fonctions ne sont pas exportés (sécurité)
- Les noms des fonctions dans la table peuvent être différents des noms
réels des fonctions

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr