I have a command line executable that is run from a C# class library. In some very rare situations the executable will hang because of the command line data passed to it. Unfortunetely this causes the application calling the c# DLL to hang whilst it waits indefinitely for the process to exit.
If the command line exe doesnt finish execution within 1 second its never going to exit. What I'd like to do is spawn a timer just after the process has started and force close the process if it hasnt exited within a few seconds.
What is the best approach here? The solution needs to have minimal impact upon performance because this command line process is the bottleneck in a highly repetitive task.
Edit: Any reason why I should use System.Timer rather than Threading.Timer or vice versa?
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = workingDirectory;
startInfo.FileName = commandLineExe;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = strArguments;
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
Please refrain from suggestions that I should try and figure out why the command line app is hanging, or that I should refactor the command line functionality into the source code. We are actively working on that problem but stability of the application needs to come first.
Just add:
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo)) {
if(!exeProcess.WaitForExit(1000))
exeProcess.Kill();
}
Related
I have developed a program which runs as a Windows service. This program starts a process to run another exe file. It's developed in C# with .NET 6.0.
I know I can use
Process.Kill()
to terminate the process, but I'd like to try to end the process cleanly before killing it. I've read through several other threads, but haven't found a solution that works. The exe file that is run as a process does not have a GUI, so CloseMainWindow doesn't work. Here is the code where I start the process. When a CancellationToken arrives, the loop exits and the service tries to end the exe process. exePath is the full path to the exe file.
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.FileName = exePath.Trim();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
bool exited = false;
while (!stoppingToken.IsCancellationRequested && !exited)
{
exited = exeProcess.WaitForExit(1000);
}
if (!exited)
{
exeProcess.CloseMainWindow(); // THIS DOES NOT WORK!!!!
exited = exeProcess.WaitForExit(5000);
}
if (!exited)
{
exeProcess.Kill();
exited = exeProcess.WaitForExit(5000);
}
}
Any suggestions or pointers to other threads would be greatly appreciated. Thank you!
I am trying to automate HandbrakeCLI using C# via the System.Diagnostics.Process class. However, as long as my program is trying to run the process, it seems like the process never advances.
Here is my process setup:
Process process = new System.Diagnostics.Process();
ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.FileName = parameters.HandbrakeLocation;
startInfo.Arguments = arguments;
process.StartInfo = startInfo;
process.Start();
string output = string.Empty;
while ((output = process.StandardOutput.ReadLine()) != null)
{
Debug.WriteLine(output);
}
process.WaitForExit();
HandbrakeCLI.exe does appear in my processes list. The Debug.WriteLine(output); line continually prints out "Encoding: task 1 of 1, 0.00 %" and the process never completes. If I kill my C# app then HandbrakeCLI instantly shoots up from 7,000k in memory to 145,000k and then does the encoding that I want it to do. Its like my C# app is holding it back.
I have tried to use Read() instead of ReadLine() and I have tried flushing the StandardOutput stream before and after the read with no success. I have a suspicion that since HandbrakeCLI overwrites stdout when it writes the encoding progress, that it won't act like a normal process when automated via C#.
I figured it out. I was redirecting stderr to my C# application, but not consuming it. The process was hanging until stderr was consumed.
I am having a Java batch process which I used in C# to run process. I want to have a testcase to check whether the batch process is running or not.
I used the batch process as:
void batch_process(string process)
{
try
{
string strFilePath = Path.Combine(batch_process_path, process);
ProcessStartInfo psi = new ProcessStartInfo(strFilePath);
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WorkingDirectory = batch_process_path;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.ErrorDialog = true;
}
}
How can this test be done?
I want to write an unit test case to check whether the process will start or not.
when you Start your new process you need to capture the returned Process, that provides access to newly started process, useful for starting, stopping, controlling, and monitoring applications.
Process exe = Process.Start(psi);
....
if exe.HasExited() ....
You could start the process using
Process process = new Process();
string strFilePath = Path.Combine(batch_process_path, process);
process.StartInfo.FileName = strFilePath;
//this line will hold this thread until the process is done.
process.WaitForExit();
then start the process on a different thread and let that thread fire an event after process.WaitForExit(); is done.
You should first start the process using the ProcessStartInfo you've just created like:
Process process = Process.Start(psi);
then you can use process.HasExited to check if the process has exited. Often, you don't need to do this, as process.WaitForExit() blocks the code until process exits.
I'm a bit unsure of the scenario from your question... but 4 techniques you can use are:
if you have started the process using var process = Process.Start(psi); then:
you can periodically check process.HasExited - http://msdn.microsoft.com/en-us/library/system.diagnostics.process.hasexited.aspx
or you can subscribe to Process.Exited - http://msdn.microsoft.com/en-us/library/system.diagnostics.process.exited.aspx
or you can block on Process.WaitForExit - http://msdn.microsoft.com/en-us/library/system.diagnostics.process.waitforexit.aspx
if your process is started in some other way and has some unique name, then you can inspect the enumeration returned by System.Diagnostics.Process.GetProcesses() to determine if your batch process is currently running.
In general... I'd prefer to use Process.Exited, but the other methods all have their place too!
I want to start a new process B.exe from the current executing process A.exe.
And as soon as B.exe is launched I want to kill A.exe (the current executing process).
Though I can start B.exe I cannot close my current process i.e A.exe.
Code I use is:
//Start the BT Setup Process
ProcessStartInfo startInfo = new ProcessStartInfo(#"C:\TEST\B.exe");
Process.Start(startInfo);
//Terminate the FSA
Process[] myProcess = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
foreach (Process process in myProcess)
{
process.CloseMainWindow();
//all the windows messages has to be processed in the msg queue
//hence call to Application DoEvents forces the MSG
Application.DoEvents();
}
Why do you want to close A from B while A cat start B and then close by itself?
Process.Start("A.exe");
Process.GetCurrentProcess().Kill(); // or Application.Exit(); or anything else
If you're falling into this quest of starting a process, and kill your own process after, use Environment.Exit(0), not Application.Exit().
Try Process.Kill() instead of Process.CloseMainWindow().
I know this is old but in .net 4.0 you can do
ProcessStartInfo startInfo = new ProcessStartInfo(#"C:\TEST\B.exe");
startInfo.UseShellExecute = true;//This should not block your program
Process.Start(startInfo);
Then Application.Exit or whatever
I tested with a winforms application using the close form method after launching a console app that just blocks on Console.readline();
If you just want to close the current process you should be able to just call Application.Exit rather than looping through and closing processes.
I want to use shell executable in order to respect user preferences of application to be started, but I also need to know when that particular application is closed.
Process editProcess = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = filename;
startInfo.Verb = "edit";
startInfo.UseShellExecute = true;
editProcess.StartInfo = startInfo;
// start the default editor
editProcess.Start();
editProcess.WaitForExit();
WaitForExit seems to return when the shell process exits and not when the real process exits.
Is there a better way of knowing when started application is exited than manually parsing registry, finding correct application to start and explicitly start that app without shell execute?
Handle the process exited event:
editProcess.Exited += process_Exited;