Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

Process Executor

Rate me:
Please Sign up or sign in to vote.
4.96/5 (10 votes)
14 May 2016MIT2 min read 16.6K   24   5
Process executor

Description

ProcessExecutor is a wrapper class for System.Diagnostic.Process which is created with the intention to manage external process within .NET application without showing up the console window and to capture all the console output logs at the same time.

Class Diagram

Image 1

Process Executor - Class Diagram

Features

  • Execute external applications
  • Configurable working directory
  • Accept process arguments
  • Abort created process and its child processes
  • Thread safe, support multi-threaded execution
  • Show / hide console window during process execution
  • Enable / disable console output to System.Diagnostics.Trace
  • Execute process as different user
  • Capture standard output and standard error from console application
  • Capture output to log file
  • Subclass as tool-specific executor
  • Option to wait for process complete
  • Notification when process completed

Usage Guide

  • Assign Application, Arguments and WorkingDirectory.
  • Call Execute() to start.
    • Process Executor will start process by calling Process.Start internally.
    • Process Executor will subscribe to OutputDataReceived and ErrorDataReceived events from ProcessHandler to capture all console output.
    • For each captured output and error messages:
      • If Output file is defined, write message to output file.
      • If option TraceLogEnabled is set, write message to System.Diagnostics.Trace.
    • Wait for process to complete if waitForExit flag is set, else return immediately.
    • At the end of execution, return error code and console output messages as ProcessResult object.
  • To terminate an executing process, call Abort() to stop process and all child processes. See section Abort for more details.

Capture Output Data

The two functions below shows how output from console window is captured in Trace and output log.
When used together Diagnostics TextBox with option ShowConsoleWindow disabled and TraceLogEnabled enabled, you will have all the console output from the triggered process redirect to your application. This is even better when the ProcessExecutor is started in the worker thread.

C#
        private void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
         {
             if (e.Data != null)
             {
                 errorDetected = true;
                 if (RedirectToFile) System.IO.File.AppendAllText(LogFile, e.Data + "\r\n");
                 else outputData.Add(e.Data);
                 if (TraceLogEnabled) Trace.WriteLine(Name + ": " + e.Data);
             }
         }
         private void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
         {
             if (e.Data != null)
             {
                 if (RedirectToFile) System.IO.File.AppendAllText(LogFile, e.Data + "\r\n");
                 else outputData.Add(e.Data);
                 if (TraceLogEnabled) Trace.WriteLine(Name + ": " + e.Data);
             }
        }

Abort

The Abort function in ProcessExecutor is useful to terminate the spawned process either when error is detected or decided to terminate by user. The Abort function will terminate the process and all its child process. This is handy to terminate all the spawned process when application in terminated.

The terminate function was not part of System.Diagnostics.Process. We make use of ManagementObjectSearcher to search for object with given object ID obtained from ProcessHandler when process started. All child process created by its parents will also be terminated. This is useful when you want to terminate a batch file and all the processes spawned from the batch file.

C#
        private static void KillProcessAndChildren(int pid)
        {
            ManagementObjectSearcher searcher = new 
                ManagementObjectSearcher(
                   "Select * From Win32_Process Where ParentProcessID=" + pid);

            ManagementObjectCollection moc = searcher.Get();
            foreach (ManagementObject mo in moc)
            {
                KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
            }
            try
            {
                Process proc = Process.GetProcessById(pid);
                proc.Kill();
            }
            catch (ArgumentException)
            {
                // Process already exited.
            }
        }

Subclass

ProcessExecutor can be used as base class for dedicated tool such as Windows Installer (msiexec.exe) and Visual Studio (devenv.com) which provide more than just process execution.

Example: WindowsInstallerClient with Install and Uninstall function.

C#
        /// <summary>
	    /// Windows Installer Client (msiexec.exe).
	    /// Uninstallation require the original MSI package.
	    /// </summary>
	    public class WindowsInstallerClient : ProcessExecutor
	    {
	        private string LogFile = "_msiexec.log";
	 
	        /// <summary>
	        /// Constructor
	        /// </summary>
	        public WindowsInstallerClient()
	        {
	            Name = "Windows Installer (msiexec.exe)";
	            Application = "C:\\Windows\\System32\\msiexec.exe";
	        }
	 
	        public void Install(string msiPackage)
	        {
	            Arguments = "/passive /I " + msiPackage + " /lei " + LogFile;
	            ProcessResult result = Execute();
	            Trace.WriteLine(System.IO.File.ReadAllText(LogFile));
	            Trace.WriteLine(Name + "Install completed. Result = " + 
	                            result.ExitCode.ToString());
	            if (result.ExitCode != 0) 
	                throw new Exception("Install failed, exit with error code " + 
	                                    result.ExitCode.ToString());
	        }
	 
	        public void Uninstall(string msiPackage)
	        {
	            Arguments = "/passive /uninstall " + msiPackage + " /lei " + LogFile;
	            ProcessResult result = Execute();
	            Trace.WriteLine(System.IO.File.ReadAllText(LogFile));
	            Trace.WriteLine(Name + "Uninstall completed. Result = " + 
	                            result.ExitCode.ToString());
	            if (result.ExitCode != 0throw new Exception("Uninstall failed, exit with error code " + 
	                                    result.ExitCode.ToString());
	        }
    }
This article was originally posted at http://codearteng.blogspot.com/feeds/posts/default

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Technical Lead
Malaysia Malaysia
Official Page: www.codearteng.com

Comments and Discussions

 
QuestionMultiThread... Pin
SergeyAB16-May-16 10:31
SergeyAB16-May-16 10:31 
AnswerRe: MultiThread... Pin
Code Artist17-May-16 17:31
professionalCode Artist17-May-16 17:31 
GeneralRe: MultiThread... Pin
SergeyAB6-Jun-16 8:54
SergeyAB6-Jun-16 8:54 
GeneralRe: MultiThread... Pin
Code Artist13-Jun-16 4:20
professionalCode Artist13-Jun-16 4:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.