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;
}
}
Related
I am creating a device application using .NET compact framework 2.0. There is a system.threading.timer in my application which executes some code. It works fine. My problem is when I am running the app by double clicking on the exe in the bin folder, the timer starts and execute all it works but it never stops. It runs in the background even after closing the app by clicking the X-button or from the file menu close button. I don't understand how and where I stop or dispose of the timer so that it doesn't run after closing the app. May be something like a form_closing event in window form application. I had searched a lot in Google but did't find any proper answer.
The application is use to generate digital output for a device
here is some code of timer event:
public static void Main()
{
// Some code related to the device like open device etc
// Then the timer
System.Threading.Timer stt =
new System.Threading.Timer(new TimerCallback(TimerProc), null, 1, 5000);
Thread.CurrentThread.Join();
}
static void TimerProc(Object stateInfo)
{
// It is my local method which will execute in time interval,
// uses to write value to the device
writeDigital(1, 0);
GC.Collect();
}
It is working fine when I run the code in debug mode, timer stops when I stop the program. But not working when I run the exe.
You could create and dispose it in Main() and pass it to any methods that require it?
private static void Main()
{
using (var timer = new System.Threading.Timer(TimerProc))
{
// Rest of code here...
}
}
More importantly, this line of code:
Thread.CurrentThread.Join();
will never return, because you are asking the current thread to wait for the current thread to terminate. Think about that for a moment... ;)
So your solution is probably to just remove that line of code.
All about GC.Collect();
Your stt object is used once and after that is pointed out to being removed and its memory reclaimed.
If you don't belive call stt.ToString(); at the end of main function, it will extend the stt live till the end of main function.
Solution(s)?
You can define the stt object as a static - it guarantees that it will be alive till the end of live of you program
recommended solution is to use GC.KeepAlive(stt); which you can call at the end of main function which will keep the stt away from destroying process.
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.
I have an app that has a BG module which is forced to run at every 4 mins for testing purpose, and it works fine. Once I launch the app(first launch) and register with the server the contents are displayed and I exit the app. The app goes to Application_Closing() state. I wait for a while(say about 15 mins) and try to launch the app, sometimes it so happens that, after the MainPage() constructor is executed, the app gets deactivated and while debugging and from the logs I observed that the app goes to Application_Deactivated() state.Basically, the app launches, its still displaying the Splash Screen(Customized) and it terminates all of a sudden. So, after I went through the log there is one question that is bothering me, i.e., if an app is launched while still the BG task is doing its job, and there is a conflict between the FG and the BG task will that in anyway result in Application Deactivation? I also have doubt that I must be doing something more inside the Application_Deactivated() method in the APp.xaml.cs class. Here is the Code.
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
Logger.log(TAG, "Application deactivated");
}
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
if (appSession != null)
{
appSession.close();
}
Logger.log(TAG, "Application closed");
}
//Log:-
From what I understand from your query, I can conclude that since the Application is running in the BG thread before it is launched, its unable to allocate UI resources which require it to be on the FG (which is not happening due to the cross threading issue). I guess you need to sort out this conflict before you proceed.
Note: I am not sure about this. Its only an observation. Hope my answer helps you.
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.
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.