FAQ Delphi .NET
FAQ Delphi .NETConsultez toutes les FAQ
Nombre d'auteurs : 15, nombre de questions : 54, dernière mise à jour : 16 juin 2021
- Comment obtenir la version de mon application ?
- Comment obtenir la version du .NET Framework en cours ?
- Comment obtenir la version de l'OS en cours ?
- Comment obtenir le répertoire d'exécution de mon application ?
- Comment obtenir le répertoire courant ?
- Comment obtenir le répertoire système ?
- Comment obtenir le nom de l'utilisateur dont la session est en cours ?
- Comment obtenir la quantité de mémoire physique allouée à mon application ?
- Comment obtenir la ligne de commande de l'application ?
- Comment obtenir les variables d'environnement ?
- Comment obtenir les chemins des répertoires spéciaux comme "Mes Documents" ?
- Comment obtenir la liste des lecteurs logiques ?
- Comment ne lancer qu'une seule instance de mon application ?
- Comment générer des nombres aléatoires ?
- Comment ouvrir un fichier avec l'application associée à son extension ?
- Comment convertir un objet d'un type de base en un objet d'un autre type de base ?
- Comment puis-je appeler une fonction présente dans une DLL win32 ?
- Comment instancier un caractère nul ?
- Comment vérifier la validité d'une adresse IP ?
- Qu'est ce que le garbage collector ?
- Comment fonctionne le Garbage Collector ?
- 5.1. Process
(6)
- Comment lancer un processus ?
- Comment arrêter un processus ?
- Comment piloter un programme console externe?
- Comment créer un programme console PIPE en redirigeant la sortie standard ?
- Comment rediriger la sortie standard d'un processus vers un composant ?
- Comment lister les processus en cours d'exécution ?
Pour obtenir la version de l'application courante, on utilise la classe System.Diagnostics.FileVersionInfo
uses
System.Diagnostics,
SysUtils;
var
VersionApplication : FileVersionInfo ;
MaVersion : String
;
Begin
// Récupére le nom de l'application via la ligne de commande
// L'argument 0 de la ligne de commande est le nom de l'application en cours d'exécution
VersionApplication := FileVersionInfo.GetVersionInfo(Paramstr(0
));
// Construction du numéro de version à partir des différentes parties le constituant
// L'utilisation de la fonction Format nécessite l'ajout de l'unité SysUtils dans la clause uses.
with
VersionApplication do
MaVersion:=Format('%d.%d.%d.%d'
, [FileMajorPart,
FileMinorPart,
FileBuildPart,
FilePrivatePart]);
Writeln('MaVersion '
+MaVersion);
// Accés direct au numéro construit 1.2.3.4
Writeln('Information de version du fichier '
+VersionApplication.Fileversion);
Readln;
end
;
Pour obtenir la version d'un fichier (EXE, DLL, OCX, etc) quelconque, il suffit de passer le chemin du fichier à la fonction GetVersionInfo
Exemple :
ver := FileVersionInfo.GetVersionInfo(Environment.GetCommandLineArgs('C:\WINDOWS\notepad.exe'
);
Un numéro de version s'affiche généralement sous la forme « numéro majeur.numéro mineur.numéro de build.numéro de référence privé ». Un numéro de version de fichier 64 bits comporte les éléments suivants :
* Les 16 premiers bits correspondent au numéro de FileMajorPart.
* Les 16 bits suivants correspondent au numéro de FileMinorPart.
* Le troisième jeu de 16 bits correspond au numéro de FileBuildPart.
* Les 16 derniers bits correspondent au numéro de FilePrivatePart.
Lien : System.Diagnostics.FileVersionInfo
Lien : System.Environment
On utilise la propriété Version de la classe System.Environment.
// Version Framework
var
VerFram : Version ;
begin
VerFram := Environment.Version;
Console.WriteLine('Version Framework = {0}'
, VerFram);
end
;
Lien : System.Environment
Lien : System.Version
On utilise la propriété OSVersion de la classe System.Environment.
// Version du système d'exploitation
var
OSver : Version ;
begin
OSver := Environment.OSVersion;
Console.WriteLine('Version OS = {0}'
, OSver);
end
;
Lien : System.Environment
Lien : System.Version
On utilise la fonction GetCommandLineArgs de la classe System.Environment.
var
Exepath : String
;
Exedir : String
;
begin
// Chemin de l'exécutable
// Pour les WinForms, on peut aussi utiliser Application.ExecutablePath
Exepath := Environment.GetCommandLineArgs()[0
];
// Répertoire de l'exécutable
Exedir := exepath.Substring(0
, exepath.LastIndexOf('\'
));
Lien : System.Environment
On utilise la propriété CurrentDirectory de la classe System.Environment.
// Répertoire courant
Console.WriteLine('Le répertoire courant est : {0}'
, Environment.CurrentDirectory);
Lien : System.Environment
On utilise la propriété SystemDirectory de la classe System.Environment.
// Répertoire système
Console.WriteLine('Répertoire système = {0}'
, Environment.SystemDirectory);
Lien : System.Environment
On utilise la propriété UserName de la classe System.Environment.
Console.WriteLine('Nom utilisateur = {0}'
, Environment.UserName);
Lien : System.Environment
On utilise la propriété WorkingSet de la classe System.Environment.
Console.WriteLine('Mémoire allouée au process en cours = {0} octets'
,
Environment.WorkingSet.ToString);
Lien : System.Environment
On utilise la propriété CommandLine de la classe System.Environment pour avoir la ligne entière dans une chaîne de caractères.
Console.WriteLine('La ligne de commande est : {0}'
, Environment.CommandLine);
On utilise la méthode GetCommandLineArgs pour obtenir un tableau de chaînes de caractères contenant chaque argument.
var
arguments : Array
of
String
;
i , j : Integer
;
begin
// Arguments de ligne de commande
arguments := Environment.GetCommandLineArgs;
j:= Length(arguments) ;
for
i := 0
to
j-1
do
Console.WriteLine('Arguments[{0}] = {1}'
, [i,arguments[i]]);
end
;
Lien : System.Environment
On utilise la méthode GetEnvironmentVariables de la classe System.Environment.
var
VarEnvironnement : IDictionary; // Ajout System.Collections
Entrees : DictionaryEntry;
begin
VarEnvironnement:= Environment.GetEnvironmentVariables;
// Pour afficher une variable dont on connait le nom
WriteLn('USERNAME = '
+ VarEnvironnement['USERNAME'
].ToString);
// Pour lister toutes les variables
For
Entrees in
VarEnvironnement do
WriteLn(Entrees.Key.ToString+' = '
+Entrees.Value.ToString);
Readln;
end
;
Lien : System.Environment
Lien : System.Collection.IDictionnary
Lien : System.Collection.IEnumerator
On utilise la méthode GetFolderPath de la classe System.Environment avec l'énumération Environment.SpecialFolder.
procedure
PrintSpecFolder;
type
TSpecialFolderDynArray = array
of
Environment.SpecialFolder;
var
Folders : TSpecialFolderDynArray;
i : Integer
;
unFolder : Environment.SpecialFolder;
begin
// Répertoire spéciaux
Console.WriteLine('Répertoire spéciaux'
);
// Récupére un tableau contenant les noms des répertoires spéciaux
Folders:= TSpecialFolderDynArray(Enum.GetValues(typeof(Environment.SpecialFolder)));
For
i:= 0
to
Length(Folders)-1
do
begin
Console.WriteLine(Folders[i]);
// Affiche le répertoire associé au nom de répertoire courant
Console.WriteLine(Environment.GetFolderPath(Folders[i]));
end
;
//----------------------------------------------------------------------------
// exemples de manipulation sur les énumérations .NET
//
// Résulat identique mais en utilisant une variable intermédiaire
For
i:= 0
to
Length(Folders)-1
do
begin
unFolder:=Folders[i];
Console.WriteLine('{0} = {1}'
, [unFolder,Environment.GetFolderPath(unFolder)]);
end
;
// Affiche directement le répertoire associé à un nom de répertoires spécial
Console.WriteLine(Environment.SpecialFolder.MyMusic);
// Recherche un élément par un nom de chaîne
UnFolder:=System.Enum.Parse(TypeOf(Environment.SpecialFolder),'MyMusic'
) as
Environment.SpecialFolder;
// Boxing nécessaire avec l'affichage par Writeln
WriteLn('Le nom est = '
+Tobject(unFolder).ToString);
// Pas de boxing ni de transtypage avec l'affichage par Console.Writeline
Console.WriteLine(System.Enum.Parse(TypeOf(Environment.SpecialFolder),'MyMusic'
));
//----------------------------------------------------------------------------
Readln;
end
;
Lien : System.Environment
On utilise la méthode GetLogicalDrives de la classe System.Environment.
procedure
PrintLogicalDrives ;
// Uses : ajout de Borland.Vcl.Types pour TStringDynArray;
var
Drives : TStringDynArray;
i : Integer
;
begin
// Lecteurs logiques
Console.WriteLine('Lecteurs logiques'
);
drives := Environment.GetLogicalDrives;
for
i := 0
to
Length(drives)-1
do
Console.WriteLine(drives[i]);
end
;
Lien : System.Environment
Il arrive souvent de souhaiter interdire à une application d'avoir plusieurs instances en mémoire.
Voici une classe qui lors du démarrage de l'application, s'assure qu'elle n'est pas déjà en cours d'exécution.
Elle utilise un objet Mutex nommé, donc potentiellement visible par tous les autres processus.
uses
SysUtils,
System.Threading;
type
TSingleInstanceApp=class
private
FMutex : Mutex;
MutexOwned : Boolean
;
public
Constructor
Create(Nom : String
);
// Application déjà lancée ?
Function
IsRunning : Boolean
;
Destructor
Destroy; override
;
end
;
{ TSingleInstanceApp}
Constructor
TSingleInstanceApp.Create(Nom : String
);
begin
inherited
Create;
FMutex:=Mutex.Create(False
, Nom);
MutexOwned:=False
;
end
;
Function
TSingleInstanceApp.IsRunning : Boolean
;
begin
try
// Acquisition du mutex.
// Si MutexOwned vaut True, l'application acquiert le mutex car il est "libre"
// sinon le mutex a déjà été acquis lors du lancement d'une instance précédente.
MutexOwned:=FMutex.WaitOne(0
, true
);
finally
result:=Not
MutexOwned;
end
;
end
;
Destructor
TSingleInstanceApp.Destroy;
// Libération du mutex si il a été acquis
Begin
// Sécurise ce traitement ('thread-safe').
Monitor.Enter(Self
);
Try
if
MutexOwned
then
FMutex.ReleaseMutex;
inherited
Destroy;
Finally
Monitor.Exit(Self
);
end
;
end
;
Pour utiliser notre classe, il suffit de procéder ainsi dans le Main de notre application.
var
MonApplication : TSingleInstanceApp;
begin
MonApplication:= TSingleInstanceApp.Create('{123456789 - ABCD - EFEG - XXXX}'
);
if
MonApplication.IsRunning
then
begin
Writeln(ParamStr(0
)+' est déjà en cours d''exécution, une seule instance est autorisée.'
);
MonApplication.Free;
Halt(1
);
end
;
Writeln('Pressez une touche pour continuer'
);
Readln;
MonApplication.Free;
end
.
Important :
Si une application lambda en cours d'exécution crée un mutex ayant le même nom que celui de notre application, cette dernière ne pourra plus se lancer.
Elle se comportera comme si une autre instance de l'application était déjà en cours.
Il existe une technique pour l'éviter mais cela sort de notre sujet. Veuillez donc choisir un nom assez compliqué pour votre mutex.
La classe System.Random nous permet de générer des nombres aléatoires.
Il s'agit en fait de nombres pseudo-aléatoires, car la séquence générée dépend de l'initialisation.
program
random;
{$APPTYPE CONSOLE}
uses
SysUtils,
Types;
var
rnd : System.Random;
d : double
;
i,j : Integer
;
rndNumbers : TByteDynArray;
begin
// Pour générer toujours la même séquence,
// on passe la même valeur au constructeur.
// Random rnd = new Random(100);
// Initialisation par défaut basée sur le temps.
// La séquence est différente à chaque fois.
rnd:=System.Random.Create;
// Génération de 15 nombres aléatoires compris entre 0 et 255
rndNumbers:=new(TByteDynArray,15
);
rnd.NextBytes(rndNumbers);
for
i:=0
to
14
do
begin
// On peut aussi faire un modulo pour n'obtenir que
// des nombres entre 0 et 100 par exemples
if
(rndNumbers[i] > 100
)
then
Writeln(Format('%5d est supérieure à 100'
,[rndNumbers[i]]))
else
Writeln(Format('%3d est inférieure à 100'
,[rndNumbers[i]]));
end
;
Writeln;
// Pour générer des nombres aléatoire de type Integer
i:=rnd.Next;
Writeln(i.ToString+#13#10
);
j:=rnd.Next(500
, 1000
); // j sera compris entre 500 et 1000
Writeln(j.ToString+#13#10
);
// Pour générer des nombre aléatoire de type Double
// d sera compris entre 0,0 et 1,0.
// Il suffit de combiner cet appel à celui de Next()
// pour avoir des doubles supérieurs à 1,0
d:=rnd.NextDouble;
Writeln(d.ToString);
Readln;
end
.
A noter que la function Random de l'unité Borland.Delphi.System mappe la classe System.Random.
Lien : System.Random
On peut ouvrir des documents dont l'extension est connue du shell Windows comme les .txt ou les .doc en utilisant la classe System.Diagnostics.Process
Exemple :
Ouverture d'un fichier texte ayant l'extension '.txt'.
{$APPTYPE CONSOLE}
uses
SysUtils,
System.Diagnostics;
var
prc : System.Diagnostics.Process;
begin
// Instance de la classe Process
prc := System.Diagnostics.Process.Create;
// Nom du fichier dont l'extension est connue du shell à ouvrir
prc.StartInfo.FileName:='monfichier.txt'
;
// Démarrage du processus.
// Notepad, si il est associé aux fichiers .txt,
// sera lancé et ouvrira le fichier monfichier.txt
prc.Start ;
// On libère les ressources dont on a plus besoin.
prc.Close; // Attention Close ne met pas fin au processus.
Lien : System.Diagnostics.Process
La classe System.Convert permet de convertir des objets de types de base. Elle propose de nombreuses méthodes pour effectuer toutes sortes de conversions possibles entre les types de bases.
Il existe d'autres méthodes pour effectuer ce type de conversion, mais l'avantage de la classe System.Convert est qu'elle est indépendante du langage utilisé.
Extrait du SDK 1.1 FR :
"La classe System.Convert fournit un jeu complet de méthodes pour les conversions prises en charge. Elle constitue une façon, indépendante du langage, d'effectuer les conversions et est disponible pour tous les langages qui ciblent le Common Language Runtime. Alors que divers langages peuvent recourir à différentes techniques pour la conversion des types de données, la classe Convert assure que toutes les conversions communes sont disponibles dans un format générique."
Voici quelques exemples :
uses
SysUtils;
var
i : Integer
;
s : String
;
begin
// Conversion d'un entier vers une chaîne de caractères
i:=10
;
s:=Convert.ToString(i);
//Autres possibilités
// Appel la méthode TObject.ToString
s:=i.ToString;
// Portable Win32 /.NET/, appel en interne de la méthode Convert.ToString
S:=IntToStr(i);
// Conversion d'une chaine vers un entier
i:= Convert.ToInt32(s);
//Autre possibilité
// Portable Win32 /.NET, appel en interne de la méthode Borland.Vcl.Units.SysUtils.StrToInt
i:= StrToInt(s);
// Notez que si la conversion ne peut se faire, une exception est levée.
// Ce serait le cas si S='Chaîne NonNumérique', cf. System.FormatException
Il est aussi possible d'utiliser la méthode Parse de chaque type de base. Elle permet entre autre de gérer un format propre à une culture spécifiée au travers d'une interface IFormatProvider.
s := '35000'
;
i := System.Int32.Parse(s);
Voir Aussi
La classe System.BitConverter : Convertit les types de données de base en tableau d'octets et un tableau d'octets en types de données de base.
l'unité Borland.Vcl.Convert : La classe TConvert basée autour d'un Double permet de nombreuses convertions.
Borland.Vcl.ConvUtils : Vous pouvez utiliser la fonction Convert pour exécuter des conversions simples ou complexes. Cette fonction emploie une syntaxe simple et une syntaxe moins simple réservée aux conversions entre types de mesure complexes.
Lien : System.Convert
Virtual Library Interfaces ou comment ajouter l'appel dynamique à P/Invoke
Présenté par Olivier Dahan lors des Borland Devtracks (Mars 2005).
Voir l'aide en ligne de Delphi 2005 : ms-help://borland.bds3/bds3dnetguide/html/VirtualLibraryInterfaces.htm
- Simplifie l'importation de DLL Win32 sous .Net
- Ajoute la flexibilité indispensable pour le « Late Binding » absent de P/Invoke
Problème avec P/Invoke : peu pratique, verbeux, le nom de la DLL ou son chemin ne peut être résolu au runtime si la DLL n'est pas trouvée cela provoque une erreur d'exécution.
Déclaration originale dans la DLL Win32 :
Function
ConvertCtoF(CentValue: Integer
): Integer
; stdcall
;
Function
ConvertFtoC(FahrValue: Integer
): Integer
; stdcall
;
Déclaration typique P/Invoke sous .Net utilisant les attributs personnalisés :
[DllImport('Win32DLL.dll'
, CharSet = CharSet.Auto, EntryPoint = 'ConvertCtoF'
)]
Function
ConvertCtoF; external
;
[DllImport('Win32DLL.dll'
, CharSet = CharSet.Auto, EntryPoint = 'ConvertFtoC'
)]
Function
ConvertFtoC; external
;
Un exemple VLI
Il est nécessaire d'effectuer les trois opérations suivantes :
1 - Ajouter Borland.Vcl.Win32 à la clause uses.
Uses
Borland.Vcl.Win32;
2 - Déclarer une interface contenant les fonctions exportées et non managées que vous souhaitez appeler.
type
// Il n'est pas nécessaire d'utiliser l'attribut DllImport sur ce prototype.
IWin32DLLInt = interface
function
ConvertCtoF(CentValue: Integer
): Integer
;
function
ConvertFtoC(FahrValue: Integer
): Integer
;
end
;
3 - Appeler la fonction Supports pour vérifier que la DLL non managée existe et que les fonctions dans la déclaration d'interface sont vraiment exportées.
var
MyDLL : String
; // Nom complet de la DLL
MyWin32DLL : IWin32DLLInt; // Interface contenant les fonctions exportées et non managées
begin
MyDLL := ExtractFilePath(Application.ExeName) +'\mylib\Win32DLL.dll'
;
// Appel à travers l'interface
if
not
SysUtils.Supports(MyDLL, IWin32DLLInt, MyWin32DLL)
then
Writeln('Ne peut charger Win32DLL.dll'
) // Erreur
else
NewInt := MyWin32DLL.ConvertCtoF(100
); // Appel de la fonction de la DLL non-managée
program
FaqDLL;
{$APPTYPE CONSOLE}
uses
Borland.Vcl.Win32,
SysUtils;
type
// Il n'est pas nécessaire d'utiliser l'attribut DllImport sur ce prototype.
IWin32DLLInt = interface
function
ConvertCtoF(CentValue: Integer
): Integer
;
function
ConvertFtoC(FahrValue: Integer
): Integer
;
end
;
var
MyDLL : String
; // Nom complet de la DLL
MyWin32DLL : IWin32DLLInt; // Interface contenant les fonctions exportées et non managées
NewInt : Integer
;
begin
MyDLL := ExtractFilePath(Environment.GetCommandLineArgs[0
]) +'\mylib\Win32DLL.dll'
;
// Si la fonction Supports renvoie True, la DLL prend en charge toutes les fonctions nommées dans
// la déclaration de l'interface, et vous savez donc que leur appel est sans danger.
if
not
SysUtils.Supports(MyDLL, IWin32DLLInt, MyWin32DLL)
then
Writeln('Ne peut charger Win32DLL.dll'
) // Erreur
else
NewInt := MyWin32DLL.ConvertCtoF(100
); // Appel de la fonction de la DLL non-managée
Readln;
end
.
var
monCaractere : char
;
monCaractere := #0
;
C'est aussi simple que cela
Pour vérifier la validité d'une adresse IP on utilise les expressions régulières définies dans l'espace de nom System.Text.RegularExpressions.
uses
System.Text.RegularExpressions ;
function
TWinForm.CheckIpAddr( ipAddress : String
) : Boolean
;
var
re : String
;
begin
re := '^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$'
;
result := Regex.IsMatch( ipAddress,re);
end
;
Version sans expression régulière.
On se sert de la méthode Split de la classe String pour parser la chaîne, puis on analyse les différentes sous-chaînes.
function
CheckIpAddrNoRegex( ipAddress : String
) : Boolean
;
var
ipPartList : array
of
String
;
ipPartNumber : byte
;
Resultat : Boolean
;
begin
Resultat := True
;
if
(ipAddress = nil
) OR
(ipAddress = ''
)
then
Resultat := False
;
ipPartList:=ipAddress.Split( ['.'
] );
if
Length(ipPartList) <> 4
then
Resultat := False
;
try
begin
ipPartNumber := Convert.ToByte(ipPartList[0
] );
ipPartNumber := Convert.ToByte(ipPartList[1
] );
ipPartNumber := Convert.ToByte(ipPartList[2
] );
ipPartNumber := Convert.ToByte(ipPartList[3
] );
end
;
Except
on
E : Exception do
Resultat:=False
;
end
;
Result:=Resultat;
end
;
Lien : Utilisation des expressions régulières en .Net
Lien : Regex
Consulter le tutoriel indiqué dans la section Lien.
Lien : Destructeurs d'objet et Finaliseurs sous .NET, mise en oeuvre avec Delphi 2005.
Extrait du SDK .NET 1.1 :
"
Le garbage collector (également appelé ramasse-miettes) du .NET Framework manage l'allocation et la libération de mémoire dans votre application. Chaque fois que vous utilisez l'opérateur Create pour créer un objet, le runtime alloue de la mémoire pour l'objet à partir du tas managé. Tant que de l'espace d'adressage est disponible dans le tas managé, le runtime continue à allouer de l'espace pour les nouveaux objets.
Toutefois, la mémoire n'est pas infinie. Le garbage collector doit finir par effectuer un garbage collection afin de libérer de la mémoire. Le moteur d'optimisation du garbage collector détermine le meilleur moment pour effectuer un garbage collection en fonction des allocations en cours. Lorsque le garbage collector effectue un garbage collection, il recherche les objets figurant dans le tas managé qui ne sont plus utilisés par l'application et effectue les opérations nécessaires pour récupérer leur mémoire.
Ce qui suit est extrait d'un échange sur le forum dotnet.
C'est très schématique mais cela résume bien comment le .NET Framework s'y prend pour gérer la mémoire.
Le .NET Framework : Salut OS, j'ai des trucs à lancer, j'peux te prendre de la ram ?
L'OS : Hé Salut ! Je t'en pris, sers-toi !
Le .NET Framework : Sympa mec. J't'en prend 50Mo maintenant, j'ai besoin que de 15 Mo,
mais comme ça je te dérange pas si j'ai besoin de plus.
...
Le .NET Framework : Hé l'OS, t'es short niveau mémoire ?
L'OS : Non non, tout va bien.
Le .NET Framework : Bon, alors je garde mes 50 Mo encore un peu.
L'OS : Oki.
...
SQL Server : Bonjour M. l'OS, j'ai un gros besoin de mémoire...au moins 200 Mo.
L'OS : Ben sers-toi donc.
SQL Server : Ouais mais y a plus que 180Mo !
L'OS : Ah OK, attend 2 millisecondes stp...
L'OS : Hé Framework, tu peux me rendre un peu de RAM ?
Le .NET Framework : No problemo, j'te fais ça tout de suite...
Le .NET Framework : Garbage Collector, soit un amour et va rendre de la mémoire à l'OS.
Garbage Collector : J'y cours patron.
C'est clair non ?
Lien : Programmation d'un garbage collection
Lien : Destructeurs d'objet et Finaliseurs sous .NET, mise en oeuvre avec Delphi 2005.