(win32) classe dans une dll

classe dans une dll (win32) - C++ - Programmation

Marsh Posté le 26-08-2003 à 12:02:08    

bonjour, j'ai compilé une dll avec une classe dedans, dont j'ai la déclaration :
 
typedef class MaClasse
{
   public:
   void Membre();
} MaClasse, *pMaClasse;
 
comment faire pour l'instancier apres avoir chargé ma dll ?
 
HMODULE hMod = LoadLibrary("MaDLL" );


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-08-2003 à 12:02:08   

Reply

Marsh Posté le 26-08-2003 à 12:06:37    

typedef class <= what's that
 
 
Fo que tu reprennes tes cours sur les DLL  

Reply

Marsh Posté le 26-08-2003 à 12:33:07    

vaut mieux faire
 
class MaClasse {
//
};
typedef MaClasse * pMaClasse;
 
?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-08-2003 à 12:34:45    

c juste que je trouve ca moche :O
dans l'ensemble chui rarement fan des types qui cachent qu'un objet est un ptr... enfin bon c pas le pb
 
tu peux pas instance directement une classe comme tu compte le faire, ou alors il faut exporter ta classe de ta dll
 
T'utilise quoi cmme compilo ?

Reply

Marsh Posté le 26-08-2003 à 12:42:39    

