ServiceController - Can't stop the service [C#] - c#

I read many posts here with a similar question, but none helped me solve my problem.
I want to stop the service with the ServiceController object. But it fails and I get an exception: System.ComponentModel.Win32Exception (0x80004005). I don't understand why.. I run the program with "Run as administrator".
ServiceController ctrl = ServiceController.GetServices().Where(s => s.ServiceName == "service_name").SingleOrDefault();
if (ctrl == null) return;
if (ctrl.Status.Equals(ServiceControllerStatus.Running))
{
try
{
ctrl.Stop();
}
catch(Exception ex)
{
Log(ex.ToString(), 3);
}
}
If I call the net stop command from the code, then everything works. Why?
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
cmd.StandardInput.WriteLine("net stop service_name");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();

After our continued chat discussion ServiceController following was discovered :
ServiceController was able to Start the service, but not Stop
From the System Logs it was evident that ServiceController crashes when trying to stop
ServiceControllers Start & Stop works fine with other services such as PrintSpooler
Using CMD or Process.Start we can stop service by sc stop "servicename"
Finally the problem was with the Service itself and the way it was constructed

Related

Communicate with process in C#

I need to communicate with external executable (ampl.exe) using standard input and standard output. This exe make calculations during some minutes with some display in the console. It has a prompt so I can succesively launch calculations by using its standard input as soon as a calculation is finished.
The external exe is launched as :
var myProcess = new Process();
myProcess.StartInfo = new ProcessStartInfo("ampl.exe");
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.Start();
I communicate with it by using myProcess.StandardInput and myProcess.StandardOutput (synchronous way).
I use standard input to launch the calcul, for example :
myProcess.StandardInput.WriteLine("solve;");
I want to wait the end of the solve statement, get results in files, prepare new calculation input files and then launching a second solve.
My problem is that I do now know when the first calculation is finished, that is when the exe is waiting for new command in its standard input.
The only way I found is to add a specific display command and wait for getting it it its standard output :
myProcess.StandardInput.WriteLine("solve;");
myProcess.StandardInput.WriteLine("print 'calculDone';");
string output = myProcess.StandardOutput.ReadLine();
while (!output.Contains("calculDone"))
{
output = myProcess.StandardOutput.ReadLine();
}
Is there another way avoiding to use this display command to do this ?
Edit : following advices, I tried the asynchronous way. But I still need to print 'CalculDone' to know when the solve statement ended. I do not get the prompt of ampl.exe (which is 'ampl : ') in the standard output of the process.
AutoResetEvent eventEnd = new AutoResetEvent(false);
var myProcess = new Process();
myProcess.StartInfo = new ProcessStartInfo("ampl.exe");
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.EnableRaisingEvents = true;
myProcess.OutputDataReceived += (sender, e) =>
{
if (e.Data == "commandDone")
{
eventEnd.Set();
}
else if (e.Data != null)
{
Console.WriteLine("ampl: {0}", e.Data);
}
};
myProcess.Start();
myProcess.BeginOutputReadLine();
myProcess.StandardInput.WriteLine("solve;");
myProcess.StandardInput.WriteLine("print 'commandDone';");
eventEnd.WaitOne();
The best option would be to use the Processs.OutputDataReceived event instead of a tight while loop. It’s like the event async pattern, you launch an asynchronous task and wait for an event callback telling you it’s done. The continuation of the asynchronous task would go in the event handler. Remember to unsubscribe the event handler the first time it goes off, otherwise it will be firing when you don’t want it to.
Another option I have never tried is Process.WaitForInputIdle() method, but I’m not sure if this will work in your particular case. If it does you wouldn’t need to write anything to the input stream.

Restart an application by itself

