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

Linker dynamiquement sans .def

25 réponses
Avatar
Michaël Monerau
Bonjour,

Je cherche à faire un système de "plugin" pour mon programme.
C'est-à-dire que toutes les .dll dans le répertoire "plugins" de mon
prog doivent être chargées, et doivent présenter une interface définie.

Pour cela, dans le programme principal, je fais un LoadLibrary sur
toutes les dlls. Puis, j'appelle GetProcAddress avec les bons arguments.

Actuellement, je n'ai réussi à faire marcher cela que dans un seul cas :
lorsque j'écris un .def à la main pour les dlls plugin qui disent
exactement quelles fonctions doivent être exportées. Là, GetProcAddress
s'y retrouve.

Maintenant, comme il risque d'y avoir pas mal de fonctions à exporter et
à lier ainsi dynamiquement, j'aimerais me passer de l'étape de la
création du .def. Mais même si je mets un "__declspec(dllexport)" devant
les fonctions à exporter, elles ne sont pas reconnues par GetProcAddress
sans le .def pour linker les plugins...

Tout d'abord, est-ce normal ? Si oui, comment puis-je faire pour éviter
d'avoir à écrire le .def à chaque fois (génération auto ?) ? Je subodore
que cela vienne du name mangling, mais j'attends vos
confirmations/infirmations ;-)

--
Michaël << Cortex >> Monerau

10 réponses

1 2 3
Avatar
PurL
Michaël Monerau wrote:
Bonjour,

Je cherche à faire un système de "plugin" pour mon programme.
C'est-à-dire que toutes les .dll dans le répertoire "plugins" de mon
prog doivent être chargées, et doivent présenter une interface
définie.




exactement ce que je suis en train de faire :)

Pour cela, dans le programme principal, je fais un LoadLibrary sur
toutes les dlls. Puis, j'appelle GetProcAddress avec les bons
arguments.




pareil...

Actuellement, je n'ai réussi à faire marcher cela que dans un seul
cas : lorsque j'écris un .def à la main pour les dlls plugin qui
disent exactement quelles fonctions doivent être exportées. Là,
GetProcAddress s'y retrouve.




Je compile sous BCB5.0 et les fonctions de la DLL que je souhaite exportée
sont de la forme :
extern "C" __declspec(dllexport) void __stdcall MaFunc(int index)

Ca marche bien, mais dans tous ça, je n'utilise pas de .DEF, d'ailleurs je
n'ai meme pas ce type de fichier ?
Si quelqu'un a une explication...

Je subodore que cela vienne du name mangling, mais j'attends vos
confirmations/infirmations ;-)



c'est quoi le name mangling ?

PurL.
Avatar
Dominique Vaufreydaz
Bonjour,

Je compile sous BCB5.0 et les fonctions de la DLL que je souhaite exportée
sont de la forme :
extern "C" __declspec(dllexport) void __stdcall MaFunc(int index)
Ca marche bien, mais dans tous ça, je n'utilise pas de .DEF, d'ailleurs je
n'ai meme pas ce type de fichier ?
Si quelqu'un a une explication...



Je extern C resous ton programme. Si ta fonction n'etais défini a la C,
son nom exporte contiendrait aussi les definition de type puisqu'en C++,
ce qui est critique entre 2 fonction c'est le nom et les parametres (pas
celui de retour cependant...).

Je subodore que cela vienne du name mangling, mais j'attends vos
confirmations/infirmations ;-)


c'est quoi le name mangling ?



enleve le extern "C" et regarde avec dependancy walker le nom
de tes fonctions, tu comprendras... En plus, a une epoque, sur la
version C++ des noms de fonction, Visual/Borland n'utilisait
pas la meme convention de nom (je ne sais pas dire si c'est
toujours le cas...).

Perso, j'exporte une fonction en C pure qu iensuite mle permet
de declarer ce qu'est capable de faire monb module et tout roule
dans mes plugins...

Doms.
--
Impose ta chance, serre ton bonheur et va vers ton risque.
A te regarder, ils s'habitueront.
René Char, Les Matinaux.
----
http://Dominique.Vaufreydaz.free.fr/
http://TitchKaRa.free.fr/
http://logiciels.ntfaqfr.com/
Avatar
Michaël Monerau
PurL a écrit :
Je compile sous BCB5.0 et les fonctions de la DLL que je souhaite exportée
sont de la forme :
extern "C" __declspec(dllexport) void __stdcall MaFunc(int index)



Comme le disait Doms, tu utilises "extern "C"", ce qui "désactive" le
name mangling sur ta fonction (voir explication ci-dessous).