j'utilise vc++7, dsl de pas l'avoir précisé :(
 
sinon, pour exporter ma classe il me semble que je doive faire :
 

Code :
  1. class __declspec(dllexport) MaClasse {
  2. //
  3. };


 
ou, d'apres le générateur de vc++ pour pouvoir utiliser le meme header pour la DLL et pour les executables qui l'appeleront :
 

Code :
  1. #ifdef MADLL_EXPORTS
  2. #define MADLL_API __declspec(dllexport)
  3. #else
  4. #define MADLL_API __declspec(dllimport)
  5. #endif
  6. class MADLL_API MaClasse {
  7. //
  8. };


 
ensuite donc je charge ma DLL avec LoadLibrary (c'est impératif)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-08-2003 à 12:47:06    

Citation :

ensuite donc je charge ma DLL avec LoadLibrary (c'est impératif)


 
hum
la c'est embetant
tu peux pas utiliser la lib que visual te recrache et la linker a ton exe ?

Reply

Marsh Posté le 26-08-2003 à 12:48:35    

BlackGoddess a écrit :

ensuite donc je charge ma DLL avec LoadLibrary (c'est impératif)


 
Tu ne pourras donc pas importer directement des classes comme ça. En effet, la seule fontion disponible est alors GetProcAddress qui ne sait charger que des fonctions.
Il faut que tu passes par des techniques un peu différente. COM est celle utilisée en standard dans Windows mais tu peux faire des choses plus simple (une fonction dans ta dll qui fait un new et renvoie un pointeur vers ton objet et une fonction pour le deleter peut suffire).


---------------
each day I don't die is cheating
Reply

Marsh Posté le 26-08-2003 à 13:27:11    

gatorette a écrit :


 
En effet, la seule fontion disponible est alors GetProcAddress qui ne sait charger que des fonctions.
Il faut que tu passes par des techniques un peu différente. COM est celle utilisée en standard dans Windows mais tu peux faire des choses plus simple (une fonction dans ta dll qui fait un new et renvoie un pointeur vers ton objet et une fonction pour le deleter peut suffire).
 


Excellente info, gatorette, merci. (C'est un pb qui me taraudait moi aussi...)


---------------
NOUVEAU! Le guide de l'édition en version ebook : http://marcautret.free.fr/autret/150q-ebook/
Reply

Marsh Posté le 26-08-2003 à 13:55:05    

tu peux pas utiliser la lib que visual te recrache et la linker a ton exe ?
 
>> c'est pour créer un système de plugin, je ne peux pas me permettre de relinker mon projet à chaque ajout/suppression de plugin.
 
excellente idée gatorette merci, sinon aurais-tu des infos sur la technique COM ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-08-2003 à 13:59:19    

bon, ben methode 3dsmax que je trouve de tres bon gout : classe de base avec methode virtuelle pure, deux fonction exportee de la dll :
 
->une donnant le nombre de plug in contenu
->une creant un objet "plugin numero i"
 
et roule simone

Reply

Marsh Posté le 26-08-2003 à 13:59:19   

Reply

Marsh Posté le 26-08-2003 à 14:13:56    

je maitrise pas encore super bien le ++ du c ... je vais donc deja me documenter sur les méthodes virtuelles pures avant d'essayer de comprendre ...


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-08-2003 à 14:19:43    

j'ai testé la méthode de gatorette :  
 
dans ma dll :
 

Code :
  1. #include <windows.h>
  2. class CTest
  3. {
  4. public:
  5. CTest();
  6. ~CTest();
  7. void Membre();
  8. };
  9. CTest::CTest()
  10. {
  11. MessageBox(NULL, "CTor", "CTest", NULL);
  12. }
  13. CTest::~CTest()
  14. {
  15. MessageBox(NULL, "DTor", "CTest", NULL);
  16. }
  17. void CTest::Membre()
  18. {
  19. MessageBox(NULL, "Membre", "CTest", NULL);
  20. }
  21. CTest* WINAPI _new()
  22. {
  23. return new CTest();
  24. }
  25. void WINAPI _delete(CTest* Test)
  26. {
  27. delete Test;
  28. }


 
j'ai exporté les fonctions _new et _delete
 
puis dans mon executable :
 

Code :
  1. #include <windows.h>
  2. class CTest
  3. {
  4. public:
  5. CTest();
  6. ~CTest();
  7. void Membre();
  8. };
  9. typedef CTest* (WINAPI* fnew)();
  10. typedef void (WINAPI* fdelete)(CTest* Test);
  11. int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int ns)
  12. {
  13. HMODULE hMod = LoadLibrary("testdll" );
  14. fnew _new = (fnew)GetProcAddress(hMod, "_new" );
  15. fdelete _delete = (fdelete)GetProcAddress(hMod, "_delete" );
  16. CTest* test = _new();
  17. test->Membre();
  18. _delete(test);
  19. return 0;
  20. }


 
le problème à la compilation :
 
error LNK2019: symbole externe non résolu "public: void __thiscall CTest::Membre(void)" (?Membre@CTest@@QAEXXZ) référencé dans la fonction _WinMain@16


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-08-2003 à 14:22:25    

joue la comme ca
 
:
 
DLL :
 

Code :
  1. class CTest
  2. {
  3. public:
  4. virtual void Membre()=0;
  5. };
  6. class CTest2:public CTest
  7. {
  8. public:
  9. virtual void Membre(){}
  10. }
  11. extern "C"
  12. {
  13. CTest* WINAPI _new()
  14. {
  15. return new CTest2();
  16. }
  17. void WINAPI _delete(CTest* Test)
  18. {
  19. delete Test;
  20. }
  21. }


 
 
Exe :

Code :
  1. class CTest
  2. {
  3. public:
  4. virtual void Membre()=0;
  5. };


 
le reste a peu pres comme tu fais

Reply

Marsh Posté le 26-08-2003 à 14:22:53    

+ oublie pas le . res de ta dll

Reply

Marsh Posté le 26-08-2003 à 14:26:22    

Normal l'erreur, t'as pas défini ta methode.
Tente en spécifiant ta classe comme importée.
Je trouve que ton code commence à ressembler à une classe C++ utilisée à la C.
Pourquoi ne pas exporter une structure et des fonctions C et écrire un wrapper C++ ?
 
Sinon COM pour un plugin c'est bien oui. Mais c'est pas évident...


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 26-08-2003 à 14:39:51    

merci, ca marche impeccable.
 
par contre il va vraiment falloir que je me documente sur les méthodes virtuelles parce que je tatonne ...


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 26-08-2003 à 19:28:17    

Juste pour repondre a Gatorette, on peu si utilisation MFC (et AFXEXT) creer des DLL exportant des Class (pure ou pas).
Par contre jamais teste si Win32 pure.
 
Edit : BlackGoddess au fait pkoi LoadLibrary imperatif pour toi ?


Message édité par VisualC++ le 26-08-2003 à 19:28:51
Reply

Marsh Posté le 26-08-2003 à 23:49:42    

VisualC++
 
bien, si je fais mon plugin en dll (la méthode la moins contraignante je pense par rapport a la 2eme méthode : COM car il n'y a pas besoin d'enregistrer son plugin alors qu'avec COM d'apres ce que j'ai compris c'est obligatoire) il y a 2 méthodes pour la charger : l'inclure "en dur" au linkage, ou la charger avec LoadLibrary puis appeler ses fonctions avec GetProcAddress.
 
la méthode au linkage est à éliminer car je ne sais pas par avance le nom de mes plugins, leur nombre, etc. Reste donc la 2eme méthode.
 
Si tu vois une autre solution je suis preneur :)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 27-08-2003 à 01:16:03    

VisualC++ a écrit :

Juste pour repondre a Gatorette, on peu si utilisation MFC (et AFXEXT) creer des DLL exportant des Class (pure ou pas).
Par contre jamais teste si Win32 pure.


 
Je ne connais pas ce type de DLL (j'utilise de moins en moins les MFCs maintenant que j'ai découvert la WTL) mais je ne pense pas que tu puisse lier ta bibliothèque de façon dynamique.
Et de façon statique, il est possible (avec Visual C++) d'exporter n'importe quelle classe MFC ou non (exception faite des classes avec templates).


---------------
each day I don't die is cheating
Reply

Marsh Posté le 27-08-2003 à 01:43:29    

BlackGoddess a écrit :

...il n'y a pas besoin d'enregistrer son plugin alors qu'avec COM d'apres ce que j'ai compris c'est obligatoire...


 
Il est obligatoire d'enregistrer ses interfaces avec COM mais ce n'est pas très contraignant (quelques fonctions à implémenter qui sont créées automatiquement si tu utilises ATL ou que tu peux facilement adapter d'un exemple sinon). Mais l'avantage de COM est que tu n'as pas besoin de connaître le nom ou l'emplacement des DLLs.
COM a aussi l'avantage d'être la technologie utilisée par Microsoft pour avoir des "objets dynamiques". Les technologies récentes de Microsoft l'utilisent partout (Shell, DirectX...) et que beaucoup de gens connaissent et savent utiliser. De plus, c'est un système éprouvé et qui a dû demander pas mal de réflexion.
Il peut être intéressant de te pencher sur DirectShow et ses filtres. Le peu que j'en connaisse, c'est un système très riche. De plus, selon ton application, il peut être intéressant de pouvoir réutiliser les centaines (?), milliers (?) de filtres existants.
 
J'ai fait l'apologie de COM ici, mais c'est juste pour te montrer que la complexité n'est pas insurmontable et que c'est une technologie qui a certains avantages. Mais j'utilise pour le moment mon propre système que j'ai développé !
Une voie à explorer (si tu as le temps), c'est de regarder comment sont faits les API de logiciels communs utilisant des plug-ins (Winamp, 3DS-Max, Photoshop...).


---------------
each day I don't die is cheating
Reply

Marsh Posté le 27-08-2003 à 01:54:04    

3ds c'est comme j'ai expliqué : une DLL exportant des classes via une fonction de dll exporté (je suis hyper clair je sais)
 
Enfin, plus precisement :
 
la dll comprends deux fonctions :
->nombre de plugs in contenu
->fonction pour avoir une description du plug in n°i
 
la description donne le type du plug in (modifier, export...) et a aussi un fonction permettant la creation de l'objet plug in en lui meme. Ceux ci derivent tjs de classes de bases issu de 3dsmax (SimpleModifier....)
 
C'est relativement simple a faire, et assez efficace aussi

Reply

Marsh Posté le 27-08-2003 à 13:56:12    

Moi je fais comme ca :
 

Code :
  1. // A partager entre le code client et la dll
  2. class Interface
  3. {
  4. public:
  5.   virtual void Release() = 0;
  6.   virtual void Methode1() = 0;
  7.   virtual void Methode2() = 0;
  8. };
  9. // Dans la DLL
  10. class Implementation : public Interface
  11. {
  12. public:
  13.   Implementation() { }
  14.   ~Implementation() { }
  15.   void Release()
  16.   {
  17.     delete this;
  18.   }
  19.   void Methode1() { }
  20.   void Methode2() { }
  21. };
  22. extern "C" __declspec(dllexport) void CreerInstance( Interface *& blah )
  23. {
  24.   blah = new Implementation;
  25. }
  26. // Code client
  27. typedef void (* BLEH)( Interface *& );
  28. HMODULE hLib = LoadLibrary( "gnagna.dll" );
  29. BLEH fonction = reinterpret_cast<BLEH>(GetProcAddress( hLib, "CreerInstance" ));
  30. Interface * objet;
  31. fonction( objet );
  32. object->Methode1();
  33. object->Methode2();
  34. object->Release();

Reply

Marsh Posté le 27-08-2003 à 23:59:17    

c'etait la méthode abordée par chrisbk en plus développée, elle me plait beaucoup :)
 
je ne savais pas qu'il était possible de faire : delete this;
ca evite de devoir exporter une 2eme fonction :)
 
merci beaucoup :)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 28-08-2003 à 01:10:03    

BlackGoddess a écrit :

je ne savais pas qu'il était possible de faire : delete this;
ca evite de devoir exporter une 2eme fonction :)


Il n'est pas impossible de faire des delete this; mais je trouve que cela devrait être évité à tout prix (et je ne suis pas le seul !).
Voici quelques articles sur le sujet ici ; et surtout celui-ci   qui présente pas mal de raisons de ne pas faire delete this.
 
--edit--
Correction d'un tag


Message édité par gatorette le 28-08-2003 à 01:10:47

---------------
each day I don't die is cheating
Reply

Marsh Posté le 28-08-2003 à 09:22:56    

mmh.
 
et si on fait :

Code :
  1. // Code client
  2.   typedef void (* BLEH)( Interface *& );
  3.  
  4.   HMODULE hLib = LoadLibrary( "gnagna.dll" );
  5.   BLEH fonction = reinterpret_cast<BLEH>(GetProcAddress( hLib, "CreerInstance" ));
  6.   Interface * objet;
  7.   fonction( objet );
  8.   object->Methode1();
  9.   object->Methode2();
  10.   delete object;


 
je suppose que c'est mauvais car le heap de l'executable et le heap de la dll n'est le meme ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 28-08-2003 à 09:32:52    

BlackGoddess a écrit :

je suppose que c'est mauvais car le heap de l'executable et le heap de la dll n'est le meme ?


 
Je ne sais pas trop sur ce point là, mais c'est de toute façon mauvais car tu n'es pas sûr de la façon dont ton objet a été créé.
 
Que se passe t'il si le plug-in se comporte comme ça :

Code :
  1. // variable globale
  2. Interface monObj;
  3. // fonction de création
  4. Interface * WINAPI CreerObjet()
  5. {
  6. return( &monObj );
  7. }


 
Ton application va planter au moment du delete ! Il me semble important de laisser la responsabilité de la création et de la destruction à la même personne.


---------------
each day I don't die is cheating
Reply

Marsh Posté le 28-08-2003 à 09:54:21    

Citation :

je suppose que c'est mauvais car le heap de l'executable et le heap de la dll n'est le meme ?


 
Oui. C'est même pire que ça, car les lib standards peuvent être différentes ou de version différente (genre un prog BCB qui fait un delete sur un objet d'une dll VC++ ...).


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 28-08-2003 à 12:19:43    

