Je souhaite exécuter un programme de ligne de commande externe à partir de mon application Mono/.NET. Par exemple, je voudrais lancer mencoder . C'est possible:
Lorsque vous créez votre objet Process
, définissez StartInfo
de manière appropriée:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "program.exe",
Arguments = "command line arguments to your executable",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
puis démarrez le processus et lisez-le:
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
// do something with line
}
Vous pouvez utiliser int.Parse()
ou int.TryParse()
pour convertir les chaînes en valeurs numériques. Vous devrez peut-être commencer par manipuler des chaînes si les chaînes que vous lisez contiennent des caractères numériques non valides.
Vous pouvez traiter votre sortie de manière synchrone ou de manière asynchrone.
1: exemple synchrone
static void runCommand()
{
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c DIR"; // Note the /c command (*)
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start();
//* Read the output (or the error)
string output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
string err = process.StandardError.ReadToEnd();
Console.WriteLine(err);
process.WaitForExit();
}
Remarque qu'il est préférable de traiter à la fois sortie et erreurs: elles doivent être traitées séparément.
(*) Pour certaines commandes (ici StartInfo.Arguments
), vous devez ajouter le /c
directive , sinon le processus se fige dans la WaitForExit()
.
2: exemple asynchrone
static void runCommand()
{
//* Create your Process
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c DIR";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
//* Start process and handlers
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
}
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
//* Do your stuff with the output (write to console/log/StringBuilder)
Console.WriteLine(outLine.Data);
}
Si vous n'avez pas besoin d'effectuer des opérations compliquées avec la sortie, vous pouvez contourner la méthode OutputHandler, en ajoutant simplement les gestionnaires directement en ligne:
//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
Très bien, pour ceux qui veulent lire les erreurs et les sorties, mais qui obtiennent des blocages avec l'une des solutions fournies dans d'autres réponses (comme moi), voici une solution que j'ai construite après avoir lu l'explication MSDN de la propriété StandardOutput.
La réponse est basée sur le code de T30:
static void runCommand()
{
//* Create your Process
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c DIR";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
//* Set ONLY ONE handler here.
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
//* Start process
process.Start();
//* Read one element asynchronously
process.BeginErrorReadLine();
//* Read the other one synchronously
string output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
process.WaitForExit();
}
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
//* Do your stuff with the output (write to console/log/StringBuilder)
Console.WriteLine(outLine.Data);
}
La méthode standard .NET consiste à lire le flux Process ' StandardOutput . Il existe un exemple dans les documents MSDN liés. De même, vous pouvez lire depuis StandardError et écrire dans StandardInput .
vous pouvez utiliser la mémoire partagée pour que les 2 processus puissent communiquer, consultez MemoryMappedFile
vous créerez principalement un fichier mappé en mémoire mmf
dans le processus parent à l'aide de l'instruction "using", puis créerez le deuxième processus jusqu'à ce qu'il se termine et le laissera écrire le résultat dans mmf
à l'aide de BinaryWriter
, puis lira le résultat à partir de mmf
en utilisant le processus parent , vous pouvez également passer le nom mmf
en utilisant des arguments de ligne de commande ou le coder en dur.
lorsque vous utilisez le fichier mappé dans le processus parent, assurez-vous que le processus enfant écrit le résultat dans le fichier mappé avant que le fichier mappé ne soit publié dans le processus parent.
Exemple: Processus parent
private static void Main(string[] args)
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("memfile", 128))
{
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(512);
}
Console.WriteLine("Starting the child process");
// Command line args are separated by a space
Process p = Process.Start("ChildProcess.exe", "memfile");
Console.WriteLine("Waiting child to die");
p.WaitForExit();
Console.WriteLine("Child died");
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryReader reader = new BinaryReader(stream);
Console.WriteLine("Result:" + reader.ReadInt32());
}
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
Processus enfant
private static void Main(string[] args)
{
Console.WriteLine("Child process started");
string mmfName = args[0];
using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(mmfName))
{
int readValue;
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryReader reader = new BinaryReader(stream);
Console.WriteLine("child reading: " + (readValue = reader.ReadInt32()));
}
using (MemoryMappedViewStream input = mmf.CreateViewStream())
{
BinaryWriter writer = new BinaryWriter(input);
writer.Write(readValue * 2);
}
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
pour utiliser cet exemple, vous devez créer une solution avec 2 projets à l'intérieur, puis extraire le résultat de la construction du processus enfant de% childDir%/bin/debug et le copier dans% parentDirectory%/bin/debug, puis exécuter le projet parent
childDir
et parentDirectory
sont les noms de dossiers de vos projets sur le PC bonne chance :)
Il est possible d'obtenir la sortie Shell d'un processus en ligne de commande comme décrit ici: http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx
Cela dépend de mencoder. Si elle affiche cet état sur la ligne de commande, alors oui :)
Comment lancer un processus (tel qu'un fichier bat, un script Perl, un programme console) et afficher sa sortie standard sur un formulaire Windows:
processCaller = new ProcessCaller(this);
//processCaller.FileName = @"..\..\hello.bat";
processCaller.FileName = @"commandline.exe";
processCaller.Arguments = "";
processCaller.StdErrReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.StdOutReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.Completed += new EventHandler(processCompletedOrCanceled);
processCaller.Cancelled += new EventHandler(processCompletedOrCanceled);
// processCaller.Failed += no event handler for this one, yet.
this.richTextBox1.Text = "Started function. Please stand by.." + Environment.NewLine;
// the following function starts a process and returns immediately,
// thus allowing the form to stay responsive.
processCaller.Start();
Vous pouvez trouver ProcessCaller
sur ce lien: Lancement d’un processus et affichage de sa sortie standard
Vous pouvez enregistrer la sortie du processus en utilisant le code ci-dessous:
ProcessStartInfo pinfo = new ProcessStartInfo(item);
pinfo.CreateNoWindow = false;
pinfo.UseShellExecute = true;
pinfo.RedirectStandardOutput = true;
pinfo.RedirectStandardInput = true;
pinfo.RedirectStandardError = true;
pinfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
var p = Process.Start(pinfo);
p.WaitForExit();
Process process = Process.Start(new ProcessStartInfo((item + '>' + item + ".txt"))
{
UseShellExecute = false,
RedirectStandardOutput = true
});
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
if (process.ExitCode != 0) {
}