C# Stop process started by my own process - c#

I made a launcher for my ARK Server where I can easily change my settings and start.
I start the server with this:
Process serverprocess = new Process();
serverprocess.StartInfo.FileName = Path.GetFileName(serverpath);
serverprocess.StartInfo.Arguments = launch;
serverprocess.StartInfo.UseShellExecute = false;
serverprocess.Start();
serverprocess.WaitForExit();
But when I press CTRL+C it doesn't wait until the ARK Server stops, it still runs in background while my app is killed.
I did some testing, the server recieves the shutdown signal and stops (which takes some time, espeically when the server isn't fully started). But when it takes time to stop the server is still running while my app already closed.
Doublepressing CTRL+C will kill the server but since the first press already brings me out of the console I'm unable to doublepress.
Any idea how I can prevent my app from beeing closed while still stopping the ARK server?
Adding Console.TreatControlCAsInput = true; will stop the server from even recieving the signal.
Thank you!

My test is ok
Process proc = new Process();
proc.StartInfo.FileName = "/bin/bash";//sh
proc.StartInfo.Arguments = "-c \" " + command + " && echo 'OK'\"";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();

You should properly close your program for it to close properly your server. Here you go:
var serverProcess = Process.Start(new ProcessStartInfo
{
FileName = Path.GetFileName(serverpath),
Arguments = launch,
UseShellExecute = false
});
while (Console.ReadLine() != "exit")
{
Thread.Sleep(500);
}
serverProcess.Close();

Related

Why does Kaspersky anti-virus prevent my program from capturing the output of its child process?

I have a C# program that launches a child process and captures its output in a string. This works on most Windows machines (Windows 7 and newer), but when Kaspersky anti-virus is present, Process.StandardOutput.ReadToEnd() returns null. There is no error code or exception. The child process is a trusted console application. The process takes 5 or 6 seconds to run.
The code for launching the child process is as follows:
ProcessStartInfo psi = new ProcessStartInfo();
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.FileName = "icao.exe";
psi.Arguments = im_path + "image.jpg";
Process p = new Process();
p.StartInfo = psi;
p.Start();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
MessageBox.Show(error);
p.WaitForExit();
int exitCode = p.ExitCode;
MessageBox.Show(exitCode+"");
Why does output end up being null when Kaspersky is present?
My guess is that Kaspersky's heuristics are seeing that your program wants to execute another exe. Because nothing is telling Kaspersky that this is ok, it flags your program as possible malware, because it wants to interface with other programs that are developed by other companies. If you are able to I would try white listing your program with Kaspersky and see if that solves your issue.

kill process and get the output c#

Hi am creating a console application that executes another windows console application.
Sometimes the application never end its execution, an I need to force kill it, if exceeded a time. When the application is force killed I am unable to get the output of the application.
There is a way to get the output before killing the running process in order to write to a file or get it after killing it?
Process process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "robocopy.exe";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.Arguments = parameters;
process.Start();
//set the maximum allowed time in which the robocopy lives
if (process.WaitForExit(15000))
{
logInfo = process.StandardOutput.ReadToEnd();
//do something else
}
else
{
process.Kill();
logInfo = process.StandardOutput.ReadToEnd();
//write the output to a file
}

C#: Calling a php script and beeing able to stop it

I am currently working on a C# Program which needs to call a local PHP script and write its output to a file. The problem is, that I need to be able to stop the execution of the script.
First, I tried to call cmd.exe and let cmd write the output to the file which worked fine. But I found out, that killing the cmd process does not stop the php cli.
So I tried to call php directly, redirect its output and write it from the C# code to a file. But here the problem seems to be, that the php cli does not terminate when the script is done. process.WaitForExit() does not return, even when I am sure that the script has been fully executed.
I cannot set a timeout to the WaitForExit(), because depending on the arguments, the script may take 3 minutes or eg. 10 hours.
I do not want to kill just a random php cli, there may be others currently running.
What is the best way to call a local php script from C#, writing its output to a file and beeing able to stop the execution?
Here is my current code:
// Create the process
var process = new System.Diagnostics.Process();
process.EnableRaisingEvents = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "php.exe";
// CreateExportScriptArgument returns something like "file.php arg1 arg2 ..."
process.StartInfo.Arguments = CreateExportScriptArgument(code, this.content, this.options);
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
// Start the process or cancel, if the process should not run
if (!this.isRunning) { return; }
this.currentProcess = process;
process.Start();
// Get the output
var output = process.StandardOutput;
// Wait for the process to finish
process.WaitForExit();
this.currentProcess = null;
To kill the process I am using:
// Mark as not running to prevent starting new
this.isRunning = false;
// Kill the process
if (this.currentProcess != null)
{
this.currentProcess.Kill();
}
Thanks for reading!
EDIT
That the cli does not return seems to be not reproducible. When I test a different script (without arguments) it works, probably its the script or the passing of the arguments.
Running my script from cmd works just fine, so the script should not be the problem
EDIT 2
When disabling RedirectStandardOutput, the cli quits. could it be, that I need to read the output, before the process finishes? Or does the process wait, when some kind of buffer is full?
EDIT 3: Problem solved
Thanks to VolkerK, I / we found a solution. The problem was, that WaitForExit() did not get called, when the output is not read (probably due to a full buffer in the standard output). My script wrote much output.
What works for me:
process.Start();
// Get the output
var output = process.StandardOutput;
// Read the input and write to file, live to avoid reading / writing to much at once
using (var file = new StreamWriter("path\\file", false, new UTF8Encoding()))
{
// Read each line
while (!process.HasExited)
{
file.WriteLine(output.ReadLine());
}
// Read the rest
file.Write(output.ReadToEnd());
// flush to file
file.Flush();
}
Since the problem was that the output buffer was full and therefore the php process stalled while waiting to send its output, asynchronously reading the output in the c# program is the solution.
class Program {
protected static /* yeah, yeah, it's only an example */ StringBuilder output;
static void Main(string[] args)
{
// Create the process
var process = new System.Diagnostics.Process();
process.EnableRaisingEvents = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "php.exe";
process.StartInfo.Arguments = "-f path\\test.php mu b 0 0 pgsql://user:pass#x.x.x.x:5432/nominatim";
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
output = new StringBuilder();
process.OutputDataReceived += process_OutputDataReceived;
// Start the process
process.Start();
process.BeginOutputReadLine();
// Wait for the process to finish
process.WaitForExit();
Console.WriteLine("test");
// <-- do something with Program.output here -->
Console.ReadKey();
}
static void process_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data)) {
// edit: oops the new-line/carriage-return characters are not "in" e.Data.....
// this _might_ be a problem depending on the actual output.
output.Append(e.Data);
output.Append(Environment.NewLine);
}
}
}
see also: https://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline%28v=vs.110%29.aspx

