Skip to content

Instantly share code, notes, and snippets.

@uzbekdev1
Forked from mxpv/ProcessUtil.cs
Created June 5, 2018 20:14
Show Gist options
  • Save uzbekdev1/6f296a1edfb7809f604020fe9abbdab1 to your computer and use it in GitHub Desktop.
Save uzbekdev1/6f296a1edfb7809f604020fe9abbdab1 to your computer and use it in GitHub Desktop.
Process start helper utility with CancellationToken and async output reading support
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using Microsoft.Win32.SafeHandles;
namespace ConsoleApplication
{
public class ProcessUtil : IDisposable
{
private readonly Process _process = new Process();
private readonly object _eventLock = new object();
public ProcessUtil(string path, string args = null)
{
ProcessStartInfo startInfo = _process.StartInfo;
startInfo.FileName = path;
if (args != null)
{
startInfo.Arguments = args;
}
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.CreateNoWindow = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
_process.OutputDataReceived += OnOutputDataReceived;
_process.ErrorDataReceived += OnErrorDataReceived;
}
~ProcessUtil()
{
Dispose(false);
}
public event EventHandler<DataReceivedEventArgs> OutputDataReceived = delegate { };
public event EventHandler<DataReceivedEventArgs> ErrorDataReceived = delegate { };
public int ExitCode
{
get { return _process.ExitCode; }
}
public ProcessStartInfo StartInfo
{
get { return _process.StartInfo; }
}
public void Start()
{
try
{
_process.Start();
_process.BeginErrorReadLine();
_process.BeginOutputReadLine();
}
catch (Win32Exception exception)
{
throw new InvalidOperationException(exception.Message, exception);
}
}
public void Kill()
{
_process.Kill();
}
public void Wait()
{
_process.WaitForExit();
}
public void Wait(CancellationToken token)
{
using (var waitHandle = new SafeWaitHandle(_process.Handle, false))
{
using (var processFinishedEvent = new ManualResetEvent(false))
{
processFinishedEvent.SafeWaitHandle = waitHandle;
int index = WaitHandle.WaitAny(new[] { processFinishedEvent, token.WaitHandle });
if (index == 1)
{
Kill();
throw new OperationCanceledException();
}
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
_process.Dispose();
}
}
private void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
{
lock (_eventLock)
{
ErrorDataReceived(sender, e);
}
}
private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
lock (_eventLock)
{
OutputDataReceived(sender, e);
}
}
}
}
using System;
namespace ConsoleApplication
{
class Program
{
static void Main()
{
var proc = new ProcessUtil(@"c:\Windows\Microsoft.NET\Framework64\v2.0.50727\CasPol.exe", @"-u -lg");
proc.Start();
proc.OutputDataReceived += (e, args) => Console.WriteLine("STDOUT: {0}", args.Data);
proc.ErrorDataReceived += (e, args) => Console.WriteLine("STDERR: {0}", args.Data);
proc.Wait();
Console.WriteLine("Exit code: {0}", proc.ExitCode);
Console.ReadKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment