2012-04-12 41 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