一个C#写的调用外部进程类
2008-05-21 07:00 作者: 肖波 出處: 天極網
C# 調用外部進程的類,網上可以搜出很多來,為什么要再寫一遍,實在是因為最近從網上拷貝了一個簡單的例程用到項目中,運行有問題,后來研究了半天,才解決了這些問題。于是打算重寫,一來說說調用一個外部進程這么簡單的一件事究竟會有哪些問題,二來也希望我寫的這個相對比較完整的類可以為軟件開發的同道們節約一些腦細胞,以便集中優勢兵力解決那些真正高深復雜的軟件問題。
在開始正題之前,我們先來看一看網上比較常見的執行外部進程的函數
private?string?RunCmd(string?command) ?{ ?//例Process ?Process?p?=?new?Process(); ?p.StartInfo.FileName?=?"cmd.exe";?//確定程序名 ?p.StartInfo.Arguments?=?"/c?"?+?command;?//確定程式命令行 ?p.StartInfo.UseShellExecute?=?false;?//Shell的使用 ?p.StartInfo.RedirectStandardInput?=?true;?//重定向輸入 ?p.StartInfo.RedirectStandardOutput?=?true;?//重定向輸出 ?p.StartInfo.RedirectStandardError?=?true;?//重定向輸出錯誤 ?p.StartInfo.CreateNoWindow?=?true;?//設置置不顯示示窗口 ?p.Start();?//00 ?//p.StandardInput.WriteLine(command);?//也可以用這種方式輸入入要行的命令 ?//p.StandardInput.WriteLine("exit");?//要得加上Exit要不然下一行程式 ?return?p.StandardOutput.ReadToEnd();?//輸出出流取得命令行結果 ?} |
這個方法應該是比較常見的調用外部進程的方法,我以前也一直是這樣調用外部進程的,也沒有碰到過什么問題。但這次調用的外部進程比較特殊,用這種方法調用就出現了兩個問題。
第一個問題是這個被調用的外部進程有時候會出現異常,出現異常后Windows會彈出錯誤報告框,程序于是吊死在那里,必須手工干預。這個問題比較好解決,程序中設置一下注冊表搞定。
第二個問題是調用這個外部進程(是一個控制臺進程)后,程序會阻塞在p.StandardOutput.ReadToEnd();這一句,永遠無法出來,被調用的那個控制臺程序也被吊死。但該控制臺進程在CMD 中是可以正常執行的。后來看來一些資料才發現原來原因是出在該控制臺程序控制臺輸出大量字符串,管道重定向后,調用程序沒有及時將管道中的輸出數據取出,結果導致管道被阻塞,程序吊死。在這里還有另外一個問題,雖然這次沒有遇到,但網上有其他人遇到,就是錯誤信息管道不及時取出數據,也會被阻塞,而且如果要同時取出兩個管道的數據,必須要利用一個輔助線程才能實現。
問題講完了,下面給出這個類的完整代碼
using?System; using?System.Collections.Generic; using?System.Text; using?System.Runtime.InteropServices; using?System.Threading; namespace?Laboratory.Process { ?class?ReadErrorThread ?{ ?System.Threading.Thread?m_Thread; ?System.Diagnostics.Process?m_Process; ?String?m_Error; ?bool?m_HasExisted; ?object?m_LockObj?=?new?object(); ?public?String?Error ?{ ?get ?{ ?return?m_Error; ?} ?} ?public?bool?HasExisted ?{ ?get ?{ ?lock?(m_LockObj) ?{ ?return?m_HasExisted; ?} ?} ?set ?{ ?lock?(m_LockObj) ?{ ?m_HasExisted?=?value; ?} ?} ?} ?private?void?ReadError() ?{ ?StringBuilder?strError?=?new?StringBuilder(); ?while?(!m_Process.HasExited) ?{ ?strError.Append(m_Process.StandardError.ReadLine()); ?} ?strError.Append(m_Process.StandardError.ReadToEnd()); ?m_Error?=?strError.ToString(); ?HasExisted?=?true; ?} ?public?ReadErrorThread(System.Diagnostics.Process?p) ?{ ?HasExisted?=?false; ?m_Error?=?""; ?m_Process?=?p; ?m_Thread?=?new?Thread(new?ThreadStart(ReadError)); ?m_Thread.Start(); ?} ?} ?class?RunProcess ?{ ?private?String?m_Error; ?private?String?m_Output; ?public?String?Error ?{ ?get ?{ ?return?m_Error; ?} ?} ?public?String?Output ?{ ?get ?{ ?return?m_Output; ?} ?} ?public?bool?HasError ?{ ?get ?{ ?return?m_Error?!=?""?&&?m_Error?!=?null; ?} ?} ?public?void?Run(String?fileName,?String?para) ?{ ?StringBuilder?outputStr?=?new?StringBuilder(); ?try ?{ ?//disable?the?error?report?dialog. ?//reference:?http://www.devcow.com/blogs/adnrg/archive/2006/07/14/Disable-Error-Reporting-Dialog-for-your-application-with-the-registry.aspx ?Microsoft.Win32.RegistryKey?key; ?key?=?Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"software\microsoft\PCHealth\ErrorReporting\",?true); ?int?doReport?=?(int)key.GetValue("DoReport"); ?if?(doReport?!=?0) ?{ ?key.SetValue("DoReport",?0); ?} ?int?showUI?=?(int)key.GetValue("ShowUI"); ?if?(showUI?!=?0) ?{ ?key.SetValue("ShowUI",?0); ?} ?} ?catch ?{ ?} ?m_Error?=?""; ?m_Output?=?""; ?try ?{ ?System.Diagnostics.Process?p?=?new?System.Diagnostics.Process(); ?p.StartInfo.FileName?=?fileName; ?p.StartInfo.Arguments?=?para; ?p.StartInfo.UseShellExecute?=?false; ?p.StartInfo.RedirectStandardInput?=?true; ?p.StartInfo.RedirectStandardOutput?=?true; ?p.StartInfo.RedirectStandardError?=?true; ?p.StartInfo.CreateNoWindow?=?true; ?p.Start(); ?ReadErrorThread?readErrorThread?=?new?ReadErrorThread(p); ?while?(!p.HasExited) ?{ ?outputStr.Append(p.StandardOutput.ReadLine()+"\r\n"); ?} ?outputStr.Append(p.StandardOutput.ReadToEnd()); ?while?(!readErrorThread.HasExisted) ?{ ?Thread.Sleep(1); ?} ?m_Error?=?readErrorThread.Error; ?m_Output?=?outputStr.ToString(); ?} ?catch?(Exception?e) ?{ ?m_Error?=?e.Message; ?} ?} ?} } |
轉載于:https://www.cnblogs.com/gofficer/archive/2008/10/30/1322825.html
總結
以上是生活随笔為你收集整理的一个C#写的调用外部进程类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Asp.net如何截屏
- 下一篇: Steam 7月硬件调查公布:GTX 1