IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 124, nombre de questions : 929, dernière mise à jour : 31 décembre 2023  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.

SommaireLangageCompilation (12)
précédent sommaire suivant
 

Il peut arriver que votre projet ne se compile pas pourtant le code semble correct.
Cela peut être dû au fait que le nom du répertoire de votre projet contienne des accents. Il faut donc tout simplement utiliser des caractères non accentués dans le nom du répertoire pour corriger le problème.

Mis à jour le 20 janvier 2014 NotANumber

La compilation conditionnelle est la compilation d'une partie du code ou non suivant des conditions. Ces conditions sont déterminées par une série de {$IFDEF ... } ... {$ENDIF} portant sur des identificateurs déclarés par {$DEFINE} ou {$UNDEF}.

Les utilisations courantes sont les suivantes :

Ajout de messages pour la mise au point :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
{$DEFINE MISEAUPOINT} 
procedure TForm1.Button1Click(Sender: TObject); 
Var i:Integer; 
begin 
  i:=FaitUnCalcul; 
  {$IFDEF MISEAUPOINT} 
  { Cette ligne n'est compilée que pour la mise au point } 
  ShowMessage(IntToStr(i)); 
  {$ENDIF} 
  TraiteLeCalcul(i); 
end;

Compilation suivant les versions de Delphi :

Des identificateurs sont prédéfinis pour chaque version de Delphi, ce qui permet de compiler différemment suivant la version.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
uses 
  Windows, Messages, SysUtils, Classes, Controls, Forms, StdCtrls, AppEvnts, 
{$IfDef VER130} 
  DsgnIntf; { Pour Delphi 5 } 
{$Else} 
  DesignEditors, DesignIntf; { Pour Delphi 6 et 7 } 
{$EndIf}
  • VER80 est prédéfini pour Delphi 1 ;
  • VER90 est prédéfini pour Delphi 2 ;
  • VER100 est prédéfini pour Delphi 3 ;
  • VER120 est prédéfini pour Delphi 4 ;
  • VER130 est prédéfini pour Delphi 5 ;
  • VER140 est prédéfini pour Delphi 6 ;
  • VER150 est prédéfini pour Delphi 7 ;
  • VER160 est prédéfini pour Delphi 8 ;
  • VER170 est prédéfini pour Delphi 2005 ;
  • VER180 est prédéfini pour Delphi 2006 ;
  • VER185 est prédéfini pour Delphi 2007 pour Win32 ;
  • VER190 est prédéfini pour Delphi 2007 pour .Net ;
  • VER200 est prédéfini pour Delphi 2009 ;
  • VER210 est prédéfini pour Delphi 2010 ;
  • VER220 est prédéfini pour Delphi XE ;
  • VER230 est prédéfini pour Delphi XE2 ;
  • VER240 est prédéfini pour Delphi XE3 ;
  • VER250 est prédéfini pour Delphi XE4.

Compilation suivant l'OS :

Cet exemple est tiré de la définition du type TSearchRec utilisé par FindFirst/FindNext.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  TSearchRec = record 
    Time: Integer; 
    Size: Integer; 
    Attr: Integer; 
    Name: TFileName; 
    ExcludeAttr: Integer; 
{$IFDEF MSWINDOWS} 
    FindHandle: THandle  platform; 
    FindData: TWin32FindData  platform; 
{$ENDIF} 
{$IFDEF LINUX} 
    Mode: mode_t  platform; 
    FindHandle: Pointer  platform; 
    PathOnly: String  platform; 
    Pattern: String  platform; 
{$ENDIF} 
  end;

Mis à jour le 18 octobre 2013 Alcatîz Nono40

En dehors des messages d'erreurs de compilation classiques, Delphi produit quelquefois des messages d'erreur interne.

Ils sont difficiles à résoudre car ils ne sont pas tous documentés loin s'en faut, mais il peut être utile de se faire une idée de l'origine du problème en faisant attention à la première lettre du code du message :

  • B : debugger
  • BC : debugger
  • BR : browser
  • C : codegen
  • CM : command line version of the compiler
  • D : parser
  • DB : debugger
  • DBG: debug info output
  • DM : IDE version of the compiler
  • E : parser
  • EO : debugger/evaluator
  • FN : filename / pathname parsing
  • GH : HPP generator
  • I : code generator
  • IN : inspectors
  • L : linker
  • LI : BPI file writing
  • LO : object file loading
  • M : memory allocation
  • MA : name mangling
  • MB : multi-byte (MBCS) support
  • O : object (OMF) file handling
  • P : package managment
  • R : resource writing
  • S : scanner
  • ST : standard procedure handling
  • SY : symbol table
  • T : code generator
  • TI : RTTI generator
  • U : parser
  • UD : IDE version of the compiler
  • UI : error handling
  • URW: DCU reading/writing
  • W : Object file (OMF) writing
  • X : code generator

Dans la plupart des cas la fermeture de Delphi, la suppression des fichiers .DSM et la construction complète de projet permettent de corriger cette erreur.

Le numéro donné en plus correspond à un numéro de ligne interne au compilateur. Seul Borland peut exploiter cette information.

Mis à jour le 20 janvier 2014 delphi-fan

Les fichiers .dcu de Delphi correspondent à la version compilée des unités (.pas).
Les spécifications de Borland stipulent que ces fichiers ne sont pas compatibles d'une version à l'autre de Delphi. Lorsque Delphi vous réclame un fichier .pas alors que vous n'avez que le .dcu, cela signifie que ce .dcu a été compilé avec une version différente de la vôtre. Vous devez donc obtenir une version de votre composant spécifique à votre version de Delphi.

Note : lorsque l'on parle ici de version de Delphi, il s'agit du numéro de version et non du type (personnel, entreprise, etc.).

Mis à jour le 20 janvier 2014 Pierre Castelain

Quand deux fiches doivent se référencer mutuellement, on ne doit pas placer les deux clauses uses dans la section interface de leur fichier unité respectif. Cela provoque l'erreur "Référence circulaire" à la compilation.
Dans le cas le plus simple de deux unités mutuellement dépendantes, cela signifie que les unités ne peuvent se référencer mutuellement dans la clause uses de leur section interface. Ainsi, l'exemple suivant produit une erreur de compilation :

Première unité

Code delphi : Sélectionner tout
1
2
3
4
5
6
Unit Unit1; 
  
interface 
uses Unit2; 
... 
end;
Seconde Unité
Code delphi : Sélectionner tout
1
2
3
4
5
6
unit Unit2; 
  
interface 
uses Unit1; // Impossible dans ce cas d'utilisation 
... 
end;
Pour éviter une telle erreur, utilisez l'une des méthodes suivantes :
  • Placez les deux clauses uses, avec les identificateurs d'unités, dans la section implementation de leur fichier unité respectif, c'est ce que fait la commande du menu Fichier|Utiliser l'unité.
  • Placez l'une des clauses uses dans la section interface et l'autre dans la section implementation.

Utilisons la solution numéro 2 :
Les deux unités peuvent sans problème se référencer mutuellement si l'une des références est déplacée dans la section implémentation :

Première unité, elle n'est pas modifiée.
Code delphi : Sélectionner tout
1
2
3
4
5
6
Unit Unit1; 
  
interface 
uses Unit2; 
... 
end;
Seconde Unité, on déplace la déclaration de la clause uses dans la partie implementation.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
unit Unit2; 
  
interface 
... 
implementation 
uses Unit1;  //Modification 
... 
end;
Afin de réduire les risques de références circulaires, il est préférable à chaque fois que cela est possible de lister les unités dans la clause uses de l'implémentation. C'est uniquement si des identificateurs d'une autre unité sont utilisés dans la section interface qu'il est nécessaire d'indiquer cette unité dans la clause uses de l'interface.

Mis à jour le 20 janvier 2014 Laurent Dardenne

Les versions du compilateur Delphi peuvent être testées avec des directives de compilation.

  • VER80 -> Delphi 1
  • VER90 -> Delphi 2
  • VER100 -> Delphi 3
  • VER120 -> Delphi 4
  • VER130 -> Delphi 5
  • VER140 -> Delphi 6
  • VER150 -> Delphi 7
  • VER160 -> Delphi 8
  • VER170 -> Delphi 2005

Exemple : pour faire une action différente pour Delphi 5 seulement :
Code delphi : Sélectionner tout
1
2
3
4
5
{$IFDEF VER130} 
 à faire si Delphi5 
{$ELSE} 
 à faire sinon 
{$ENDIF}
Mais on a souvent besoin de savoir si le compilateur a une version supérieure à une certaine version !
On utilise pour cela la constante RTLVersion déclarée dans System.pas.

Exemple : pour tester la version du compilateur Delphi sur une plage :
Code delphi : Sélectionner tout
1
2
3
4
5
{$IF RTLVersion >= 13} //si delphi5 ou supérieur 
 à faire si Delphi >= Delphi5 
{$ELSE} 
 à faire sinon 
{$IFEND}
RTLVersion est définie dans System.pas
Exemple pour Delphi7 :
Code delphi : Sélectionner tout
1
2
const 
RTLVersion = 15.00;

Mis à jour le 20 janvier 2014 manuker

À la différence des méthodes de classes il n'existe pas de variables de classes en Delphi. Pour les simuler on doit donc déclarer des méthodes de classe associées à une variable globale.

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
// Solution proposée par Cpdump, Sjrd et Nono40  
interface  
  
type  
  
  TMaClasse = class  
  public  
    class function GetDefaultValue : Char;  
    class procedure SetDefaultValue(New : Char);  
  end;  
  
implementation  
  
var  
  TMaClasse_DefaultValue : Char = ' ';  
  
class function TMaClasse.GetDefaultValue : Char;  
begin  
  Result := TMaClasse_DefaultValue;  
end;  
  
class procedure TMaClasse.SetDefaultValue(New : Char);  
begin  
  TMaClasse_DefaultValue := New;  
end;  
end.
Vous pouvez combiner cette approche en utilisant des propriétés. Gardez à l'esprit que ce code reste un pis-aller, étant donné que l'on accède à une propriété d'une instance non instanciée. Si jamais le code de la classe change et que la méthode n'est plus une méthode de classe alors votre code risque de planter…

Mis à jour le 20 janvier 2014 Laurent Dardenne

La solution consiste en l'utilisation d'une seule méthode héritée de TPersistent : DefineProperties. Il faut la réimplémenter et y appeler autant de fois que nécessaire la méthode DefineProperty / DefineBinaryProperty de l'objet TFiler passé en paramètre.

DefineProperty doit être utilisé si vous devez écrire/lire des types de base. DefineBinaryProperty doit être utilisé si vous devez écrire vos propriétés dans des flux.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type TMonPersistent = class(TAncetre) // TAncetre hérite de TPersistent 
private 
  ... 
  procedure LoadMyProp1(Reader : TReader); 
  procedure SaveMyProp1(Writer : TWriter); 
  procedure LoadMyProp2(Stream : TStream); 
  procedure SaveMyProp2(Stream : TStream); 
protected 
  ... 
  procedure DefineProperties(Filer : TFiler); override; 
public 
  ... 
published 
  ... 
end;
Voici la méthode DefineProperties de notre exemple. On définit une propriété virtuelle MyProp1 qui va être lue/écrite avec des objets TReader / TWriter ainsi qu'une autre MyProp2 qui va être lue/écrite depuis/vers des flux.
Code delphi : Sélectionner tout
1
2
3
4
5
6
procedure TMonPersistent.DefineProperties(Filer : TFiler); 
begin 
  inherited; // Surtout ne pas oublier la méthode héritée ! 
  Filer.DefineProperty('MyProp1', LoadMyProp1, SaveMyProp2, True); 
  Filer.DefineBinaryProperty('MyProp2', LoadMyProp2, SaveMyProp2, True); 
end;
Les quatre autres procédures se contentent de lire et d'écrire le contenu des propriétés :
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 TMonPersistent.LoadMyProp1(Reader : TReader); 
begin 
  // Lire avec les méthodes de TReader 
end; 
  
procedure TMonPersistent.SaveMyProp1(Writer : TWriter); 
begin 
  // Ecrire avec les méthodes de TWriter 
end; 
  
procedure TMonPersistent.LoadMyProp2(Stream : TStream); 
begin 
  // Lecture depuis Stream 
end; 
  
procedure TMonPersistent.SaveMyProp2(Stream : TStream); 
begin 
  // Ecriture dans Stream 
end;

Mis à jour le 20 janvier 2014 sjrd

En regardant de près dans l'unité Classes vous trouverez :

  • procedure RegisterClass(AClass: TPersistentClass);
    Cette procédure permet de recenser une classe d'objet persistant pour que le type de classe puisse être retrouvé.
  • function FindClass(const ClassName: string): TPersistentClass ;
    Cette fonction permet de localiser un type de classe par son nom. FindClass recherche les classes connues du système d'enregistrement.

Mécanisme :
En appelant RegisterClass, la classe sera recensée par le système d'enregistrement de la VCL. La méthode FindClass tente de localiser dans le système d'enregistrement, la classe dont le nom est passé en paramètre. Si la classe n'est pas trouvée alors FindClass déclenche une exception.

Le code ci-dessous met en œuvre ce mécanisme et vous permet de retrouver une fenêtre par son nom de classe.

Recommandations:
Dans un nouveau projet, créez deux nouvelles fiches TForm2 et TForm3 respectivement dans Unit2 et Unit3.
Sur TForm1 (Unit1), placez un TEdit et un TButton.
Remplacez le code de l'unit1 par celui fourni ci-dessous.

Utilisation:
À l'exécution renseignez le Tedit avec soit la valeur TForm2, soit la valeur TForm3 puis validez en cliquant sur le TButton.
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
unit Unit1; 
  
interface 
  
uses 
  Unit2, unit3, Windows, Messages, 
  SysUtils, Classes, Graphics, Controls, Forms, 
  Dialogs, StdCtrls; 
  
type 
  TForm1 = class(TForm) 
    Edit1: TEdit; 
    Button1: TButton; 
    procedure FormCreate(Sender: TObject); 
    procedure Button1Click(Sender: TObject); 
  private 
    { Private declarations } 
  public 
    { Public declarations } 
  end; 
  
var 
  Form1: TForm1; 
  
implementation 
  
{$R *.DFM} 
  
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  RegisterClass(Tform2); 
  RegisterClass(Tform3); 
end; 
  
procedure TForm1.Button1Click(Sender: TObject); 
var 
  f : Tformclass; 
begin 
  try 
    f := tformclass(findClass(edit1.text)); 
    with f.create(self) do show; 
  except 
    raise; 
  end; 
end; 
  
end.

Mis à jour le 20 janvier 2014 Pascal Jankowski

Il existe plusieurs méthodes pour alléger un exécutable sous Delphi.
Il est évident qu'il n'existe pas de solution miracle mais quelques options de compilation permettent de gagner quelques Kilo octets superflus.

Nous ne verrons ici que les méthodes les plus courantes.
- Limiter la taille des ressources images: Une TImageList avec des Bitmap de 500x500, ça grossit vite… Donc préférez des types d'images moins lourds (jpg, png, gif, etc.). Il existe de plus des descendants de TImageList qui prennent en charge ces formats.

Plusieurs paramètres dans les options du projet spécifient si le compilateur doit inclure ou non des données à l'exécutable.
Certaines peuvent être désactivées. Ces options se trouvent dans Projet\Options… onglet Linker.
- TD32 : {$D+} L'aide de Delphi a écrit :

Code other : Sélectionner tout
1
2
Active ou désactive la génération d'informations de débogage. Ces informations se présentent sous la forme de tables de numéros de lignes propres à chaque procédure, qui contiennent les adresses du code correspondant à chaque ligne du texte source. Pour les unités, les informations de débogage sont enregistrées dans le fichier unité, avec le code objet de l'unité. 
Elles augmentent la taille des fichiers unité et l'espace mémoire occupé lors de la compilation des programmes utilisant  cette unité, mais n'affectent ni la taille ni la vitesse d'exécution du programme exécutable.

- Symbole locaux : {$L+} L'aide de Delphi a écrit :
Code other : Sélectionner tout
Active ou désactive la génération d'informations concernant les symboles locaux. Il s'agit des noms et types de toutes les variables et constantes locales au module, c'est-à-dire tous les symboles de la partie implémentation du module (y compris les symboles des procédures et fonctions). Pour les unités, les informations concernant les symboles locaux sont stockés dans le fichier unité avec le code objet de l'unité. Ces informations augmentent la taille des fichiers unité et l'espace mémoire nécessaire à la compilation des programmes utilisant l'unité.

- Utiliser DCUIL/DCU de débogage : L'aide de Delphi a écrit :
Code other : Sélectionner tout
Les DCUIL/DCU de débogage contiennent des informations de débogage et sont construits avec les cadres de piles. Lorsque cette option est cochée, le compilateur ajoute le chemin des DCUIL/DCU de débogage au début du chemin de recherche de l'unité
Dans l'onglet packages:
- Construire avec les paquets d'exécution :
Si cette option est décochée, tous les packages nécessaires à l'exécution de l'application seront intégrés au fichier.
Sinon, le fichier sera beaucoup plus petit mais nécessitera, pour son déploiement, de fournir les fichiers .bpl qu'il utilise

Mis à jour le 20 janvier 2014 Pedro

Sur d'anciens projets, la compilation peut échouer en indiquant un message d'erreur dans la clause Uses d'une unité :

Code : Sélectionner tout
1
2
[Erreur fatale] info.pas(8): L'unité XXXX a été compilée avec une version différente de ZZZ.yyyy 
exe System.RTLVersion
Le problème est le suivant :
Il existe, dans le répertoire de l'unité en cause, un fichier .dcu compilé avec une autre version de Delphi que celle que vous utilisez actuellement. La présence de ces unités compilées provoque des conflits que le compilateur ne sait résoudre.

La suppression des fichiers .dcu suivi d'une recompilation du projet résout ce problème.

À noter que si vous ne disposez pas des fichiers sources, cas de composants shareware ou freeware, il n'est pas possible de résoudre ce problème.

Mis à jour le 20 janvier 2014 Laurent Dardenne

Certaines directives de compilation ayant une portée locale il reste possible de contrôler leurs activation ou désactivation pour une portion de code.

Prenons ici le cas de la directive I, l'aide en ligne de Delphi nous indique :
La directive bascule $I active ou désactive la génération automatique du code vérifiant le résultat des appels aux procédures d'E/S. Si une procédure d'E/S renvoie un code retour d'E/S non nul alors que cette bascule est activée, une exception EInOutError est déclenchée (ou le programme termine son exécution si la gestion des exceptions est désactivée). Lorsque cette bascule est désactivée, le programme doit tester les codes retour des procédures d'E/S à l'aide de la fonction IOResult.

Dans notre exemple, les directives de compilation du projet active la directive $I, elle sera donc utilisée par tout le code. Mais ici, on souhaite pouvoir tester le résultat de la fonction IOResult au lieu de déclencher une exception et seulement pour cette procédure. On donc doit désactiver provisoirement cette directive afin de ne pas avoir d'effet de bord sur le reste du code.

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
Procedure Log(Chaine:String; LogDate : Boolean); 
var F : Textfile; 
    S : String; 
begin 
 Assignfile(F, 'C:\Temp\Test.txt'); 
{$IFOPT I+}        // Si la directive I est activée 
{$DEFINE I_Plus} // Alors défini le symbole (local) 
{$I-}                 // Et désactive la directive  
{$ENDIF} 
  Append(F); //Section de code concerné 
{$IFDEF I_Plus} // Si la directive I était précédemment activée 
{$I+}             // Alors on réactive la directive  
{$ENDIF} 
{$UNDEF I_Plus} //On supprime le symbole précédemment défini 
  
 if IOresult <> 0 
  then Rewrite(F); 
 Try 
  if LogDate 
   then S:=FormatDateTime('DDDD DD MMMM YYYY HH:NN:SS',Now) 
   else S:=''; 
  
  Writeln(F,S+' '+Chaine); 
 Finally 
  Closefile(F); 
 end; 
end;
Il est bien évidement possible d'inverser la logique, par exemple :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
{$IFOPT I-}        // Si la directive I est désactivée 
{$DEFINE I_Moins} // Alors défini le symbole (local) 
{$I+}                 // Et active la directive  
{$ENDIF} 
  Append(F); //Section de code concerné 
{$IFDEF I_Moins} // Si la directive I était précédemment désactivée 
{$I-}             // Alors on déactive la directive  
{$ENDIF} 
{$UNDEF I_Moins} //On supprime le symbole précédemment défini

Mis à jour le 20 janvier 2014 Laurent Dardenne

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 © 2024 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.