2012-04-12 74 views
1

为了运行命令提示符窗口,运行程序并读取输出,我已经实现了以下代码(从tutorial改编而来)。该代码是从ButtonClick事件处理程序中调用的,该处理程序嵌套在用户控件中。使用外部过程的UI冻结

我的印象是这会让我的程序的其余部分在外部进程运行的同时运行,因为这些方法是'异步'的。但是,这似乎并不是这种情况,因为我的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

如何注册为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组件 接收进程已退出的通知。

+0

我已经在上面的代码中添加了,并删除了watiforexit()调用,但现在函数不显示消息框,任何想法? – 2012-04-12 16:12:02

+0

你删除了'cmd.WaitForExit();'对吗? – SwDevMan81 2012-04-12 16:14:53

+0

对不起,正在缓慢(然后编辑评论)。消息框现在完全不显示。你有什么想法,为什么? – 2012-04-12 16:18:05

4

你的问题是在这里:

cmd.WaitForExit(); 

这是一个阻塞调用。

如果您想要在不阻塞的情况下响应退出的进程,则需要为Exited事件添加处理程序。

+0

他们需要在调用MessageBox.Show之前等待输出 – Matthew 2012-04-12 15:54:24

+1

@Matthew:是的,我知道他们为什么在等待。我告诉他们为什么会阻止他们的用户界面。 – 2012-04-12 15:57:12

+0

啊,是的,我明白你在说什么了。我对你的建议的印象是只删除那条线而没有别的。 – Matthew 2012-04-12 16:01:22

2

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

结帐BackgroundWorker

+0

好吧,如果你不介意我的问题,那么使用异步方法的好处是什么呢? – 2012-04-12 15:56:16

+1

@ Mr.Spice函数'WaitForExit'不是异步的,这就是为什么你的线程被阻塞的原因。 – Matthew 2012-04-12 15:59:44

+0

啊我看到谢谢你 – 2012-04-12 16:04:26