[DLL] Laison dynamique d'une dll de classe

Laison dynamique d'une dll de classe [DLL] - C++ - Programmation

Marsh Posté le 03-08-2004 à 10:34:21    

Bonjour a tous.
Je suis actuellement en train d'essayer de creer une dll d'une classe C++.
La creation de la DLL est faite par les fonctions dllexport et dllimport.
A priori elle se crée bien et j'arrive meme à l'utiliser en liaison statique avec l'inclusion du fichier .lib.
Je voudrais reussir a faire une laison dynamique, mais je n'y arrive pas.
Quelles sont les différentes étapes à effectuer pour faire cette liaison dynamique?
 
PS: Dans la création de ma DLL mon fichier .cpp est exactement identique a celui au fichier classique de l'implémentation de la classe contenue dans le .h. J'ai par contre modifié le .h pour mettre les fonction ddlexport et dll import apres le nom de la classe.
 
Merci d'avance pour votre aide.
 
a+

Reply

Marsh Posté le 03-08-2004 à 10:34:21   

Reply

Marsh Posté le 03-08-2004 à 10:36:49    

regarde dans ce topic, j'explique comment appeler une dll de façon dynamique
 
http://forum.hardware.fr/forum2.ph [...] 798&cat=10


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 03-08-2004 à 11:09:22    

Harkonnen a écrit :

regarde dans ce topic, j'explique comment appeler une dll de façon dynamique
 
http://forum.hardware.fr/forum2.ph [...] 798&cat=10


 
J'ai testé ce type de programme mais dans ton cas tu fais une DLL d'une fonction pas d'une classe.
Donc quand moi j'essaie d'appeler de cette maniere une méthode de ma classe ca ne marche pas .
 
Je te donne mon exemple de DLL. Ce n'est qu'un exemple simple pour tester car mon but etant de faire la dLL d'une classe ACtions plus importante dans le cadre d'un projet.
 
J'espere que tu ve pourvoir m'aider car j'ai trop de mùalk et je sature a force lol.
 
Voila la .h de la creation de la dll
 

Code :
  1. //***************************************************************************
  2. //Classe d'exception pour la connexion internet
  3. //***************************************************************************
  4. #ifndef __DLL_MODULE_H__
  5. #define __DLL_MODULE_H__
  6. #ifdef MADLL_EXPORTS
  7. #define LINKDLL __declspec(dllexport)
  8. #pragma message("Building DLL" )
  9. #else
  10. #define LINKDLL __declspec(dllimport)
  11. #pragma message("Importing DLL" )
  12. #endif
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <math.h>
  17. #include <iostream.h>
  18. #include <winsock2.h>
  19. #pragma comment(lib, "ws2_32.lib" )
  20. class LINKDLL erreur
  21. {
  22. private:
  23.  int cause;
  24. public:
  25.     erreur(int pcause);
  26. int get_cause();
  27. void afficher_Erreur(int);
  28.  
  29. };
  30. //---------------------------------------------------------------------------
  31. #endif


 
Et le .cpp
 

