Bibliothèques et packages (Delphi)

De RAD Studio
Aller à : navigation, rechercher

Remonter à Bibliothèques et packages - Index

Une bibliothèque à chargement dynamique est une bibliothèque de liaison dynamique (DLL) sur Windows, une bibliothèque DYLIB sur Mac ou un objet partagé (SO) sur Linux. C'est une collection de routines, pouvant être appelées par des applications ou par d'autres DLL ou objets partagés. Comme les unités, les bibliothèques à chargement dynamique contiennent des ressources ou du code partagés. Mais ce type de bibliothèque est un exécutable compilé séparément qui est lié, à l'exécution, aux programmes l'utilisant.

Les programmes Delphi peuvent appeler des DLL et des objets partagés écrits dans d'autres langages, et les applications écrites dans d'autres langages peuvent appeler des DLL ou des objets partagés écrits en Delphi.

Appel de bibliothèques à chargement dynamique

Vous pouvez appeler les routines du système d'exploitation qui ne sont pas liées à votre application. Ces routines sont généralement dans une DLL ou dans un objet partagé. Sur Windows et OS X, il n'y a pas de validation à la compilation des tentatives d'importation d'une routine. Cela signifie que la bibliothèque n'a pas besoin d'être présente lors de la compilation de votre programme.

Sur d'autres plates-formes telles que Linux, il est nécessaire d'effectuer une liaison à un objet partagé pour résoudre une référence externe. Pour éviter la validation, utilisez LoadLibrary et GetProcAddress comme décrit dans la section Chargement dynamique.

Avant de pouvoir appeler les routines définies dans une DLL ou un objet partagé, il faut les importer. Cela peut se faire de deux manières : en déclarant une procédure ou une fonction externe ou par des appels directs au système d'exploitation. Quelle que soit la méthode utilisée, les routines ne sont liées à votre application qu'à l'exécution.

Delphi ne prend pas en charge l'importation des variables depuis les DLL ou les objets partagés.

Chargement statique

La manière la plus simple d'importer une procédure ou une fonction est de la déclarer en utilisant la directive externe. Par exemple :

 procedure DoSomething; external 'MYLIB.DLL';

Si vous incluez cette déclaration dans un programme, MYLIB.DLL est chargée une seule fois, au démarrage du programme. Durant toute l'exécution du programme, l'identificateur DoSomething désigne toujours le même point d'entrée dans la même bibliothèque partagée.

La déclaration des routines importées peut être placée directement dans le programme ou l'unité où elles sont appelées. Pour simplifier la maintenance, vous pouvez aussi rassembler des déclarations externes dans une "unité d'importation" distincte qui contient aussi les constantes et les types nécessaires pour l'interfaçage avec la bibliothèque. D'autres modules utilisant l'unité d'importation peuvent appeler toutes les routines qui y sont déclarées.

Chargement différé (Windows seulement)

La directive delayed peut être utilisée pour décorer une routine externe afin de différer le chargement de la bibliothèque contenant la routine. Le chargement réel se produit quand la routine est appelée pour la première fois. L'exemple suivant illustre l'utilisation de la directive delayed :

 function GetSomething: Integer; external 'somelibrary.dll' delayed;

Dans l'exemple ci-dessus, la routine GetSomething est importée depuis la bibliothèque somelibrary.dll. La directive delayed garantit que somelibrary.dll n'est pas statiquement lié à l'application, mais plutôt dynamiquement.

La directive delayed est utile dans le cas où les routines importées n'existent pas sur le système d'exploitation cible sur lequel l'application est exécutée. Les routines importées statiquement nécessitent que le système d'exploitation trouve et charge la bibliothèque au démarrage de l'application. Si la routine n'est pas trouvée dans la bibliothèque chargée, ou si la bibliothèque n'existe pas, le système d'exploitation interrompt l'exécution de l'application. L'utilisation de la directive delayed vous permet de vérifier, à l'exécution, si le système d'exploitation supporte les API requises, seulement quand vous pouvez appeler les routines importées.

Une autre utilisation potentielle de la directive delayed est associée à l'encombrement mémoire de l'application : la décoration des routines les moins utilisées, car delayed peut diminuer l'encombrement mémoire de l'application, puisque les bibliothèques sont chargées seulement quand c'est nécessaire. L'utilisation abusive de delayed peut endommager les performances en vitesse du programme (perçues par l'utilisateur final).

Remarque : Une tentative d'appel d'une routine différée qui ne peut être résolue provoque une erreur d'exécution (ou une exception, si l'unité SysUtils est chargée).

Afin d'optimiser le processus de chargement différé utilisé par la bibliothèque d'exécution RTL de Delphi, vous pouvez recenser des procédures de hook pour surveiller et modifier son comportement. Pour accomplir cela, utilisez SetDliNotifyHook2 et SetDliFailureHook2, déclarés dans l'unité SysInit. Voir également l'exemple de code DelayedLoading (Delphi).

Chargement dynamique

Vous pouvez accéder aux routines d'une bibliothèque via des appels directs aux API Windows, notamment LoadLibrary, FreeLibrary et GetProcAddress. Ils sont aussi disponibles sur OS X, Linux et Android. Ces fonctions sont déclarées dans l'unité Winapi.Windows.pas pour Windows et dans System.SysUtils.pas pour les autres plates-formes. Dans ce cas, utilisez des variables de type procédural pour référencer les routines importées.


Par exemple :

uses System.SysUtils {$IFDEF MSWINDOWS},Winapi.Windows{$ENDIF};
 
type
   TTimeRec = record
     Second: Integer;
     Minute: Integer;
     Hour: Integer;
   end;
 
   TGetTime = procedure(var Time: TTimeRec);
 
var
  Time: TTimeRec;
  Handle: HMODULE;
  GetTime: TGetTime;
begin
  Handle := LoadLibrary('libraryname');
  if Handle <> 0 then
  begin
    @GetTime := GetProcAddress(Handle, 'GetTime');
    if @GetTime <> nil then
    begin
      GetTime(Time);
      with Time do
        Writeln('The time is ', Hour, ':', Minute, ':', Second);
    end;
    FreeLibrary(Handle);
  end;
end.

Quand vous importez ainsi des routines, la bibliothèque n'est pas chargée avant l'exécution du code contenant l'appel de LoadLibrary. La bibliothèque est déchargée ultérieurement par un appel à FreeLibrary. Cela vous permet de conserver de la mémoire et d'exécuter votre programme même si certaines bibliothèques utilisées sont absentes.

Voir aussi