I have the following code:
info = new System.Diagnostics.ProcessStartInfo(\"TheProgram.exe\", String.Join(\" \", args));
info.CreateNoWindow = true;
info.Win
Currently accepted answer doesn't work (throws exception) and there are too many workarounds but no complete code. This is obviously wasting lots of people's time because this is a popular question.
Combining Mark Byers' answer and Karol Tyl's answer I wrote full code based on how I want to use the Process.Start method.
I have used it to create progress dialog around git commands. This is how I've used it:
private bool Run(string fullCommand)
{
Error = "";
int timeout = 5000;
var result = ProcessNoBS.Start(
filename: @"C:\Program Files\Git\cmd\git.exe",
arguments: fullCommand,
timeoutInMs: timeout,
workingDir: @"C:\test");
if (result.hasTimedOut)
{
Error = String.Format("Timeout ({0} sec)", timeout/1000);
return false;
}
if (result.ExitCode != 0)
{
Error = (String.IsNullOrWhiteSpace(result.stderr))
? result.stdout : result.stderr;
return false;
}
return true;
}
In theory you can also combine stdout and stderr, but I haven't tested that.
public struct ProcessResult
{
public string stdout;
public string stderr;
public bool hasTimedOut;
private int? exitCode;
public ProcessResult(bool hasTimedOut = true)
{
this.hasTimedOut = hasTimedOut;
stdout = null;
stderr = null;
exitCode = null;
}
public int ExitCode
{
get
{
if (hasTimedOut)
throw new InvalidOperationException(
"There was no exit code - process has timed out.");
return (int)exitCode;
}
set
{
exitCode = value;
}
}
}
public class ProcessNoBS
{
public static ProcessResult Start(string filename, string arguments,
string workingDir = null, int timeoutInMs = 5000,
bool combineStdoutAndStderr = false)
{
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
using (var process = new Process())
{
var info = new ProcessStartInfo();
info.CreateNoWindow = true;
info.FileName = filename;
info.Arguments = arguments;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
if (workingDir != null)
info.WorkingDirectory = workingDir;
process.StartInfo = info;
StringBuilder stdout = new StringBuilder();
StringBuilder stderr = combineStdoutAndStderr
? stdout : new StringBuilder();
var result = new ProcessResult();
try
{
process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
outputWaitHandle.Set();
else
stdout.AppendLine(e.Data);
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
errorWaitHandle.Set();
else
stderr.AppendLine(e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (process.WaitForExit(timeoutInMs))
result.ExitCode = process.ExitCode;
// else process has timed out
// but that's already default ProcessResult
result.stdout = stdout.ToString();
if (combineStdoutAndStderr)
result.stderr = null;
else
result.stderr = stderr.ToString();
return result;
}
finally
{
outputWaitHandle.WaitOne(timeoutInMs);
errorWaitHandle.WaitOne(timeoutInMs);
}
}
}
}
}