bien, encore merci pour ces précisions :)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 28-08-2003 à 13:47:03    

Il n'y a aucun problème a faire un delete this;, la méthode Release de COM fait la même chose.
De plus dans le logiciel qu'on développe pour le moment on a une 30aine d'interfaces créées de cette façon, ca n'a jamais planté, et c'est compilé avec 7 compilateurs différents sur 4 OS et 3 consoles...

Reply

Marsh Posté le 28-08-2003 à 13:51:35    

lool je prends note de la fiabilité évidente de cette méthode :)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 28-08-2003 à 15:06:53    

gatorette a écrit :


Que se passe t'il si le plug-in se comporte comme ça :

Code :
  1. // variable globale
  2. Interface monObj;
  3. // fonction de création
  4. Interface * WINAPI CreerObjet()
  5. {
  6. return( &monObj );
  7. }


 
Ton application va planter au moment du delete ! Il me semble important de laisser la responsabilité de la création et de la destruction à la même personne.


 
Une interface (ou une classe abstraite, pour parler en C++) ne peut pas être instanciée...
 

Reply

Marsh Posté le 28-08-2003 à 15:55:01    

Ashe2 a écrit :


Une interface (ou une classe abstraite, pour parler en C++) ne peut pas être instanciée...


 
J'ai appelé abusivement ma classe Interface. Ce qui rend mon code peu compréhensible.
 
Code dans la DLL :

Code :
  1. class Interface
  2. {
  3. //
  4. // des fonctions purement virtuelles
  5. //
  6. };
  7. class MonPlugin : public Interface
  8. {
  9. //  
  10. // implémentation des fonctions d'Interface
  11. //
  12. }
  13. // variable globale  
  14. MonPlugin monObj;
  15. // fonction de création  
  16. Interface * WINAPI CreerObjet()
  17. {
  18. return( &monObj );
  19. }


 
J'espère que c'est plus clair.


---------------
each day I don't die is cheating
Reply

Marsh Posté le 28-08-2003 à 16:28:48    

Désolé, tt facon j'avais pas vu que tu parlais du code du plugin

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed