Process.Kill() related crashes - c#

Or not!
I have a fairly simple application timer program. The program will launch a user selected (from file dialog) executable and then terminate the process after the user specified number of minutes. During testing I found that a crash occurs when I call the Process.Kill() method and the application is minimized to the system tray.
The executable in question is Frap.exe which I use frequently and is the reason I wrote the app timer in the first place. I always minimize fraps to the tray, and this is when the crash occurs.
My use of Kill() is straight forward enough...
while (true)
{
//keep checking if timer expired or app closed externally (ie. by user)
if (dtEndTime <= DateTime.Now || p.HasExited)
{
if (!p.HasExited)
p.Kill();
break;
}
System.Threading.Thread.Sleep(500);
}
In searching for alternatives methods to close an external application programmatically, I found only Close() and Kill() (CloseMainWindow is not helpful to me at all). I tried using Close(), which works providing the application is minimized the tray. If the app is minimized, Close() doesn't cause a crash but the app remains open and active.
One thing I noticed in a few posts posts regarding closing external applications was the comment: "Personally I'd try to find a more graceful way of shutting it down though." made in THIS thread found here at stack flow (no offense to John). Thing is, I ran across comments like that on a few sites, with no attempt at what a graceful or elegant (or crash-free!!) method might be.
Any suggestions?
The crash experienced is not consistant and I've little to offer as to details. I am unable to debug using VS2008 as I get message - cant debug crashing application (or something similar), and depending on what other programs I have running at the time, when the Kill() is called some of them also crash (also programs only running in the tray) so I'm thinking this is some sort of problem specifically related to the system tray.

Is it possible that your code is being executed in a way such that the Kill() statement could sometimes be called twice? In the docs for Process.Kill(), it says that the Kill executes asynchronously. So, when you call Kill(), execution continues on your main thread. Further, the docs state that Kill will throw a Win32Exception if you call it on an app that is already in the process of closing. The docs state that you can use WaitForExit() to wait for the process to exit. What happens if you put a call to WaitForExit() immediately following the call to Kill(). The loop looks ok (with the break statement). Is it possible that you have code entering that loop twice?
If that's not the problem, maybe there is another way to catch that exception:
Try hooking the AppDomain.CurrentDomain.UnhandledException event
(currentDomain is a static member)
The problem is that Kill runs asynchronously, so if it's throwing an exception, it's occurring on a different thread. That's why your exception handler doesn't catch it. Further (I think) that an unhandled async exception (which is what I believe you have) will cause an immediate unload of your application (which is what is happening).
Edit: Example code for hooking the UnhandledExceptionEvent
Here is a simple console application that demonstrates the use of AppDomain.UnhandledException:
using System;
public class MyClass
{
public static void Main()
{
System.AppDomain.CurrentDomain.UnhandledException += MyExceptionHandler;
System.Threading.ThreadPool.QueueUserWorkItem(DoWork);
Console.ReadLine();
}
private static void DoWork(object state)
{
throw new ApplicationException("Test");
}
private static void MyExceptionHandler(object sender, System.UnhandledExceptionEventArgs e)
{
// get the message
System.Exception exception = e.ExceptionObject as System.Exception;
Console.WriteLine("Unhandled Exception Detected");
if(exception != null)
Console.WriteLine("Message: {0}", exception.Message);
// for this console app, hold the window open until I press enter
Console.ReadLine();
}
}

My first thought is to put a try/catch block around the Kill() call and log the exception you get, if there is one. It might give you a clue what's wrong. Something like:
try
{
if(!p.HasExited)
{
p.Kill();
}
break;
}
catch(Exception ex)
{
System.Diagnostics.Trace.WriteLine(String.Format("Could not kill process {0}, exception {1}", p.ToString(), ex.ToString()));
}

