web-dev-qa-db-fra.com

ProcessInfo et RedirectStandardOutput

J'ai une application qui appelle un autre processus dans une fenêtre de commande et ce processus contient des statistiques de mise à jour qui s'affichent dans la fenêtre de la console. Je pensais que c'était une opération assez simple mais je n'arrive pas à le faire fonctionner. Est-ce que je manque quelque chose?

string assemblyLocation = Assembly.GetExecutingAssembly().Location;

Process process = new Process
{
    ProcessStart =
    {
        RedirectStandardOutput = true,
        UseShellExecute = false,
        WindowStyle = ProcessWindowStyle.Hidden,
        Arguments = arg,
        FileName = assemblyLocation.Substring(0, assemblyLocation.LastIndexOf("\\")) + "\\ffmpeg.exe",
        CreateNoWindow = true
    }
};

process.Start();

Console.WriteLine(process.StandardOutput.ReadToEnd());

process.WaitForExit();

Idéalement, ce que je voudrais, c’est que les résultats de la modification au sein de ce processus que j’atteins ou que des données parviennent au lecteur et que je récupère les événements.

Toute aide serait formidable, j’ai l’impression que c’est une question pour les débutants, mais que quelque chose me manque.

27
Brandon Grossutti

J'ai déjà expérimenté cela. Parfois, la façon dont le processus que vous appelez les sorties à la console n’est pas compatible avec ce type de redirection de sortie. J'ai eu la chance dans ce cas de pouvoir modifier le processus externe pour résoudre ce problème. 

Vous pouvez essayer d’exécuter votre code sur un autre processus qui renvoie la console et voir s’il fonctionne correctement. Il lit à peu près droit pour moi en ce moment.

MODIFIER:

Je suis allé tirer un bloc de code que j'avais l'habitude de faire. Ceci est dans une application WPF qui redirige la sortie du processus vers la fenêtre. Notez la liaison d'événement. Puisqu'il s'agit de WPF, je dois appeler mon appel pour écrire les données. Puisque vous ne craignez pas le blocage, vous devriez simplement pouvoir le remplacer par:

Console.WriteLine(e.Data);

J'espère que ça aide!

    private static void LaunchProcess()
    {
        Process build = new Process();
        build.StartInfo.WorkingDirectory =  @"dir";
        build.StartInfo.Arguments = "";
        build.StartInfo.FileName = "my.exe";

        build.StartInfo.UseShellExecute = false;
        build.StartInfo.RedirectStandardOutput = true;
        build.StartInfo.RedirectStandardError = true;
        build.StartInfo.CreateNoWindow = true;
        build.ErrorDataReceived += build_ErrorDataReceived;
        build.OutputDataReceived += build_ErrorDataReceived;
        build.EnableRaisingEvents = true;
        build.Start();
        build.BeginOutputReadLine();
        build.BeginErrorReadLine();
        build.WaitForExit();
    }

    // write out info to the display window
    static void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        string strMessage = e.Data;
        if (richTextBox != null && !String.Empty(strMessage))
        {
            App.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate()
            {
                Paragraph para = new Paragraph(new Run(strMessage));
                para.Margin = new Thickness(0);
                para.Background = brushErrorBrush;
                box.Document.Blocks.Add(para);
            });
       }
    } 
48
patjbs

Je ne suis pas certain du problème que vous rencontrez, mais si vous souhaitez agir dès la génération de la sortie, essayez de vous connecter à l'événement OutputDataReceived du processus. Vous pouvez spécifier des gestionnaires pour recevoir la sortie du processus de manière asynchrone. J'ai utilisé cette approche avec succès.

ProcessStartInfo info = new ProcessStartInfo(...)
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;

Process p = Process.Start(info);
p.OutputDataReceived += p_OutputDataReceived;
p.ErrorDataReceived += p_ErrorDataReceived;

p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();

..

void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
  Console.WriteLine("Received from standard out: " + e.Data);
}

void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
  Console.WriteLine("Received from standard error: " + e.Data);
}

Voir le processus OutputDataReceived event off pour plus d'informations.

21
Michael Petrotta

Utiliser des expressions lambda, etc.:

var info = new ProcessStartInfo(path)
{
    RedirectStandardError = true,
    RedirectStandardOutput = true,
    UseShellExecute = false,
    Verb = "runas",
};

var process = new Process
{
    EnableRaisingEvents = true,
    StartInfo = info
};

Action<object, DataReceivedEventArgs> actionWrite = (sender, e) =>
{
    Console.WriteLine(e.Data);
};

process.ErrorDataReceived += (sender, e) => actionWrite(sender, e);
process.OutputDataReceived += (sender, e) => actionWrite(sender, e);

process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
11
abatishchev

Fait intéressant, vous ne pouvez pas lire à partir de la sortie standard et de l'erreur standard en même temps:

si vous redirigez à la fois la sortie standard et l’erreur standard, puis essayez de lire les deux, pour exemple en utilisant le code C # suivant.

[C #] 

chaîne de sortie = p.StandardOutput.ReadToEnd ();

erreur de chaîne = p.StandardError.ReadToEnd ();

p.WaitForExit ();

Dans ce cas, si le processus enfant écrit du texte en erreur standard, il bloquera le fichier process, car le processus parent ne peut pas lire l'erreur standard tant qu'il n'est pas terminé lecture de la sortie standard. Cependant, le processus parent ne lira pas à partir de la norme sortie jusqu'à la fin du processus. Une solution recommandée à cette situation est de créer deux afin que votre application puisse lire la sortie de chaque flux sur un thread séparé.

http://msdn.Microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.71).aspx

4
Matthew Lock

code fluide a fonctionné dans VS2010

void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        if (String.IsNullOrEmpty(e.Data) == false)
        {
            new Thread(() =>
            {
                this.Dispatcher.Invoke(new Action(() =>
                {
                    // Add you code here
                }));
            }).Start();
        }
    }
1
Rock

Vérifiez que la sortie attendue n'est pas envoyée à la sortie StandardError au lieu de la sortie StandardOutput

0
stackuser83