Ca marche bien, mais dans tous ça, je n'utilise pas de .DEF, d'ailleurs je
n'ai meme pas ce type de fichier ?
Si quelqu'un a une explication...



Sous Visual, un .def est un fichier qui donne explicitement les symboles
à exporter dans la dll. Je pense qu'il doit y avoir un équivalent sous
BCB... Au cas où tu enlèves le "extern "C"", tu as forcément un moyen
d'exporter tout de même les symboles que tu veux. Mais je ne connais pas
BCB :p

Je subodore que cela vienne du name mangling, mais j'attends vos
confirmations/infirmations ;-)



c'est quoi le name mangling ?



Le name mangling est un mécanisme des compilateurs (ou plus précisément
linker) C++. Comme, en C++, on peut overloader les fonctions (même nom
de fonction pour des paramètres de types différents), pour s'y
retrouver, le linker voit tes fonctions sous une forme totalement
différente du simple nom. En effet, si tu as :

void mafonction (int id);
void mafonction (float id_f);

Le linker et le compilateur doivent bien avoir un moyen pour
différencier les deux. La solution qu'il utilisent est que la fonction
est vue comme un arrangement énorme de symboles définissant tout (les
noms "décorés", ou mangled names), des paramètres à la convention
d'appel. Ainsi, si le linker doit lier à la fonction "float", bin elle
utilise son nom décoré et tout le monde sait directement de quoi il est
question.

Le problème qu'on rencontre à l'export des symboles automatiquement,
c'est que c'est le nom décoré qui est exporté, et non celui qu'on a
écrit. Donc dans GetProcAddress, il faudrait appeler avec comme argument
le nom décoré, ce qui est en pratique complètement infaisable (c'est une
suite de @, de f, i, ... où seul le linker s'y retrouve).

En C, l'overloading n'étant pas permis (mmh... pas sûr ?), le name
mangling n'intervient pas. Du coup, si tu mets "extern "C"", ça explique
pourquoi le nom n'est pas décoré quand il est exporté.
--
Michaël "Cortex" Monerau
http://www.drag-network.com
Avatar
adebaene
"Manuel Leclerc" wrote in message news:<40758895$...
Michaël Monerau a écrit :

> Je subodore que cela vienne du name mangling, mais
> j'attends vos confirmations/infirmations ;-)

A mon avis tu subodores super bien. Utilises un
outils pour voir sous quels noms tes fonctions
sont exportées, et tu ne seras pas déçu du voyage.

Perso, je ne sais pas me passer du point DEF, et
j'attends la "bonne" réponse avec impatience.


extern "C" si tu n'exportes que des fonctions (pas des classes). Ca
évite le name mangling

Arnaud
Avatar
Michaël Monerau
Manuel Leclerc a écrit :
Tu ajoutes une couche de complexité avec un avantage que je ne
vois pas. Plus de risque de bug, et puis c'est tout. Quel est
le problème avec le DEF ?



Pour éclaircir ta vision, voilà concrètement ce que ça donne :

class IPlugin
{
public:
virtual void InitPlugin () = 0;
virutal std::string GetVersion () = 0;
virtual std::string GetName () = 0;
// ...
};

On a donc affaire à un classe abstraite. Dans un nouveau plugin, il me
suffit de faire :

class PluginPerso : public IPlugin
{
public :
virtual void InitPlugin () {...}
virtual std::string GetVersion () {return "v1.0";}
virtual std::string GetName () {return "test";}
// ...
}

Maintenant, il suffit d'une seule fonction exportée "GetInterface" par
exemple :

DLL_EXPORT IPlugin* GetInterface ()
{
return new PluginPerso ();
}

Bon, il faudra bien penser au delete... Mais ça ne fait qu'une seule
fonction dans le .def, et ça fait donc un .def facilement copiable pour
tous les plugins. Et comme disait Quentin, comme le .def n'est pas
"vérifié", il vaut mieux l'utiliser le moins possible.

C'est donc plus dans l'esprit POO du C++. Maintenant, c'est vrai que si
tu es habitué au C, ça peut paraître beaucoup de peine pour le même
résultat ;-) Cependant, ici, on laisse le compilo se débrouiller tout
seul avec ses adresses de fonction dans la vtable, ce qui réduit le
risque de bugs, justement.
--
Michaël "Cortex" Monerau
http://www.drag-network.com
Avatar
adebaene
"Quentin Pouplard" wrote in message news:...
Manuel Leclerc wrote:
> Quentin Pouplard a écrit :
>
> > Manuel Leclerc wrote:
> >
> > > [snip COM like stuff]
> > >
> > > Tu ajoutes une couche de complexité avec un avantage que je ne
> > > vois pas. Plus de risque de bug, et puis c'est tout. Quel est le
> > > problème avec le DEF ?
> >
> > Je ne suis pas d'accord, on parle de C++ et donc en principe de
> > POO...
> > et donc tu auras quoi?
> >
> > [...]
>
> Ha mais moi j'avais pas compris que c'était du C++/OO/COM/toussa.

COM repose sur les mêmes
concepts, la grosse différence est que la dll n'expose pas une fonction
qui crée l'instance



Bien sûr que si! Quelles sont les méthodes exportées par une DLL COM?
Entre autres GetClassObject qui fait exactment la même chose (c'est
une fonction "factory" qui te renvoie une instance d'un objet).

Le problème, c'est que les DLL ne sont pas conçues pour exporter de
manière portable des objets (à cause du name-mangling et de l'abscence
de normalisation sur la représentation d'un "objet"). Donc quand on
doit mettre un modèle objet dans une DLL, on s'arrange pour n'exporter
que des méthodes "C" qui servent de point d'entrée pour accéder aux
objets de la DLL.

Arnaud
Avatar
Manuel Leclerc
Michaël Monerau a écrit :

Manuel Leclerc a écrit :

> Tu ajoutes une couche de complexité avec un avantage
> que je ne vois pas. Plus de risque de bug, et puis
> c'est tout. Quel est le problème avec le DEF ?

Pour éclaircir ta vision, voilà concrètement ce que ça donne :

class IPlugin
[...]



Bof. En C, tu fais une structure de pointeurs de fonctions et
tu as exactement le même résultat. Et tu peux écrire ton
plugin en Delphi, si ça t'amuse. Je vois vraiment pas
l'intérêt de continuer à discuter de cette histoire
d'utiliser du C++ pour faire une interface binaire entre
deux codes indépendants.

--
Pour netscape, il est fournit avec le bouquin : regarde à la fin du
livre, y a une disquette 5'1/4. On la voit pas au début parce qu'ils
l'ont plié en deux pour qu'elle tienne dans le bouquin. Tu y trouveras
l'install de Netscape 2.02 pour windows XP et le JDK 1.0_3b. --benou
Avatar
Martinez Jerome
Dominique Vaufreydaz wrote:
enleve le extern "C" et regarde avec dependancy walker le nom
de tes fonctions, tu comprendras... En plus, a une epoque, sur la
version C++ des noms de fonction, Visual/Borland n'utilisait
pas la meme convention de nom (je ne sais pas dire si c'est
toujours le cas...).



C'est toujours le cas (BCB6 et VC7)
Utiliser du C++ dans les DLL est impossible entre differents
compilateurs, a *proscrire* lors de la creation d'interface de plugins.
Avatar
Martinez Jerome
Michaël Monerau wrote:


Sous Visual, un .def est un fichier qui donne explicitement les symboles
à exporter dans la dll. Je pense qu'il doit y avoir un équivalent sous
BCB... Au cas où tu enlèves le "extern "C"", tu as forcément un moyen
d'exporter tout de même les symboles que tu veux. Mais je ne connais pas
BCB :p



avec le .def, de la meme maniere.
Mais le name mangling etant different entre les compilo, l'appel d'un
programme ecrit sous BCB plantera si il fait appel a une DLL ecrite en
VC, meme si les .def sont identiques :((

(si c'est faux, je veux la solution!!!)
Avatar
Michaël Monerau
Manuel Leclerc a écrit :

Bof. En C, tu fais une structure de pointeurs de fonctions et
tu as exactement le même résultat. Et tu peux écrire ton
plugin en Delphi, si ça t'amuse. Je vois vraiment pas
l'intérêt de continuer à discuter de cette histoire
d'utiliser du C++ pour faire une interface binaire entre
deux codes indépendants.



En effet, on peut y arriver aussi. Mon point était que c'est moins
élégant, et moins pratique. Avec cette solution, il n'y a qu'à faire un
copier-coller et changer le corps des quelques fonctions vite fait. Le
tableau des pointeurs de fonctions est maintenu automatiquement par le
compilo quand il fait sa vtable pour les fonctions virtuelles.

L'intérêt de causer de ça, c'est que c'est ma question du départ :) Ca
décide un paquet de choses pour mon projet, et je voudrais être sûr de
faire le bon choix ;)


--
Michaël "Cortex" Monerau
http://www.drag-network.com
1 2 3