Log Process execution

I am trying to restart a windows service from the same windows service with this piece of code
var proc = new Process();
var psi = new ProcessStartInfo();
psi.CreateNoWindow = true;
psi.FileName = "cmd.exe";
psi.Arguments = "/C net stop \"EmailService-3.1.0\ && net start \"EmailService-3.1.0\"";
psi.LoadUserProfile = false;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo = psi;
It is not working and I have no idea why, is there anything I can do to log or determine what is happening or get the output of what is happening when the net stop command is called?
You can redirect the output of the net stop command, but as per TomT's comment, this seems a very roundabout way to restart a service.
psi.Arguments = "/C net stop \"EmailService-3.1.0\" > C:\\svclog.txt "; //&& net start \"EmailService-3.1.0\"";
I can see a missing quotation mark after the name of your service in the stop command. Otherwise it can be a permission issue. Maybe the user with whom your service has logged in does not have enough privileges to stop a service.

restart windows service from the same windows service

I am trying to restart a windows service from the same windows service with this code:
var psi = new ProcessStartInfo("net.exe", "stop " + serviceName);
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = true;
psi.WorkingDirectory = Environment.SystemDirectory;
var st = Process.Start(psi);
st.WaitForExit();
psi = new ProcessStartInfo("net.exe", "start " + serviceName);
psi.UseShellExecute = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.WorkingDirectory = Environment.SystemDirectory;
st = Process.Start(psi);
st.WaitForExit();
It is not working but is this even possible from the same service?
If it is possible then can anyone suggest why this does not work?
I don't believe there's a clean way of doing this. Once you stop the service, the process is no longer there to start it.
One slightly dirty solution:
You could configure the service to restart on error (e.g. at installation/registration time).
Then when you want to restart programmatically have your service exit with an error e.g. by calling:
Environment.Exit(-1)
or
Environment.FailFast("Service stopped because...")
Note: If there is a cleaner way of doing this programmatically the account the service is running under would require permissions to be able to restart the service.
It doesn't work because once you reach the middle, execution stops in since both parent and child process exit:
/* Running */ var psi = new ProcessStartInfo("net.exe", "stop " + serviceName);
/* Running */ psi.WindowStyle = ProcessWindowStyle.Hidden;
/* Running */ psi.UseShellExecute = true;
/* Running */ psi.WorkingDirectory = Environment.SystemDirectory;
/* st stops svc */ var st = Process.Start(psi);
/* both exit */ st.WaitForExit();
/* never reached */ psi = new ProcessStartInfo("net.exe", "start " + serviceName);
/* never reached */ psi.UseShellExecute = true;
/* never reached */ psi.WindowStyle = ProcessWindowStyle.Hidden;
/* never reached */ psi.WorkingDirectory = Environment.SystemDirectory;
/* never reached */ st = Process.Start(psi);
/* never reached */ st.WaitForExit();
Configure the service in windows to restart itself on failure and then do an unclean exit as #StevieB suggested.
Configure the service to restart itself with a 1000 ms delay on failure:
sc failure serviceName reset= 60 actions= restart/1000
You have a deadlock. net is waiting for your service to end, and you are using st.WaitForExit() to wait for net to end.
Eventually net gives up waiting and closes. Then you call net again. But your service never exited in the first place, so the second net invocation sees the service is already started and does nothing.
Finally you return the the main service event loop and see the stop request, and your service exits.
You should be able to write a batch file with the above commands, invoke it, and return to the event loop. Then the first net will wait until the service stops, and the second net will start it again.

Categories

Resources