Chargement DLL dynamique avec fonctions

cs_christophedlr Messages postés 267 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 23 août 2023 - 30 déc. 2006 à 19:04
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 - 11 janv. 2007 à 22:29
Bonsoir à tous,

Dans mon logiciel, je prévois plusieurs langues possibles par fichiers DLL.

J'ai trouvé sur delphipage, un moyen de charger dynamiquement une DLL, mais cela ne fonctionne pas pour l'importation de fonctions.

Je fais comment quand c'est un function est non procedure que j'utilise ?

Merci d'avance pour vos réponses.

4 réponses

WhiteHippo Messages postés 1154 Date d'inscription samedi 14 août 2004 Statut Membre Dernière intervention 5 avril 2012 3
31 déc. 2006 à 00:51
Bonsoir,

Que ce soit une procédure ou une fonction la méthode est toujours la même :
    - Déclaration du type
      type
        TMaFonction = function( Parametre1 : Extended ) : Integer ;

    - "Ouverture" de la dll 
      const
        NOM_DLL = 'MaDLL.dll' ;

      var
        DLLInstance : THandle ;

      DLLInstance := LoadLibrary( NOM_DLL ) ;

    - Lien vers la fonction (ou la procédure), via une variable du type précedemment créé
      const
        NOM_FONCTION_DANS_DLL = 'ExtendedToInteger' ;
      var
        MaFonction : TMaFonction ;
   
      @MaFonction := GetProcAdress( DLLInstance, NOM_FONCTION_DANS_DLL ) ;
      
    - Appel de la fonction (ou de la procédure)
      var
        i : Integer ;
   
      i := MaFonction( 3.5 ) ;

     - "Fermeture" de la DLL en fin d'utilisation
      FreeLibrary( DLLInstance ) ;
   
Cependant, il faut faire attention à la définition du type. En effet en fonction du langage sous lequel la DLL a été developpé, les conventions d'appel ne sont pas forcement celle de Delphi. Il faudra alors ajouter derrière la déclaration du type soit  cdecl ou stdcall. Par exemple ;
         cdecl si DLL développée en C ou C++
         stdcall pour les API de Windows en autre

La déclaration sera alors :
            type
        TMaFonction = function( Parametre1 : Extended ) : Integer ; cdecl;

N.B. De plus, le passage de paramètres ne se fait pas de la même façon en fonction de la convention utilisée. En Delphi (pascal), ils sont transmis tels qu'ils sont déclarés, mais en cdecl(C ou C++) ou stdcall ils sont transmis en ordre inverse.

Cordialement.
<hr />L'imbécile prétentieux est celui qui se croit plus intelligent
0
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
31 déc. 2006 à 17:38
tout a fait whitehyppo, c'est la bonne methode pour charger une DLL.

avec en precision et exemple :

unit MADLLAPI;

interface

{$DEFINE LOADLIBAUTO}

uses windows, sysutils{, ...};

var
  func1 : function(args) : retour; {$IFDEF LINUX}cdecl{$ELSE}stdcall{$ENDIF};
  func2 : function(args) : retour; {$IFDEF LINUX}cdecl{$ELSE}stdcall{$ENDIF};
  proc1 : procedure(args); {$IFDEF LINUX}cdecl{$ELSE}stdcall{$ENDIF};
  proc2 : procedure(args); {$IFDEF LINUX}cdecl{$ELSE}stdcall{$ENDIF};

function IsLoaded : boolean;

{$IFDEF LOADLIBAUTO}
{$ELSE}
function LoadLib : boolean;
{$ENDIF}

implementation

var
  LIBHANDLE : THandle = INVALID_HANDLE_VALUE;
  LIBLOADED : boolean = false;
  LIBNAME   : string  = 'madll.dll';

function IsLoaded : boolean;
begin
  result := LIBLOADED;
end;

function LoadLib : boolean;
begin
  result := false;

  if LIBLOADED or (not FileExists(LIBNAME)) then exit;

  LIBHANDLE := LoadLibrary(PChar(LIBNAME));
  LIBLOADED := LIBHANDLE <> INVALID_HANDLE_VALUE;

  if LIBLOADED then begin
  { ADD DLL PROCS HERE -- }


    @func1 := GetProcAddress(LIBHANDLE,'libFunc1');
    @func2 := GetProcAddress(LIBHANDLE,'libFunc2');

    @proc1 := GetProcAddress(LIBHANDLE,'libProc1');
    @proc2 := GetProcAddress(LIBHANDLE,'libProc2');


  { --------------------- }
  end;

  if LIBLOADED then
     FreeLibrary(LIBHANDLE);

  result := LIBLOADED;
end;

{$IFDEF LOADLIBAUTO}
initialization
  LoadLib;

{$ENDIF}
end;

<hr size="2" width="100%" />Croc (click me)
0
WhiteHippo Messages postés 1154 Date d'inscription samedi 14 août 2004 Statut Membre Dernière intervention 5 avril 2012 3
31 déc. 2006 à 18:18
Bonjour,






Allons foxi, faut aller jusqu'au bout de ta pensée  :





uses
{$IFDEF LINUX}{...}{$ELSE}windows{$ENDIF} sysutils{, ...};

var
  LIBHANDLE : THandle = INVALID_HANDLE_VALUE;
  LIBLOADED : boolean = false;
  {$IFDEF LINUX}    
    LIBNAME   : string  = 'madll.so'; // Shared Object (. so ) pour Linux 
  {$ELSE}
    LIBNAME   : string  = 'madll.dll'; // Dynamic Link Library (.dll) pour Windows 
  {$ENDIF}

Par contre je ne suis pas entièrement d'accord avec toi. Les DLL écrites en C ou en C++ sont nombreuses et ne sont pas obligatoirement linuxiennes. Le {$IFDEF} ne me semble pas nécessaire, tout dépend du contexte de développement de la DLL. D'autant plus que tu pourrais avoir deux fonctions avec des conventions d'appel différentes au sein même d'une unique DLL.



 



Cordialement.
<hr />

"Frappe ta tête contre une calebasse... et si tu entends un son creux, ne te presse pas d'en déduire que c'est la calebasse qui est vide..."
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
11 janv. 2007 à 22:29
Salut,


LoadLibrary et GetProcAdress sont des routines de l'API Win32 de toute
façon, donc je ne crois pas que le reste compile tel quel sous kylix ou
freepascal...


Je rejoins WhiteHippo sur les conventions d'appels : on peut en Delphi
comme en C sélectionner la convention que l'on souhaite fonction par
fonction (A partir du moment ou elle est supportée bien sûr). Le tout
est d'avoir la même convention dans les déclarations de la dll et de
l'exe.


christophedlr > Si la méthode marche que pour les  procédures
et pas pour les fonctions, il semble effectivement que tu est un souci
de convention.
0
Rejoignez-nous