I want to build my application with the function to restart itself. I found on codeproject
ProcessStartInfo Info=new ProcessStartInfo();
Info.Arguments="/C choice /C Y /N /D Y /T 3 & Del "+
Application.ExecutablePath;
Info.WindowStyle=ProcessWindowStyle.Hidden;
Info.CreateNoWindow=true;
Info.FileName="cmd.exe";
Process.Start(Info);
Application.Exit();
This does not work at all...
And the other problem is, how to start it again like this?
Maybe there are also arguments to start applications.
Edit:
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=31454&av=58703
I use similar code to the code you tried when restarting apps. I send a timed cmd command to restart the app for me like this:
ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C ping 127.0.0.1 -n 2 && \"" + Application.ExecutablePath + "\"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
Application.Exit();
The command is sent to the OS, the ping pauses the script for 2-3 seconds, by which time the application has exited from Application.Exit(), then the next command after the ping starts it again.
Note: The \" puts quotes around the path, incase it has spaces, which cmd can't process without quotes.
Hope this helps!
Why not use
Application.Restart();
??
More on Restart
Why not just the following?
Process.Start(Application.ExecutablePath);
Application.Exit();
If you want to be sure the app does not run twice either use Environment.Exit(-1) which kills the process instantaneously (not really the nice way) or something like starting a second app, which checks for the process of the main app and starts it again as soon as the process is gone.
You have the initial application A, you want to restart.
So, When you want to kill A, a little application B is started, B kill A, then B start A, and kill B.
To start a process:
Process.Start("A.exe");
To kill a process, is something like this
Process[] procs = Process.GetProcessesByName("B");
foreach (Process proc in procs)
proc.Kill();
A lot of people are suggesting to use Application.Restart. In reality, this function rarely performs as expected. I have never had it shut down the application I am calling it from. I have always had to close the application through other methods such as closing the main form.
You have two ways of handling this. You either have an external program that closes the calling process and starts a new one,
or,
you have the start of your new software kill other instances of same application if an argument is passed as restart.
private void Application_Startup(object sender, StartupEventArgs e)
{
try
{
if (e.Args.Length > 0)
{
foreach (string arg in e.Args)
{
if (arg == "-restart")
{
// WaitForConnection.exe
foreach (Process p in Process.GetProcesses())
{
// In case we get Access Denied
try
{
if (p.MainModule.FileName.ToLower().EndsWith("yourapp.exe"))
{
p.Kill();
p.WaitForExit();
break;
}
}
catch
{ }
}
}
}
}
}
catch
{
}
}
Winforms has the Application.Restart() method, which does just that. If you're using WPF, you can simply add a reference to System.Windows.Forms and call it.
Another way of doing this which feels a little cleaner than these solutions is to run a batch file which includes a specific delay to wait for the current application to terminate. This has the added benefit of preventing the two application instances from being open at the same time.
Example windows batch file ("restart.bat"):
sleep 5
start "" "C:\Dev\MyApplication.exe"
In the application, add this code:
// Launch the restart batch file
Process.Start(#"C:\Dev\restart.bat");
// Close the current application (for WPF case)
Application.Current.MainWindow.Close();
// Close the current application (for WinForms case)
Application.Exit();
My solution:
private static bool _exiting;
private static readonly object SynchObj = new object();
public static void ApplicationRestart(params string[] commandLine)
{
lock (SynchObj)
{
if (Assembly.GetEntryAssembly() == null)
{
throw new NotSupportedException("RestartNotSupported");
}
if (_exiting)
{
return;
}
_exiting = true;
if (Environment.OSVersion.Version.Major < 6)
{
return;
}
bool cancelExit = true;
try
{
List<Form> openForms = Application.OpenForms.OfType<Form>().ToList();
for (int i = openForms.Count - 1; i >= 0; i--)
{
Form f = openForms[i];
if (f.InvokeRequired)
{
f.Invoke(new MethodInvoker(() =>
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}));
}
else
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}
if (cancelExit) break;
}
if (cancelExit) return;
Process.Start(new ProcessStartInfo
{
UseShellExecute = true,
WorkingDirectory = Environment.CurrentDirectory,
FileName = Application.ExecutablePath,
Arguments = commandLine.Length > 0 ? string.Join(" ", commandLine) : string.Empty
});
Application.Exit();
}
finally
{
_exiting = false;
}
}
}
This worked for me:
Process.Start(Process.GetCurrentProcess().MainModule.FileName);
Application.Current.Shutdown();
Some of the other answers have neat things like waiting for a ping to give the initial application time to wind down, but if you just need something simple, this is nice.
For .Net application solution looks like this:
System.Web.HttpRuntime.UnloadAppDomain()
I used this to restart my web application after changing AppSettings in myconfig file.
System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
configuration.AppSettings.Settings["SiteMode"].Value = model.SiteMode.ToString();
configuration.Save();

Process created by Process.Start() terminates when the parent application is closed

I'm using C# and Mono 2.10.2 on Debian 6.
So the scenario is that I created a process with Process.Start() like the following:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.WorkingDirectory = "/home/lucy/";
p.StartInfo.FileName = "/bin/sh";
p.StartInfo.Arguments = "/home/lucy/test.sh";
p.EnableRaisingEvents = true;
p.ErrorDataReceived += new DataReceivedEventHandler(ShellProc_ErrorDataReceived);
p.Start();
The shell script which is in this case called test.sh is ran which does several things including starting a java application. The problem I am recieving is when the c# application is terminated the bash script/java application also terminates.
I have looked at several other similar questions posted here on Stack Overflow and none come to an obvious conclusion, including this one:
How to create a Process that outlives its parent
According to some users and supposedly the docs, processes created by Process.Start() should not be terminated when the application terminates, but obviously in my case that is not true. So could this be a Mono related issue and if that is indeed the case then is there any alternatives to how I'm doing it now as I am out of ideas.
Here is a complete sample that works for me:
using System;
using System.Diagnostics;
class Tick {
static void Main(string[] args) {
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
p.StartInfo.FileName = "/bin/sh";
p.StartInfo.Arguments = "test.sh";
p.EnableRaisingEvents = true;
p.ErrorDataReceived += new DataReceivedEventHandle(ShellProc_ErrorDataReceived);
p.Start();
System.Threading.Thread.Sleep (5000);
Console.WriteLine ("done");
}
static void ShellProc_ErrorDataReceived (object sender, DataReceivedEventArgs ea)
{
}
}
and then test.sh is:
while true; do
date;
sleep 1;
done
When I run the sample from a terminal, the test.sh script will continue to output data after the sample program has exited.
Update 1/Solution: This actually was not mono's fault and was indeed my own fault, the answer below helped me come to the conclusion that it was something else in my application that was causing the processes started by the application to terminate when the application terminates and the actual thing that was causing this was some GC stuff, specifically GC.Collect(), my fault, sorry and I hope this helps anybody who has a similar problem.

