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 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 lancer un processus depuis notre application, on utilise la classe System.Diagnostics.Process.
Dans cette solution on ne mémorise pas une instance de la classe Process mais uniquement l'ID du processus exécuté.
Function
StartProcess(FName,Arguments :String
):Integer
;
// Nécessite l'ajout de l'unité System.Diagnostics dans la clause uses.
var
MonProcessus : System.Diagnostics.Process ;
begin
If
FName<>''
then
begin
// Instance de la classe Process
MonProcessus := System.Diagnostics.Process.Create;
With
MonProcessus do
begin
// Nom de l'executable à lancer
StartInfo.FileName:=FName;
// Arguments à passer à l'exécutable à lancer
StartInfo.Arguments:=Arguments;
// Démarrage du processus
Start;
// Récupére l'ID unique du process
Result:=ID;
// On libère les ressources dont on n'a plus besoin.
Close; // Attention Close ne met pas fin au processus.
end
;
end
else
Result:= -1
;
end
;
Exemple d'appel :
var
ProcessID : Integer
;
begin
ProcessID:=StartProcess('Notepad.exe'
,'C:\Windows\System.ini'
);
...
Si vous souhaitez être averti de l'arrêt d'un de vos processus, vous devez renseigner le délégué Process.Exited et positionner la propriété Process.EnableRaisingEvents à True.
Dans ce cas le code précédent devient :
...
With
MonProcessus do
begin
// Nom de l'executable à lancer
StartInfo.FileName:=FName;
// Arguments à passer à l'exécutable à lancer
StartInfo.Arguments:=Arguments;
// La propriété EnableRaisingEvents indique si le composant doit être averti en cas d'arrêt
// d'un processus par le système d'exploitation.
// Elle est utilisée lors du traitement asynchrone pour avertir votre application qu'un processus
// n'est plus exécuté.
EnableRaisingEvents:=True
;
// Renseigne le délégué de fin de process
Include(Exited ,@FinProcess);
// Démarrage du processus
...
La procédure référencée étant :
procedure
FinProcess(Sender: System.Object
; AArgs: System.EventArgs);
// Procédure appelée lors de la fin d'exécution d'un programme externe
begin
Writeln('Code de fin du processus : '
+(Sender as
System.Diagnostics.Process).ExitCode.ToString);
Writeln('Appuyez sur une touche pour terminer.'
);
end
;
Lien : System.Diagnostics.Process
Lien : Exécution synchrone d'un programme console dans une application C#
Lien : Comment arrêter un processus ?
Pour arrêter un processus, il faut soit disposer d'un objet System.Diagnostics.Process qui représente le processus soit un ID de processus qui permet de récupérer une instance de la classe Process.
La méthode utilisée pour arrêter un processus est différente selon qu'il s'agit d'une application console ou fenêtrée.
Pour les applications fenêtrées (WinForm / VCL) il est préférable d'utiliser la méthode CloseMainWindow afin que l'application reçoive le message d'arrêt et se termine correctement. Si l'appel échoue, on peut alors forcer l'arrêt avec la méthode Kill.
Ce dernier point n'est pas mis en oeuvre dans cette solution.
Procedure
KillProcess(ProcessID : Integer
);
// Nécessite l'ajout de l'unité de System.Diagnostics dans la clause uses.
var
MonProcessus : System.Diagnostics.Process ;
begin
// Voir "Comment lancer un processus ?"
Readln;
try
// Récupére une instance d'un Processus à partir d'un ID
MonProcessus:=System.Diagnostics.Process.GetProcessById(ProcessID);
// Obtient le Handle de la fenêtre principale
// Pour terminer le processus
if
MonProcessus.MainWindowHandle<>0
// Pour un programme fenêtré
then
MonProcessus.CloseMainWindow
// Pour un programme console, c'est la seule possibilité.
else
MonProcessus.Kill;
// On libère les ressources dont on n'a plus besoin.
MonProcessus.Close;
except
on
System.ArgumentException do
Writeln('Erreur le processus '
+IntToStr(ProcessID)+' n''existe pas !'
);
end
;
end
;
Lien : System.Diagnostics.Process
Lien : Comment lancer un processus
Il est possible de réorganiser les entrées/sorties standards entre 2 applications. L'application principale gérant les entrées/sorties d'une application secondaire externe.
L'exemple suivant est suffisament documenté pour en comprendre le fonctionnement.
Le principe :
on redirige l'entrée et la sortie standard avec ceux du programme externe en connectant la sortie standard ( CON /écran) de l'application principale sur l'entrée du programme externe et l'entrée standard ( CON /Clavier ) de l'application principale sur la sortie du programme externe.
On peut ainsi, de l'application courante, envoyer des informations vers le programme externe et en recevoir à partir de ce même programme externe.
program
Batch;
{$APPTYPE CONSOLE}
// Pilote un prg externe
uses
System.Diagnostics,
System.IO; //StreamWriter
var
MyProcess : System.Diagnostics.Process ;
ProcessInformation : System.Diagnostics.ProcessStartInfo;
Chaine: String
;
begin
ProcessInformation:=System.Diagnostics.ProcessStartInfo.Create;
With
ProcessInformation do
begin
// On désactive le shell
// permet de rediriger les flux d'entrée, de sortie et d'erreur.
// Dans ce cas 'WorkingDirectory' n'est pas utilisé
UseShellExecute := False
;
// On redirige la sortie standard du programme externe
// Permet d'écrire à un emplacement autre que le flux de sortie standard (généralement l'écran du moniteur).
// Utilisé pour écrire des données dans un fichier, par exemple.
RedirectStandardOutput := True
;
// On redirige l'entrée standard du programme externe
//permet de lire à partir d'une source autre que le flux d'entrée standard (généralement le clavier).
//Utilisé pour lire des données dans un fichier, par exemple.
RedirectStandardInput := True
;
// si UseShellExecute := False : On définit le programme à exécuter
FileName := 'C:\Windows\System32\Debug.exe'
;
end
;
MyProcess := System.Diagnostics.Process.Create;
With
MyProcess do
begin
StartInfo:=ProcessInformation;
// Exécute le programme externe
Start;
(*
Prg principale prg externe
-------- ---------
| |IN IN | |
| |<--\ /--> | |
| | \ / | |
| | \/ | |
| |OUT /\ OUT | |
| |--> / \ <-- | |
-------- ---------
Dans le prg principale :
on écrit vers OUT
on lit à partir de IN
*)
//Redirige l'entrée et la sortie standard avec ceux du prg externe
// Connecte la sortie standard ( CON /écran) sur l'entrée du programme externe
// On peut donc, via Writeline, entrer une saisie destinée au programme externe
System.Console.SetOut(MyProcess.StandardInput);
// Connecte l'entrée standard ( CON /Clavier ) sur la sortie du programme externe
// On peut donc, via Readline, lire un résultat provenant du programme externe
System.Console.SetIn(MyProcess.StandardOutput);
Close;
end
;
// Envoie 3 commande au prg externe, ici DEBUG,
// ? : demande d'afficher l'aide
// D : demande un dump (128 octets)
// Q : Quitte et termine l'application externe
System.Console.Out
.Writeline('?'
+#10#13
+'D'
+#10#13
+'Q'
);
// Lit le résultat affiché par DEBUG
// Lecture en une seule fois
//Chaine:=System.Console.In.ReadToEnd;
// Lecture ligne par ligne
Chaine:=''
; // Nécessaire sinon la variable 'Chaîne' n'est pas instancié !
While
Assigned(Chaine) do
begin
Chaine:=System.Console.In
.ReadLine;
// Ecrit sur la sortie standard TextOutput
// Si on remplace par Console.WriteLine(Chaine) le comportement est différent !
WriteLn(chaine); // Est égale à TextOutput.Writeln. Cf IL-Dasm
end
;
//Restaure les valeurs par défaut
//Pas nécessaire de mémoriser les valeurs, on récrée un objet.
// Sous Delphi c'est redondant cf. TextOutput...
System.Console.SetOut(StreamWriter.Create(System.Console.OpenStandardOutput));
System.Console.SetIn(StreamReader.Create(System.Console.OpenStandardInput));
readln;
end
.
Lien : System.Diagnostics.Process
Lien : Comment créer un programme console PIPE en redirigeant la sortie standard ?
Pour manipuler les entrées/sorties standard de l'application courante, il est préférable de ne plus utiliser les fonctions assign, reset, etc. (voir la FAQ Delphi Win32), bien qu'elles soient présentes à des fins de compatibilité.
On peut utiliser les classes TextInput,TextOutput et TextErrOutput.
Ces classes permettent de manipuler aisément les handles des entrées/sorties standard.
Elles sont de type Text, les instances sont construites par défaut via un constructeur de classe et sont référencées dans l'unité System.pas.
Ces instances, étant construites avant tout autres objets de l'application, référencent toujours les entrées-sorties de la console d'origine.
Je différencie donc ici la manipulation des entrées/sorties standard de l'application courante de celle d'une application externe exécutée à partir de l'application courante.
La solution proposée ici se teste dans une console avec :
type upper.dpr|upper.exe
program
upper;
{$APPTYPE CONSOLE}
// Redirection de type 'PIPE', comportement similaire au programme FIND.EXE ou SORT.EXE
// Renvoie une chaîne reçue en entrée (input) en majuscule sur la sortie (output)
Var
Chaine: String
;
Begin
{ TextInput et TextOutPut sont construit autour de la classe :
Text = class
Mode: Word;
Flags: Word;
Factory: ITextDeviceFactory;
Reader: System.IO.TextReader;
Writer: System.IO.TextWriter;
Filename: string;
...
}
While
not
(Eof) Do
Begin
// TextInput { Entrée standard }
// TextInput.Intput=Text
// TextInput.Input.Reader := System.Console.In;
Readln(TextInput.Input,Chaine); // Lit sur l'entrée standard
// TextOutput { Sortie standard}
// TextInput.Output=Text
// TextInput.Output.Writer := System.Console.Out;
Writeln(TextOutput.OutPut,chaine.ToUpper); // Ecrit sur la sortie standard
// Erreur standard :
// TextErrOutput.ErrOutput := Text
// TextErrOutput.ErrOutput.Writer := System.Console.Error;
end
;
end
.
La version simplifiée :
program
upper2;
{$APPTYPE CONSOLE}
// Redirection de type 'PIPE', comportement similaire au programme FIND.EXE ou SORT.EXE
// Renvoie une chaîne reçue en entrée (input) en majuscule sur la sortie (output)
Var
Chaine: String
;
Begin
While
not
(Eof) Do
Begin
Readln(Chaine); // Lit sur l'entrée standard
Writeln(chaine.ToUpper); // Ecrit sur la sortie standard
end
;
end
.
Lien : System.Diagnostics.Process
Il est possible de rediriger la sortie standard d'un processus et de l'afficher dans un TextBox multiligne par exemple.
procedure
TWinForm.RedirectStdOutput;
var
proc : System.Diagnostics.Process ;
output : String
;
begin
proc:=System.Diagnostics.Process.Create;
// On désactive le shell
proc.StartInfo.UseShellExecute:=false
;
// On redirige la sortie standard
proc.StartInfo.RedirectStandardOutput:=true
;
// On définit la commande
proc.StartInfo.FileName:='EditeurFAQ.exe'
;
// Démarrage de la commande
proc.Start;
// Lecture de la sortie de la commande
output:=proc.StandardOutput.ReadToEnd;
Console.WriteLine(output);
// Attente de la fin de la commande
proc.WaitForExit;
// Libération des ressources
proc.Close;
end
;
Pour lister les processus en cours on utilise la méthode GetProcesses de la classe System.Diagnostics.Process.
uses
SysUtils,
System.Diagnostics;
var
AllProcess : array
of
System.Diagnostics.Process ;
prc : System.Diagnostics.Process;
begin
// Pour tous les processus en cours sur l'ordinateur local
AllProcess:= Process.GetProcesses ;
For
prc in
AllProcess do
Writeln(Prc.ProcessName);
Writeln;
// Pour tous les processus notepad en cours sur l'ordinateur local
AllProcess := Process.GetProcessesByName('svchost'
) ;
If
length(AllProcess)>0
then
For
prc in
AllProcess do
With
prc do
Writeln(ProcessName+'. Mémoire allouée:'
+PrivateMemorySize.ToString);
end
.
Lien : System.Diagnostics.Process