Les génériques sous Delphi.NET

Au cœur du système
- Concepts généraux
- L’API WIN32
- GDI & Programmation Graphique
- Les DLL 32 bits
- Création de Composants
- Communication sous TCP/IP
- Création d'applications INTERNET
- Les ActiveX
- Les communications entre applications
- Utilisation des pilotes ODBC
- Les Threads
Ø La charte graphique du CERSIAT
Page 2 sur 370
De plus en plus, DELPHI s'impose comme un outil professionnel de développement dans les entreprises. Ce tome est dédié plus particulièrement aux développeurs désirant concevoir des applications sophistiquées en environnement Windows 32 bits.
La richesse et le succès de DELPHI sont sans nul doute dus au fait que rien n'est impossible à réaliser avec ce produit. C'est l'outil à tout faire, l'outil universel.
L'objectif de ce tome est de donner aux stagiaires des notions de programmation système (accès au système, création de composants, communications)
Page 4 sur 370
Sommaire
Concepts généraux 7
Rappel sur les différents types de base .8
Composition d’une application DELPHI .14
Les pointeurs 20
Les unités de code 22
La gestion des exceptions 26
L’API Win32 .35
Fonctions d’entrée utilisateur ..35
Interface de programmation graphique 35
E/S dans les fichiers 36
La base de registre .41
Fichiers d’initialisation 42
Informations sur le système ..44
Manipulations de chaînes et jeux de caractères 45
Horloges 46
Gestion des systèmes de fichiers .46
GDI et programmation graphique 69
Le Canvas 69
Couleurs et tracés 87
Les DLL ..95
Chargement statique d’une DLL ..99
Chargement dynamique d’une DLL .100
DLL graphique ..102
Création de composants 107
Construire et installer un composant 108
Construire un composant 112
Ajouter des propriétés .113
Ajouter une méthode 115
Ajouter un événement .115
Les communications sous TCP/IP .143
Utilisation des sockets sous Windows ..144
Ecriture d’un client et d’un serveur ..155 utilisation des composants INTERNET ..157
HTTP 157
FTP 161
SMTP ..161
POP3 161
Les ActiveX ..255
Présentation .255
Création de contrôles ActiveX ..256
Déploiement d’ActiveX sur le WEB ..261
Les communications entre applications windows .263
Gestion du presse-papiers ..263

