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

Langage C++ Discussion :

erreur dans l'appel d'une fonction d'une DLL


Sujet :

Langage C++

  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 erreur dans l'appel d'une fonction d'une DLL
    Bonjour,

    J'ai programmé un exemple de DLL (A.dll) en C++. J'ai définit une fonction dans cette DLL comme suit

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    //Fichier A.h
    #define ADLL_API __declspec(dllexport) 
    ADLL_API long __cdecl  run(void);
    J'appelle la fonction run dans un programme exécutable comme ceci
    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
     
    HINSTANCE _a;
    	_a = LoadLibrary(L"A.dll");
     
    	if (_a == NULL)
    	{
    		std::cout << "DLL not loaded" << std::endl;
    		system("pause");
    		return 0;
    	}
     
     
    	// Call to run function in DLL A
    	typedef long (*runFunction)();
    	runFunction run = (runFunction)GetProcAddress(_a, "run");
    	if (!run)
    	{
    		std::cout << "Function not loaded" << std::endl;
    		system("pause");
    		return 0;
    	}
    	run();
    Le test que j'effectue pour l'appel de la fonction "run" m’indique qu'elle n'est pas chargé alors que la DLL A.dll est bien chargé.
    Si quelqu'un a identifié la source de l'erreur qui ne me permet pas d'appeler la fonction run

    Merci

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Attention, il y a une différence entre le fait de compiler la dll et celui de l'utiliser.

    Quand tu compile la dll, tu dois t'assurer que chaque fonction exportée sera précédée de la convention d'appel __declspec(dllexport), alors que quand tu l'utilise, tu devra veiller ce qu'elle soit précédée de la convention d'appel __declspec(dllimport).

    Tu as donc deux solutions, l'une étant clairement plus pratique que l'autre

    La moins pratique consiste à avoir deux fichiers d'en-tête : un qui serait utilisé pour la compilation, et qui utiliserait __declspec(dllexport), et l'autre qui serait utilisé pour l'utilisation et utiliserait __declspec(dllimport).

    Cette idée est "pas mal" tant que l'api de ta dll reste simple et, surtout, tant que tu décide de ne pas en fournir le code source.

    Mais elle présente un inconvénient majeur pour le développeur : il doit s'assurer de garder les deux fichiers d'en-tête à jour. Et la loi de Finagle aidant, on peut parier gros sur le fait que, tôt ou tard, il "oublira" de mettre l'un des fichiers à jour

    Cela nous mène donc à la solution la plus pratique : faire en sorte que le compilateur choisisse la bonne convention d'appel en fonction des circonstances (qui interviendront dans les options du projet).

    Pour ce faire, on utilise généralement le préprocesseur, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #if defined(BUILD_BYDLL)
    #    define MYDLL_API __declspec(dllexport)
    #else
    #    define MYDLL_API __declspec(dllimport)
    #endif
    Où BUILD_BYDLL représente un symbole (dont tu peux choisir le nom à ta guise) qui devra n'être défini que lorsque tu compile ta dll et où MYDLL_API sera le symbole (dont tu peux aussi choisir le nom) qui sera utilisé pour préciser la convention d'appel pour chaque fonction.

    L'idéal étant sans doute de le mettre dans un fichier d'en-tête qu'il te suffira d'inclure dans tous les autres. Cela lui donnerait sans doute la forme de
    mydll_api.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /* un "include guard classique" */
    #ifndef MYDLL_API_HPP_INCLUDED
    #define MYDLL_API_HPP_INCLUDED
    #if defined(BUILD_MYDLL)
    #    define MYDLL_API __declspec(dllexport)
    #else
    #    define MYDLL_API __declspec(dllimport)
    #endif  
     
    #endif
    Par la suite, tu pourras sans doute souhaiter disposer d'une biliothèque statique, en plus d'une DLL. Le truc, c'est que cette convention d'appel est inutile (dangereuse ) dans ce cas. Il faudrait alors le modifier pour lui donner une forme proche de
    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
    /* un "include guard classique" */
    #ifndef MYDLL_API_HPP_INCLUDED
    #define MYDLL_API_HPP_INCLUDED
     
    #if defined(SHARED_LIBRARY)
    /* si on compile une dll */
     
    #    if defined(BUILD_MYDLL)
    #        define MYDLL_API __declspec(dllexport)
    #    else
    #        define MYDLL_API __declspec(dllimport)
    #    endif
    #else 
    /* on compile une bibliothèque statique */
    #define MYDLL_API
    #endif  
     
    #endif
    Et le fin du fin sera de rendre ta bibliothèque compatible avec les différents systèmes d'exploitation. Or __declspec est une spécificité propre à windows.

    Tu pourrais donc modifier ce fichier une dernière fois pour lui donner une forme (finale) proche de
    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
    23
    24
    /* un "include guard classique" */
    #ifndef MYDLL_API_HPP_INCLUDED
    #define MYDLL_API_HPP_INCLUDED
     
    #if defined(WIN32)
    /* on est sous windows */
    #    if defined(SHARED_LIBRARY)
        /* si on compile une dll */
     
    #        if defined(BUILD_MYDLL)
    #            define MYDLL_API __declspec(dllexport)
    #        else
    #            define MYDLL_API __declspec(dllimport)
    #        endif
    #    else 
        /* on compile une bibliothèque statique */
    #    define MYDLL_API
    #    endif 
    #else
        /* pour tous les autres systèmes d'exploitation*/
        #define MYDLL_API
    #endif
     
    #endif
    Voili voilou ;
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    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
    Merci pour ton aide,

    J'ai suivi vos instruction en modifiant mon fichier d’entête mais ma fonction n'est toujours pas chargé lors de son appel d'un programme externe. Voila ma modif

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #if defined( ADLL_EXPORTS)
    	#define ADLL_API __declspec(dllexport) 
    #else
    	#define ADLL_API __declspec(dllimport) 
    #endif
     
    ADLL_API long __cdecl  run(void);
    La solution qui me permet de pouvoir appeler ma fonction est d'inclure les dossier de mon .lib de ma DLL "A.lib" et l chemin vers mes fichiers d’entête de ma DLL. ce qui donne le programme externe suivant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    # include "A.h"
    int _tmain(int argc, _TCHAR* argv[])
    {
        // Appel de la fonction de la DLL run
        long ret = run()
    }
    Cette solution implique de fournir les .lib de ma DLL et le dossier des fichiers header avec la DLL contrairement à la première solution où il faut fournir juste la DLL

    Merci

  4. #4
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    En utilisant DependencyWalker on doit pouvoir afficher les noms exacts des points d'entrée dans la DLL.
    Pour les fonctions C++, elles sont toujours édulcorées en ajoutant les caractéristiques des paramètres en entrée et le type de retour.
    En ajoutant extern "C" on va utiliser un modèle C, et le nom de la fonction devrait être trouvé tel quel (ou avec un préfixe valant '_')

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 073
    Points : 12 119
    Points
    12 119
    Par défaut
    Cette solution implique de fournir les .lib de ma DLL et le dossier des fichiers header avec la DLL
    Ce que devrait faire tout bon fournisseur de librairie externe, ainsi que l’équivalent des .lib pour toutes les chaines de compilations et version de compilateur supportées.
    SINON, C'EST DES GUIGNOLS !!!

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Sinon, tu peux toujours jouer avec LoadLibrary et GetProcAddress... Mais je te souhaites bonne chance

    Au fait, y a pas un truc pour récupérer, depuis la dll, tous les nom de fonctions qu'elle exporte
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    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
    Merci pour votre aide et vos suggestions

    pour récupérer tous les noms de la DLL je crois qu'on peut lancer DependencyWalker. il donne le nom de la fonction éventuellement l'id associé

    Ce que devrait faire tout bon fournisseur de librairie externe, ainsi que l’équivalent des .lib pour toutes les chaines de compilations et version de compilateur supportées.
    SINON, C'EST DES GUIGNOLS !!!
    Je suis d'accord bacelar mais ça m'arrive de trouver des librairie avec seulement la DLL fourinit et une doc décrivant le prototype des fonctions fournis dans la librairie

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 073
    Points : 12 119
    Points
    12 119
    Par défaut
    pour récupérer tous les noms de la DLL je crois qu'on peut lancer DependencyWalker
    Il y a plein d'outils, méthodes pour générer plus ou moins automatiquement des .lib à partir de .dll:
    https://adrianhenke.wordpress.com/20...file-from-dll/

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Attention, générer un .lib à partir de la DLL est déconseillé.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    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
    Merci pour vos réponses et vos suggestions

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

Discussions similaires

  1. Dans quel script est la definition d'une classe, d'une fonction,
    Par debutant100 dans le forum Général Python
    Réponses: 6
    Dernier message: 05/04/2011, 19h19
  2. Ou est l'erreur - ou une différence entre une fonction et une macro ?
    Par Daranc dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 07/12/2009, 07h35
  3. Réponses: 9
    Dernier message: 08/07/2009, 17h10
  4. getattr() ? Appel d'une fonction depuis une fonction
    Par frites.saucisse dans le forum Général Python
    Réponses: 8
    Dernier message: 10/10/2008, 14h21
  5. Réponses: 4
    Dernier message: 17/03/2004, 17h24

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