Code :
  1. #include "erreur.h"
  2. #define _WSAEINTR "10004 Interrupted function call"
  3. #define _WSAEACCES "10013 Permission denied"
  4. #define _WSAEFAULT "10014 Bad address"
  5. #define _WSAEINVAL "10022 Invalid argument"
  6. #define _WSAEMFILE "10024 Too many open files"
  7. #define _WSAEWOULDBLOCK "10035 Resource temporarily unavailable"
  8. #define _WSAEINPROGRESS "10036 Operation now in progress"
  9. #define _WSAEALREADY "10037 Operation already in progress"
  10. #define _WSAENOTSOCK "10038 Socket operation on non-socket"
  11. #define _WSAEDESTADDRREQ "10039 Destination address required"
  12. #define _WSAEMSGSIZE "10040 Message too long"
  13. #define _WSAEPROTOTYPE "10041 Protocol wrong type for socket"
  14. #define _WSAENOPROTOOPT  "10042 Bad protocol option"
  15. #define _WSAEPROTONOSUPPORT "10043 Protocol not supported"
  16. #define _WSAESOCKTNOSUPPORT "10044 Socket type not supported"
  17. #define _WSAEOPNOTSUPP "10045 Operation not supported"
  18. #define _WSAEPFNOSUPPORT "10046 Protocol family not supported"
  19. #define _WSAEAFNOSUPPORT  "10047 Address family not supported by protocol family"
  20. #define _WSAEADDRINUSE "10048 Address already in use"
  21. #define _WSAEADDRNOTAVAIL  "10049 Cannot assign requested address"
  22. #define _WSAENETDOWN "10050 Network is down"
  23. #define _WSAENETUNREACH "10051 Network is unreachable"
  24. #define _WSAENETRESET "10052 Network dropped connection on reset"
  25. #define _WSAECONNABORTED "10053 Software caused connection abort"
  26. #define _WSAECONNRESET "10054 Connection reset by peer"
  27. #define _WSAENOBUFS "10055 No buffer space available"
  28. #define _WSAEISCONN "10056 Socket is already connected"
  29. #define _WSAENOTCONN "10057 Socket is not connected"
  30. #define _WSAESHUTDOWN "10058 Cannot send after socket shutdown"
  31. #define _WSAETIMEDOUT "10060 Connection timed out"
  32. #define _WSAECONNREFUSED "10061 Connection refused"
  33. #define _WSAEHOSTDOWN "10064 Host is down"
  34. #define _WSAEHOSTUNREACH "10065 No route to host"
  35. #define _WSAEPROCLIM "10067 Too many processes"
  36. #define _WSASYSNOTREADY  "10091 Network subsystem is unavailable"
  37. #define _WSAVERNOTSUPPORTED "10092 WINSOCK.DLL version out of range"
  38. #define _WSANOTINITIALISED "10093 Successful _WSAStartup not yet performed"
  39. #define _WSAEDISCON "10094 Graceful shutdown in progress"
  40. #define _WSATYPE_NOT_FOUND "10109 Class type not found"
  41. #define _WSAHOST_NOT_FOUND "11001 Host not found"
  42. #define _WSATRY_AGAIN "11002 Non-authoritative host not found"
  43. #define _WSANO_RECOVERY "11003 This is a non-recoverable error"
  44. #define _WSANO_DATA "11004 Valid name, no data record of requested type"
  45. erreur::erreur( int pcause )
  46. {
  47. cause = pcause;
  48. }
  49. int erreur::get_cause()
  50. {
  51. return cause;
  52. }
  53. void erreur::afficher_Erreur(int pcode)
  54. {
  55. switch (pcode)
  56. {
  57. case 10004: printf("%s\n",_WSAEINTR);
  58.    break;
  59. case 10013: printf("%s\n",_WSAEACCES);
  60.    break;
  61. case 10014: printf("%s\n",_WSAEFAULT);
  62.    break;
  63. case 10022: printf("%s\n",_WSAEINVAL);
  64.    break;
  65. case 10024: printf("%s\n",_WSAEMFILE);
  66.    break;
  67. case 10035: printf("%s\n",_WSAEWOULDBLOCK);
  68.    break;
  69. case 10036: printf("%s\n",_WSAEINPROGRESS );
  70.    break;
  71. case 10037: printf("%s\n",_WSAEALREADY );
  72.    break;
  73. case 10038: printf("%s\n",_WSAENOTSOCK );
  74.    break;
  75. case 10039: printf("%s\n",_WSAEDESTADDRREQ );
  76.    break;
  77. case 10040: printf("%s\n",_WSAEMSGSIZE );
  78.    break;
  79. case 10041: printf("%s\n",_WSAEPROTOTYPE );
  80.    break;
  81. case 10042: printf("%s\n",_WSAENOPROTOOPT  );
  82.    break;
  83. case 10043: printf("%s\n",_WSAEPROTONOSUPPORT );
  84.    break;
  85. case 10044: printf("%s\n",_WSAESOCKTNOSUPPORT );
  86.    break;
  87. case 10045: printf("%s\n",_WSAEOPNOTSUPP );
  88.    break;
  89. case 10046: printf("%s\n",_WSAEPFNOSUPPORT );
  90.    break;
  91. case 10047: printf("%s\n",_WSAEAFNOSUPPORT );
  92.    break;
  93. case 10048: printf("%s\n",_WSAEADDRINUSE );
  94.    break;
  95. case 10049: printf("%s\n",_WSAEADDRNOTAVAIL );
  96.    break;
  97. case 10050: printf("%s\n",_WSAENETDOWN);
  98.    break;
  99. case 10051: printf("%s\n",_WSAENETUNREACH );
  100.    break;
  101. case 10052: printf("%s\n",_WSAENETRESET );
  102.    break;
  103. case 10053: printf("%s\n",_WSAECONNABORTED );
  104.    break;
  105. case 10054: printf("%s\n",_WSAECONNRESET);
  106.    break;
  107. case 10055: printf("%s\n",_WSAENOBUFS);
  108.    break;
  109. case 10056: printf("%s\n",_WSAEISCONN );
  110.    break;
  111. case 10057: printf("%s\n",_WSAENOTCONN );
  112.    break;
  113. case 10058: printf("%s\n",_WSAESHUTDOWN );
  114.    break;
  115. case 10060: printf("%s\n",_WSAETIMEDOUT );
  116.    break;
  117. case 10061: printf("%s\n",_WSAECONNREFUSED );
  118.    break;
  119. case 10064: printf("%s\n",_WSAEHOSTDOWN );
  120.    break;
  121. case 10065: printf("%s\n",_WSAEHOSTUNREACH );
  122.    break;
  123. case 10067: printf("%s\n",_WSAEPROCLIM );
  124.    break;
  125. case 10091: printf("%s\n",_WSASYSNOTREADY );
  126.    break;
  127. case 10092: printf("%s\n",_WSAVERNOTSUPPORTED );
  128.    break;
  129. case 10093: printf("%s\n",_WSANOTINITIALISED );
  130.    break;
  131. case 10094: printf("%s\n",_WSAEDISCON );
  132.    break;
  133. case 10109: printf("%s\n",_WSATYPE_NOT_FOUND );
  134.    break;
  135. case 11001: printf("%s\n",_WSAHOST_NOT_FOUND );
  136.    break;
  137. case 11002: printf("%s\n",_WSATRY_AGAIN );
  138.    break;
  139. case 11003: printf("%s\n",_WSANO_RECOVERY );
  140.    break;
  141. case 11004: printf("%s\n",_WSANO_DATA );
  142.    break;
  143. default : printf("Nothing..." );
  144. }
  145. }


 
