1

我已经实现了以下代码(改编自教程),以便运行命令提示符窗口、运行程序并读取输出。该代码是从嵌套在用户控件中的 ButtonClick 事件处理程序调用的。

我的印象是,由于这些方法是“异步的”,这将允许我的程序的其余部分在外部进程运行时运行。但是,情况似乎并非如此,因为我的 UI 将在操作运行时冻结。我应该补充一点,当 cmd 进程结束时收到的输出是正确的。

很抱歉转储大量这样的代码,只是不知道此时还能做什么!

任何帮助将不胜感激。

public static void runExternalProcess()
{
    StringBuilder output = new StringBuilder();

    Process cmd = new Process();
    cmd.StartInfo.FileName = "cmd.exe";          
    cmd.StartInfo.UseShellExecute = false;
    cmd.StartInfo.CreateNoWindow = true;
    cmd.StartInfo.RedirectStandardOutput = true;

    cmd.OutputDataReceived += new DataReceivedEventHandler(outputEventHandler);        
    cmd.StartInfo.RedirectStandardInput = true;        
    cmd.Start();
    cmd.BeginOutputReadLine();      

    StreamWriter sortStreamWriter = cmd.StandardInput; 
    StreamWriter sw = cmd.StandardInput;

    if (sw.BaseStream.CanWrite)
    {
        sw.WriteLine("ping www.google.com");
    }

    sw.Close();

    cmd.WaitForExit();

    MessageBox.Show(output.ToString());

    cmd.Close();
}

private static void outputEventHandler(object sendingProcess, DataReceivedEventArgs e)
{
    if (!String.IsNullOrEmpty(e.Data))
    {
        output.Append(e.Data + Environment.NewLine);
    }
}
4

3 回答 3

4

你的问题在这里:

cmd.WaitForExit();

这是一个阻塞调用。

如果要响应进程退出而不阻塞,则需要为 Exited 事件添加处理程序。

于 2012-04-12T15:53:20.690 回答
4

如何注册Exited活动并在MessageBox那里展示:

StringBuilder output = new StringBuilder();
Process cmd = new Process();

public void RunExternalPing()
{
   cmd.StartInfo.FileName = "cmd.exe";
   cmd.StartInfo.UseShellExecute = false;
   cmd.StartInfo.CreateNoWindow = true;
   cmd.StartInfo.RedirectStandardOutput = true;
   cmd.StartInfo.RedirectStandardInput = true;

   cmd.EnableRaisingEvents = true;
   cmd.OutputDataReceived += 
      new DataReceivedEventHandler(cmd_OutputDataReceived);
   cmd.Exited += new EventHandler(cmd_Exited);

   cmd.Start();
   cmd.BeginOutputReadLine();
   StreamWriter sw = cmd.StandardInput;
   sw.WriteLine("ping www.google.com");
   sw.Close();
}

void cmd_Exited(object sender, EventArgs e)
{
   MessageBox.Show(output.ToString());
   cmd.Dispose();
}

private void cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
   if (!String.IsNullOrEmpty(e.Data))
   {
      output.Append(e.Data + Environment.NewLine);
   }
}

来自 MSDN:

当关联进程退出时,有两种方式得到通知:同步和异步。同步通知依赖于调用 WaitForExit 方法来暂停应用程序的处理,直到相关组件退出。异步通知依赖于 Exited 事件。在任何一种情况下,必须将 EnableRaisingEvents 设置为 true,Process 组件才能接收进程已退出的通知。

于 2012-04-12T15:58:58.743 回答
2

所有这些代码都是线性的,如果您不想冻结您所在的线程,您应该创建一个新线程并在该线程完成时执行回调。

查看BackgroundWorker

于 2012-04-12T15:53:47.280 回答