FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 123, nombre de questions : 920, dernière mise à jour : 8 novembre 2019  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).

Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.

L'équipe Delphi de Developpez.com.

Commentez


SommaireSystèmeDLL (11)
précédent sommaire suivant
 

"DLL" signifie "Dynamic-Link Library" ou, en Français, "Bibliothèque à liaison dynamique".
Il s'agit d'un fichier contenant, à l'instar d'un exécutable, du code compilé compréhensible par le processeur. La différence avec un exécutable réside dans le mode d'exploitation de ce code :
il est présent dans la DLL sous forme de différentes fonctions/procédures exportées, c'est-à-dire disponibles "de l'extérieur".

Ainsi tout exécutable, s'il a accès à la DLL, peut appeler et recevoir le résultat d'une fonction qu'elle contient. La seule contrainte est de connaitre la liste et les types des paramètres de la fonction appelée. Ceci explique le terme "bibliothèque" : un ensemble de fonctions exportées.

La partie "liaison dynamique" explicite le fait que le chargement d'une fonction d'une DLL se fait lors de l'exécution de l'application appelante, donc dynamiquement. On commence par charger en mémoire le code de la fonction à appeler (c'est le système qui s'en charge), puis on passe les paramètres pour passer à l'exécution du code de la fonction.

Un exemple de DLL assez courant nous est fourni par Microsoft : les contrôles ActiveX. Il s'agit de DLL qui exportent ici une interface et ses fonctions, permettant la création et l'exploitation du contôle développé et déployé par l'intermédiaire de cette DLL.

L'avantage de bibliothèques comme les DLL est de donner la possibilité d'externaliser des fonctions, d'en regrouper par domaines d'application et surtout de rendre ces fonctions réutilisables à partir de plusieurs applications.

Mis à jour le 14 janvier 2014 Bestiol

Lien MSDN : DLLs

Il faut utiliser l'utilitaire TDUMP, fourni avec Delphi. Dans une fenêtre de commandes :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
 
C:\WINNT\SYSTEM32>tdump -ee -m zipdll.dll 
Turbo Dump  Version 5.0.16.12 Copyright (c) 1988, 2000 Inprise Corporation 
    Display of File ZIPDLL.DLL 
 
EXPORT ord:0001='GetZipDllVersion' 
EXPORT ord:0002='ZipDllExec' 
EXPORT ord:0003='___CPPdebugHook'
Malheureusement, il n'est pas possible de connaître les paramètres attendus par les fonctions ; il faut donc avoir la documentation de la DLL.
On peut également utiliser l'outil gratuit Dependency Walker, qui montre en plus les dépendances entre modules.

Mis à jour le 18 octobre 2013 Bloon

Voici une fonction pour tester si une fonction existe dans une DLL. Ceci permet d'éviter les erreurs de liaison dynamique, suivant les versions de Windows par exemple.

Code delphi : Sélectionner tout
1
2
3
4
5
6
function FunctionDetect(LibName, FuncName: string):boolean;  
Var LibHandle:THandle;  
begin  
  LibHandle := LoadLibrary(PChar(LibName));  
  Result := (LibHandle<>0)And(GetProcAddress(LibHandle, PChar(FuncName)) <> nil);  
end;

Mis à jour le 14 janvier 2014 Nono40

Les fonctions ou procédures exportées d'une DLL sont accessibles à tout exécutable qui en connaît les paramètres. Il existe deux méthodes de liaison avec une DLL : la méthode statique, et la méthode dynamique.

Pour illustrer ces deux méthodes, imaginons que vous disposiez d'une DLL 'exemple.dll' qui exporte une fonction sous le nom de 'Somme' avec un index égal à 1. Cette fonction prend pour paramètre deux Integer, et renvoie également un Integer.

Méthode statique

Il s'agit de la méthode la plus simple à mettre en place. Il faut commencer par déclarer la fonction à importer dans votre unité de la manière suivante :

Code delphi : Sélectionner tout
function Somme(A, B: Integer): Integer; external 'exemple.dll' name 'Somme';
" external 'exemple.dll'" indique dans quel fichier DLL trouver la fonction, et " name 'Somme'" donne le nom d'exportation de la fonction dans la DLL.
Préciser le nom était ici facultatif, dans la mesure où la déclaration de la fonction utilisait déjà le nom d'exportation voulu dans la DLL.

Il est également possible de demander l'importation par index :
Code delphi : Sélectionner tout
function Somme(A, B: Integer): Integer; external 'exemple.dll' index 1;
Maintenant que votre fonction est déclarée, vous pouvez l'utiliser comme une fonction normale :
Code delphi : Sélectionner tout
ShowMessage(IntToStr(Somme(1, 2)));
Ce code affichera tout simplement une boîte de dialogue contenant le texte '3'.

Méthode dynamique

Contrairement à la méthode statique où Delphi se charge de la liaison avec la DLL en fonction de vos déclarations, la méthode dynamique vous donne toute latitude sur ce plan.
Il faut donc charger en mémoire la DLL, y récupérer l'adresse de la procédure/fonction qui vous intéresse puis utiliser cette adresse pour l'appeler.

Cela se fait avec quelques API. Voici comment charger puis appeler la fonction 'Somme' de la DLL 'exemple.dll' :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
procedure ChargerEtAppelerSomme; 
var 
  HandleDLL: THandle; 
  Somme: function (A, B: Integer): Integer; 
begin 
  Somme := nil; 
  //Chargement de la DLL 
  HandleDLL := LoadLibrary(pAnsiChar('exemple.dll')); 
  
  //Si la DLL n'est pas chargée on ne continue pas 
  If HandleDLL = 0 then Exit; 
  
  //Récupération de l'adresse de la fonction nommée 'Somme' 
  Somme := GetProcAddress(HandleDLL, pAnsiChar('Somme')); 
  
  //Appel de la fonction si on a bien récupéré son adresse 
  If Assigned(Somme) then 
    ShowMessage(IntToStr(Somme(1, 2))); 
end;
La variable HandleDLL recevra l'identifiant de notre DLL chargée en mémoire après l'appel à LoadLibrary. La variable Somme, quant à elle, est un pointeur sur une fonction dont les paramètres et le retour sont identiques à la fonction que nous souhaitons importer de la DLL.
L'adresse de Somme est ici récupérée grâce à son nom. Elle pourrait l'être grâce à son index en utilisant cette ligne de code :
Code delphi : Sélectionner tout
Somme := GetProcAddress(HandleDLL, pAnsiChar('1'));
Dans ces exemples, nous n'avons pas utilisé de convention d'appel comme stdcall (la plus courante). Pour plus de précisions à ce sujet, consultez les cours sur les DLL.

Mis à jour le 14 janvier 2014 Bestiol

Il peut être utile de connaître la liste des Dlls utilisées par l'application lors de la diffusion de celle-ci. La procédure donnée ci-dessous retourne la liste des Dlls actuellement chargées par le programme.
Cette fonction n'est utilisable que sous Windows NT ou supérieur.

Code Delphi : Sélectionner tout
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
function GetLoadedDLLList(liste: TStrings;Options: TModuleOptions): Boolean; 
type 
  TModuleArray = array[0..1] of HMODULE; 
  PHModule = ^TModuleArray; 
  EnumModType = function (hProcess: Longint; lphModule: PHModule; 
    cb: DWord; var lpcbNeeded: DWord): Boolean; stdcall; 
var 
  psapilib : HModule; 
  EnumProc : EnumModType; 
  Modules  : PHModule; 
  Nombre   : DWord; 
  i        : Longint; 
  FileName : array[0..MAX_PATH] of Char; 
  S        : string; 