Utilisation de DDE ..265
Utilisation de OLE ..273
Données accessibles par le réseau 287
Utilisation de pilotes ODBC 295
Qu'est-ce qu'un pilote ODBC ? ..295
Configurations initiales 296
Remarques sur ODBC .301
Les + de DELPHI 3 .301
Les Threads 305la creation d’un thread ..306
La synchronisation des threads 315 la charte graphique du cersiat .319 Règles de base pour construire une IHM ..327
Portage des applications 3.11 vers NT4.0 ..363
Grille d'évaluation d'une IHM lors du maquettage .366
CONCEPTS GÉNÉRAUX
Delphi pour une programmation RADieuse
RAD signifie Développement rapide d'application (Rapid Application Development). Ce terme décrit la nouvelle génération d'environnements de développement logiciel. Dans un environnement RAD, les programmeurs utilisent des outils plus intuitifs et visuels. Il est difficile de regarder un bout de code qui crée une fenêtre et de la visualiser, mais le RAD permet de créer la fenêtre en quelques clics.
Avantages de Delphi
Delphi apporte une grande souplesse au développeur. Lorsque Delphi génère un fichier .EXE, il s'agit d'un vrai exécutable. Aucun autre fichier n'est nécessaire pour l'exécution. Vous obtenez donc une application plus propre, et plus facile à distribuer et à maintenir. Vous n'avez à distribuer qu'un seul fichier, sans dépendre de DLL ou d'autres fichiers.
Delphi vous offre donc un compilateur optimisé qui vous donnera une application rapide sans qu'il soit nécessaire de fournir plus d'efforts pour optimiser le programme qu'il n'en avait fallu pour l'écrire.
Les différences entre Delphi 3 et Delphi 2
Bien que l'EDI de Delphi 3 semble inchangé, on compte de nombreuses différences cachées sous le capot. Les principales améliorations sont les suivantes :
- Architecture des bases de données et connectivité. L'architecture des bases de données a été complètement revue afin de suivre une approche multi-liaisons plutôt que la traditionnelle conception Client/Serveur. Vous pouvez ainsi créer des applications client extrêmement légères. Le support natif des bases de données Access a enfin été intégré, afin de permettre une transition aisée des applications VB sous Delphi 3.
- Contrôles ActiveX. Vous pouvez créer vos propres contrôles ActiveX ou utiliser des contrôles déjà écrits dans vos applications Delphi.
- Applications Web. Vous pouvez créer des applications client ou serveur, dans un environnement Web.
Ceci donne à Delphi 3 de nombreux atouts dans la course à Intranet.
RAPPEL SUR LES DIFFÉRENTS TYPES DE BASE
Regardons quels sont les différents "types" de données et l'emploi qu'en fait Delphi 3 :
- Types entiers
- Types réels
- Le type Currency
- Types booléens
- Types caractère
- Types chaîne
- Types variant
TYPES ENTIERS
Le type de données entier est utilisé pour représenter des nombres entiers. Il existe plusieurs types capables de stocker une valeur entière.
Type |
Intervalle de valeur |
Octets nécessaires |
Peut contenir un nombre négatif |
Byte |
0..255 |
1 |
Non |
Word |
0..65535 |
2 |
Non |
ShortInt |
-128..127 |
1 |
Oui |
SmallInt |
-32768..23767 |
2 |
Oui |
Integer |
-2147483648..2147483647 |
4 |
Oui |
Cardinal |
0..2147483647 |
4 |
Non |
Longint |
-2147483648..2147483647 |
4 |
Oui |
Vous pouvez remarquer que différents types entiers peuvent avoir des capacités de stockage radicalement différentes. Remarquez aussi que tout a un prix. La quantité de mémoire nécessaire augmente avec la capacité de stockage.
Integer est l'un des deux types génériques de Delphi 3. Les types génériques sont ceux qui sont affectés par l'unité centrale ou le système d'exploitation sur lesquels le compilateur est implémenté. Sous un système d'exploitation 32 bits tel que Windows 95 ou Windows NT, les types génériques ont leur capacité de stockage définie par le système d'exploitation.
TYPE RÉELS
Après le type entier, vient logiquement le type de données real (réel). Ces types de données real sont conçus pour contenir un nombre avec une partie fractionnelle.
Type |
Intervalle ![]() |
Octets nécessaires |
Real |
± 2.9 * 10-39 à ± 1.7 * 1038 |
6 |
Single |
± 1.5 * 10-45 à 3.4 * 1038 |
4 |
Double |
± 5.0 * 10-324 à 1.7 * 10328 |
8 |
Extended |
± 3.4 * 10-4932 à 1.1 * 104392 |
10 |
Comp |
- 263 à 263 – 1 |
8 |
L'intervalle des valeurs que ces types peuvent accepter est impressionnant. Vous avez de quoi faire avant d'avoir besoin de générer un nombre qui dépasse 1.1 * 104392.
Le type Comp est en fait un très grand nombre entier, et non un nombre réel. Ce type est inclus dans ce tableau parce qu'il est mis en œuvre de la même façon que les types à virgule flottante. Il s'agit en fait d'un entier à 64 bits.
Essayez dans la mesure du possible d'utiliser des types de données Single ou Double plutôt que Real. Les Real sont plus lents à manipuler (il ne s'agit pas d'un type natif pour l'unité à virgule flottante du microprocesseur, chaque opération nécessite donc des conversions) et prennent plus de place ou sont moins précis que Single ou Double.
TYPE CURRENCY
Un nouveau type de données qui mérite que l'on s'y intéresse est le type Currency (devise). Jusqu'à présent dans la plupart des langages, le développeur devait utiliser un type Real pour représenter des valeurs monétaires. Delphi 3 propose à cet usage spécifique un type Currency. Ce type est un type à virgule flottante qui est compatible dans ses affectations avec tous les autres types à virgule flottante, type Variant compris (nous reviendrons sur ce type par la suite). Le type Currency a une précision à quatre décimales et on le stocke sous forme d'entier à 64 bits (les quatre chiffres les moins significatifs représentent les quatre chiffres situés après la virgule).
Quel est l'intérêt d'un tel type ? Les principaux avantages sont au nombre de deux :
- Le type Currency est plus précis lorsqu’il s'agit de traiter de grands nombres.
- Le type Currency est utilisé dans CurrencyField et dans d'autres composants. Il est compatible avec les types de base de données représentant des devises.
Le type Currency est un type de données à virgule fixe recommandé pour les calculs monétaires. Il est stocké en tant qu'entier scalaire de 64 bits avec les quatre chiffres les moins significatifs représentant implicitement quatre décimales. L'intervalle de valeurs de Currency est compris entre -922 337 203 685 477,5808 et 922 337 203 685 477,5807. Combinés avec d'autres types réels dans des affectations et des expressions, les valeurs de type Currency sont automatiquement graduées en divisant ou en multipliant par 10 000. Puisque les nombres stockés au format Currency sont des représentations exactes, les opérations sur les valeurs Currency ne sont pas sujettes à des erreurs d'arrondi.
TYPES BOOLÉENS
Les type de données booléen sont les plus simples et les plus utilisés qui soient. Les variables de ce type représentent une quantité logique, True (vrai) et False (faux) par exemple. Vous pouvez alors vous demander pourquoi le Tableau suivant dresse la liste des cinq types booléens différents. Ceci s'explique par des raisons de compatibilité. Dans certains cas, Windows exige une valeur booléenne dont la taille est d'un Word. Dans ces cas-là, d'autres types Booléen peuvent être utiles.Type Intervalle Octets nécessaires
Boolean Booléen à un octet (le plus répandu) 1
ByteBool Booléen à un octet 1
Bool Booléen de taille Word 2
WordBool Booléen de taille Word 2
LongBool Booléen de taille deux Words 4
A quoi sert un type Boolean ? Il s'applique à tout ce qui peut se décrire par OUI ou NON, VRAI ou FAUX, ARRET ou MARCHE. Une des choses les plus importantes à remarquer est que les variables de type Boolean peuvent accepter les opérateurs and, or et not. Ceci vous permet de les manipuler plus librement.
TYPES CARACTÈRE
Le type Char est sans doute bien connu de ceux d'entre vous qui avez programmé en C ou C+ +. Les types caractère ont été conçus pour ne stocker qu'un seul caractère. Un caractère a une taille d'un octet. Un rapide calcul vous montrera que 28(un octet) donne la possibilité de choisir parmi 256 caractères différents dans une variable de type Char. Si vous consultez la table ASCII, vous verrez qu'il existe des caractères ASCII allant de 0 à 255 (en informatique, on commence généralement à partir de zéro, et non à partir de un).
Une des nouveautés apportées par Delphi 3 est l'ajout (ou plutôt la redéfinition des types caractère). Le type Char est maintenant l'équivalent du type ANSIChar. ANSIChar est toujours un caractère ANSI 8 bits. Par ailleurs, un troisième type de caractère, WideChar, vous permet d'utiliser un type de caractère 16 bits. A quoi bon trois types différents ? Cette fois encore, il s'agit d'une question de compatibilité. Delphi 3 prend en charge le standard Unicode, comme le montre le Tableau suivant. Le type de données WideChar est le résultat de cette prise en charge. Un caractère Unicode utilise les 16 bits du type WideChar. Si vous placez une valeur normale ANSIChar dans une variable de type WideChar, l'octet de poids fort sera zéro et le caractère ANSI sera stocké dans l'octet de poids faible. Bien que Windows NT respecte parfaitement Unicode, ce n'est pas le cas de Windows 95. Si vous écrivez des applications destinées aux deux plates-formes, pensez à utiliser la fonction SizeOf() et ne partez pas du principe que les caractères ne font qu'un octet de long.
Type de caractère Taille en octets Contient
ANSIChar 1 1 caractère ANSI
WideChar 2 1 caractère Unicode
Char 1 Pour l’instant égal à ANSIChar.
Souvenez-vous qu'une variable de type char ne peut contenir qu'un seul caractère. Si vous regardez quel est le caractère ASCII numéro 66, vous verrez qu'il s'agit de la lettre "B". Vous pouvez utiliser le signe # pour indiquer à Delphi 3 que vous souhaitez utiliser la représentation décimale d'un caractère plutôt que le caractère lui-même (ex : choix := #66). Le type de données caractère est très utile et nous amène à passer au type suivant, le type de données String (chaîne de caractères).
TYPES CHAÎNE
Le type de données String est plus souvent utilisé que le type Char. Dans Delphi 1, le type String était une concaténation de 255 caractères au maximum. En d'autres termes, il s'agissait d'un tableau de caractères. Delphi 3 gère les chaînes différemment. Le tableau suivant rappelle les quatre types chaîne disponibles sous Delphi 3.
Type de chaîne Longueur Contient Terminaison nulle
ShortString 255 ANSIChar Non
AnsiString Jusqu’à environ 3 Go ANSIChar Oui
String 255 ou jusqu’à 3 Go ANSIChar Oui ou non
WideString Jusqu’à environ 1.5 Go WideChar Oui
Delphi prend en charge les chaînes longues. Cette prise en charge est activée par la directive de compilation $H+. Cette directive est présente par défaut. Lorsque cette directive est utilisée, une variable du type String peut contenir une chaîne de longueur quasi illimitée (environ 3 Go).
Là aussi, Borland a donné au développeur le choix entre rester compatible avec Delphi 1.0 et suivre le progrès. Le type String est par défaut (avec la directive $H+ activée) égale au type AnsiString. Le type AnsiString est une chaîne terminée par un null qui est allouée dynamiquement. Le grand avantage d'une variable de ce type est justement son allocation dynamique. A mesure que vous placez des chaînes plus longues dans cette variable, Delphi 3 réalloue la mémoire nécessaire à votre variable. Un autre avantage du type AnsiString est qu'il est déjà terminé par un null. Vous n'avez donc plus à utiliser les anciennes commandes de type StrPCopy() pour effectuer des conversions entre des chaînes de type Pascal (de longueur fixe) et des chaînes à terminaison nulle.
Quel est l'intérêt de ces terminaisons nulles ? Encore une question de compatibilité. Dans la plupart des appels aux routines systèmes, telles que l'API Win32, il est nécessaire de transmettre aux appels des chaînes à terminaison nulle. L'ancienne chaîne Pascal (désormais appelée ShortString) n'avait pas de terminaison nulle et devait être convertie avant d'être utilisée dans un appel API.
Delphi 3 assure la compatibilité avec Delphi 1.0 en proposant le type ShortString. Ce type est équivalent au type String de Delphi 1.0. Vous pouvez encore définir une chaîne de longueur spécifique, même si la directive $H+ est invoquée.
Voyez l'exemple qui suit :
{$H+} {Les chaînes longues sont maintenant activées} var
NouvelleString : String; { cette chaîne a une terminaison nulle et elle est allouée dynamiquement }
AncienneString : String[20]; { En définissant la longueur de cettechaîne, Delphi 3 fait automatiquement de AncienneString un type ShortString, dont la longueur maximale est de 20 caractères }
Les composants VCL de Delphi 3 utilisent désormais le type AnsiString pour toutes les propriétés et les paramètres d'événements. Cela simplifie vos interactions avec les VCL et les API, en les uniformisant. Ainsi, vos applications interagissent parfaitement avec d'autres.
TYPE VARIANT
Le type variant est un nouveau type de données dont la caractéristique première est de permettre la manipulation de tout type d’objet et spécialement des tableaux de taille variable et sans type.
Le coté pratique du type variant
Pour présenter l’intérêt de ce nouveau type, voici un exemple simple ou la valeur d’une variable sera considéré soit comme un entier, soit comme une chaîne de caractères, suivant son contexte :
procedure TForm1.Button1Click(Sender : TObject); var
v : variant; begin
v := 34;
:=v; end;
M Vous serez peut être tenté de n’utiliser que des variables de type variant, mais cette souplesse a un coût. Une variable de type variant consomme beaucoup plus de ressources qu’une variable de type standard.
Les problèmes liés au type variant
Le type variant procède à un transtypage automatique suivant le contexte dans lequel on se trouve.