Si tu ve que je t'envoie mon main de test demande moi je te le posterai.
Merci d'avance
 
a+

Reply

Marsh Posté le 03-08-2004 à 12:18:51    

Heuuh ... t'as pas l'impression de réinventer la roue avec ta gestion d'erreur là ??

Reply

Marsh Posté le 03-08-2004 à 12:47:04    

Cricri_ a écrit :

Heuuh ... t'as pas l'impression de réinventer la roue avec ta gestion d'erreur là ??

+1 [:mlc]
GetLastError(), c'est pas fait pour les chiens


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 03-08-2004 à 13:07:00    

Harkonnen a écrit :

+1 [:mlc]
GetLastError(), c'est pas fait pour les chiens


 
Tout d'abord premierement ca n'est qu'un exemple.
Deuxiemement GetLasterror() te retourne une erreur du type  10051 et il te dit pas a koi cela correspond. Voila pourquoi je redéfinis les constante de type WSA.
Bref peut importe la question n'est pas sur l'utilité relative ou non de mon programme mais plutot sur comment utiliser le constructeur et les méthodes de ma classe erreur via une liaison dynamique.
 
Si toi ou d'autres personnes ont une réponse aux appels dynamique de méthodes d'une classe exportée de la manière décrite plus haut merci de m'éclairer car je suis au fond du trou dans le noir total.
 
Merci d'avance


Message édité par TouperTinois le 03-08-2004 à 13:10:30
Reply

Marsh Posté le 03-08-2004 à 14:04:33    

quand on charge une bibliothèque dynamique de façon explicite (avec un LoadLibrary sous Windows et un dlopen sous unix), on ne peux pas appeler simplement un constructeur d'une classe de cette bibliothèque.
La façon la plus simple est, comme l'a dit Harkonnen, de définir une fonction qui va te permettre de construire cet objet. Une fois l'objet construit, tu peux le manipuler normalement.
 

Code :
  1. //dans le(s) entête(s) de la dll
  2. class X
  3. {
  4. public:
  5.     X();
  6.     ~X();
  7.     void f();
  8.     // etc.
  9. };
  10. extern "C" X* get_new_X_instance();
  11. // dans l'implémentation de la dll
  12. X::X()
  13. { ... }
  14. X* get_new_X_instance() { return new X; }
  15. // et dans ton pg principal:
  16. typedef X* (* CONSTRUCTEUR_DE_X) ();
  17. HINSTANCE lib = Loadlibrary("ma_bibliotheque.dll" );
  18. CONSTRUCTEUR_DE_X constucteur = (CONSTRUCTEUR_DE_X) GetProcAddress(lib,"get_new_X_instance" );
  19. // on récupère une instance
  20. X* instance = constructeur();
  21. // on peut la manipuler
  22. instance->f();
  23. // blabla ...
  24. delete X;


 
