création d'une dll et probleme avec GetProcAddress [VC++] - Programmation
Marsh Posté le 02-08-2001 à 14:12:14
DllMain c'est la point d'entrée de la dll quand elle est chargée. Sa permet éventuellement d'initialiser des variables.
C'est obligatoire comme Winmain pour les EXE.
Montre la partie du source qui charge les fonctions.
Marsh Posté le 02-08-2001 à 14:32:10
HINSTANCE hLib = LoadLibrarymyDll.dll" );
FARPROC fp_func = GetProcAddress(hLib, "fonction1" );
c'est tout.
En fait, je viens de trouver d'ou vient l'erreur. Par contre, je n'arrive pas encore à l'exliquer...
Si ma dll est compilée avec des fichiers d'extention .cpp et .hpp, le nom des fonctions exportées ne correspond plus au nom originial des fonctions. Par contre, si je renomme ces fichiers .c et .h, puisque pour le moment il n'y a que de C, alors tout fonction correctement.
C'est gênant par ce que à terme, je voudrais quand même exporter des classes et des fonctions C++.
Marsh Posté le 02-08-2001 à 14:32:56
oups... faute de frappe...
HINSTANCE hLib = LoadLibrary("myDll.dll" );
FARPROC fp_func = GetProcAddress(hLib, "fonction1" );
c'est tout.
En fait, je viens de trouver d'ou vient l'erreur. Par contre, je n'arrive pas encore à l'exliquer...
Si ma dll est compilée avec des fichiers d'extention .cpp et .hpp, le nom des fonctions exportées ne correspond plus au nom originial des fonctions. Par contre, si je renomme ces fichiers .c et .h, puisque pour le moment il n'y a que de C, alors tout fonction correctement.
C'est gênant par ce que à terme, je voudrais quand même exporter des classes et des fonctions C++.
Marsh Posté le 02-08-2001 à 14:37:52
SoWhatIn22 a écrit a écrit : oups... faute de frappe... HINSTANCE hLib = LoadLibrary("myDll.dll" ); FARPROC fp_func = GetProcAddress(hLib, "fonction1" ); c'est tout. En fait, je viens de trouver d'ou vient l'erreur. Par contre, je n'arrive pas encore à l'exliquer... Si ma dll est compilée avec des fichiers d'extention .cpp et .hpp, le nom des fonctions exportées ne correspond plus au nom originial des fonctions. Par contre, si je renomme ces fichiers .c et .h, puisque pour le moment il n'y a que de C, alors tout fonction correctement. C'est gênant par ce que à terme, je voudrais quand même exporter des classes et des fonctions C++. |
Avec des fichiers cpp, le nom de tes fonctions externes est plus complique que le nom dans ton fichier car y'a une description de la fonction. (ex : appartient a telle classe)
Compile ta DLL et avec Quickview regarde les exports et la tu verras des noms a rallonge, c'est eux que tu dois utiliser.
Salut.
Marsh Posté le 02-08-2001 à 14:41:48
Sous C++ Builder il y a une option pour résoudre ce problème mais sous Visual je sais pas.
Sinon tu peux créer un .def avec le nom de fonctions
Marsh Posté le 02-08-2001 à 14:55:19
Yep y a probablement des underscores ou un truc comme ca.
Pour savoir tu peux compiler avec le .h mais SANS le .lib et au link il te dit les fonctions qu'il manque...
Sinon, le DllMain n'est pas obligatoire !
(je m'en passe très bien)
Marsh Posté le 02-08-2001 à 16:12:37
> regarde les exports et la tu verras des noms a rallonge
ben en effet, ya des noms à rallonge.
En fait, ca parait logique, puisqu'en C++ une meme fonction peut avoir un nombre d'arguments différents, et 2 classes différentes peuvent avoir une fonction du même nom. D'ou la decoration du nom des fonctions.
Le probleme, c'est que cela ne m'arrange pas du tout... Parce que je ne crois pas qu'on puisse savoir à l'avance comment s'appelle ce nom.
Bref, les dll en c++, c'est le bordel si on veut les charger dynamiquement.
Y'aurrait bien le moyen de mettre une interface en C, mais bon, ca fait encore une couche en plus, mais c'est lourd.
Je vais quand même essayer un de creuser un peu le sujet.
On va bien voir.
merci à tous.
Marsh Posté le 02-08-2001 à 16:23:15
Ah ben les DLL ca peut pas marcher avec du C++, juste du C!
Parce qu'une methode virtuelle ou une méthode pas statique ca peut pas s'appeler comme ca.
Une DLL c'est une bibliothèque de fonctions (méthodes statiques en C++)...
M'enfin, la méthode que je t'ai dis peut fonctionner...
Marsh Posté le 02-08-2001 à 16:39:43
le plus simple c'est de faire c'est de faire une fonction extern "C" donc chargeable par LoadLibrary sans Pb qui renvoie des pointeurs sur les methodes C++ ou qui fabrique les classes...
Marsh Posté le 02-08-2001 à 16:46:29
>Ah ben les DLL ca peut pas marcher avec du C++, juste du C!
Si ca fonctionne. Sans probleme, même. Si le projet inclue les headers et le .lib généré en même temps que la dll, alors aucun soucis.
Le probleme vient lors du chargement dynamique de la dll et lorsque l'on veut alors récuperer des pointeurs sur les fonctions. En fait, les fonctions sont bien exportées, mais les noms sont un peu différents. Et en fait, ces noms sont produits par le compilateur lui même, et il n'y a pas de norme la dessus. Donc les noms peuvent changer selon que la dll est générée avec un compilateur ou un autre.
Par contre, ce que dit BENB est tout à fait vrai. Disons que rajouter des 'wrapper functions' rajoute encore une petite couche d'interface. C'est cela que je voulais essayer d'éviter. Mais apparement ca ne va pas être possible. Donc: wrappers...
Marsh Posté le 02-08-2001 à 16:55:38
Il suffit de créer une fonction C qui encapsule le contructeur.
Après tu peux appeler directement les fonctions de ta classe déclarées avec le mot clef "_export".
Marsh Posté le 02-08-2001 à 17:30:25
seblamb a écrit a écrit : Il suffit de créer une fonction C qui encapsule le contructeur. Après tu peux appeler directement les fonctions de ta classe déclarées avec le mot clef "_export". |
Ben non, parce que justement les fonctions déclarées avec _export verront leur nom changer, d'ou la nécessité d'écrire des fonctions d'interface.
De plus, si tu exportes directement la classe:
class __declspec(dllexport) myClass
{
etc...
};
alors toutes les fonctions membres sont exportées automatiquement. Ca évite de définir une fonction d'interface en C pour toutes les méthodes et les attributs publiques.
Mais avec le GetProcAddress, ca ne fonctionne plus car tu ne connais pas le nom des fonctions.
Voila tout mon probleme.
remarque, juste pour info:
MSDN:
" You used the _export keyword, which is now obsolete. Use __declspec(dllexport) instead"
Marsh Posté le 02-08-2001 à 17:34:42
mais tu n'as plus besoin de faire GetProcAdresse pour ces fonctions.
Tu fait un GetProcAdresse sur la fonction qui te renvois un pointeur sur un objet du type de la classe qui se trouve dans la dll.
Ensuite tu utilise le pointeur comme d'hab.
[edtdd]--Message édité par seblamb--[/edtdd]
Marsh Posté le 02-08-2001 à 17:36:12
Tu dois pouvoir aussi faire un .def dans lequel tu donne le nom d'export de certaines fonctions...
Marsh Posté le 02-08-2001 à 17:56:17
seblamb a écrit a écrit : mais tu n'as plus besoin de faire GetProcAdresse pour ces fonctions. Tu fait un GetProcAdresse sur la fonction qui te renvois un pointeur sur un objet du type de la classe qui se trouve dans la dll. Ensuite tu utilise le pointeur comme d'hab. |
ton truc ne peux pas marcher, car comme tu ne peux pas exporter directement ta classe, son type n'est pas déclaré dans le code qui charge cette dll. Tu ne peux donc pas instancier une variable de ce type puisqu'il est inconnu. Donc tu peux à la limite prendre un void *. Sauf qu'après, impossible de lui appliquer des fonctions membres. Et le casting est impossible puisqu'encore une fois, tu ne connais pas le type.
Marsh Posté le 02-08-2001 à 18:18:31
SoWhatIn22 a écrit a écrit : ton truc ne peux pas marcher, car comme tu ne peux pas exporter directement ta classe, son type n'est pas déclaré dans le code qui charge cette dll. Tu ne peux donc pas instancier une variable de ce type puisqu'il est inconnu. Donc tu peux à la limite prendre un void *. Sauf qu'après, impossible de lui appliquer des fonctions membres. Et le casting est impossible puisqu'encore une fois, tu ne connais pas le type. |
Bien sur que on peut exporter une classe...
ou alors j'ai ete dans un reve pendant quatre ans...
Marsh Posté le 02-08-2001 à 18:57:58
BENB a écrit a écrit : Bien sur que on peut exporter une classe... ou alors j'ai ete dans un reve pendant quatre ans... |
<B>D</B>ans le cas d'un chargement implicite de la dll, oui. Dans le cas d'un chargement explicite, donc avec LoadLibrary puis des GetProcAddress, non. Ou alors explique moi comment tu fais pour importer un type?
Dans mon exemple:
class __declspec(dllexport) myClass
{
etc...
};
si tu charges la dll implicitement, alors le type myClass est connu. Avec un chargement explicite, il ne l'est pas.
Ou alors ya une subtilité que je n'ai pas vu? On m'aurait caché des choses?!
Marsh Posté le 03-08-2001 à 08:53:23
SoWhatIn22 a écrit a écrit : <B>D</B>ans le cas d'un chargement implicite de la dll, oui. Dans le cas d'un chargement explicite, donc avec LoadLibrary puis des GetProcAddress, non. Ou alors explique moi comment tu fais pour importer un type? Dans mon exemple: class __declspec(dllexport) myClass { etc... }; si tu charges la dll implicitement, alors le type myClass est connu. Avec un chargement explicite, il ne l'est pas. Ou alors ya une subtilité que je n'ai pas vu? On m'aurait caché des choses?! |
chargement explicite ou implicite, le type doit etre suffisament connu pour pouvoir etre instancie. en General les types de la Dll sont des derives d'un type connu et tu recuperes par GetProcAdress une methode "Factory" qui permet de construire ces nouveaux types...
Encore tu peu crer un type factory associe a chaque autre classe de la Dll, variables globales(*) de la Dll ils s'enregistrent dans une liste lors du chargement de celle-ci...
(*) evidement cette methodologie est criticable, je cite une methode simple, elle peut etre construite de maniere plus sioux.
Marsh Posté le 03-08-2001 à 10:28:52
BENB a écrit a écrit : chargement explicite ou implicite, le type doit etre suffisament connu pour pouvoir etre instancie. en General les types de la Dll sont des derives d'un type connu et tu recuperes par GetProcAdress une methode "Factory" qui permet de construire ces nouveaux types... |
Tout à fait ok avec ça.
BENB a écrit a écrit : Encore tu peu crer un type factory associe a chaque autre classe de la Dll, variables globales(*) de la Dll ils s'enregistrent dans une liste lors du chargement de celle-ci... |
La je ne comprends pas bien ce que tu veux dire. Tu mets des types en variables globales? Je ne comprends pas ce que cela veux dire. Si tu peux m'éclairer...
Marsh Posté le 03-08-2001 à 11:11:25
Und es gros problèmes du C++ dans une DLL, c'est que tu peux pas charger une adresse de classe dans la DLL (un pointeur sur une classe) et la caster en la classe que tu veux. Même en supposant que c'est la même classe. Ca marche que dans le cas où t'as le même compilateur. Parce que les variables d'instances seront pas forcément placées et alignées pareil en mémoire.
C'est pour ca que je dis qu'une DLL c'est plutôt pour du C (et des structures) et pas trop pour le C++...
Enfin, j'ai jamais vérifié ce que je dis, mais y a de fortes chances.
Si tu maitrises les 2 cotés de la DLL, alors utilises un .lib. Un .def sert pas à grand chose puisque si t'utilises du C++, le .lib suffit. Si t'utilises un autres langages, tu pourras pas avoir la notion des objets C++...
Dans ce 2e cas, il faut que tu fasses une interface C (extern "C" ) à tes classes, en passant à chaque fonction C (correspondant à une méthode public) un cookie (le this).
Marsh Posté le 03-08-2001 à 11:22:14
robUx4 a écrit a écrit : C'est pour ca que je dis qu'une DLL c'est plutôt pour du C (et des structures) et pas trop pour le C++... |
Si tu fais un chargement implicite, donc en compilant avec le .lib, tu peux exporter une classe sans aucun probleme. Je le fais et ca fonctionne tres bien. Le probleme survient quand on veut faire des chargements explicites avec un LoadLibrary. Et le chargement explicite est parfois bien pratique. Par exemple pour que ton programme puisse fonctionner même si la dll n'est pas présente.
Marsh Posté le 03-08-2001 à 11:54:01
SoWhatIn22 > Une factory, tu n'a generalement besoin que d'une instance, donc tu declare une globale de ce type dans la Dll oui
sinon tu peux faire des chargement explicites en utilisant le .lib... le .lib de l'exe pour compiler la Dll... et du coup c'est l'exe qui fait un LoadLibrary et pas de Pb pour echanger classes et methodes C++...
Marsh Posté le 03-08-2001 à 12:05:05
BENB a écrit a écrit : le .lib de l'exe pour compiler la Dll... |
Tu peux être plus précis je vois pas trop ce que tu veux dire.
Marsh Posté le 03-08-2001 à 12:08:21
BENB a écrit a écrit : SoWhatIn22 > Une factory, tu n'a generalement besoin que d'une instance, donc tu declare une globale de ce type dans la Dll oui sinon tu peux faire des chargement explicites en utilisant le .lib... le .lib de l'exe pour compiler la Dll... et du coup c'est l'exe qui fait un LoadLibrary et pas de Pb pour echanger classes et methodes C++... |
je suis désolé mais je n'arrive pas à comprendre ce que tu veux dire. Qu'est-ce que tu appelles une factory, exactement.
Et "le .lib de l'exe pour compiler la Dll": comprends pas du tout ce que tu veux dire
Apres, j'arrete de t'embeter, promis
Marsh Posté le 03-08-2001 à 13:24:10
Une Factory une Usine a classe, elle permet d'instancier des classes inconnues derivees d'une classe mere connue en general. Ce peut etre une methode ou une classe. Une classe permet d'en faire des liste avec des icones + description de la classe instanciee par l'usine.
On peut donc accoitre facilement les fonctionnalites d'un programme en chargeant des Dll qui contiendront des classes + factory. ces dll importent la classe de base qui est dans l'exe donc la Dll depends de l'exe et non le contraire, a la compil + link sera genere un .lib en plus de l'exe, et la Dll sera compilee avec le .lib
Au run le prog ne charge pas la Dll implicitement (il ne la connait pas), mais par un LoadLibrary, et la il lui faut recuperer la factory. Si c'est une methode il va faire un GetProcAdress. Si c'est une classe on peut instancier un exemplaire de celle-ci dans la Dll. La Factory dans son constructeur s'enregistre dans une liste, et le tour est joue.
Bien sur le probleme c'est que la Dll depend de l'exe et ne peut etre utilisee qu'avec lui. Ceci dit en mettant les classes meres dans une autre Dll dont dependent a la fois l'exe et la Dll courante on resoud ce probleme...
Bon bien sur on peut aussi utiliser COM, mais c'est moins rigolo...
Marsh Posté le 03-08-2001 à 13:50:58
pas simple ton truc. Je vais quand même aller voir ca de plus plres. Ca pourrait être instructif.
merci
Marsh Posté le 03-08-2001 à 14:01:56
Au pire, rien ne t'empeche d'avoir des fonctions en points d'entree et de les faire retourner des objets...
Marsh Posté le 03-08-2001 à 14:31:15
darthguy a écrit a écrit : Au pire, rien ne t'empeche d'avoir des fonctions en points d'entree et de les faire retourner des objets... |
mais ces objets doivent etre connus pour etre retournes... d'ou la dependance...
Marsh Posté le 03-08-2001 à 14:36:08
Ouaip. De toutes manieres, t'as forcement la dependance dans un sens. Mais je vois pas quel est l'interet de faire en sorte que se soit la dll qui soit dependante et pas l'inverse. Ca te permet d'exporter des objets plus simplement ?
Marsh Posté le 03-08-2001 à 14:46:52
darthguy a écrit a écrit : Ouaip. De toutes manieres, t'as forcement la dependance dans un sens. Mais je vois pas quel est l'interet de faire en sorte que se soit la dll qui soit dependante et pas l'inverse. Ca te permet d'exporter des objets plus simplement ? |
et d'en ajouter sans modifier l'executable, ce qui est comfortable quand ce sont tes clients qui font ces objets...
Marsh Posté le 02-08-2001 à 13:47:25
hello,
des petits soucis.
Je crée une dll avec VC++ 6.0.
Dans une appli, j'inclu le .h correspondant et le .lib, et la pas de soucis, je peux utiliser les fonctions de la dll.
Par contre, si j'essaye de charger la dll avec LoadLibrary et que j'essaye de faire un GetProcAddress pour récupperer un pointeur sur une des fonctions, alors pas moyen: pointeur NULL et erreur windows = ERROR_PROC_NOT_FOUND;
Si qq1 a une idée?
D'autre part, je ne comprends pas bien à quoi sert la fonction BOOL APIENTRY DllMain qu'il essaye de me générer. C'est visiblement un poiunt d'entrée pour la dll, mais le comportement est le même que je laisse cette fonction ou que je la vire.
Encore une fois, si qq1 a des explications ou un lien, je suis preneur.
Merci.