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(Environment.GetCommandLineArgs[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.
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('\'));
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 GetCommandLineArgs pour obtenir un tableau de chaînes de caractères contenant chaque argument.
var arguments : ArrayofString ;
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;
On utilise la fonction 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 variablesFor Entrees in VarEnvironnement do
WriteLn(Entrees.Key.ToString+' = '+Entrees.Value.ToString);
Readln;
end;
On utilise la fonction GetFolderPath de la classe System.Environment avec l'énumération Environment.SpecialFolder.
procedure PrintSpecFolder;
type
TSpecialFolderDynArray = arrayof 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 de répertoires spéciaux
Folders:= TSpecialFolderDynArray(Enum.GetValues(typeof(Environment.SpecialFolder)));
For i:= 0 to Length(Folders)-1 dobegin
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édiaireFor i:= 0 to Length(Folders)-1 dobegin
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;
On utilise la fonction 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;
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=classprivate
FMutex : Mutex;
MutexOwned : Boolean;
publicConstructor Create(Nom : String);
// Application déjà lancée ?Function IsRunning : Boolean;
Destructor Destroy; override;
end;
{ TSingleInstanceApp}Constructor TSingleInstanceApp.Create(Nom : String);
begininherited Create;
FMutex:=Mutex.Create(False, Nom);
MutexOwned:=False;
end;
Function TSingleInstanceApp.IsRunning : Boolean;
begintry // 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é acquisBegin // Sécurise ce traitement ('thread-safe').
Monitor.Enter(Self);
Tryif 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
thenbegin
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 dobegin // On peut aussi faire un modulo pour n'obtenir que // des nombres entre 0 et 100 par exemplesif (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.
Anoter que la functions Random de l'unité Borland.Delphi.System mappe la classe System.Random.
On peut ouvrir des documents dont l'extension est connue du shell windows comme les .txt ou les .doc avec
la classe System.Diagnostics.Process
Exemple : Ouverture d'un fichier texte .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.
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é 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.
Ce qui suit est extrait d'un échange sur le forum dotnet.
C'est très shé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.
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 VLIIl 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 = interfacefunction 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éesbegin
MyDLL := ExtractFilePath(Application.ExeName) +'\mylib\Win32DLL.dll';
// Appel à travers l'interfaceifnot SysUtils.Supports(MyDLL, IWin32DLLInt, MyWin32DLL)
then Writeln('Ne peut charger Win32DLL.dll') // Erreurelse 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 = interfacefunction 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.ifnot SysUtils.Supports(MyDLL, IWin32DLLInt, MyWin32DLL)
then Writeln('Ne peut charger Win32DLL.dll') // Erreurelse NewInt := MyWin32DLL.ConvertCtoF(100); // Appel de la fonction de la DLL non-managée
Readln;
end.
Avec les expressions régulières.
On utilise le namespace 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 fonction Split de la classe String pour parser la chaine, puis on analyse les différentes sous-chaînes.
function TWinForm.CheckIpAddrNoRegex( ipAddress : String ) : Boolean ;
var ipPartList : arrayofString ;
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;
trybegin
ipPartNumber := Convert.ToByte( ipPartList[0] );
ipPartNumber := Convert.ToByte( ipPartList[1] );
ipPartNumber := Convert.ToByte( ipPartList[2] );
ipPartNumber := Convert.ToByte( ipPartList[3] );
end ;
Excepton E : Exception do
Resultat := False;
end ;
Result := Resultat ;
end ;