C'est la méthode la plus simple. A noter que contrairement à ce qui apparait ici, il est souvent préférable d'exporter également un desctructeur pour que la destruction ai lieu dans la bibliothèque.

Reply

Marsh Posté le 03-08-2004 à 14:46:34    

SoWhatIn22 a écrit :


C'est la méthode la plus simple. A noter que contrairement à ce qui apparait ici, il est souvent préférable d'exporter également un desctructeur pour que la destruction ai lieu dans la bibliothèque.


 
Je te remercie pour ton aide. Je vais tester ca tout de suite. Mias j'ai encore une question si je peut abuser lol.
Une fois que tu as appelé ta fonction qui crée une nouvelle instance de la classe de la DLL avec ce pointeur tu pêut accéder a toutes les méthodes de la classe. Quand tu y accèdes il y a un chargement de la DLL encore ou alors c'est indépendant de la DLL ensuite.
 
Merci en tout cas pour ce code que je vais tester.
++
 
EDIT :  
 
Il y avait un probleme car LoadLibrary a 2 L en majuscule mais ca j'ai changé. Le problème est que le compilateur me di qu'il ne reconnais pas le mot constructeur() (undeclared identifier). ET faut il que j'insere le .h de la dll dans le main ou pas. En gros quelles sont les insertions a faire dans mon prog principal.


Message édité par TouperTinois le 03-08-2004 à 15:22:12
Reply

Marsh Posté le 03-08-2004 à 15:15:45    

>Une fois que tu as appelé ta fonction qui crée une
> nouvelle instance de la classe de la DLL avec ce
> pointeur tu pêut accéder a toutes les méthodes de
> la classe.
 
oui
 
> Quand tu y accèdes il y a un chargement de la DLL encore
 
tu n'as pas bien compris ce qu'est le chargement d'une dll; pour faire simple: la dll n'est chargée qu'une seule fois, suite à l'appel de la fonction LoadLibrary. Elle n'est déchargée que lors de l'appel ultérieur de la fonction FreeLibrary.
 

Reply

Marsh Posté le 03-08-2004 à 15:29:27    

SoWhatIn22 a écrit :

>
tu n'as pas bien compris ce qu'est le chargement d'une dll; pour faire simple: la dll n'est chargée qu'une seule fois, suite à l'appel de la fonction LoadLibrary. Elle n'est déchargée que lors de l'appel ultérieur de la fonction FreeLibrary.


 
Oki j'ai bien compris mais saurais tu d'ou viens l'erreur de compilation au niveau du terme constructeur().
il di undeclared identifier.
En fait je comprend pas trop ton #define pe etre est ce le pb.
Faut il inclure le X.h dans le prog principal.
 
merci


Message édité par TouperTinois le 03-08-2004 à 15:30:23
Reply

Marsh Posté le 03-08-2004 à 15:29:27   

Reply

Marsh Posté le 03-08-2004 à 16:33:00    

> En fait je comprend pas trop ton #define pe etre est ce le pb.  
 
Ce n'est pas un #define, c'est un typedef! c'est complètement différent. Dans mon exemple, CONSTRUCTEUR_DE_X est un type: une instance de ce type est une fonction qui retourne un X* et qui ne prend pas d'argument.
 
un typedef est une déclaration de *type*.
 
> Faut il inclure le X.h dans le prog principal
 
Si tu en as besoin, oui! Sinon, il faut au moins déclarer le type de X.

Code :
  1. class X;
  2. typedef X* (* CONSTRUCTEUR_DE_X) ();


 
Mais de toute façon, si tu veux par la suite appeler des méthodes de l'instance créée, il faudra forcément inclure le header de la classe X, sans quoi le compilateur ne sera pas en mesure de générer le code puisque'il ne connait pas le type de l'instance que tu veux manipuler...


Message édité par SoWhatIn22 le 03-08-2004 à 16:37:17
Reply

Marsh Posté le 04-08-2004 à 10:07:55    

SoWhatIn22 a écrit :

> En fait je comprend pas trop ton #define pe etre est ce le pb.  


 
Merci pour tes conseils mais j'ai toujours des problemes de compil.
Je te donne mon main car je comprend pas pourquoi ca fonctionne pas c'est très bizarre car je pensais avoir compris ce que tu m'a di et en fait ca marqhe pas erreur de compilation.
Pour info j'ai mis la DLL dans le repertoire debug du projet du main et dans winNT/system.
 

