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 :

Utilisation d'une fonction de bibliothèque qui change de nom


Sujet :

C

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut Utilisation d'une fonction de bibliothèque qui change de nom
    Hello,

    J'ai une application qui utilise une bibliothèque dont le codeur est quelque peu cavalier, et qui change les noms de fonction sans trop de soucier des implications.

    Une version donnée de mon application doit pouvoir utiliser une version quelconque de cette bibliothèque. Je sais à partir de quelle version de la bibliothèque ont lieu les changements de noms de fonction.

    Sachant que je la bibliothèque a une fonction fournissant son nom de version, est-il possible, à l'exécution, de faire un branchement dans le code pour gérer ça ?

    Le problème est que mon code n'est "linkable" que pour pour une version donnée de l'API. Comment faire ??

    Merci !

  2. #2
    Membre expérimenté Avatar de Grulim
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    234
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 234
    Par défaut
    1ère Solution change de bibliothèque/de codeur
    2ème solution, sous Windows, tu peux charger explicitement la bibliothèque et obtenir un pointeur sur chaque fonction manuellement (pratique si tu en as 100 ).
    3ème solution, faire 2 versions de ton programme, une avant changement et l'autre après.

  3. #3
    Invité(e)
    Invité(e)
    Par défaut
    Bonjour,

    Pour charger une bibliothèque, on utilise LoadLibrary / GetProcAddress sous Windows, dlopen / dlsym sous unixoïdes.

    Après, il faut savoir que demander l'adresse d'une fonction qui n'existe pas renvoie juste NULL, ça pourrait permettre de déterminer la version de la bibliothèque (mais le mieux, c'est d'avoir une fonction get_version).

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par Grulim Voir le message
    1ère Solution...
    2ème solution...
    3ème solution...
    La 1ère solution n'est pas envisageable. :-)

    La 2ème solution ne me semble pas applicable, car mon programme est en mode console.

    La 3ème solution est celle que j'applique actuellement, mais elle ne me satisfait pas.

    Sachant que mon application est en fait appelée par un programme Java, peut-être devrais-je me débarrasser de cette appli en C, la transposer en Java, et utiliser JNA pour appeler l'API C...

    Et suite à la réponse de mabu, tout semble en effet laisser penser qu'il faut effectivement passer en Java, qui via JNA offre à peu près la même chose.

  5. #5
    Membre expérimenté Avatar de Grulim
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    234
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 234
    Par défaut
    Citation Envoyé par oodini Voir le message
    La 2ème solution ne me semble pas applicable, car mon programme est en mode console.
    ??? Je parle de l'OS quand j'écris Windows...

  6. #6
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Tu peux même faire un code auto-adaptable : tenter de charger la fonction initiale, si ça foire (retour de GetProcAddress valant NULL) tu tentes la "nouvelle", si ça re-foire tu déclares réellement l'erreur à l'utilisateur (à priori, DLL corrompue et/ou trop "nouvelle").

    Le fait que l'application tourne en mode console ou pas n'a absolument aucune importance, LoadLibrary et GetProcAddress sont certes des fonctions de l'API Win32, mais elles n'exigent aucunement la moindre interface graphique (ni même la présence d'une console, d'ailleurs).
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    À priori, c'est effectivement le comportement que je souhaite.

    Je m'y connais fort peu en chargement dynamique de bibliothèque.
    L'API me fournit des .h, un .lib, et un .dll. Jusqu'à présent, j'utilisais bêtement les .h et le .lib. Je suppose que le .dll offre exactement les mêmes services, mais est chargeable dynamiquement avec l:es fonctions que vous évoquez ?

  8. #8
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par oodini Voir le message
    L'API me fournit des .h, un .lib, et un .dll. Jusqu'à présent, j'utilisais bêtement les .h et le .lib. Je suppose que le .dll offre exactement les mêmes services, mais est chargeable dynamiquement avec l:es fonctions que vous évoquez ?
    Le .LIB permet de lier la DLL à l'exécutable de façon "statique" (oui, je sais, ça parait bizarre à lire), dans le sens où l'exécutable devient publiquement dépendant de la DLL et ne peut plus démarrer sans elle (sauf cas particulier de delayed loading, mais qui ne permettrait pas de résoudre ton problème quoi qu'il en soit). De plus, ce .LIB permet aussi d'exporter de la DLL des entités qui ne sont normalement pas exportables, tel que des classes C++ ou des variables globales. Comme tu es en C, seul les variables globales pourraient poser un problème.

    En gros, le principe se résume ainsi :
    • Ne plus inclure le .LIB dans ton projet.
    • "Traduire" le .H actuellement fourni vers un .H d'importation : tes fonctions vont devenir, pour chacune, un "couple" pointeur fonctionnel / type fonctionnel.
    • Un fichier .C devra contenir les variables fonctionnelles ainsi déclarées. Il faudra initialiser chacun de ces pointeurs de fonctions à NULL, par propreté.
    • L'édition de lien se passera sans problème, car ton .H fourni avec ta DLL trouvera ses petits dans ton fichier .C, sous forme de pointeurs de fonctions (qui ne valent rien de bon pour le moment, bien sûr).
    • Dans tes .C/.H nouvellement créés, tu vas ajouter une fonction du genre "int LoadMyDLL(char* DllName)", que tu appelleras au début du main(), destinée à connecter la DLL.
    • Pour chaque fonction, tu vas charger la fonction correspondante de la DLL, ou la "nouvelle" si cela échoue. A la fin de la chaîne de tentatives de chargement, tu testes si ton pointeur de fonction est NULL ou pas : si oui, c'est une erreur critique (=> boum), sinon, la fonction est correctement connectée.
    • Éventuellement, au lieu de provoquer une erreur, tu peux connecter la fonction manquante à une fonction stub, qui affichera un message du genre "Function XXXX is missing, please check version of YYYYY.dll"
    • Le principe est le même pour les variables globales, la différence étant dans le fait qu'il faut caster comme un goret et utiliser quelques trucs sales pour changer l'adresse de ta globale (ou alors, n'utiliser que le pointeur et devoir donc modifier le code utilisant ladite globale).
    • Le reste du programme ne devrait pas avoir besoin d'être modifié, et continuera à ne référencer que le .H d'origine. Seul le fichier contenant le main() devra explicitement faire référence à TON module de chargement.


    Si tu es à l'aise avec les outils de génération automatique de code et/ou les analyses de texte, tu peux même automatiser complètement la création de ces fichiers de chargement : après tout, c'est déjà ce que fait Visual C++ lorsqu'il compile la DLL, la seule différence étant qu'il n'est pas tolérant à la faute contrairement à ce que permettra ton importation manuelle. Cerise sur le gâteau, ton code d'importation est compatible avec GCC si besoin, voire d'autres langages, si la DLL n'utilise pas de conventions d'appel exotiques ou de name-mangling.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Merci pour cette réponse complète !!

    J'ai toutefois encore quelques questions, notamment une sur les deux premiers points et le dernier.

    L'API contient une quarantaine de .h, et seules deux fonctions posent problème. Ne puis-je continuer à utiliser le .lib, et à en faire appel au chargement dynamique que pour les fonctions qui posent problème ?

    Je n'ai pas besoin de variables globales, et les performances ne sont pas un problème.

    J'ai par ailleurs vérifié dans Depends.exe, et les fonctions ne semblent pas "manglées".

  10. #10
    Membre expérimenté Avatar de Grulim
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    234
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 234
    Par défaut
    Ce n'est malheureusement pas possible de mixer les 2 modes.

  11. #11
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Bon, alors je vais partir sur la solution sans .lib.

    En revanche, le second point me laisse perplexe. Si un .h déclare :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int maFonction(int a, int b);
    que dois-je faire exactement, pour le .h ??

  12. #12
    Membre expérimenté Avatar de Grulim
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    234
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 234
    Par défaut
    C'est plus dans le .c que la magie opère...

    Ton code devrait ressembler à ça (pas tester) :
    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
    typedef int (* maFonctionLib_type) (int a, int b);
     
    int maFonction(int a, int b)
    {
      static maFonctionLib_type pfn;
      if( pfn == NULL )
      {
        pfn = (maFonctionLib_type)GetProcAdress(hDll, "maFonctionLibVersion1");
        if( pfn == NULL )
        {
          pfn = (maFonctionLib_type)GetProcAdress(hDll, "maFonctionLibVersion2");
        }
      }
      return (*pfn)( a, b );
    }
    une macro ferait bien l'affaire...

  13. #13
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Bon, ça me rassure : c'est ce que j'avais fait, d'après vos explications. :-)

    En revanche, l'utilisation du .lib en sus ne semble pas gêner... Il faut dire que mon programme ne tourne pas vraiment, pour cause d'autre problème. Peut-être qu'à l'usage, le .lib se révélera effectivement gênant.

  14. #14
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par oodini Voir le message
    En revanche, l'utilisation du .lib en sus ne semble pas gêner...
    En fait, tout dépend s'il reste des symboles non-résolus (=> piochés dans le .LIB) ou pas (=> le mettre ou pas n'a aucune importance).

    Toutefois, par "sécurité", je te conseille de l'enlever.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  15. #15
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    En fait, tout dépend s'il reste des symboles non-résolus (=> piochés dans le .LIB) ou pas (=> le mettre ou pas n'a aucune importance).
    Ben je l'ai justement laissé pour piocher dedans sans charger dynamiquement toutes les fonctions qui ne me posent pas problème.

  16. #16
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    ya une question que je me pose...

    Pourquoi ne pas faire simplement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      switch ( NumVersion )
        {
             case 1 :
                return FonctionVer1( a, b );
             case 2 :
                return FonctionVer2(a,b);
       }
    ?

    puisqu'au link il faut les 2 ??

  17. #17
    Membre expérimenté Avatar de Grulim
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    234
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 234
    Par défaut
    Citation Envoyé par oodini Voir le message
    Ben je l'ai justement laissé pour piocher dedans sans charger dynamiquement toutes les fonctions qui ne me posent pas problème.
    Mais l'utilisateur qui a version de la dll avec des noms de fonction différents va se prendre un message d'erreur à l'exécution...

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Citation Envoyé par Grulim Voir le message
    Ce n'est malheureusement pas possible de mixer les 2 modes.
    Si, avec le chargement retardé (delay-loading DLLs) c'est possible, sous Visual Studio.

    Mais là, on se retrouve à gérer des exceptions Win32 ou fournir des fonctions callback...
    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.

  19. #19
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Je suis parti pour virer complètement l'usage du .lib.

    Mais se taper 15 fonctions pour 2 d'entre elles qui posent problème, c'est agaçant...

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    C'est dans ce genre de cas que le chargement retardé pourrait être intéressant, justement.
    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.

Discussions similaires

  1. Réponses: 5
    Dernier message: 22/04/2013, 14h10
  2. [XL-2007] Mettre variables dans une matrice qui est utilisée par une fonction
    Par Agalis dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 03/04/2012, 09h08
  3. Utilisation d'une fonction codee dans une bibliothèque .so
    Par vandamme dans le forum Bibliothèques
    Réponses: 6
    Dernier message: 21/08/2007, 10h02
  4. Utilisation d'une fonction Transact-SQL ds une requête SQL
    Par Fl0ppeur dans le forum Langage SQL
    Réponses: 1
    Dernier message: 21/02/2006, 13h42
  5. Utilisation d'une fonction dans une procedure
    Par MaxiMax dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 09/08/2005, 15h51

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