C # I can find a lot of classes that call external processes on the Internet. Why do I need to write them again? It is because I recently copied a simple routine from the Internet and used it in the project, after studying for a long time, I solved these problems. So I plan to write such a blog post to explain what problems will C # encounter when calling an external process that is so simple, I also hope that the relatively complete Class I have written can save some brain cells for the software developers so that they can concentrate their strength to solve the truly advanced and complex software problems.
Before getting started, let's take a look at the common functions that execute external processes on the Internet.
- PrivatestringRunCmd (stringcommand)
- {
- // Process example
- Processp=NewProcess();
-
- P. StartInfo. FileName="Cmd.exe"; // Determine the program name
- P. StartInfo. Arguments="/C"+ Command; // determine the program command line
- P. StartInfo. UseShellExecute=False; // Use of Shell
- P. StartInfo. RedirectStandardInput=True; // Redirect Input
- P. StartInfo. RedirectStandardOutput=True; // Redirect output
- P. StartInfo. RedirectStandardError=True; // Redirect Output Error
- P. StartInfo. CreateNoWindow=True; // Set to not display the window
-
- P. Start (); // 00
-
- // P. StandardInput. WriteLine (command); // you can enter the command to be executed in this way.
- // P. StandardInput. WriteLine ("exit"); // you must add Exit or the next program line.
-
- Returnp. StandardOutput. ReadToEnd (); // output the stream to obtain the command line result
-
- }
This method should be a common method for calling external processes in C #. I have been calling external processes in this way and have never encountered any problems. However, the external process called this time is special, and two problems occur when this method is used.
The first problem is that the called external process sometimes suffers an exception. When an exception occurs, an error report box will pop up in Windows. The program then hangs there and must be manually intervened. This problem is better solved. Set the registry in the program.
The second problem is that C # calling an external process is a console process), the program will be blocked in p. standardOutput. the ReadToEnd (); statement can never come out, and the called console program is also suspended. However, the console process can be executed normally in CMD. Later, it seems that some materials found that the original cause was that a large number of strings were output in the console of the console. After the pipeline was redirected, the calling program did not promptly retrieve the output data in the pipeline, leading to blocking of the pipeline, the program is suspended. There is another problem here. Although we haven't met this time, there are other people on the Internet, that is, the error message pipeline will be blocked if the data is not retrieved in time, in addition, if you want to extract data from two pipelines at the same time, you must use an auxiliary thread.
The question is over. The complete code for this class is provided below.
- 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;
- }
- }
-
- }
- }
- Analysis of C # Insecure code
- Analysis on C # Calling ImageAnimator
- C # connect to Access and SQL Server databases
- C # fixed and active Variables
- Describes the value types in C #.