Code :
  1. #include "erreur.h"
  2. #include <windows.h>
  3. void main()
  4. {
  5. class erreur;
  6. typedef erreur* (* CONSTRUCTEUR_DE_ERREUR) ();
  7.  
  8.   HINSTANCE lib = LoadLibrary("Madll.dll" );
  9.   CONSTRUCTEUR_DE_ERREUR constucteur = (CONSTRUCTEUR_DE_ERREUR) GetProcAddress(lib,"get_new_erreur_instance" );
  10.  
  11.   // on récupère une instance  
  12.   erreur* instance = constructeur();
  13.  
  14.   // on peut la manipuler  
  15.   instance->get_cause();
  16.   // blabla ...  
  17.   //delete X;   
  18. }


 
Voila l'erreur de compil obtenue.

Code :
  1. Compiling...
  2. main2.cpp
  3. C:\DOCUMENTS AND SETTINGS\ADMINISTRATOR\DESKTOP\STAGE ISICO 1A\MADLL\main2\main2.cpp(221) : error C2065: 'constructeur' : undeclared identifier
  4. C:\DOCUMENTS AND SETTINGS\ADMINISTRATOR\DESKTOP\STAGE ISICO 1A\MADLL\main2\main2.cpp(221) : error C2440: 'initializing' : cannot convert from 'int' to 'class erreur *'
  5.         Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
  6. Error executing cl.exe.
  7. Creating browse info file...


 
MErci encore a toi par avance.
Je sais que je suis pas très très fort mais bon faut bien apprendre :)


Message édité par TouperTinois le 04-08-2004 à 10:31:44
Reply

Marsh Posté le 04-08-2004 à 16:11:05    

1. si tu inclus le header erreur.h (je suppose que la classe erreur doit être déclarée dedans), alors tu n'as pas besoin de redéclarer le type (class erreur; )
 
je te donne un exemple qui fonctionne sous win32

Code :
  1. #include <iostream>
  2. #include <windows.h>
  3. typedef int (*FTYPE) ();
  4. static int glob=7;
  5. int f()
  6. {
  7. return glob;
  8. }
  9. class X;
  10. typedef X* (* CONSTRUCTEUR_DE_X) ();
  11. class X
  12. {
  13. public:
  14. X() {}
  15. ~X(){}
  16. int f() const { return 42; }
  17. };
  18. X* factory()
  19. {
  20. return new X;
  21. }
  22. int main(int argc, char* argv[])
  23. {
  24. HINSTANCE lib;
  25. FTYPE fptr;
  26. CONSTRUCTEUR_DE_X constructeur;
  27. fptr=f;
  28.     lib = LoadLibrary("Madll.dll" );
  29. if(lib)
  30. {
  31.  constructeur = (CONSTRUCTEUR_DE_X) GetProcAddress(lib,"get_new_erreur_instance" );
  32.  if(!constructeur)
  33.  {
  34.   constructeur=factory;
  35.  }
  36. }
  37. X* x=constructeur();
  38. std::cout << "f(): " << fptr() << std::endl;
  39. std::cout << "constructeur(): " << x->f() << std::endl;
  40. std::cin.ignore();
  41. return 0;
  42. }

Reply

Marsh Posté le 04-08-2004 à 16:31:29    

Dans ce header que je suppose s'arrete avant le main
ou ets ce que tu exportes la fonction factory qui crée l'instance.
Pourquoi menlange tu le .h et le .cpp. Est ce important ou est ce que je pe le séparer comme je l'ai montré au dessus.
 
vais essayer ca merci :)
 

Reply

Marsh Posté le 04-08-2004 à 22:27:48    

J'ai fait le ménage, le boulet est banni et ses posts supprimés ;)

Reply

Marsh Posté le 04-08-2004 à 22:31:22    

antp a écrit :

J'ai fait le ménage, le boulet est banni et ses posts supprimés ;)


c'était allopassxp encore ?


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 04-08-2004 à 22:45:37    

Harkonnen a écrit :

c'était allopassxp encore ?


 
Pas sûr, mais y a des chances.


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 06-08-2004 à 09:06:13    

Si quelqu'un a une idée pour que la liaison marche je vous remercie car je dois créer des dll importantes pour un projet que je dois rendre sous peu.
(rien a voir avec ma classe d'exception merdique)  
 
merci ++

Reply

Marsh Posté le 18-10-2009 à 17:31:39    

Je réponds bien bien tard, mais y'aurait pas simplement eu une faute de frappe dans son code? ("constucteur" au lieu de "constRucteur" ).
 
Enfin bref en tout cas merci pour l'info je saurai ainsi comment faire moi aussi (je suis tombé ici en cherchant une réponse sur mon meilleur ami :D)

Reply

Sujets relatifs:

Leave a Replay

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