描述C#調(diào)用外部進(jìn)程
C#調(diào)用外部進(jìn)程的類,網(wǎng)上可以搜出很多來,為什么要再寫一遍,實在是因為最近從網(wǎng)上拷貝了一個簡單的例程用到項目中,運行有問題,后來研究了半天,才解決了這些問題。于是打算寫這么一篇博文,一來說說C#調(diào)用外部進(jìn)程這么簡單的一件事究竟會有哪些問題,二來也希望我寫的這個相對比較完整的類可以為軟件開發(fā)的同道們節(jié)約一些腦細(xì)胞,以便集中優(yōu)勢兵力解決那些真正高深復(fù)雜的軟件問題。
在開始正題之前,我們先來看一看網(wǎng)上比較常見的執(zhí)行外部進(jìn)程的函數(shù)
- privatestringRunCmd(stringcommand)
- {
- //例Process
- Processp=newProcess();
- 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;//設(shè)置置不顯示示窗口
- p.Start();//00
- //p.StandardInput.WriteLine(command);//也可以用這種方式輸入入要行的命令
- //p.StandardInput.WriteLine("exit");//要得加上Exit要不然下一行程式
- returnp.StandardOutput.ReadToEnd();//輸出出流取得命令行結(jié)果果
- }
這個方法應(yīng)該是比較常見的C#調(diào)用外部進(jìn)程的方法,我以前也一直是這樣調(diào)用外部進(jìn)程的,也沒有碰到過什么問題。但這次調(diào)用的外部進(jìn)程比較特殊,用這種方法調(diào)用就出現(xiàn)了兩個問題。
***個問題是這個被調(diào)用的外部進(jìn)程有時候會出現(xiàn)異常,出現(xiàn)異常后Windows會彈出錯誤報告框,程序于是吊死在那里,必須手工干預(yù)。這個問題比較好解決,程序中設(shè)置一下注冊表搞定。
第二個問題是C#調(diào)用外部進(jìn)程(是一個控制臺進(jìn)程)后,程序會阻塞在p.StandardOutput.ReadToEnd();這一句,永遠(yuǎn)無法出來,被調(diào)用的那個控制臺程序也被吊死。但該控制臺進(jìn)程在CMD 中是可以正常執(zhí)行的。后來看來一些資料才發(fā)現(xiàn)原來原因是出在該控制臺程序控制臺輸出大量字符串,管道重定向后,調(diào)用程序沒有及時將管道中的輸出數(shù)據(jù)取出,結(jié)果導(dǎo)致管道被阻塞,程序吊死。在這里還有另外一個問題,雖然這次沒有遇到,但網(wǎng)上有其他人遇到,就是錯誤信息管道不及時取出數(shù)據(jù),也會被阻塞,而且如果要同時取出兩個管道的數(shù)據(jù),必須要利用一個輔助線程才能實現(xiàn)。
問題講完了,下面給出這個類的完整代碼
- usingSystem;
- usingSystem.Collections.Generic;
- usingSystem.Text;
- usingSystem.Runtime.InteropServices;
- usingSystem.Threading;
- namespaceLaboratory.Process
- {
- classReadErrorThread
- {
- System.Threading.Threadm_Thread;
- System.Diagnostics.Processm_Process;
- Stringm_Error;
- boolm_HasExisted;
- objectm_LockObj=newobject();
- publicStringError
- {
- get
- {
- returnm_Error;
- }
- }
- publicboolHasExisted
- {
- get
- {
- lock(m_LockObj)
- {
- returnm_HasExisted;
- }
- }
- set
- {
- lock(m_LockObj)
- {
- m_HasExisted=value;
- }
- }
- }
- privatevoidReadError()
- {
- StringBuilderstrError=newStringBuilder();
- while(!m_Process.HasExited)
- {
- strError.Append(m_Process.StandardError.ReadLine());
- }
- strError.Append(m_Process.StandardError.ReadToEnd());
- m_Error=strError.ToString();
- HasExisted=true;
- }
- publicReadErrorThread(System.Diagnostics.Processp)
- {
- HasExisted=false;
- m_Error="";
- m_Process=p;
- m_Thread=newThread(newThreadStart(ReadError));
- m_Thread.Start();
- }
- }
- classRunProcess
- {
- privateStringm_Error;
- privateStringm_Output;
- publicStringError
- {
- get
- {
- returnm_Error;
- }
- }
- publicStringOutput
- {
- get
- {
- returnm_Output;
- }
- }
- publicboolHasError
- {
- get
- {
- returnm_Error!=""&&m_Error!=null;
- }
- }
- publicvoidRun(StringfileName,Stringpara)
- {
- StringBuilderoutputStr=newStringBuilder();
- try
- {
- //disabletheerrorreportdialog.
- //reference:http://www.devcow.com/blogs/adnrg/archive/2006/07/14/
Disable-Error-Reporting-Dialog-for-your-application-with-the-registry.aspx- Microsoft.Win32.RegistryKeykey;
- key=Microsoft.Win32.Registry.LocalMachine.OpenSubKey
(@"software\microsoft\PCHealth\ErrorReporting\",true);- intdoReport=(int)key.GetValue("DoReport");
- if(doReport!=0)
- {
- key.SetValue("DoReport",0);
- }
- intshowUI=(int)key.GetValue("ShowUI");
- if(showUI!=0)
- {
- key.SetValue("ShowUI",0);
- }
- }
- catch
- {
- }
- m_Error="";
- m_Output="";
- try
- {
- System.Diagnostics.Processp=newSystem.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();
- ReadErrorThreadreadErrorThread=newReadErrorThread(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(Exceptione)
- {
- m_Error=e.Message;
- }
- }
- }
- }
【編輯推薦】