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++ Discussion :

Erreur lors de l'utilisation d'une fonction d'une DLL


Sujet :

C++

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juillet 2008
    Messages : 6
    Points : 3
    Points
    3
    Par défaut Erreur lors de l'utilisation d'une fonction d'une DLL
    Bonjour,

    j'ai un réel problème à lire une fonction contenue dans une DLL. Mon code est présenté ci-dessous. En mode DEBUG, le programme semble voir la DLL et la fonction, car ma variable verification indique 1.

    Cependant, lorsque j'arrive à la ligne où j'appelle ma fonction :

    XsatTPtillnerroth4(T,P,&variable_out1,&variable_out2,&variable_out3,&variable_out4,&variable_out5,&variable_out6,&variable_out7,&variable_out8);

    j'ai cette erreur : Unhandled exception at 0x0d69ca14 in CC6.exe 0xC0000005 : Access violation reading location 0x41430329.

    J'ai l'impression que cela a rapport avec mes pointeurs ... mais je suis assez débutant en C ++ alors je ne suis pas certain.

    Quelqu'un peut m'aider avec ceci ?

    Merci

    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    void addk(float *y, float *x, double t, double p, float *xkv)
    {	
    	//On défini le format de la fonction 1 de Brice à aller chercher
    	typedef void(_stdcall* FunctionDLL_1)(double,double,double*,double*,double*,double*,double*,double*,double*,double*);
     
    	// On commence par mettre la température et la pression dans les unités de la DLL de Brice
    	// Présentement, elles sont dans les unités internes de CHEMCAD (RANKINE et PSIA)
    	double T = t*0.5556;
    	double P = p*0.0068948;
     
    	// On défini le chemin de la DLL
    	HINSTANCE DLL_path;
    	FunctionDLL_1 XsatTPtillnerroth4;
    	DLL_path = LoadLibrary("./propthermo.dll");
    	XsatTPtillnerroth4 = (FunctionDLL_1)GetProcAddress(DLL_path,"XsatTPtillnerroth4");
     
     
    	double verification;	
     
    	if (XsatTPtillnerroth4 != NULL)
    	//if (PRESSdll != NULL)
    	{
    		verification = 1;
    	}
    	else
    	{	
    		verification = 0;
    	}
     
    	//On défini les variables à utiliser dans les fonctions en entrée et sortie
    	double variable_out1;
    	double variable_out2;
    	double variable_out3;
    	double variable_out4;
    	double variable_out5;
    	double variable_out6;
    	double variable_out7;
    	double variable_out8;
     
    	//On appelle alors la fonction en définissant en premier le nom des variables
    	XsatTPtillnerroth4(T,P,&variable_out1,&variable_out2,&variable_out3,&variable_out4,&variable_out5,&variable_out6,&variable_out7,&variable_out8);
     
     
    	// On libère la dll après sont calcul
    	FreeLibrary(DLL_path);
     
    }

  2. #2
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    XsatTPtillnerroth4 = (FunctionDLL_1)GetProcAddress(DLL_path,"XsatTPtillnerroth4");
    Est-ce que tu es sur que c'est bien la signature de ta fonction de dll dans les quotes?

    Si tu utilises directement un .def pour indiquer les fonctions exportées par ta dll, alors ça devrait passer.

    Part contre si tu es sous visual studio et que tu utilises "__declspec( dllexport )" alors le nom de ta fonction sera généré et décoré. Vérifie dans le .def généré pour voir si le nom corresponds bien réellement?

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juillet 2008
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Je ne connais pas trop les DLL, mais je n'ai pas de fichier .def, mais seulement propthermo.dll qui a été généré à partir de code fortran.

    J'ai par contre utilisé le logicial DEPENDENCY WALKER pour savoir les modules à utiliser avec ma dll. Dans ce logiciel, le nom des fonctions présentes étaient inscrites et il s'agissait bien exactement de XsatTPtillnerroth4.

    De plus, est-ce que ma variable vérification serait égale à 1 si je n'avais pas le bon nom de fonction ?

  4. #4
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Oui, je posais la question dans le doute, parcequ'il y aurait pu y avoir une autre fonction avec une signature différente (et qui aurait du coup pas exactement le même nom, peut être avec des décorations).

  5. #5
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Mais la fonction utilise bien _stdcall ?
    C'est une source classique d'erreur avec les DLLs

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juillet 2008
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    En fait, ma fonction dans ma dll provient d'un code FORTRAN. Est-ce que le _stdcall est pas défaut celui de Fortran ?

    De plus, je me demandais si je devais utiliser un EXTERN "C" quelques part vu que c'est un dll venant du fortran.

  7. #7
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Haaaa.... essayes donc avec _cdecl !

    Il y a 3 types de passage de paramètres sous Visual:
    _stdcall: l'appelant empile les paramètres, l'appelé les dépile => code plus court, impossibilité d'utiliser des varargs
    _cdecl: l'appelant empile les paramètres *et* les dépile => code plus long (dépilage dupliqué à chaque appel), possibilité d'utiliser les varargs (l'appelant sait combien de paramètres il a empilé)
    _fastcall: l'appelant utilse au maximum les registres => code plus rapide.

    A noter que _cdecl est la valeur par défaut pour le C/C++, et comme tu passes par un LoadLibrary, GetProcAddress, nul besoin de faire un extern "C" (qui sert juste à indiquer au compilo que ce qui suit ne doit *pas* être décoré).
    Hors ton code spécifie un _stdcall (type d'appel de l'API windows)... d'ou certainement l'erreur...

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juillet 2008
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Je ne suis pas sûr de comprendre ta dernière phrase où tu dis d'écrire à l'extérieur de mon code un

    _stdcall(type d'appel de l'API windows)

    Par extérieur de mon code veux-tu dire hors de ma fonction ADDK ?
    Le type d'appel de l'API windows sera _cdecl selon ce que j'ai pu comprendre ?

    Peux-tu me donner un peu plus de détails.

    Merci !

  9. #9
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Toutes les fonctions windows (ou presque) et en tout cas, la grande majorité des interfaces COM utilisent la convention _stdcall

    C'est à dire que l'appelant va empiler les paramètres, appeler la fonction, et ... c'est tout ! La fonction appelée est charger de dépiler ces paramètres. Si elle ne le fait pas, la pile est corrompue !

    TU as déclaré ta fonction par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    typedef void(_stdcall* FunctionDLL_1)(double,double,double*,double*,double*,double*,double*,double*,double*,double*);
    Ce qui veut dire que pour un appel à un *FunctionDLL_1, le compilateur va générer exactement ce qui est dit plus haut: Empilage des paramètres, appel de la fonction, et c'est tout ! Si la fonction appellée ne dépile pas les paramètres => corruption de pile.

    Mais ce mode de passage par paramètres n'est PAS le mode par défaut en C++, le mode par défaut est _cdecl, qui permet (entre autre) d'utiliser l'ellipsis...
    La DLL que tu invoques a forcément un mode de passage de paramètre. Si ce mode est inconnu, je parierai d'abord sur ce mode là (_cdecl).

    Donc... je te suggères de remplacer le _stdcall par _cdecl....
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    typedef void(_cdecl* FunctionDLL_1)(double,double,double*,double*,double*,double*,double*,double*,double*,double*);

  10. #10
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juillet 2008
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Finalement, j'ai trouvé mon erreur et c'était tout autre chose.

    Il fallait bien que j'utilise de _stdcall, mais j'avais des erreurs dans la déclaration et dans l'appel de ma fontion XsatTPtillnerroth4.

    Voici le nouveau code qui fonctionne, je le met tout d'un coup que quelqu'un d'autre ait le même problème que moi.

    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
    void addk(float *y, float *x, double t, double p, float *xkv)
    {	
    	typedef void(_stdcall* FunctionDLL_1)(double&,double&,double&,double&,double&,double&,double&,double&,double&,double&);
     
    	// On commence par mettre la température et la pression dans les unités de la DLL de Brice
    	// Présentement, elles sont dans les unités internes de CHEMCAD (RANKINE et PSIA)
    	double T = t*0.5556;
    	double P = p*0.0068948*1000000;
     
    	// On défini le chemin de la DLL
    	HINSTANCE DLL_path;
    	FunctionDLL_1 XsatTPtillnerroth4;
    	DLL_path = LoadLibrary("./PropThermo.dll");
    	XsatTPtillnerroth4 = (FunctionDLL_1)GetProcAddress(DLL_path,"XsatTPtillnerroth4");
    	double verification;	
     
    	if (XsatTPtillnerroth4 != NULL)
    	//if (PRESSdll != NULL)
    	{
    		verification = 1;
    	}
    	else
    	{	
    		verification = 0;
    	}
     
    	//On défini les variables à utiliser dans les fonctions en entrée et sortie
    	double variable_out1;
    	double variable_out2;
    	double variable_out3;
    	double variable_out4;
    	double variable_out5;
    	double variable_out6;
    	double variable_out7;
    	double variable_out8;
     
    	//On appelle alors la fonction en définissant en premier le nom des variables
    	XsatTPtillnerroth4(T,P,variable_out1,variable_out2,variable_out3,variable_out4,variable_out5,variable_out6,variable_out7,variable_out8);
     
    	// On libère la dll après sont calcul
    	FreeLibrary(DLL_path);
     
    	//On redéfini les variables avec des noms plus significatifs
    	double concentration_liquide = variable_out1;
    	double densité_liquide = variable_out2;
    	double densité_vapeur = variable_out3;
    	double concentration_vapeur = variable_out4;
    	double enthalpie_liquide = variable_out5;
    	double entropie_liquide = variable_out6;
    	double enthalpie_vapeur = variable_out7;
    	double entropie_vapeur = variable_out8;
     
    	//On transfère les concentrations en pourcentages en concentrations unitaire	
    	double concentration_nh3_vapeur = concentration_vapeur;
    	double concentration_nh3_liquide = concentration_liquide;
    	double concentration_eau_vapeur = 1-concentration_nh3_vapeur;
    	double concentration_eau_liquide = 1-concentration_nh3_liquide;
     
    	//On fait le calcul pour le premier fluide qui est l'ammoniac
    	xkv[0] = concentration_nh3_vapeur/concentration_nh3_liquide;
    	xkv[1] = concentration_eau_vapeur/concentration_eau_liquide;
    	x[0] = concentration_nh3_liquide;
    	x[1] = concentration_eau_liquide;
    	y[0] = concentration_nh3_vapeur;
    	y[1] = concentration_eau_vapeur;
     
    }
    Merci quand même à tous pour votre aide

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    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 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Les fonctions des DLLs sont bien supposées être extern "C" et __stdcall.

    Et aussi, selon la façon dont a été créée une DLL C ou C++, ses fonctions possèderont une décoration __stdcall ou non (la méthode paresseuse donne des fonctions avec décoration __stdcall, la méthode recommandée donne des fonctions au nom nu).

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

Discussions similaires

  1. Appel d'une fonction dans une fonction d'une même classe
    Par script73 dans le forum Général Python
    Réponses: 3
    Dernier message: 06/03/2015, 11h18
  2. Réponses: 3
    Dernier message: 28/05/2008, 00h07
  3. [PHPMailer] Erreur lors de l'utilisation de la fonction mail
    Par onlytime dans le forum Bibliothèques et frameworks
    Réponses: 1
    Dernier message: 04/04/2008, 17h11
  4. Réponses: 3
    Dernier message: 29/04/2006, 14h02
  5. Réponses: 4
    Dernier message: 17/03/2004, 18h24

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