Frage

Ich habe ein Formular mit 3 Kontrollen:

  1. Ein Textfeld, in dem der Benutzer Befehle eingibt, die an eine Konsolenanwendung gesendet werden können,
  2. Eine Schaltfläche, um die zugesandten Befehle zu bestätigen und
  3. Ein schreibgeschütztes Textfeld zum Anzeigen der Ausgabe aus der Anwendung.

Ich möchte, dass der Benutzer Befehle in das erste Textfeld eingibt. Drücken Sie die Schaltfläche, um über das zweite Textfeld Feedback einzugeben und zu empfangen.

Ich weiß, wie man benutzt ProcessStartInfo.RedirectStandardOutput Die App hängt jedoch jedoch, wenn ich benutze StandardOutput.ReadToEnd().

Ich habe mir die Asynchron angesehen Process.BeginOutputReadLine() Aber obwohl meine App nicht hängt, bekomme ich irgendwie keine Antwort in der Textbox, sie macht absolut nichts.

Hier ist mein Code:

public partial class MainForm : Form
{

    private void MainForm_Load(object sender, EventArgs e)
    {
        InitializeInterpreter();
    }

    private void InitializeInterpreter()
    {
        InterProc.StartInfo.UseShellExecute = false;
        InterProc.StartInfo.FileName = "app.exe";
        InterProc.StartInfo.RedirectStandardInput = true;
        InterProc.StartInfo.RedirectStandardOutput = true;
        InterProc.StartInfo.RedirectStandardError = true;
        InterProc.StartInfo.CreateNoWindow = true;
        InterProc.OutputDataReceived += new DataReceivedEventHandler(InterProcOutputHandler);

        InterProc.Start();
    }

    private static void InterProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
    {
        if (!String.IsNullOrEmpty(outLine.Data))
        {
           OutputTextBox.Append(Environment.NewLine + outLine.Data);
        }
    }

    private void Enterbutton_Click(object sender, EventArgs e)
    {
        InterProc.StandardInput.Write(CommandtextBox.Text);
        InterProc.BeginOutputReadLine();
    }
}

Gibt es eine Möglichkeit, dass ich diesen reibungslos laufen kann? Vielen Dank.

War es hilfreich?

Lösung

Wenn Sie etwas Interaktives wünschen, habe ich diesen Code funktioniert (Ihre geändert, Einzelheiten zu Änderungen unten)

    private void InitializeInterpreter()
    {
        InterProc.StartInfo.UseShellExecute = false;
        InterProc.StartInfo.FileName = "Echoer.exe";
        InterProc.StartInfo.RedirectStandardInput = true;
        InterProc.StartInfo.RedirectStandardOutput = true;
        InterProc.StartInfo.RedirectStandardError = true;
        InterProc.StartInfo.CreateNoWindow = true;
        InterProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        InterProc.OutputDataReceived += new DataReceivedEventHandler(InterProcOutputHandler);

        bool started = InterProc.Start();

        InterProc.BeginOutputReadLine();

    }

    private void AppendTextInBox(TextBox box, string text)
    {
        if (this.InvokeRequired)
        {
            this.Invoke((Action<TextBox, string>)AppendTextInBox, OutputTextBox, text);
        }
        else
        {
            box.Text += text;
        }
    }

    private void InterProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
    {
        AppendTextInBox(OutputTextBox, outLine.Data + Environment.NewLine);
    }

    private void Enterbutton_Click(object sender, EventArgs e)
    {
        InterProc.StandardInput.WriteLine(CommandTextBox.Text);
    }

Also habe ich die BeginnoutputReadline auf kurz nach dem Beginn des Prozesses verschoben. Das stellt sicher, dass es wirklich nur einmal angerufen wird. Ich habe auch einen Aufruf durchgeführt, der zum Aufräumen von Thread -Anrufen erforderlich war. Hoffentlich sollte dies für Sie funktionieren.

Andere Tipps

Die beste Lösung, die ich gefunden habe, ist:

private void Redirect(StreamReader input, TextBox output)
{
    new Thread(a =>
    {
        var buffer = new char[1];
        while (input.Read(buffer, 0, 1) > 0)
        {
            output.Dispatcher.Invoke(new Action(delegate
            {
                output.Text += new string(buffer);
            }));
        };
    }).Start();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            CreateNoWindow = true,
            FileName = "app.exe",
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            UseShellExecute = false,
        }
    };
    if (process.Start())
    {
        Redirect(process.StandardError, textBox1);
        Redirect(process.StandardOutput, textBox1);
    }
}

Ich habe so etwas Code verwendet:

    public static void Run(string fileName, string arguments, out string standardOutput, out string standardError, out int exitCode)
    {
        Process fileProcess = new Process();
        fileProcess.StartInfo = new ProcessStartInfo
        {
            FileName = fileName,
            Arguments = arguments,
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            UseShellExecute = false,
            WindowStyle = ProcessWindowStyle.Hidden,
            CreateNoWindow = true,
        };

        bool started = fileProcess.Start();

        if (started)
        {
            fileProcess.WaitForExit();
        }
        else
        {
            throw new Exception("Couldn't start");
        }

        standardOutput = fileProcess.StandardOutput.ReadToEnd();
        standardError = fileProcess.StandardError.ReadToEnd();
        exitCode = fileProcess.ExitCode;

    }

Aber es ist nicht interaktiv. Aber wenn die App interaktiv ist, dauert sie sowieso viel mehr Code.

Wohin rufst du an StandardOutput.ReadToEnd()? Ich hatte einmal ein ähnliches Problem, weil ich angerufen habe Process.WaitForExit() Vor StandardOutput.ReadToEnd(). Ich hatte eine große Menge an Eingang und der Ausgangspuffer war vor Abschluss voll und mein Prozess wurde blockiert.

Sie müssen anrufen StandardOutput.ReadToEnd()Vor Process.WaitForExit().

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top