begin 
  Result := False; 
  Liste.Clear; 
  
  { Cette fonction n'est possible que sous Windows NT ou supérieur} 
  if Win32Platform <> VER_PLATFORM_WIN32_NT then 
    Exit; 
  
  { Ouverture de la DLL pour obtenir la fonction voulue} 
  psapilib := LoadLibrary('psapi.dll'); 
  if psapilib = 0 then 
    Exit; 
  try 
    { Recherche de l'adresse de la fonction d'énumération} 
    EnumProc := GetProcAddress(psapilib, 'EnumProcessModules'); 
    if not Assigned(EnumProc) then 
      Exit; 
  
    { Le premier appel permet de connaître le nombre d'éléments} 
    if Not EnumProc(GetCurrentProcess, Nil , 0 , Nombre) then 
      Exit; 
    { Réservation de la mémoire ne fonction du nombre} 
    GetMem(Modules,Nombre*SizeOf(HMOdule)); 
    Try 
      { Obtention de la liste des modules} 
      if EnumProc(GetCurrentProcess, Modules, Nombre*SizeOf(HMOdule), Nombre) then 
      begin 
for I := 0 to Nombre-1 do 
begin 
  { Pour chaque module, obtention du nom complet} 
  GetModuleFileName(Modules^[i], FileName, MAX_PATH); 
  { Et ajout dans la liste ( seulement les Dll )} 
  if CompareText(ExtractFileExt(FileName), '.dll') = 0 then 
  begin 
    S := FileName; 
    if moRemovePath in Options then 
      S := ExtractFileName(S); 
    { Stockage de la chaîne} 
    if liste.IndexOf(S) = -1 Then 
      liste.Add(S); 
  end; 
end; 
      end; 
    Finally 
      FreeMem(Modules) 
    End; 
    Result := True; 
  finally 
    FreeLibrary(psapilib); 
  end; 
end;

Pour utiliser cette fonction, il suffit de passer un TStrings en paramètre ; le deuxième paramètre permet de sélectionner entre le nom complet des dll (avec chemin) ou le nom seul des Dlls.

Voici un exemple d'appel :
Code Delphi : Sélectionner tout
1
2
3
4
procedure TForm1.Button1Click(Sender: TObject); 
begin 
  GetLoadedDLLList(Memo1.Lines,[]); 
end;

Mis à jour le 18 octobre 2013 sur_uix

La procédure suivante permet d'obtenir les informations de version d'un programme win32.(EXE, DLL, DRV, etc…). La procédure donnée ci-dessous retourne la liste des informations de version :

Code Delphi : Sélectionner tout
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
procedure GetFileInfo2(const FileName: string;liste: TStrings); 
const 
  VersionInfo: array [1..8] of string 
      = ('FileDescription', 'CompanyName'   , 'FileVersion', 
'InternalName'   , 'LegalCopyRight', 'OriginalFileName', 
'ProductName'    , 'ProductVersion'); 
var 
  Handle   : DWord; 
  Info     : Pointer; 
  InfoData : Pointer; 
  InfoSize : LongInt; 
  DataLen  : UInt; 
  LangPtr  : Pointer; 
  InfoType : string; 
  i        : integer; 
begin 
  { Demande de la taille nécessaire pour stocker les infos de Version} 
  InfoSize:=GetFileVersionInfoSize(PChar(FileName), Handle); 
  if (InfoSize > 0) then 
  begin 
    { Réservation de la mémoire nécessaire} 
    GetMem(Info, InfoSize); 
  
    try 
      if GetFileVersionInfo(PChar(FileName), Handle, InfoSize, Info) then 
      begin 
for i:= 1 to 8 do 
begin 
  InfoType := VersionInfo[i]; 
  if VerQueryValue(Info,'\VarFileInfo\Translation',LangPtr, DataLen) then 
    InfoType:=Format('\StringFileInfo\%0.4x%0.4x\%s'#0,[LoWord(LongInt(LangPtr^)), 
HiWord(LongInt(LangPtr^)), InfoType]); 
  if VerQueryValue(Info,@InfoType[1],InfoData,Datalen) then 
    liste.add(VersionInfo[i]+' : '+strPas(InfoData)); 
end; 
      end; 
    finally 
      FreeMem(Info, InfoSize); 
    end; 
  end; 
end;

Exemple d'appel de la fonction :
Code Delphi : Sélectionner tout
1
2
3
4
procedure TForm1.Button2Click(Sender: TObject); 
begin 
  GetFileInfo('c:\windows\system\user32.dll',Memo1.lines); 
end;

Mis à jour le 18 octobre 2013 sur_uix

Vous avez créé un composant dans une DLL ou un paquet, que vous avez ensuite placé sur une form de l'exe via Parent, et lors de cette affectation à Parent, vous obtenez le message d'erreur " Impossible d'affecter TFont à TFont". Alors vous avez la réponse ici.

Cause La faute est à la propriété ParentFont du composant qui est positionnée à True.
Que fait cette propriété ? Si elle est à True, le composant recopie sa fonte à partir de son parent, via la méthode Assign de TFont.

C'est lors de ce Assign que plante l'application. Cette méthode, telle qu'implémentée dans TFont, recopie, pour des questions de performances, uniquement le Handle des deux fontes.

Hors un handle Windows ne peut être partagé par plusieurs modules. Les deux modules en question ici sont la DLL/le paquet et l'exécutable.

Donc lorsque Assign vérifie que le handle qu'il affecte est correct, il génère une exception. Cette exception est celle que vous obtenez.

Solution
Simplement passez à False la propriété ParentFont avant de modifier le parent du composant.

Mis à jour le 14 janvier 2014 sjrd

Lorsque notre application commence à prendre de l'ampleur, ou tout simplement lorsque nous cherchons à réutiliser au mieux notre code, nous pensons vite à l'utilisation des DLL. D'abord pour y mettre de simples fonctions puis, rapidement, nous avons besoin de partager des éléments plus complexes, voire des objets et là généralement les choses se gâtent (qui n'a pas eu droit aux violations d'accès ?).

Pour faire cela nous avons deux possibilités : soit nous utilisons une méthode plus ancienne qui consiste à utiliser une classe mère, soit nous utilisons les interfaces. Mais dans tous les cas, l'utilisation de l'unité Sharememest indispensable pour pouvoir partager certains types de données comme les stringet pour pouvoir partager des objets. Cette unité doit être déclarée en tête des usesdu projet principal ainsi que du projet de la DLL.
De plus l'utilisation de sharemem implique la distribution de la DLL 'BORLNDMM.DLL' avec notre application. Une alternative à sharemem existe cependant, il s'agit de FastSharemem que nous pouvons trouver ici : http://www.codexterity.com/fastsharemem.htm.
Celle-ci est plus rapide à l'exécution et ne nécessite aucun déploiement supplémentaire. Son emploi est simple puisqu'il suffit de remplacer dans les uses sharemem par Fastsharemem.

Première méthode : utilisation d'une classe mère

Principe : il s'agit de créer une ossature de classe qui ne contiendra que des méthodes abstraites mais qui sera connue de notre application et de nos DLL.
Exemple : supposons que nous souhaitons partager un objet qui possède une méthode qui fait l'addition de deux nombres, voici une classe mère qui pourrait servir à notre application et à nos DLL :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unit uClasseMere; 
  
interface 
  
Type 
  TClasseMere = class  
  Private 
     FOperande1 : integer; 
     FOperande2 : integer; 
  public 
     function Addition : integer; virtual; abstract; 
     Property Operande1 : Integer read FOperande1 write FOperande1; 
     Property Operande2 : Integer read Foperande2 write Foperande2; 
  end; 
  
implementation 
  
end.
Définition de l'objet échangé :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
unit uObjetTest; 
  
interface 
  
uses 
  uClasseMere; 
  
Type 
  TObjetTest = class( TClasseMere) 
  public 
     function Addition :integer; 
  end; 
  
implementation 
  
function TobjetTest.Addition:Integer; 
begin 
   result := Operande1 + Operande2; 
end; 
  
end.
Maintenant dans notre DLL, voici ce que nous pourrions faire :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
library pluginDLL1; 
uses 
  ShareMem, 
  SysUtils, 
  Classes, 
  uObjetTest in 'uObjetTest.pas'; 
  
{$R *.res} 
  
function Execute( aObjet : TObjetTest):integer; stdcall; 
begin 
   result := aObjet.Addition; 
end; 
  
Exports Execute; 
  
begin 
end.
Enfin voici un exemple d'utilisation dans notre application :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
uses 
   uClasseMere, uObjetTest; 
  
......... 
  
// Déclaration statique de la DLL 
function Execute( aObjet : TclasseMere):integer; stdcall; external 'PluginDLL1.dll'; 
  
  
procedure TForm1.Button1Click(Sender: TObject); 
var 
 wObjetTest : TObjetTest; 
begin 
  wObjetTest := TObjetTest.Create; 
  try 
    wObjetTest.Operande1 := 3; 
    wObjetTest.Operande2 := 2; 
   showMessage( inttostr( Execute( wObjetTest))); 
  finally 
    Free; 
  end; 
end;
Remarque : ne pas oublier d'ajouter l'unité Sharemem (ou FastSharemem) en tête de la liste des uses de l'application.

Deuxième méthode : Utilisation des interfaces

Principe : Une interface est un peu comme une classe à quelques différences près tout de même : elle ne possède aucune propriété mais uniquement des méthodes, elle n'implémente aucune des méthodes qu'elle définit et par conséquent, elle ne peut être instanciée. Une interface est destinée à être héritée par une classe qui devra implémenter les méthodes qu'elle a définies. En quelque sorte, une interface est un contrat passé avec la ou les classes qui en héritent.
Vous l'avez donc sûrement deviné, le principe va consister à définir une interface connue de notre application ainsi que de nos DLL :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
unit uInterface; 
  
interface 
  
type 
  IAddition = Interface 
    function Calcul:integer; 
  end; 
  
implementation 
  
end.
Voici maintenant le code de notre DLL :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
library PluginDLL1; 
  
uses 
  ShareMem, 
  SysUtils, 
  Classes, 
  uInterface in 'uInterface.pas'; 
  
{$R *.res} 
  
function Execute( aObjet : IAddition):integer; stdcall; 
begin 
   result := aObjet.Calcul; 
end; 
  
exports Execute; 
  
begin 
end.
Du côté de notre application :

Définition de l'objet :
Code delphi : Sélectionner tout
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
unit uObjetTest; 
  
interface 
  
Uses 
  uInterface; 
  
Type 
  TObjetTest = class( TinterfacedObject, IAddition) 
  Private 
     FOperande1 : integer; 
     FOperande2 : integer; 
  public 
     function Calcul :integer; 
     Property Operande1 : Integer read FOperande1 write FOperande1; 
     Property Operande2 : Integer read Foperande2 write Foperande2; 
  end; 
  
implementation 
  
function TobjetTest.Calcul:Integer; 
begin 
   result := FOperande1 + FOperande2; 
end; 
  
end.
Enfin, l'utilisation de notre DLL :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
uses 
   uInterface; 
  
......... 
  
// Déclaration statique de la DLL 
function Execute( aObjet : IAddition):integer; stdcall; external 'PluginDLL1.dll'; 
  
procedure TForm1.Button1Click(Sender: TObject); 
var 
 wObjetTest : TObjetTest; 
begin  
   wObjetTest := TObjetTest.Create; 
   try 
      wObjetTest.Operande1 := 3; 
      wObjetTest.Operande2 := 2; 
      showMessage( inttostr( Execute( wObjetTest))); 
   finally 
      wObjetTest :=nil 
  end; 
end;
Remarque : ne pas oublier de d'ajouter l'unité Sharemem (ou FastSharemem) en tête de la liste des uses de l'application.

Mis à jour le 14 janvier 2014 skywaukers

La particularité du type string sous Delphi pose un évident problème de compatibilité avec le standard d'échange entre un programme exécutable et une DLL. Windows étant entièrement "C++ Like", les chaines de caractères sont des pointeurs. Il existe donc différentes méthodes pour passer un type string en paramètre dans une DLL…

  • Utiliser les PChar
  • Utiliser ShareMem : comme vous avez pu le constater, lorsque vous utilisez l'assistant de Delphi pour générer un projet de DLL, on peut lire un laïus à propos de ShareMem. Il suffit en fait de déclarer l'unité ShareMem en premier dans la liste des uses et on peut dès lors utiliser directement les string en paramètre dans les DLL. Cependant cette méthode comporte un inconvénient: celui de la portabilité. Il est en effet impératif de fournir, avec l'exécutable, le fichier "borlndmm.dll"
    (Borland Memory Manager: ce fichier se trouve dans "bin" de votre installation de Delphi).
  • Utiliser FastShareMem : cette unité est ce que l'on pourrait appeler une "solution miracle".
    Pas de DLL externe à fournir, plus rapide que ShareMem (jusqu'à 8 fois selon le créateur), il suffit juste, comme ShareMem, de déclarer FastShareMem en premier dans les uses... Cerise sur le gateau: il est FreeWare...

Mis à jour le 14 janvier 2014 Pedro smyley

Lorsque vous ne souhaitez pas utiliser d'unité voire de DLL supplémentaire avec vos DLL, vous devez proscrire le type String dans les échanges de paramètres entre vos applications et vos DLL.

Il faut donc trouver une alternative à ce type. Le type de chaîne de caractères standard de Windows se trouve être la chaîne à zéro terminal (AZT), correspondant au type pChar dans Delphi.

Ce type étant un pointeur, il faut allouer de l'espace mémoire avant de pouvoir stocker la chaîne.
On se retrouve donc avec un problème : si une DLL alloue de la mémoire pour un pChar qu'elle passera à l'application lors de l'appel d'une fonction, elle ne sera pas en mesure de libérer cette mémoire par la suite, et l'application ne pourra pas non plus effectuer cette tâche, qui pour des raisons évidentes ne lui revient pas.

Il existe alors deux solutions. La première, un peu lourde, consiste à créer une fonction dédiée à la libération de la chaîne dans la DLL.
La seconde est une astuce couramment utilisée dans les API Windows : dans un premier temps, l'application appelle la fonction qui doit lui renvoyer un pChar (le pChar étant passé par référence dans les paramètres) avec nilen paramètre, ce qui indiquera à la fonction qu'elle doit renvoyer la taille de mémoire à allouer. L'application réserve alors l'espace indiqué, puis rappelle la fonction en lui passant le pointeur vers la zone mémoire nouvellement créée pour récupérer le résultat.
Une fois ce dernier exploité, l'application sera en mesure de libérer elle-même la mémoire allouée à la chaîne.

Voici une illustration de ce procédé :
Dans la DLL :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Dans la DLL :  
//La fonction renvoie à proprement parler la taille de la chaîne, le message est passé en paramètre  
function MessageTexte(Buffer: pChar): Cardinal; stdcall;  
var  
  msg: String;  
begin  
  //On récupère le résultat. Notez que le type string n'est pas proscrit en interne  
  msg := FonctionQuiRenvoieLeMessage();  
  
  Result := Length(msg);  
  
  //Si le buffer a été alloué, on y effectue une copie de la chaîne  
  if Buffer <> nil then  
    StrCopy(Buffer, pAnsiChar(msg));  
end;  
  
exports  
  MessageTexte;
Dans l'application appelante :
Code delphi : Sélectionner tout
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
function MessageTexte(Buffer: pChar): Cardinal; stdcall; external 'MaDLL.dll';  
  
implementation  
  
{$R *.dfm}  
  
procedure TForm1.Button1Click(Sender: TObject);  
var  
  Taille: Cardinal;  
  Buf: pChar;  
begin  
  
  //On récupère la taille du message  
  Taille := MessageTexte(nil);  
  
  //Puis on alloue la mémoire nécessaire  
  GetMem(Buf, Taille);  
  
  //On récupère/traite le résultat  
  MessageTexte(Buf);  
  ShowMessage(String(Buf));  
  
  //Et enfin on peut libérer la mémoire  
  FreeMem(Buf);  
end;
Il existe une autre solution (et sûrement d'autres encore en plus de celle-ci), plus exactement une variante de la précédente, qui utilise les atomes. L'intérêt est que l'atome, une fois créé, peut être supprimé indifféremment du côté de la DLL ou de l'application.
De plus, un unique appel est fait à la DLL pour récupérer la taille et le message.

Voici un exemple de code :

Dans la DLL :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
uses ..., Windows;  
  
...  
  
function MessageTexte(var Atome: Word): Cardinal; stdcall;  
var  
  msg: pAnsiChar;  
begin  
  msg := 'message';  
  
  Atome := GlobalAddAtom(msg);  
  
  Result := Length(msg);  
end;  
  
exports 
 MessageTexte;
Dans l'application appelante :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function MessageTexte(var Atome: Word): Cardinal; stdcall; external 'dll.dll';  
  
implementation  
  
{$R *.dfm}  
  
procedure TForm1.Button1Click(Sender: TObject);  
var  
  Atome: Word;  
  Taille: Cardinal;  
  Buf: pChar;  
begin  
  Taille := MessageTexte(Atome);  
  
  GetMem(Buf, Taille);  
  
  GlobalGetAtomName(Atome, Buf, Taille);  
  
  ShowMessage(Buf);  
  
  FreeMem(Buf);  
  GlobalDeleteAtom(Atome);  
end;

Mis à jour le 14 janvier 2014 Bestiol

Lors de l'utilisation d'une DLL, nous pouvons être confrontés à quelques difficultés lors du passage d'un tableau en paramètre.
Voici comment procéder…

Soit une fonction d'une DLL écrite en C++ :

Code c++ : Sélectionner tout
int WINAPI RemplirTableau(int* TabInt);
Sous Delphi, nous déclarons la fonction correspondante :
Code delphi : Sélectionner tout
FDLLRemplirTableau: function(var iTab : integer): Integer;stdcall;
Le mot clé var permet d'indiquer que la variable est passée par référencement.

Et nous l'utilisons de la manière suivante :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
var 
  ... 
  MonTab : array of integer; 
  MaValeurRetour : integer; 
begin 
  ... 
  SetLength(MonTab, 20); 
  
  MaValeurRetour := FDLLRemplirTableau(MonTab[0]); 
  ...

Mis à jour le 14 janvier 2014 Benjamin GAGNEUX

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2019 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.