从控制台应用程序发送输入/获取输出 (C#/WinForms)

发布于 2024-08-12 13:01:39 字数 1539 浏览 8 评论 0原文

我有一个包含 3 个控件的表单:

  1. 供用户输入的文本框 发送到控制台的命令 应用程序,
  2. 确认命令的按钮 被发送和
  3. 一个只读文本框来显示 应用程序的输出。

我想要的是用户在第一个文本框中输入命令,按下按钮输入并通过第二个文本框接收反馈。

我知道如何使用 ProcessStartInfo.RedirectStandardOutput,但是,当我使用 StandardOutput.ReadToEnd() 时,应用程序会挂起。

我查看了异步 Process.BeginOutputReadLine() ,但是,即使我的应用程序没有挂起,不知何故我在文本框中没有得到任何响应,它绝对没有任何作用。

这是我的代码:

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

有什么方法可以让它顺利运行吗?谢谢。

I have a form with 3 controls:

  1. A textbox for the user to enter
    commands to send to a console
    application,
  2. A button to confirm the commands to
    be sent and
  3. A read-only textbox to display the
    output from the application.

What I want is for the user to enter commands in the first textbox, press the button to enter and receive feedback via the second textbox.

I know how to use ProcessStartInfo.RedirectStandardOutput but, however, the app hangs when I use StandardOutput.ReadToEnd().

I had a look at the asynchronous Process.BeginOutputReadLine() but, even though my app does not hang, somehow I get no response in the textbox, it does absolutely nothing.

Here's my 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();
    }
}

Is there any way I can have this run smoothly? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

楠木可依 2024-08-19 13:01:39

如果您想要一些交互式的内容,我可以让这段代码起作用(您的代码已修改,修改的详细信息如下)

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

因此,我将 BeginOutputReadLine 移至进程启动后。这确保了它实际上只被调用一次。我还执行了清理线程调用所需的调用。希望这对你有用。

If you want something interactive, I got this code to work (yours modified, details on modifications below)

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

So, I moved the BeginOutputReadLine to just after the process is started. That ensures it's really only called once. I also did an invoke required to clean up thread calls. Hopefully this should work for you.

梦幻的心爱 2024-08-19 13:01:39

我发现的最佳解决方案是:

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

The best solution I have found is:

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);
    }
}
冷了相思 2024-08-19 13:01:39

我使用过类似这样的代码:

    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;

    }

但它不是交互式的。但如果应用程序是交互式的,那么无论如何它都会需要更多的代码。

I've used code something like this:

    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;

    }

But it's not interactive. But if the app is interactive, it'll take a lot more code anyway.

牵强ㄟ 2024-08-19 13:01:39

您在哪里调用 StandardOutput.ReadToEnd()?我曾经遇到过类似的问题,因为我在 StandardOutput.ReadToEnd() 之前调用了 Process.WaitForExit() 。我有大量的输入,并且输出缓冲区在完成之前已满,并且我的进程被阻塞。

您必须在 Process.WaitForExit() 之前调用 StandardOutput.ReadToEnd()

Where are you calling StandardOutput.ReadToEnd()? I once had a similar problem because I was calling Process.WaitForExit() before StandardOutput.ReadToEnd(). I had a large amount of input, and the output buffer was full before completion and my process was blocked.

You must call StandardOutput.ReadToEnd()before Process.WaitForExit().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文