描述C#調(diào)用外部進(jìn)程
C#調(diào)用外部進(jìn)程的類(lèi),網(wǎng)上可以搜出很多來(lái),為什么要再寫(xiě)一遍,實(shí)在是因?yàn)樽罱鼜木W(wǎng)上拷貝了一個(gè)簡(jiǎn)單的例程用到項(xiàng)目中,運(yùn)行有問(wèn)題,后來(lái)研究了半天,才解決了這些問(wèn)題。于是打算寫(xiě)這么一篇博文,一來(lái)說(shuō)說(shuō)C#調(diào)用外部進(jìn)程這么簡(jiǎn)單的一件事究竟會(huì)有哪些問(wèn)題,二來(lái)也希望我寫(xiě)的這個(gè)相對(duì)比較完整的類(lèi)可以為軟件開(kāi)發(fā)的同道們節(jié)約一些腦細(xì)胞,以便集中優(yōu)勢(shì)兵力解決那些真正高深復(fù)雜的軟件問(wèn)題。
在開(kāi)始正題之前,我們先來(lái)看一看網(wǎng)上比較常見(jiàn)的執(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;//重定向輸出錯(cuò)誤
- p.StartInfo.CreateNoWindow=true;//設(shè)置置不顯示示窗口
- p.Start();//00
- //p.StandardInput.WriteLine(command);//也可以用這種方式輸入入要行的命令
- //p.StandardInput.WriteLine("exit");//要得加上Exit要不然下一行程式
- returnp.StandardOutput.ReadToEnd();//輸出出流取得命令行結(jié)果果
- }
這個(gè)方法應(yīng)該是比較常見(jiàn)的C#調(diào)用外部進(jìn)程的方法,我以前也一直是這樣調(diào)用外部進(jìn)程的,也沒(méi)有碰到過(guò)什么問(wèn)題。但這次調(diào)用的外部進(jìn)程比較特殊,用這種方法調(diào)用就出現(xiàn)了兩個(gè)問(wèn)題。
***個(gè)問(wèn)題是這個(gè)被調(diào)用的外部進(jìn)程有時(shí)候會(huì)出現(xiàn)異常,出現(xiàn)異常后Windows會(huì)彈出錯(cuò)誤報(bào)告框,程序于是吊死在那里,必須手工干預(yù)。這個(gè)問(wèn)題比較好解決,程序中設(shè)置一下注冊(cè)表搞定。
第二個(gè)問(wèn)題是C#調(diào)用外部進(jìn)程(是一個(gè)控制臺(tái)進(jìn)程)后,程序會(huì)阻塞在p.StandardOutput.ReadToEnd();這一句,永遠(yuǎn)無(wú)法出來(lái),被調(diào)用的那個(gè)控制臺(tái)程序也被吊死。但該控制臺(tái)進(jìn)程在CMD 中是可以正常執(zhí)行的。后來(lái)看來(lái)一些資料才發(fā)現(xiàn)原來(lái)原因是出在該控制臺(tái)程序控制臺(tái)輸出大量字符串,管道重定向后,調(diào)用程序沒(méi)有及時(shí)將管道中的輸出數(shù)據(jù)取出,結(jié)果導(dǎo)致管道被阻塞,程序吊死。在這里還有另外一個(gè)問(wèn)題,雖然這次沒(méi)有遇到,但網(wǎng)上有其他人遇到,就是錯(cuò)誤信息管道不及時(shí)取出數(shù)據(jù),也會(huì)被阻塞,而且如果要同時(shí)取出兩個(gè)管道的數(shù)據(jù),必須要利用一個(gè)輔助線程才能實(shí)現(xiàn)。
問(wèn)題講完了,下面給出這個(gè)類(lèi)的完整代碼
- 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;
- }
- }
- }
- }
【編輯推薦】