Pour mieux comprendre ce processus, codons les appels suivants :
function somme(a, b : Variant) : Variant; begin
result := a + b ; end ;
procedure TForm1.Button1Click(Sender: TObject); begin
with listbox1 do begin
(somme('3', '4')); {34} (somme(3, 4)); {7} (somme('3', 4)); {7} (somme(3, '4')); {7} end; end;
Concrètement, un type variant est une structure mémoire de 16 octets, dont un champ représente le type de la variable référencée. Ce type peut être connu en utilisant la fonction VarType.
function VarType(const V : Variant) : Integer;
La fonction VarType renvoie le code du type du variant donné. La valeur renvoyée est construite à partir des constantes suivantes déclarées dans l'unité System.
constante Valeur Description
varEmpty $0000; Le variant est à Unassigned.
varNull $0001; Le variant est à Null.
varSmallint $0002; Entier signé sur 16 bits (type Smallint).
varInteger $0003; Entier signé sur 32 bits (type Integer).
varSingle $0004; Valeur à virgule flottante à simple précision (type Single).
varDouble $0005; Valeur à virgule flottante à double précision (type Double).
varCurrency $0006; Valeur à virgule flottante monétaire (type Currency).
varDate $0007; Valeur date et heure (type TdateTime).
varOleStr $0008; Référence à une chaîne Unicode allouée dynamiquement.
varDispatch $0009; Référence à un objet OLE Automation (pointeur d'interface IDispatch).
varError $000A; Code d'erreur du système d'exploitation.
varBoolean $000B; Booléen sur 16 bits (type WordBool).
varVariant $000C; Variant ( utilisé uniquement dans les tableaux de variants).
varUnknown $000D; Référence à un objet OLE inconnu (pointeur d'interface IUnknown).
varByte $0011; Entier non signé 8 bits (type Byte).
VarString $0100; Référence à une chaîne Pascal allouée dynamiquement (type AnsiString).
VarTypeMask $0FFF; Masque de bit pour l’extraction du code type.
VarArray $2000; Bit indiquant un tableau de variants.
Les bits de poids faible du code du type d'un variant (les bits définis par le masque de bit VarTypeMask) définissent le type du variant. Le bit varArray est initialisé si le variant est un tableau du type donné.
Le type d'un variant peut être modifié en utilisant la fonction standard VarAsType.
Voici notre fonction Somme, réécrite pour contrôler la validité des différentes opérations. On peut par exemple décider que dans le cas de deux paramètres de type différent, l’opération doit être réalisée avec le type du premier paramètre, sauf pour les opérations illégales comme l’ajout d’une date à une chaîne de caractères.
function somme(a, b : Variant) : variant; var
erreur : Boolean; begin
erreur := False;
if VarType(a) <> VarType(b) then begin
case VarType(a) of
VarBoolean, VarArray : erreur :=True;
VarString : erreur := VarType(b) in [VarDate, VarBoolean]; end; if erreur then raise Exception.Create ('Addition Impossible');
case VarType(a) of
VarString : result := a + String(b); else
result := a + b; end; end else
result := a + b;
end;
procedure TForm1.Button1Click(Sender: TObject); begin
with listbox1 do begin
(somme('3', '4')); {34} (somme(3, 4)); {7} (somme('3', 4)); {34}
(somme(3, '4')); {7} end; end;
COMPOSITION D’UNE APPLICATION DELPHI
A première vue, un programme simple semble n'être composé que d'un fichier de projet et d'une unité. En réalité, d'autres fichiers sont créées pour vous en coulisse à mesure que vous travaillez sur votre programme. Pourquoi se soucier des fichiers créés par Delphi ? Imaginez un peu votre tête si vous effaciez par mégarde un fichier indispensable à l'application critique sur laquelle vous vous échinez depuis des semaines Dans tous les cas de figure, il n'est jamais inutile de bien comprendre ce qui compose un projet Delphi et de savoir d'où viennent tous ces fichiers supplémentaires que vous n'avez pas créés, et ce qu'ils font.
Cette partie aborde plusieurs sujets importants, qui pour certains mériteraient qu'on leur consacre plus que quelques lignes. Mais nous ne ferons que tracer les grandes lignes d'un projet Delphi. Si vous avez besoin de plus de détails concernant un sujet particulier, vous pouvez vous reporter à l'aide en ligne ou aux manuels Delphi. Cette section se propose de vous donner une vue d'ensemble, facilement assimilable.
Une fois que vous saurez ce qui constitue un projet Delphi, vous serez à même de gérer des projets. L'EDI de Delphi comprend un Gestionnaire de projet qui vous assiste dans cette tâche. Cependant, la gestion de projet ne se limite pas à l'utilisation d'un menu. Si vous désirez un projet organisé et bien géré, vous devez penser à définir une structure de répertoires apte à stocker votre code, en utilisant des noms appropriés pour les fichiers, les fiches, les composants et les variables. La meilleure méthode consiste à vous organiser dès le début et à vous tenir à cette organisation jusqu'à l'achèvement du projet.
PROJETS
Un projet Delphi est constitué de fiches, d'unités, de paramètres d'options, de ressources, etc.
Toutes ces informations résident dans des fichiers. La plupart de ces fichiers sont créés par Delphi à mesure que vous construisez votre application. Les ressources telles que les bitmaps, les icônes, etc. se trouvent dans des fichiers provenant de sources tierces ou sont créées avec les nombreux outils et éditeurs de ressources dont vous disposez. De plus, des fichiers sont également créés par le compilateur. Jetons un bref coup d'œil sur ces fichiers.
Les fichiers suivants sont créés par Delphi à mesure que vous concevez votre application :
- Le fichier projet (.dpr). Stocke des informations concernant les fiches et les unités. Le code d'initialisation se trouve aussi là.
- Le fichier d'unités (.pas). Stocke du code. Certaines unités sont associées à des formes, d'autres se contentent de stocker des fonctions et des procédures.
- Fichier de fiches (.dfm). Ce fichier binaire est créé par Delphi pour stocker des informations concernant vos fiches. A chaque fiche correspond un fichier Unit (.pas). Ainsi, à est associé un fichier .
- Fichier d'options de projet (.dfo). Contient les paramètres d'option du projet.
- Fichiers d'informations de paquet (.drf). Ce sont des fichiers binaires utilisés par Delphi pour la gestion des paquets.
- Fichier de ressources (.res). Ce fichier binaire contient une icône utilisée par le projet. Ce fichier ne doit pas être créé ou modifié par l'utilisateur. Delphi met à jour ou recrée constamment ce fichier.
- Fichiers de sauvegarde (.~dp, .~df, .~pa). Ce sont des fichiers de sauvegarde pour les fichiers de projet, de fiches et d'unités, respectivement.
Les fichiers suivants sont créés par le compilateur.
- Fichier exécutable (.exe). C'est le fichier exécutable de votre application. Il s'agit d'un fichier exécutable indépendant qui n'a besoin de rien d'autre que luimême, sauf si vous utilisez des bibliothèques contenues dans des DLL, VBX ou autres.
- Fichier d'objet unité (.dcu). Ce fichier est la version compilée des fichiers d'unités (.pas) et sera lié dans le fichier d'exécutable final.
- Bibliothèque de liaison dynamique (ou DLL) (.dll). Ce fichier est créé si vous concevez vos propres DLL.
Enfin, voici d'autres fichiers Windows qui peuvent être utilisés avec Delphi.
- Fichiers d'aide (.hlp). Ce sont des fichiers d'aide Windows standard qui peuvent être utilisés avec votre application.
- Fichiers graphiques ou d'images (.wmf, .bmp, .ico). Ces fichiers sont fréquemment utilisés dans les applications Windows pour leur donner un aspect agréable et convivial.
Le fichier de projet (.dpr) lui-même contient en fait du code Pascal Objet et constitue la partie principale de votre application qui lance les choses lorsque vous exécutez votre application. Ce qui est amusant, c'est que vous pouvez construire une application Delphi sans jamais être obligé de voir ce fichier. Il est créé et modifié automatiquement par Delphi à mesure que votre application se construit. Le nom que vous donnez à votre fichier de projet sera aussi celui de votre fichier exécutable. Le code ci-après montre à quoi ressemblerait un fichier de projet si vous commenciez un projet sans changer les noms des fichiers ou des fiches.