I dont think I should claim this to be "THE ANSWER" but its a decent 'work around'. Adding the following to lines of code...
p.WaitForInputIdle(10000);
am.hWnd = p.MainWindowHandle;
...stopped the crashing issue. These lines were placed immediately after the Process.Start() statement. Both lines are required and in using them I opened the door to a few other questions that I will be investigating over the next few days. The first line is just an up-to 10 second wait for the started process to go 'idle' (ie. finish starting). am.hWnd is a property in my AppManagement class of type IntPtr and this is the only usage of both sides of the assignment. For lack of better explaination, these two lines are analguous to a debouncing method.
I modified the while loop only slightly to allow for a call to CloseMainWindow() which seems to be the better route to take - though if it fails I then Kill() the app:
while (true)
{
//keep checking if timer expired or app closed externally (ie. by user)
if (dtEndTime <= DateTime.Now || p.HasExited) {
try {
if (!p.HasExited) // if the app hasn't already exitted...
{
if (!p.CloseMainWindow()) // did message get sent?
{
if (!p.HasExited) //has app closed yet?
{
p.Kill(); // force app to exit
p.WaitForExit(2000); // a few moments for app to shut down
}
}
p.Close(); // free resources
}
}
catch { // blah blah }
break;
}
System.Threading.Thread.Sleep(500);
}
My initial intention for getting the MainWindowHandle was to maximize/restore an app if minimized and I might implement that in the near future. I decided to see if other programs that run like Fraps (ie, a UI but mostly run in the system tray (like messanger services such as Yahoo et al.)). I tested with XFire and nothing I could do would return a value for the MainWindowHandle. Anyways, this is a serperate issue but one I found interesting.
PS. A bit of credit to JMarsch as it was his suggestion RE: Win32Exception that actually lead me to finding this work around - as unlikely as it seems it true.

Related

Foreground services and repetitive tasks which need to be executed on time

I'm developing an app which basically performs some tasks on timer tick (in this case - searching for beacons) and sends results to the server. My goal was to create an app which does its job constantly in the background. Fortunately, I'm using logging all over the code, so when we started to test it we found that sometime later the timer's callback wasn't being called on time. There were some pauses which obviously had been caused by standby and doze mode. At that moment I was using a background service and System.Threading.Timer. Then, after some research, I rewrote the services to use Alarm Manager + Wake locks, but the pauses were still there. The next try was to make the service foreground and use it with a Handler to post delayed tasks and everything seemed to be fine while the device was connected to the computer. When the device is not connected to a charger those pauses are here again. The interesting thing is that we cannot actually predict this behavior. Sometimes it works perfectly fine and sometimes not. And this is really strange because the code to schedule it is pretty simple and straightforward:
...
private int scanThreadsCount = 0;
private Android.OS.Handler handler = new Android.OS.Handler();
private bool LocationInProgress
{
get { return Interlocked.CompareExchange(ref scanThreadsCount, 0, 0) != 0; }
}
public void ForceLocation()
{
if (!LocationInProgress) DoLocation();
}
private async void DoLocation()
{
Interlocked.Increment(ref scanThreadsCount);
Logger.Debug("Location is started");
try
{
// Location...
}
catch (Exception e)
{
Logger.Error(e, "Location cannot be performed due to an unexpected error");
}
finally
{
if (LocationInterval > 0)
{
# It's here. The location interval is 60 seconds
# and the service is running in the foreground!
# But in the screenshot we can see the delay which
# sometimes reaches 10 minutes or even more
handler.PostDelayed(ForceLocation, LocationInterval * 1000);
}
Logger.Debug("Location has been finished");
Interlocked.Decrement(ref scanThreadsCount);
}
}
...
Actually it can be ok, but I need that service to do its job strictly on time, but the callback is being called with a few seconds delay or a few minutes and that's not acceptable.
The Android documentation says that foreground services are not restricted by standby and doze mode, but I cannot really find the cause of that strange behavior. Why is the callback not being called on time? Where do these 10 minutes pauses come from? It's pretty frustrating because I cannot move further unless I have the robust basis. Does anybody know the reason of such a strange behavior or any suggestions how I can achieve the callback to be executed on time?
P.S. The current version of the app is here. I know, it's quite boring trying to figure out what is wrong with one's code, but there are only 3 files which have to do with that problem:
~/Services/BeaconService.cs
~/Services/BeaconServiceScanFunctionality.cs
~/Services/BeaconServiceSyncFunctionality.cs
The project was provided for those who would probably want to try it in action and figure it out by themselves.
Any help will be appreciated!
Thanks in advance

The definitive code that prevents a c# console app from exiting [until custom cleanup code has completed]

Can we work together to come up with something that works for control-c, control-break, log off, window X button pressed, etc?
Here is what I have so far:
class Program
{
private static ConsoleEventHandlerDelegate consoleHandler;
delegate bool ConsoleEventHandlerDelegate(CtrlTypes eventCode);
static void Main(string[] args)
{
consoleHandler = new ConsoleEventHandlerDelegate(ConsoleCtrlCheck);
SetConsoleCtrlHandler(consoleHandler, true);
System.Diagnostics.Process.GetCurrentProcess().Exited
+= delegate(object sender, EventArgs e)
{
GeneralManager.Stop();
};
Console.CancelKeyPress += delegate(object sender,
ConsoleCancelEventArgs e)
{
e.Cancel = false;
GeneralManager.Stop();
};
GeneralManager.Start();
}
private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
switch (ctrlType)
{
case CtrlTypes.CTRL_C_EVENT:
Console.WriteLine("CTRL+C received!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_BREAK_EVENT:
isclosing = true;
Console.WriteLine("CTRL+BREAK received!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_CLOSE_EVENT:
Console.WriteLine("Program being closed!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_LOGOFF_EVENT:
case CtrlTypes.CTRL_SHUTDOWN_EVENT:
Console.WriteLine("User is logging off!");
GeneralManager.Stop();
break;
}
return true;
}
#region unmanaged
[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleEventHandlerDelegate
handlerProc, bool add);
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
public enum CtrlTypes
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
#endregion
}
Two problems:
In the Managed Control-Break handler, if we set e.Cancel = true it fails with an exception for .Net4. This is noted in the MSDN article with no work-around: http://msdn.microsoft.com/en-us/library/system.consolecanceleventargs.cancel.aspx
I don't know how to cancel the close in the ConsoleCtrlCheck. I get a second or two to do some cleanup, but I'd rather cancel and make sure it all gets done properly.
UPDATE:
Thanks for the replies. Upvoted both. Will wait to see if anyone can come up with a reply that directly solves what I asked for, otherwise will accept one of the "use NT services" answers.
I need to wait for pending user requests to complete, disconnect them cleanly, run a few queries on the database to reflect the change(s) in state and so forth. It's a TCP server.
Then don't run it as a Console or any other kind of Client app.
Just run it as a Windows (NT) Service and the only events you'll have to worry about are Power loss and a stop signal.
Use a UPS and make sure you can close in a reasonable timespan.
I have not tried to do this kind of thing with a console app, but you may do better with a Windows Forms (or WCF app). They will give you a FormClosing event which is cancellable. Alternately, use a Windows Service if you are writing a network service, it provides an interface to cleanly stop your application.
If you are really keen on a console app, perhaps a try {} finally {} clause around all your code or something more exotic like a critical finaliser may allow you to run clean up code. But this is really not the right tool for the job.
And there are cases which you cannot prevent you app being closed, eg: power failure, or Task Manager kill command (and if an app didn't close via the X, Task Manager is the first tool I'd reach for).
So, code your service application such that all client requests are logged to a transaction log (like SQL server does). If you are unexpectedly interrupted (by whatever circumstance) anything which has happened up until that point is in the log. When your service next starts, replay that log.
One of your things to log will be "I was shutdown cleanly at time T". If you restart and don't find that item at the end of your log, you know something went wrong, and you can take whatever action is required.
If you need to know what your service is doing, use one of the many logging frameworks to pipe events to a second app, which just displays activity.
I spent couple hours looking at this and as I don't have time now to build a working code; as while it's probably short, getting it right would take a while. I'll just give you link to the various stuff that's needed to get this done:
http://pastebin.com/EzX3ezrf
Summarizing the lessons from the code in the paste:
Need a message pump to handle some/all of WM_QUERYENDSESSION, WM_ENDSESSION, CTRL_SHUTDOWN_EVENT (in c# SystemEvents.SessionEnding may cover some/all of these)
Easiest way to get a message pump is to make it a hidden form/window app, but I recall it's possible to build as a console app and add a message pump also. I didn't include that code in the paste though.
"If an application must block a potential system shutdown, it can call the ShutdownBlockReasonCreate function"
As AllocConsole is used to create the console, you need to use SetConsoleCtrlHandler and use ExitThread(1) in the handler. This is a "hack" that kills off the thread that would close the console otherwise. It's used in FarManager. see interf.cpp for example
You need to also initialize and clean up the console when using AllocConsole.
Pressing CTRL+C is reported to mess up the input. I'm not sure if FarManager is handling this scenario. There's some code in the CTRL_BREAK_EVENT handler in interf.cpp that I'm not sure what it does.
FarManager also handles WM_POWERBROADCAST, probably to do with suspending
If all that isn't enough (should be), you can also add the console into another process and IPC your messages to it like shown here. Why does closing a console that was started with AllocConsole cause my whole application to exit? Can I change this behavior?
RMTool can be used to simulate logoff/shutdown messages for testing: http://download.microsoft.com/download/d/2/5/d2522ce4-a441-459d-8302-be8f3321823c/LogoToolsv1.0.msi
MSDN has some C# code also at microsoft.win32.systemevents.sessionending.aspx
and microsoft.win32.systemevents.aspx (hidden form example)
The mischel.com/pubs/consoledotnet/consoledotnet.zip has a sample winTest project with AllocConsole being used and some of the events handled.

Checking if a console application is still running using the Process class

I'm making an application that will monitor the state of another process and restart it when it stops responding, exits, or throws an error.
However, I'm having trouble to make it reliably check if the process (Being a C++ Console window) has stopped responding.
My code looks like this:
public void monitorserver()
{
while (true)
{
server.StartInfo = new ProcessStartInfo(textbox_srcdsexe.Text, startstring);
server.Start();
log("server started");
log("Monitor started.");
while (server.Responding)
{
if (server.HasExited)
{
log("server exitted, Restarting.");
break;
}
log("server is running: " + server.Responding.ToString());
Thread.Sleep(1000);
}
log("Server stopped responding, terminating..");
try
{ server.Kill(); }
catch (Exception) { }
}
}
The application I'm monitoring is Valve's Source Dedicated Server, running Garry's Mod, and I'm over stressing the physics engine to simulate it stopping responding.
However, this never triggers the process class recognizing it as 'stopped responding'.
I know there are ways to directly query the source server using their own protocol, but i'd like to keep it simple and universal (So that i can maybe use it for different applications in the future).
Any help appreciated
The Responding property indicates whether the process is running a Windows message loop which isn't hung.
As the documentation states,
If the process does not have a MainWindowHandle, this property returns true.
It is not possible to check whether an arbitrary process is doing an arbitrary thing, as you're trying to.

How to make script/program to make it so an application is always running?

I have a simple .exe that needs to be running continuously.
Unfortunately, sometimes it crashes unexpectedly, and there's nothing that can be done for this.
I'm thinking of like a C# program that scans the running application tree on a timer and if the process stops running it re-launches it... ? Not sure how to do that though....
Any other ideas?
It's fairly easy to do that, but the "crashes unexpectedly, and there's nothing that can be done for this" sounds highly suspect to me. Perhaps you mean the program in question is from a third party, and you need to work around problems they can't/won't fix?
In any case, there's quite a bit of sample code to do exactly what you're talking about.
The first solution would be to fix your EXE, so it does not crash. If you can not fix it now, you probably need to add exception handling, so you can catch the exception, and not close the EXE.
Second solution is to write simple guard programm that will start your simple .exe and will monitor specific process handle. It will restart your program when it closes.
easiest way is to have you program see if an instance of itself is running and exit if it is. Set up a scheduled task to run it every couple of minutes.
class Program
{
static void Main(string[] args)
{
if (IsRunning())
{
return;
}
else
{
for (int x = 0; x < 10; x++)
{
//Do Stuff
System.Threading.Thread.Sleep(1000);
}
}
}
private static bool IsRunning()
{
Process[] P = Process.GetProcessesByName( Process.GetCurrentProcess().ProcessName ) ;
return P.Count() > 1;
}
}
One trick occasionally employed by malware in days past was to have two processes that each monitor the currently running processes and restart the other process if it is terminated.
The System.Diagnostics namespace has classes which can help, particularly "Process".
For example
static Process[] Process.GetProcesses()
returns a list of all the currently running processes.
If your other process is not in this list, you just restart it with, for example
Process.Start()
Your program needs to initially start your target process itself (with Process.Start), then simply wait for it to terminate (with WaitForExit on object that is returned by Process.Start()). After that whole procedure is repeated.
This way you'd be sure that you are watching the process you are interested in, and you don't need to poll process list at all.
Process.Start() and WaitForExit() usage example.

Why would Application.Exit fail to work?

I have an application that has been getting strange errors when canceling out of a dialog box. The application can't continue if the box is cancelled out of, so it exits, but it is not working for some reason, and thus it keeps running and crashes.
I debugged this problem, and somehow the application runs right past the Application.Exit call. I'm running in Debug mode, and this is relevant because of a small amount of code that depends on the RELEASE variable being defined. Here is my app exit code. I have traced the code and it entered the ExitApp method, and keeps on going, returning control to the caller and eventually crashing.
This is an application which provides reports over a remote desktop connection, so that's why the exit code is a bit weird. Its trying to terminate the remote session, but only when running under release because I don't want to shut down my dev machine for every test run.
private void ExitApp()
{
HardTerminalExit();
Application.Exit();
}
// When in Debug mode running on a development computer, this will not run to avoid shutting down the dev computer
// When in release mode the Remote Connection or other computer this is run on will be shut down.
[Conditional("RELEASE")]
private void HardTerminalExit()
{
WTSLogoffSession(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, false);
}
I've run a debugger right past the Application.Exit line and nothing happens, then control returns to the caller after I step past that line.
What's going on? This is a Windows Forms application.
This is an article which expands on the same train of thought you are going through: http://www.dev102.com/2008/06/24/how-do-you-exit-your-net-application/
Basically:
Environment.Exit - From MSDN: Terminates this process and gives the
underlying operating system the
specified exit code. This is the code
to call when you are using console
application.
Application.Exit - From MSDN: Informs all message pumps that they
must terminate, and then closes all
application windows after the messages
have been processed. This is the code
to use if you are have called
Application.Run (WinForms
applications), this method stops all
running message loops on all threads
and closes all windows of the
application. There are some more
issues about this method, read about
it in the MSDN page.
Another discussion of this: Link
This article points out a good tip:
You can determine if System.Windows.Forms.Application.Run has been called by checking the System.Windows.Forms.Application.MessageLoop property. If true, then Run has been called and you can assume that a WinForms application is executing as follows.
if (System.Windows.Forms.Application.MessageLoop)
{
// Use this since we are a WinForms app
System.Windows.Forms.Application.Exit();
}
else
{
// Use this since we are a console app
System.Environment.Exit(1);
}
Having had this problem recently (that Application.Exit was failing to correctly terminate message pumps for win-forms with Application.Run(new Form())), I discovered that if you are spawning new threads or starting background workers within the constructor, this will prevent Application.Exit from running.
Move all 'RunWorkerAsync' calls from the constructor to a form Load method:
public Form()
{
this.Worker.RunWorkerAsync();
}
Move to:
public void Form_Load(object sender, EventArgs e)
{
this.Worker.RunWorkerAsync();
}
Try Environment.Exit(exitCode).
I have went though this situation in many cases I use Thread.CurrentThread.Abort()
and the process is closed. It seems that Application.Exit isn't hooking up properly with current thread.
Also ensure any threads running in your application have the IsBackground property set to true. Non-background threads will easily block the application from exiting.
Make sure you have no Console.ReadLine(); in your app and Environment.Exit(1); will work and close your app.
I created the following that will exit the app anywhere. You don't have to worry if the Form is running or not, the test determines that and calls appropriate Exit.
public void exit(int exitCode)
{
if (System.Windows.Forms.Application.MessageLoop)
{
// Use this since we are a WinForms app
System.Windows.Forms.Application.Exit()
}
else
{
// Use this since we are a console app
System.Environment.Exit(exitCode);
}
} //* end exit()
Is this application run (in the Main method) using Application.Run()? Otherwise, Application.Exit() won't work.
If you wrote your own Main method and you want to stop the application, you can only stop by returning from the Main method (or killing the process).
Try this :
in Program.cs file :
after Application.Run(new form());
add Application.Exit();
private void frmLogin_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
DialogResult result = MessageBox.Show("Do you really want to exit?", "Dialog Title", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
Environment.Exit(0);
}
else
{
e.Cancel = true;
}
}
else
{
e.Cancel = true;
}
}

Categories

Resources