我也写了同样的应用程序,使用Windows窗体在按钮被按下后运行进程,并读取其标准输出。当我在button1_Click()中调用"test()“方法时,我的程序被阻塞了。但是当我在"Form1“构造函数中调用"test()”时,一切都像预期的那样工作。问题出在哪里?
using System;
using System.Windows.Forms;
namespace DISMassistant
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
process1.StartInfo.RedirectStandardError = true;
process1.StartInfo.RedirectStandardOutput = true;
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.FileName = "cmd.exe";
process1.StartInfo.Arguments = "/?";
}
public void button1_Click(object sender, EventArgs e)
{
}
public void test()
{
process1.Start();
process1.BeginOutputReadLine();
process1.BeginErrorReadLine();
process1.WaitForExit();
process1.CancelOutputRead();
process1.CancelErrorRead();
process1.Close();
}
private void process1_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
if (string.IsNullOrEmpty(e.Data)) return;
richTextBox1.Text += e.Data + "\n";
}
private void process1_ErrorDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
if (string.IsNullOrEmpty(e.Data)) return;
richTextBox1.Text += e.Data + "\n";
}
}
}发布于 2019-11-12 17:34:51
修复了示例代码中所有缺失的部分,就没有问题了(当然,除了您不想在图形用户界面应用程序中使用WaitForExit之外):
// Warning - The code below is WRONG! Awful even, since it will _appear_ to work in some cases.
void Main()
{
Application.Run(new Form1());
}
public class Form1 : Form
{
Process process1 = new Process();
Button button1;
RichTextBox richTextBox1;
public Form1()
{
button1 = new Button { Text = "Run" };
button1.Click += button1_Click;
Controls.Add(button1);
richTextBox1 = new RichTextBox { Left = 100 };
Controls.Add(richTextBox1);
process1.StartInfo.RedirectStandardError = true;
process1.StartInfo.RedirectStandardOutput = true;
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.FileName = "cmd.exe";
process1.StartInfo.Arguments = "/?";
}
public void button1_Click(object sender, EventArgs e)
{
test();
}
public void test()
{
process1.Start();
process1.OutputDataReceived += process1_OutputDataReceived;
process1.ErrorDataReceived += process1_ErrorDataReceived;
process1.BeginOutputReadLine();
process1.BeginErrorReadLine();
process1.WaitForExit();
process1.CancelOutputRead();
process1.CancelErrorRead();
process1.Close();
}
private void process1_OutputDataReceived(object sender,
System.Diagnostics.DataReceivedEventArgs e)
{
if (string.IsNullOrEmpty(e.Data)) return;
richTextBox1.Text += e.Data + "\n";
}
private void process1_ErrorDataReceived(object sender,
System.Diagnostics.DataReceivedEventArgs e)
{
if (string.IsNullOrEmpty(e.Data)) return;
richTextBox1.Text += e.Data + "\n";
}
}但是,这仍然是您不想做的事情。GUI控件不应该从创建它们的线程之外的其他线程访问。我在测试应用程序中没有遇到问题,但即使它正常工作,这也只是一场等待发生的灾难。
碰巧RichTextBox对Text属性的处理有点奇怪。如果句柄还没有创建,Text只会更改类中的一个字段。它不执行任何多线程访问检查或其他任何操作。现在,当实际创建句柄时,此字段的值将实际应用于控件的文本-在正确的线程上。
这可能就是你看到自己怪异行为的原因。在表单构造函数中,句柄尚未创建。从后台线程访问仍然不是一个好主意,但在大多数情况下,它实际上不会破坏任何东西(您可能会丢失一些进程输出)。当显示表单时,将创建句柄,并且文本框显示“正确”输出。
当表单已经创建(并显示)时,这一点会发生变化。在单线程单元线程上,您需要自己处理多线程。无论出于什么原因,RichTextBox都不是(总是)那样的控件。因此,在STA上,代码碰巧工作-不可靠或不安全,但它不会挂起,也不会崩溃。
但您的UI线程似乎处于多线程单元中。在MTA中,当您尝试将文本分配给RichTextBox (使用创建的句柄)时,消息将被编组到UI线程。但是您的UI线程正忙于等待进程退出!因此,你被吊死了。
你怎么解决这个问题呢?
https://stackoverflow.com/questions/58768417
复制相似问题