IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++/CLI Discussion :

Dépendances de DLL C++/CLI


Sujet :

C++/CLI

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 4
    Par défaut Dépendances de DLL C++/CLI
    Je suis débutant en C++/CLI et je bloque sur un problème... Je vais tenter de l'expliquer le plus clairement possible :

    J'ai créé deux DLL C++/CLI :
    La première (A) est utilisée par la seconde (B).
    "A" définit quelques classes abstraites, et quelques classes concrêtes (toutes managées).
    "B" définit uniquement des classes concrêtes (managées également) qui héritent des classes abstraites définies dans "A". Notez que toutes les classes définies dans "A" sont importées quelque part dans "B".
    Toutes les classes concrêtes définies dans A et B servent à wrapper des objets natifs C++ (pour y accéder depuis du C#) qui sont définis dans d'autres DLL (natives, mais compilées avec /clr, comme A et B).

    Je compile bien mes DLL, je les référence dans le C#, et c'est là que le problème apparait :
    Dans l'explorateur d'objets, ma DLL "A" est vide, et ma DLL "B" contient tous les objets de "A" et "B" réunis.
    Aprés réflexion, j'ai trouvé ca (à peu près) normal étant donné que "A" ne contient aucun ".cpp" ; uniquement des ".h" ; et que "B" inclut tout "A"...

    Je me suis alors dit qu'en mettant des .cpp dans "A" ca changerait le problème.
    En effet, j'ai simplement rajouté dans "A" un fichier ".cpp" qui contenait uniquement l'include du fichier ".h" correspondant (pas de code).
    Résultat dans l'explorateur d'objets : "B" contient toujours TOUT, mais "A" contient maintenant ses propres classes. Du coup, le projet C# ne compile même plus, vu qu'il a des classes définies dans les deux DLLs !

    Enfin, j'ai essayé de mettre le code d'une méthode dans le fichier ".cpp" ajouté dans "A".. Et là, problème de link ("B" ne trouve pas le symbole de la méthode en question). Or "A" ne me génère pas de fichier .lib (je ne connais pas bien le conditions sous lesquelles un .lib est généré avec une DLL). Donc je ne sais pas comment linker correctement dans ce cas là...

    Si vous avez la moindre idée qui pourrait m'être utile, ca m'interesse
    Merci d'avance

  2. #2
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    Logiquement les dlls du C++/CLI sont des assemblies mangées, comme pour le C# donc a priori tu n'as pas besoin des fichiers lib puisqu'il s'agit de rajouter une référence vers une dll managée. De plus, tous les fichiers de A devraient être dans A et B ne contiendrait alors aucun fichier de A ( ni *.h, ni *.cpp ) mais devrait juste importer l'espace de nom ( using namespace A ). Tout celà devrai marchier normallement, pour peut que toutes les classes utilisées soient managées ...

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 4
    Par défaut
    Merci pour ta réponse rapide smyley
    Je ne comprends pas bien quand tu dis "B ne contiendrait alors aucun fichier de A mais devrait juste importer l'espace de nom" :
    J'ai quand même besoin dans les fichiers de B de faire référence aux .h de A, je suis donc obligé de mettre dans B des ' #include "FichierDeA.h" '...
    Et c'est là que ca pose problème, car le fichier ainsi inclus se retrouve déclaré dans A et dans B !
    (Toutes mes classes sont managées...)

    J'ai créé un exemple simple dont les fichiers sont dans test_cli.zip (j'utilise visual) :


    Dans un projet DLL_A, j'ai le fichier TestA.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    #pragma once
     
    namespace Test
    {
    	public ref class TestA
    	{
    	public:
    		TestA(void)
    		{}
    	};
    }
    et le fichier TestA.cpp qui va avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    #include "StdAfx.h"
    #include "TestA.h"
    Si je ne met pas ce fichier CPP, la dll générée est vide.

    De la même façon, je crée un projet DLL_B qui contient TestB.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #pragma once
     
    namespace Test
    {
    	public ref class TestB
    	{
    	public:
    		TestB(void);
    	};
    }
    Cette fois, l'implémentation est dans TestB.cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #include "StdAfx.h"
    #include "TestB.h"
     
    #include "TestA.h"
     
     
    Test::TestB::TestB(void)
    {
    	Test::TestA ta;
    }
    Maintenant, je référence les deux DLL dans un projet C#, et j'obtiens l'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    {CheminVersProjetC#}\Form1.cs(15,14): erreur CS0433: Le type 'Test.TestA' existe dans '{CheminVersRepDeSortie}\DLL_A.dll' et dans '{CheminVersRepDeSortie}\DLL_B.dll'
    {CheminVersRepDeSortie}\DLL_A.dll : (Fichier concerné)
    {CheminVersRepDeSortie}\DLL_B.dll : (Fichier concerné)
    Voilà le test basique.

    Un autre test consiste à ne pas créer de fichier TestA.cpp : Ca fonctionne mais tout (TestA et TestB) se trouve dans la DLL_B. C'est pas bon (dans le cas réel d'utilisation, je veux avoir deux DLL qui utilisent A, et avec ce comportement, j'aurais une définition des classes de A dans ces deux DLL...)

    Enfin, un dernier test consiste à mettre du code de la classe TestA dans TestA.cpp (comme c'est fait pour B, avec la définition du constructeur dans le cpp). Mais dans ce cas, DLL_B ne passe pas le link :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    TestB.obj : error LNK2020: jeton non résolu (06000002) Test.TestA::.ctor
    (C'est le constructeur de TestA qui est défini dans le cpp, qui correspond bien au jeton non résolu ...)

    Voilà, je pense que le problème est assez clair (n'hésitez pas à me demander des précisions si besoin !).
    Ce qui m'emnnuie c'est que ce comportement semble logique (sauf pour le problème de link, mais je galère toujours avec les problèmes de link...).

    Encore une fois, je vous remercie d'avance pour votre aide !

  4. #4
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    je vais éssayer pour voir

  5. #5
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    voilà, la solution VS 2005 est dans DLL_A

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 4
    Par défaut Résolu !
    C'était bien ça... Le "using namespace" dont tu avais parlé... En fait je n'arrive pas à le faire dans mon projet... Il me dit qu'il ne connait pas le namespace !
    J'ai peur que ce soit un cas non couvert dans l'exemple : soit à cause des classes templates, soit à cause de fonctions type C (qui ne sont pas dans des classes).
    Je vais essayer de reproduire le problème dans le programme d'exemple...

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 4
    Par défaut
    Ca y est, j'y suis enfin arrivé !
    Bon j'ai vraiment fait une erreur de débutant : je n'avais pas référencé l'assembly dans les "propriétés communes" de mes sous-projets (équivalents de DLL_B).
    En tout cas, merci beaucoup

    Bon, maintenant que ca marche, je tombe dans sur autre problème ...
    Les sous-projets (équivalents de DLL_B) ne peuvent pas accéder aux objets natifs wrappés par les classes managées du projet parent... Et ce, même si les objets natifs sont accessibles depuis les sous projets...
    J'ai ouvert un autre topic pour ca, même si j'ai une (plutôt deux) solution(s) de contournement...

    Merci encore !

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 19
    Par défaut .lib pour le wrapper
    J'aimerais revenir sur une question posé au début:dans quel cas un .lib est généré à la compilation d'un DLL?

    Voici mon problème:
    3 elements:
    * un dll c++
    * un wrapper cli wrappant la dll c++
    * une dll C# utilisant le wrapper

    Mon wrapper cli a besoin du .lib généré par la dll c++ pour le link.
    Ce .lib n'est généré que si ma dll c++ contient une fct exporté or je n'en ai pas!
    quand je met une fct exporté (juste pour tester) dans ma dll, le .lib est créé mais cette lib ne convient pas au wrapper (pb de convention __cdecl et __clrcall).

    Quand je génère un .lib a partir de mon projet dll c++ (compilé en lib), le .lib est il le meme que celui généré lors de la compilation en tant que dll?(il me semble que non).Puis je utiliser ce .lib pour mon wrapper (en tout cas la compilation fonctionne!ou est passé le pb de __cdecl et __clrcall ???)

    Merci pour votre aide

  9. #9
    Rédacteur
    Avatar de nico-pyright(c)
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    6 414
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 6 414
    Par défaut
    pour avoir une lib, il faut exporter des fonctions (que ce soit avec dllexport ou par .def)
    Pour que ton wrapper puisse l'exploiter, il faut que les conventions d'appels soient les memes.
    Le mieux est de les définir explicitement dans le prototype de la fonction. Soit les garder _cdecl et dans ton wrapper, les expliciter.
    Soit tout passer en stdcall

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 19
    Par défaut
    Pour que ton wrapper puisse l'exploiter, il faut que les conventions d'appels soient les memes.
    Le mieux est de les définir explicitement dans le prototype de la fonction. Soit les garder _cdecl et dans ton wrapper, les expliciter.
    -->c'est à dire (expliciter)?

    Soit tout passer en stdcall
    -->mais dans ce cas mon wrapper n'est plus utilisable depuis le C#!

    J'ai remarqué qu'en mettant 'virtual' devant les méthodes wrappé le link fonctionne, mais j'ai des methodes statique dc pas de 'virtual' !

  11. #11
    Rédacteur
    Avatar de nico-pyright(c)
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    6 414
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 6 414
    Par défaut
    relis bien le lien dans la faq que je t'ai donné : http://dotnet.developpez.com/faq/cpp...r#errorLNK2031

    ca veut dire qu'il faut dans le prototype mettre en clair _cdcel

    et si tu as les sources de la lib, rien ne t'empeche de tout recompiler en stdcall

    mais bon, le plus simple reste de mettre _cdcel explicitement dans ton wrapper c++/cli pour les fonctions exportées à utiliser

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 19
    Par défaut Ah bon?
    Je rappel que mon wrapper est concu pour etre utilisé par du C#!
    Il est donc ecrit en c++/cli.
    Dans les propriété, calling convention est bien __cdecl (/Gd) donc comme la DLL a wrapper.
    si je met __declspec(dllimport) devant la méthode du wrapper j'obtiens naturellement l'erreur
    error C3387: ... : __declspec(dllexport)/__declspec(dllimport) cannot be applied to a member of a managed type

  13. #13
    Membre averti
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 19
    Par défaut Pistes
    Je pense qu'il faudrait trouver une compatibilité entre les 2 conventions d'appel (une sorte de wrapper de convention d'appel, un truc normalisé si c existe!).

    Quelles sont les autres pistes?
    Le 'virtual' fonctionne mais pour les méthodes static?

  14. #14
    Rédacteur
    Avatar de nico-pyright(c)
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    6 414
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 6 414
    Par défaut
    mais non, il ne faut pas exporter les méthodes du wrapper, mais les méthodes de la lib C
    Le wrapper écrit en C++/CLI, ca sera une assembly qui pourra etre utilisée telle quelle par du C#, comme une autre assembly.

    Le C# utilise l'assembly écrite en C++/CLI qui encapsule et utilise la dll écrite en C.

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 19
    Par défaut Ca c ok
    C'est codé en C++ et non en C...bref.

    Si j'utilise le .lib de ma DLL C++ natif c'est justement pr ne pas faire d'export (librairie statique)!
    J'ai essayé avec l'export - DllImport avec mes méthodes statique et ca compile mais c'est pas propre tous ca (a cause des export)!

  16. #16
    Rédacteur
    Avatar de nico-pyright(c)
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    6 414
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 6 414
    Par défaut
    si tu veux pas t'emmerder avec des libs et des exports, le plus simple c'est de recompiler ta lib avec le switch /clr et d'inclure dans le projet une nouvelle classe ref qui fait le wrapper, tout ca sera dans le meme assembly managé et c'est le C++ interop qui fait tout le boulot pour toi

  17. #17
    Membre averti
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 19
    Par défaut OK
    Tout dans le meme assembly c'est ce que j'avais fait au début et effectivement c plus simple!

    J'ai mis des export dans ma lib et tout fonctionne (sans meme faire d'import dans mon wrapper!).
    Ce que je n'avais pas compris c'est que le .lib généré lors de la compilation de la DLL n'est pas vraiment une lib statique!Oui c'est un .lib, mais pas du tout le meme que le .lib généré en compilant le projet en librairie statique (la taille du fichier est 10 fois plus petite!).

    Voila donc c'est résolu.
    MERCI!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [SP-2007] WebPart et dépendance à une DLL
    Par Keilen dans le forum SharePoint
    Réponses: 4
    Dernier message: 13/04/2010, 14h39
  2. [VS2008] dépendances msvcr90.dll et sp1
    Par Ange_blond dans le forum Visual Studio
    Réponses: 0
    Dernier message: 31/03/2010, 18h12
  3. Dépendances de dll non voulues
    Par laedit dans le forum Framework .NET
    Réponses: 6
    Dernier message: 05/11/2009, 17h27
  4. Réponses: 16
    Dernier message: 18/01/2009, 23h17
  5. Linker DLL C++/CLI entre elles
    Par xxiemeciel dans le forum C++/CLI
    Réponses: 2
    Dernier message: 07/06/2007, 16h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo