Overview:
Relevant class attributes
To manage the execution of an external process the following class data are used:
private System.Diagnostics.Process m_process = null;
private bool m_processStarted = false;
private EnvDTE.OutputWindowPane m_outputPane = null;
bool m_catchStdOutAndStdErr = true;
bool m_getNotificationWhenProcessTerminates = true;
private bool m_checkForMemoryLeaks = false;
Starting a process
public void StartProcess(string exePath, string args, string workDir)
{
try
{
string argsToUse = "";
if (args != null)
{
argsToUse = args;
}
ThreadHelper.ThrowIfNotOnUIThread();
if (!System.IO.File.Exists(exePath))
{
m_mainEvents.OnTestTerminated(false, exePath, false, new TimeSpan(0));
WriteLine(1, "Executable not found: " + exePath);
return;
}
if (m_outputPane == null)
{
EnvDTE.OutputWindow ow = MyGlobals.myDTE.ToolWindows.OutputWindow;
m_outputPane = ow.OutputWindowPanes.Add("Run UnitTest");
}
m_outputPane.Activate();
m_outputPane.Clear();
m_process = new System.Diagnostics.Process();
m_process.StartInfo.FileName = exePath;
m_process.StartInfo.WorkingDirectory = workDir;
m_process.StartInfo.Arguments = argsToUse.Trim();
if (m_getNotificationWhenProcessTerminates)
{
m_process.Exited += new System.EventHandler(Process_Exited);
m_process.EnableRaisingEvents = true;
}
if (m_catchStdOutAndStdErr)
{
m_process.StartInfo.UseShellExecute = false;
m_process.StartInfo.RedirectStandardOutput = true;
m_process.StartInfo.RedirectStandardError = true;
m_process.StartInfo.CreateNoWindow = true;
m_process.OutputDataReceived += new System.Diagnostics.
DataReceivedEventHandler(StandardOutputReceiver);
m_process.ErrorDataReceived += new System.Diagnostics.
DataReceivedEventHandler(StandardErrorReceiver);
}
m_process.Start();
m_processStarted = true;
if (m_catchStdOutAndStdErr)
{
m_process.BeginOutputReadLine();
m_process.BeginErrorReadLine();
}
WriteLine(2, "Started " + m_process.StartInfo.FileName);
}
catch (Exception e)
{
string info = "EXCEPTION: Could not start executable " + exePath + " " + e.ToString();
WriteLine(1, info);
m_mainEvents.OnTestTerminated(false, exePath, false, new TimeSpan(0));
}
}
Redirection of process output
The methods StandardOutputReceiver and StandardErrorReceiver will receive any output from the started process. On each call they will pass the given data to the output pane of Visual Studio:
private void StandardOutputReceiver(object sendingProcess,
System.Diagnostics.DataReceivedEventArgs outLine)
{
if (Services.GetOptions().LimitCpuForStdOut)
{
System.Threading.Thread.Yield();
}
if (!string.IsNullOrEmpty(outLine.Data))
{
Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.Run(async delegate
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
if (m_outputPane != null)
m_outputPane.OutputString(outLine.Data + System.Environment.NewLine);
});
}
}
Kill a running process
A running process can be stopped at any time by simply calling:
Even with killing the process the callback function Executor.Process_Exited will be called.