【问题标题】:Having trouble with Process class while redirecting command prompt output to winform将命令提示符输出重定向到 winform 时出现 Process 类问题
【发布时间】:2011-10-10 19:18:23
【问题描述】:

我在市场上寻找一个“选项卡式”命令提示符应用程序,因为我厌倦了多个命令提示符窗口使我的一个桌面屏幕变得杂乱无章,当时我想到了创建自己的命令提示符窗口的可能性。虽然我知道它不会像独立产品那样出色,但我认为创建自己的产品只是为了更熟悉“System.Diagnostic”类(Process、ProcessStartInfo 等)将是一个很好的练习我以前从未真正玩过。

我几乎刚刚创建了一个准系统 winforms 应用程序,它有 2 个选项卡(包含丰富的文本字段)、一个文本字段(用于输入命令)和一个按钮(用于实际运行命令)。

我发现了各种显示如何运行命令的帖子,但我在实际执行命令并将结果返回到 Richtextbox 时遇到了问题。这是我根据我现在所知道的信息创建的一种方法: (根据以前的答案更新)

public void GetConsoleOuput(string command)
{
  string outputString;

  ProcessStartInfo startupInfo = new ProcessStartInfo()
  startInfo.FileName = "cmd.exe";
  startInfo.RedirectStandardOuput = true;
  startInfo.WindowStyle = ProcessWindowStyle.Hidden:
  startInfo.UseShellExecute = false;

  startInfo.Arguments("/C " + command);

  Process process = new Process()
  process.StartInfo = startInfo;
  process.OutputDataReceived += new DataReceivedEventHandler(AppendRichBoxText);

  process.Start()
  process.BeginOutputReadLine();

  process.WaitForExit();
  process.Close();
}

public void AppendRichBoxTet(object sender, DataReceivedEventArgs args)
{
  string outputString = args.Data;

  // need to have the richTextBox updated using it's own thread
  richTextBox.BeginInvoke( /* not sure what to put inside here */);
}

此方法的用途是不断将输出文本附加到富文本框。

在这一点上,我被困在如何执行 BeginInvoke 方法,以便这个richTextBox 将在它自己的线程上更新它的文本。

【问题讨论】:

  • 我使用的是 cygwin 的 screen.exe,但我不知道它与 cmd.exe 的效果如何

标签: c# winforms process command-prompt


【解决方案1】:

是的,你可以。您可以使用事件驱动的输出重定向 API,而不是使用 ReadToEnd(它将阻塞直到进程完成):

BeginOutputReadLine 文档中有一个示例。

编辑:对于Control.BeginInvoke,这可能是最简单的解决方案:

public void AppendRichBoxTet(object sender, DataReceivedEventArgs args)
{
  string outputString = args.Data;
  MethodInvoker append = () => richTextBox.AppendText(outputString);
  richTextBox.BeginInvoke(append);
}

【讨论】:

  • 是否有实际的 Control.BeginInvoke 方法?或者我是否在我想要更新的实际控件上调用 BeginInvoke(在本例中为 eventhandler 方法中的richTextBox)?此外,在我订阅事件并提供此异步调用以更新富文本框之后,在​​调用 process.BeginOutputReadLine 和 process.Close() 之间,我还需要在“流程”代码中做什么?在提供的示例中,可视化相当简单,因为它实际上是在创建一个 Streamwriter。另外,我应该在 process.Start() 方法之前还是之后订阅 OutputDataReceived 事件?
  • @HansGruber:你在控件上调用它——它在Control 中声明,但它是一个实例方法。您应该能够在不显式关闭它的情况下启动该过程 - 如果您愿意,您可以在 Exited 事件的处理程序中这样做。根据文档中的示例,您应该能够立即订阅 OutputDataReceived 事件。
  • 我认为我的问题是我仍然模糊不清是否将所有内容都连接起来。我添加了“process.OutputDataReceived += new DataReceivedEventHandler(ShowConsoleStuff);”开始该过程后立即。我假设每次触发 outputDataReceived 事件时,它都应该执行我创建的名为“ShowConsoleStuff”的方法中的代码。在这个方法里面是我应该做richTextBox1.BeginInvoke() 方法的地方吗?如果是这种情况,这是否意味着我必须创建一个只接受同一个文本框并调用 AppendText 的委托?
  • @HansGruber:是的,基本上就是这样。不过,lambda 表达式会在这方面为您提供帮助。
  • 我已经更新了上面的代码。我已经列出了迄今为止我对代码所做的更改。我觉得我快到了,但还没有完全到。我不完全确定我需要在 BeginInvoke() 方法中放入什么,我已经玩过它,但考虑到我仍然不完全确定我在用“UI Marshalling”做什么,我是完成这部分仍然有问题。到目前为止,我感谢您的帮助...
【解决方案2】:

这里有一些问题

1) 您没有等待进程完成。在读取输出之前,您应该使用 Wait 方法等待它完成。

2) 输出缓冲区有一定的大小,如果溢出,就会出现死锁。确保添加事件处理程序以在 std 可用时读取它,或者启动另一个线程以定期检查它。

3) 你为什么要使用 cmd.exe?

【讨论】:

  • 1) ok 添加 process.Wait() 再阅读,检查。 2)读标准输出是什么意思? 3) 有没有办法在没有 cmd.exe 的情况下执行这些命令?我只是根据 SO 上的其他类似问题并使用 Google 提出的。
  • 调用ReadToEnd() 时,(1) 更像是一个问题,而不是指导方针。一般来说,您应该只将处理程序添加到OutputDataReceived 事件并在那里执行您的richTextBox.Append()。或者使用 Jon 描述的替代方法,这同样有效,但如果您不熟悉异步调用,可能会更难掌握。
  • 好的,我订阅了 process.OutputDataReceived += new DataReceivedEventHandler(AppendRichBoxText),并创建了 AppendRichBoxText(object sender, DataReceivedEventArgs args) { richTextBox1.AppendText(args.Data); }。在我启动进程后,然后调用 process.BeginOutputReadLine(),我不知道下一步该做什么。
  • 如果您正在使用该事件,则无需调用 BeginOutputReadLine。至于接下来要做什么...... Idk,它不起作用吗?
  • 看起来在我订阅该事件,然后提供该事件处理程序方法然后启动该过程之后,OutputDataReceived 事件永远不会触发,就像我在“AppendRichBoxText”方法中放置一个断点时一样,它永远不会被调用。我可能在这里做错了什么。
猜你喜欢
  • 1970-01-01
  • 2010-10-22
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多