I have a Windows Mobile program that accesses an attached device through a third-party DLL. Each call to the device can take an unknown length of time, so each call includes a timeout property. If the call takes longer than the specified timeout to return, the DLL instead throws an exception which my app catches with no problem.
The problem that I have is with closing the application. If my application has made a call to the DLL and is waiting for the timeout to occur, and I then close the application before the timeout occurs, my application locks up and requires the PDA to be rebooted.
I can ensure that the application waits for the timeout before closing, under normal conditions. However, I am trying to use AppDomain.CurrentDomain.UnhandledException to catch any unhandled exceptions in the program and use the event to wait for this pending timeout to occur so the program can be closed finally.
My problem is that this event doesn't seem to stick around long enough. If I put a MessageBox.Show("unhandled exception"); line in the event, and then throw a new unhandled exception from my application's main form, I see the message box for a split second but then it disappears without my having clicked the OK button.
The documentation I've found on this event suggests that by the time it's called the application is fully committed to closing and the closing can't be stopped, but I didn't think it meant that the event method itself won't finish. What gives (I guess that's the question)?
Update: In full windows (Vista) this works as expected, but only if I use the Application.ThreadException event, which doesn't exist in .Net CF 2.0.
I came across this problem as well. This is a known issue in .NET CF (v2.0), but I also had it while using v3.5 (although the situations in which it occurs are more specific). You can find the (old and still active) bug report here.
Calling MessageBox.Show() causes it to close immediately, but in my case there were two workarounds:
1) Call the MessageBox.Show() a second time. It then does block until closed by the user. You can check the first MessageBox.Show() closed prematurely by checking the DialogResult. I don't remember which result it returned exactly when it failed, I remember it giving a non-default result.
2) Create a custom Form and call ShowDialog() on that. It worked for me, but others have reported it doesn't work. You could also call Show() and make it blocking yourself (don't forget to call Application.DoEvents() so it keeps processing events).
Related
My project requires a restart if the user changes the settings before the settings will take effect. I have created a DialogResult prompt that asks the user if they want to restart the program. I call a MessageBox which returns a Yes/No and if you click "no" it behaves appropriately and doesn't close the program. If you choose "yes" the application closes... and that's it, no restart. I do have some close validation going on which I've read can cause issues, but I was under the impression that was issues with the program closing, not restarting? What might cause the application to not restart? Is there more to the method than just calling it that I need to be doing?
I attempt to restart the application calling the method:
Application.Restart();
As to whether I use threads, I am not consciously using threads cause I don't really know what that means to be honest.
Generally when you use this method, your app will restart.
It is ordinarily a routine action, but I saw in your question that you have some validation logic running when the app is closed. Thus, I'm about 90% sure that this error occurred because some of those validations failed. Post the validation code, and someone can help you debug the problem.
So thanks to the link from above I found a recommendation on a different thread that was a great workaround to simply using the Application.Restart() method.
System.Diagnostics.Process.Start(Application.ExecutablePath);
Application.Exit();
It allows my program to restart very effectively in spite of my closing validation.
This would probably still be an issue if I did any closing validation related to the Application.Exit call.
We have different ways to kill a running C# program.
ctrl + C;
task bar then right click its icon, then select 'close' on the popup;
task manager, select the its executable name and then click end process;
console window, use kill command;
maybe more.
What I am asking here is how handle them in my C# program to guarantee my C# program exit gracefully when possible. I know how to trap ctrl + C, but don't the others. can you help me? thanks,
The best guarantee you have at code being run at exit is the finally statement.
Note though that your program will have to run in the try block when you use this mechanism.
I believe that the only time the block inside the finally is not executed are at:
A StackOverflowException;
Corrupted state exceptions (from .NET 4);
Forceful termination through the task manager (an unmanaged process kill);
Crash of the entire system (removing the power cable e.g.).
See Keep Your Code Running with the Reliability Features of the .NET Framework for an in depth analysis.
Scenario 2 basically calls Application.Exit(), which should amount to a graceful shutdown of all threads associated with your process. It also fires events you can use to perform any additional cleanup.
3 and 4 can be "trapped" by attaching a handler to the Application.ThreadException event of a WinForms app. This event is fired when any exception is about to be thrown out of the program to be handled by the runtime (which will terminate your assembly's execution and clean the sandbox). However, at this point there's very little you should do other than write something to the Event log or clean up any statics, like an IoC container or repository, and even that's problematic because if one of those objects caused the exception, you could very easily throw another exception in trying to deal with the last one.
Basically, if your user is using "kill" or "End Process" to close your app, there's something VERY wrong and you should probably address the underlying reason why a user would be doing that, before trying to gracefully capture such termination behaviors.
Cannot trap. You cannot avoid killing of a program. But you can always subscribe to kill. Just imaging how you can trap when people pull the power plug...
.NET 2.0
Subscribe to the AppDomain.CurrentDomain.ProcessExit event
.NET 3.5
Application.Exit Event
Useful links
AppDomain.CurrentDomain.ProcessExit and cleanup
How to detect when application terminates?
How to detect when main thread terminates?
I have an unhandled exception handler. It shows a nice GUI and allows users to send an error report. Users can even leave their name and phone number and things, and our support department calls them back. Works well, looks good, makes customers less angry. In theory, anyway.
The problem is that my application uses background threads, and the threads don't seem to care if an exception was thrown on, say, the GUI thread (which makes sense), and just continue their work. That eventually results in a WER dialog poping up if the user lets my custom exception handler window stay open long enough, making it look like the error handler itself crashed.
I don't have access to the thread objects in the scope of the exception handler, so I can't suspend them. Making the thread objects globally accessible is not a solution either. My workaround for now is to use something like Globals.Crashed = true; in my exception handler, and to have my thread methods check that property at every loop iteration. Not perfect, but it minimizes the damage.
Does anyone know a less-hacky method? Is my approach wrong? Do I have to do it like WER does and launch an external program that suspends the main program and shows the error UI?
If you have an unhandled, unknown exception, you can assume that ANYTHING has happend and that your program might fail to do even the most simple thing. Consider e.g. the case that it has consumed all available memory - then you won't be able to send the error report either, because it probably requires memory to be allocated.
A good approach is to write a separate small application that just does the error reporting. That application can pick up the details to report from a file. That way your unknown exception handler would:
Dump the info to a file in the temp directory.
Start the error reporting app with the file name as an argument.
Terminate the failing process, before it does something stupid.
The temp file should be removed by the error reporting app.
You could track all your threads in a global Collection object, so that when your handler executes, it could simply iterate through the collection object and abort the threads there.
Take a look at the code in this question, Suspend Process in C#, you'll need to tweak it so as to not suspend your GUI thread and any that aren't background ones you've started, but it should do the trick.
The better option, however, is to try and launch your error report GUI as a separate process, passing any required information to it, and then kill the original process from your unhandled exception handler, rather than allowing anything to run in a potentially corrupt state.
I have a console application written in C#/.NET that I want to run from a script (nant). If an exception occurs in the console application, I would like nant to continue, but in Windows Vista there is a popup that searches for solutions and asks for debug etc.
I would like to avoid the popup with "program stopped working" when an exception happens in the console application. How can I control this from C#/.NET?
(A similar question addresses the issue for the C language, but I would like a solution for C#/.NET.)
(To clarify: I would like the exception to be passed to nant, but without the popup.)
The JIT debugger popup occurs when there's an unhandled exception. That is, an exception tunnels all the way up the stack to the root of any thread in the runtime.
To avoid this, you can handle the AppDomain.CurrentDomain.UnhandledException event and just call Environment.Exit(1) to exit gracefully.
This will handle all exceptions on all threads within your AppDomain. Unless you're doing anything special, your app probably only has one AppDomain, so putting this in your public static void Main method should suffice:
AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
{
Console.Error.WriteLine("Unhandled exception: " + args.ExceptionObject);
Environment.Exit(1);
};
You should probably use the NAnt logger to write out the error in this case too (can't recall the API for this offhand though.)
You can also disable JIT debugging on the machine. I would only recommend this in certain circumstances such as for a dedicated build server.
Under Windows Vista you can disable this dialog for your programms.
Disable the "Problem Reports and Solutions feature". You find it under Control Panel-->Problem Reports and Solutions-->Change Settings-->Advanced Settings-->Turn off for my programs, problem reporting
Just catch the exception and log/ignore it.
The popup appears due to an unhandled exception. To avoid that make sure your main method captures all exceptions and turn them into some other useful piece of info you can pick up. Just ignoring the exception is not recommended.
Btw remember that exceptions are per thread, so if your application spawns threads or uses thread pool threads, you need a handler for these too.
Usually this only happens when your app doesnt handle an exception. If you wrap your whole console app in a try/catch bblock, and just pass back a fail code, then you will avoid this.
Sometimes, a windows application will stop working if you are using a System.Timers.Timer.
To fix this, change System.Timers.Timer by System.Windows.Forms.Timer
Greetings
I got TargetInvocationException while doing long process in another thread caused by a windows control on UI thread (Progress Bar). This exception leads my app to crash (goes to main method in debugging) and could not be caught by try catch.
I figured out what made this exception, and fix it (that was trying to assign “Value” property by a value that exceeds the maximum). But it made me wondering how I can catch exception like this (in production code) so I have an option to recover my application instead of terminating the application.
Chances are you aren't going to be able to recover very much. In terms of your operation, the state of a good number of stack frames (and objects referenced from those stack frames) is probably invalid because of the error.
Because of that, at best you can recover at a very high level and try the operation again.
If the resources you are accessing are able to be contained in a transaction, then I would suggest doing that, so that you don't have to worry about inconsistencies in persisted data.
Also, you might want to check out this thread on SO:
Best Practice for Exception Handling in a Windows Forms Application?
As well as the Exception Handling Application block from Microsoft:
http://msdn.microsoft.com/en-us/library/cc309505.aspx
You can 'handle' exceptions (really, you're just receiving notification of them) on the GUI thread via the static event Application.UnhandledException.
When you attach a handler to this event, it will be invoked for all unhandled exceptions on the WinForms UI (message pump) thread. The fact that you have this handler attached means that the Application won't exit. Without it, WinForms shuts down your application.
Catch the exception and find a mechanism to pass it back to the main or calling code.
Not sure what version of .net you are using if its 3.0+ you can do something along these lines.
private void UpdateValue(int newValue)
{
Action myAction = () => progressBar.Value = newValue;
if (progressBar.InvokeRequired)
progressBar.Invoke(myAction);
else
myAction();
}
Call this method with the new value for the progress bar it will check if the call needs marshalling and make the appropriate call. Be careful InvokeRequired is relatively expensive, so use it only where needed. You could make this into an extension method to make generic use of this pattern for other controls if needed.
Hope this helps.