Close windows application

is it possible to close a running application with another application?
I have implemented APP1.exe and APP1_UNIN.exe, I would that APP1_UNIN.exe kill running APP1.exe and uninstall it.
Is it possible?
To uninstall an application, you can start a new process and invoke msiexec.exe, and on the command line you can specify what to uninstall:
ProcessStartInfo psi;
//take your choice of which you want to use:
psi = new ProcessStartInfo("msiexec.exe", string.Format("/x {0}", "path of my msi"));
psi = new ProcessStartInfo("msiexec.exe", string.Format("/x /n {{{0}}}", "my product code"));
Process p = new Process();
p.StartInfo = psi;
p.Start();
Use System.Diagnostics.Process class:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.closemainwindow(v=VS.71).aspx
There's also a Kill method.
At least to kill the running process you can do like this:
Process[] processes = Process.GetProcesses();
foreach (Process process in processes) {
if (process.ProcessName == "APP1.exe") {
try {
process.Kill();
break;
} catch (Exception) {
//handle any exception here
}
}
}
}
Regarding uninstalling it, I'm not sure.
For closing, you can do it by killing its process. System.Diagnostics.Process
Process []pArray = Process.GetProcesses();
foreach(Process prc in pArray) {
string s = prc.ProcessName;
if (s.CompareTo("APP1") ==0) {
prc.Kill();
}
}
Yes using System.Diagnostics
You can get the process and Kill the Process.

Visual Studio debug - System.Diagnostics.Process hangs on WaitForExit

In Console Application, Windows 10, Visual Studio 2015, .NET 4.6 i call single method in Main called TestProcess. Build mode Debug, if I run app without debugging it prints correct text:
827ccb0eea8a706c4c34a16891f84e7b *test.txt
Press any key to continue
. . .
If i run app with debugging it waits for 3 seconds before printing
Error False False False '' ''
This is just simplification of real problem, this code is backbone of some complex code which also hangs in release without debugging for md5sums.exe, but works for some other programs. Coplex code also also hangs on var a = proc.WaitForExit(timeout); until timeout as in attached example. On the other hand this simplification will work in release without debugger. Also, all this problems started with Windows 10, on Windows 7 it all worked fine.
[EDIT] Can't understand why would md5sums.exe cause problems, and if I use something else ie. FileName = "ping", Arguments = "localhost" everything works as expected.
[EDIT2] My complex program stopped working on Windows 10 (Release - Run without debugging), but this example hangs on Windows 7 also (Debug - Run with debugging)
static void TestProcess()
{
using (var proc = new Process())
{
proc.StartInfo.FileName = "md5sums.exe";
proc.StartInfo.WorkingDirectory = #"C:\Temp\ProcessDebug";
proc.StartInfo.Arguments = "-u test.txt";
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
proc.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
outputWaitHandle.Set();
else
output.AppendLine(e.Data);
};
proc.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
errorWaitHandle.Set();
else
error.AppendLine(e.Data);
};
proc.Start();
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
var timeout = 1000;
var a = proc.WaitForExit(timeout);
var b = outputWaitHandle.WaitOne(timeout);
var c = errorWaitHandle.WaitOne(timeout);
if (a && b && c)
Console.WriteLine(output.ToString());
else
Console.WriteLine($"Error {a} {b} {c} '{output}' '{error}'");
}
}
}
There were 3 catches to solve this:
md5sums.exe in some cases pauses execution after finished when launched with my settings:
827ccb0eea8a706c4c34a16891f84e7b *test.txt
Press ENTER to exit
This can be observed if CreateNoWindow is set to false and stdout, stderr redirection removed. This can be fixed by using -e switch: 'Exit immediately; don't pause before returning'. This will fix all cases. But as i didn't use -e i had inconsistent behavior depending on debugger and windows version.
When running without debugging pause was not fired although all settings were same, and "Press ENTER to exit" was not in output. But running with debugging caused pause to block program until timeout, where md5sums would hang in task manager waiting for Enter.
In release mode, run without debugging, although pause fired and "Press ENTER to exit" was in output on Windows 7 md5sums returned and execution continued without blocking and hitting timeout. This was not case on Windows 10 where md5sums would live in task manger waiting for Enter and program continued after hitting timeout.

Categories