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

Delphi Discussion :

Utilisation d'une variable de type string d'une DLL en C++ dans un programme Delphi


Sujet :

Delphi

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 157
    Points : 67
    Points
    67
    Par défaut Utilisation d'une variable de type string d'une DLL en C++ dans un programme Delphi
    Bonjour,

    Je programme sous Delphi 2005. J'utilise une DLL développé en C++ sous Visual Studio 2013 contenant des fonctions avec des arguments de Type String. J'essaye de les appeler dans mon programme delphi mais j'ai une exception qui est levé

    J'ai essayé avec une DLL test (simplifier) dont le code est :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    #ifdef STRDLL_EXPORTS
    #define STRDLL_API __declspec(dllexport) 
    #else
    #define STRDLL_API __declspec(dllimport) 
    #endif
     
    #include <string>
     
    namespace NSTRDLL
    {
    	// This class is exported from the MathFuncsDll.dll
    	class MySTRDLL
    	{
    	public:
    		// Returns a + b
    		static STRDLL_API std::string concatener(std::string str1, std::string str2);
     
    		static STRDLL_API char* associer(char* str1, int str2);
     
    	};
    }

    je fais mon appel dans le programme delphi à l'aide de c'est deux fonction:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    function TForm1.LierFonction(DLL: String; var HandleDLL: THandle; NomFct: String; IndexFct: Integer = -1): Pointer;
    begin
      //Valeurs de retour par défaut
      Result := nil;
      HandleDLL := 0;
     
      //Chargement de la DLL. On récupère son handle
      HandleDLL := LoadLibrary(pAnsiChar(DLL));
     
      //Si le chargement a échoué, on sort
      If HandleDLL = 0 then
        Exit;
     
      //On récupère l'adresse de la fonction voulue, que l'on renvoie
      If IndexFct < 0 then //Si l'index est négatif on utilise le nom sous forme de chaîne
        Result := GetProcAddress(HandleDLL, pAnsiChar(NomFct))
      else                  
        //Sinon, on utilise l'index comme identifiant
        Result := GetProcAddress(HandleDLL, pAnsiChar(IndexFct));
    end;
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
       temp : integer;
       HandleDLL: THandle; //Pour stocker le handle de la DLL chargée
       concatener   : function(A, B: string): string; stdcall; //Notre fonction, sous forme de variable
     
    begin
     
      concatener  := LierFonction('STRDLL.dll', HandleDLL , '?concatener@MySTRDLL@NSTRDLL@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@0@Z');
     
        //Si Somme a bien reçu un pointeur valide sur une fonction
      If assigned(concatener ) then
      try
        ShowMessage('A + B = '+ concatener('premireChaine',' deuxiemeChaine'));
      finally
      //Ne pas oublier de libérer la DLL lorsqu'elle n'est plus nécessaire
        FreeLibrary(HandleDLL);
      end
      else
        //Sinon, on affiche un message d'erreur : appeler Somme provoquerait une violation d'accès
        ShowMessage('Erreur de chargement de la fonction "concatener"');
    Ça marche très bien avec des arguments de type C++ int, double ou char * mais pas avec des string ou j'ai le message:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     Violation d’accès à l'adresse 77ED31CA dans le module 'MSVCR120D.dll'
    Vous auriez s'il vous plait une solution pour contourner ce problème avec le type string?

    Merci

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 469
    Points : 24 905
    Points
    24 905
    Par défaut
    Tu ne devrais pas publier des fonctions avec du std::string C++ ni importer via du type string Delphi
    Ce n'est pas quelque chose que l'on peut contourner, c'est quelque chose qu'il ne faut pas faire !

    le std::string C++ et le string Delphi n'ont probablement rien à voir
    le string Delphi avant les données de la chaine, gère un compteur de référence, la longueur, le charset, la taille du char ...
    Il extrêmement peu probable que la std::string soit programmé de la même façon et de plus cette une classe en C++ cela rend ce type non viable pour l'export vers un autre langage que C++

    Même entre une DLL Delphi et un Exe Delphi ou le même couple C++Builder, utiliser le type string nécessite des subtilités :
    En Delphi, cela implique d'utiliser l'ancien ShareMem(BORLNDMM.DLL) ou le nouveau SimpleShareMem
    En C++, c'est uniquement le bon vieux BORLNDMM.DLL Utilisation des DLL dans RAD Studio (C++)

    Je note que tu utilises PAnsiChar, tu as problablement un Delphi récent genre XE...
    D'ailleurs, un string Delphi 7 n'est pas compatible avec un string XE...
    Depuis XE pour utiliser un DLL en 7, faut utiliser un AnsiString (ou même RawByteString)

    Delphi à Delphi, l'échange de string, c'est déjà toute une affaire
    Alors C++ à Delphi ... Utilise soit tu char* ou alors du BSTR* géré par OLE (WideString en Delphi)
    Passer d'un char* vers un String, tu peux utiliser StrPas sur ton PAnsiChar
    Passer d'un string vers char*, un simple transtypage ou StrPCopy
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 073
    Points : 15 467
    Points
    15 467
    Billets dans le blog
    9
    Par défaut
    Bonjour ! J'avais rencontré un problème similaire : une fonction dans une DLL recevant et renvoyant une chaîne. La différence est que ma DLL et le programme appelant étaient tous les deux en Delphi. Voici quand même le lien vers la discussion :

    http://www.developpez.net/forums/d15...voyant-chaine/

    À la fin de la discussion il y a un lien vers mon projet, qui contient des exemples d'utilisation de la DLL en Basic et en C. Comme quoi ça fonctionne.
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  4. #4
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut
    Bonjour,
    Citation Envoyé par ShaiLeTroll Voir le message
    c'est quelque chose qu'il ne faut pas faire !
    On trouve quand même pas mal d'exemples sur la toile [cf string c++ to delphi]. En réalité, cela dépend du contexte et plus spécifiquement de la manière dont a été écrite la source C++. Enfin je parle des autres C++ que Builder que je n'ai jamais voulu approcher. Donc la question est de savoir si tu as accès aux sources C++ ?

    Cordialement. Zac.

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 469
    Points : 24 905
    Points
    24 905
    Par défaut
    Citation Envoyé par Zacheus Voir le message
    On trouve quand même pas mal d'exemples sur la toile [cf string c++ to delphi]
    Oui et la plupart évoque l'utilisation de char*/ansistring ou de BSTR*/WideString
    Je n'en ai pas trouvé sur la compatibitilité str::string et ansistring/unicodestring

    Citation Envoyé par Zacheus Voir le message
    Donc la question est de savoir si tu as accès aux sources C++ ?
    Tu trouve plus simple de comprendre la façon dont a été codé la std::string en MSVC++ que d'exposer simplement du char* ?

    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut
    Bonjour,

    Citation Envoyé par ShaiLeTroll Voir le message
    Tu trouve plus simple de comprendre la façon dont ...
    Plutôt que d'essayer de déformer mes propos, pourrais-tu avoir l'obligeance de faire un effort d'interprétation : Il faut comprendre string au sens générique d'autant qu'on évoque 2 langages très différents. Je t'en serai reconnaissant. Il n'est un secret pour personne que d'utiliser des librairies C++ avec Delphi ou Lazarus est plutôt compliqué voire impossible -j'ose l'écrire avec des "chaînes" - sauf si on possède les 2 sources.

    Citation Envoyé par ShaiLeTroll Voir le message
    Oui et la plupart évoque l'utilisation de char*/ansistring ou de BSTR*/WideString
    Je n'en ai pas trouvé sur la compatibitilité str::string et ansistring/unicodestring
    D'où ma question. Avant de répondre des généralités pas toujours efficaces en terme de résolution, il est bon de connaître la configuration et les conditions initiales. Si tu accèdes aux sources C++, tu les modifies à ta convenance pour établir une passerelle entre la librairie et Delphi puisqu'il ne faut pas compter sur ce dernier pour s'adapter.

    Cordialement.

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 469
    Points : 24 905
    Points
    24 905
    Par défaut
    Citation Envoyé par Zacheus Voir le message
    Plutôt que d'essayer de déformer mes propos, pourrais-tu avoir l'obligeance de faire un effort d'interprétation.
    J'ai interprété tes propos comme je le pouvais.
    Ta formulation me faisait penser que tu parlais du code technique de la std::string et non du code métier de la DLL

    Citation Envoyé par Zacheus Voir le message
    faut comprendre string au sens générique d'autant qu'on évoque 2 langages très différents
    C'est justement ce genre de généralisation qui fait que nassim1987 a pensé que l'on pouvait mélanger std::string et string Delphi

    Pour un sujet sur l'interopérabilité inter-langage, la généralisation n'a plus sa place, seul compte une réponse précise sur les éléments communs entre ces langages donc char*<-> PAnsiChar!

    Citation Envoyé par Zacheus Voir le message
    Si tu accèdes aux sources C++
    Il n'a pas forcément besoin d'avoir les codes sources de la DLL !
    Il peut très bien faire un Wrapper en MSVC++ de la DLL pour exposer sous la forme d'une seconde DLL avec des prototypes compatible avec d'autres langages que le C++.
    DLL Originale exporte std::string -> DLL Wrapper importe du std::string et exporte char* -> EXE Delphi importe du PAnsiChar

    Personnellement, c'est ce que j'ai fait pour intégrer des Assembly (dont Crystal Report 2012) qui ne fournissait pas une interopCOM dans des projets C++Builder via des wrapper MSVC#

    Un raison supplémentaire pour ne pas changer la DLL C++ Originale c'est qu'elle est peut-être utilisée par d'autres modules C++,
    devoir modifier des modules qui fonctionnent pour juste assurer une interopérabilité inter-langage est un risque et un cout pour le projet !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

Discussions similaires

  1. Creer un filtre automatique qui utilise une variable de type string
    Par Esmax666 dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 16/06/2009, 13h53
  2. Réponses: 6
    Dernier message: 14/02/2007, 21h08
  3. Des " dans une variable de type String
    Par 4lkaline dans le forum Langage
    Réponses: 6
    Dernier message: 06/11/2006, 14h20
  4. convertir une variable de type String en Number
    Par lilbrother974 dans le forum Flash
    Réponses: 13
    Dernier message: 06/09/2006, 08h28
  5. Ajouter a une variable de type string, un entier
    Par Little-Freud dans le forum SL & STL
    Réponses: 12
    Dernier message: 05/03/2005, 19h33

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