web-dev-qa-db-ja.com

ProcessInfoおよびRedirectStandardOutput

コマンドウィンドウで別のプロセスを呼び出すアプリがあり、そのプロセスにはコンソールウィンドウに出力される統計情報の更新があります。これはかなり簡単な操作だと思いましたが、うまく動かないようです。何か不足していますか?

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();

理想的には、ヒットしたプロセス内で出力が変化したり、イベントからイベントを取得したデータがリーダーに入ったりするのが理想です。

これは初心者の質問だと思いますが、何かが足りないようです。

28

私はこれを以前に経験したことがあります。ときどき、コンソールへの出力を呼び出しているプロセスの方法は、この種の出力リダイレクトと互換性がありません。この場合、幸運にも、外部プロセスを変更してこれを回避できるようになりました。

コンソールに出力する別のプロセスでコードを実行してみて、正しく動作するかどうかを確認します。それは今、私にとって正しいことについて読んでいます。

編集:

私が行って、これを行うために使用したコードブロックをプルしました。これは、プロセス出力をウィンドウにリダイレクトするWPFアプリにあります。イベントバインディングに注意してください。これはWPFなので、呼び出しを呼び出してデータを書き出す必要があります。あなたはブロッキングについて心配していないので、あなたは単にそれを次のものに置き換えることができるはずです:

Console.WriteLine(e.Data);

うまくいけばそれは役立ちます!

    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);
            });
       }
    } 
49
patjbs

どのような問題が発生しているのか正確にはわかりませんが、出力が生成されたらすぐに対処する場合は、プロセスのOutputDataReceivedイベントにフックしてみてください。ハンドラーを指定して、プロセスから非同期で出力を受け取ることができます。私はこのアプローチをうまく使いました。

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);
}

詳細については、 OutputDataReceived イベントオフプロセスを参照してください。

22

ラムダ式などの使用:

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();
12
abatishchev

興味深いことに、標準出力と標準エラーを同時に読み取ることはできません。

標準出力と標準エラーの両方をリダイレクトしてから、たとえば次のC#コードを使用して両方を読み取ろうとした場合。

[C#]

文字列出力= p.StandardOutput.ReadToEnd();

string error = p.StandardError.ReadToEnd();

p.WaitForExit();

この場合、親プロセスは標準出力からの読み取りが完了するまで標準エラーから読み取ることができないため、子プロセスが標準エラーにテキストを書き込むと、プロセスはブロックされます。ただし、親プロセスは、プロセスが終了するまで標準出力から読み取りません。この状況に対する推奨される解決策は、2つのスレッドを作成して、アプリケーションが各ストリームの出力を別々のスレッドで読み取ることができるようにすることです。

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

4
Matthew Lock

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

期待する出力が、StandardOutput出力ではなくStandardError出力に送信されていないことを確認します。

0
stackuser83