When trying to press the standard Windows 7 logoff button while my WPF app is running, I get "This program is preventing Windows from logging off". I would like to force it to close without having to press "Force log off".
Similarly, pressing "End Task" in the (applications) Task Manager causes it to become non-responsive rather than just close the program.
I have tried adding this to Window_Closing, but this doesn't seem to do it:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Environment.Exit(0);
}
I'm new to WPF, but it seems to me that the window is not closing properly. How can I prevent the "program is preventing Windows from logging off" when executing the Windows logoff, or "Program is not responding" when killing it from task manager?
This should only be an issue if your application is not responding to the close events sent from Windows.
This will typically happen if you are executing code on the UI thread, which prevents it from responding to messages. As such, putting something in the closing events and similar will have no effect, as they won't be able to process until after your "work" finishes.
The proper way to handle this is to move your work onto background threads. This keeps the application responsive, which allows it to respond to the request from Windows to Close.
Related
I want to log if a customer tries to force close the application. I'm aware of having no chance to catch a process kill. But it should be possible through the main form closing event to get informed about the 'CloseReason.TaskManagerClosing' reason.
But any tests I did under Windows 8.1 I always got a CloseReason.UserClosing reason. But in this case (compared to a normals CloseReason.UserClosing) I've about 0.2s to run user code afterwards my program is killed!
Is this a new behavior in Windows 8.1?
Yes, I see this. And yes, this is a Windows change, previous versions of Task Manager sent the window the WM_CLOSE notification directly. I now see it issue the exact same command that's issued when you close the window with the Close button (WM_SYSCOMMAND, SC_CLOSE). Or press Alt+F4 or use the system menu. So Winforms can no longer tell the difference between the Task Manager and the user closing the window and you do get CloseReason.UserClosing.
What happens next is expected, if you don't respond to the close command quickly enough then Task Manager summarily assassinates your program with TerminateProcess().
Do keep in mind that trying to save data when the user aborts your program through Task Manager is a bad practice. Your user will normally use this if your program is malfunctioning, you can't really trust the data anymore and you risk writing garbage. This is now compounded by your saving code being aborted, high odds for a partially written file or dbase data that isn't usable anymore.
There is no simple workaround for this, the odds that Windows is going to be patched to restore old behavior are very close to zero. It is very important that you save your data in a transactional way so you don't destroy valuable data if the saving code is aborted. Use File.Replace() for file data, use a dbase transaction for dbase writes.
An imperfect way to detect this condition is by using the Form.Deactivate and Activate events. If you saw the Deactivate event and the FormClosing event fires then reasonable odds that another program is terminating yours.
But the normal way you deal with this is the common one, if the user ends the program without saving data then you display a dialog that asks whether to save data. Task Manager ensures that this doesn't go further than that.
Another solution for determining when the Task Manager is closing the program is by checking if the main form, or any of its controls, has focus. When you close via the Task Manager, the application is not focused, whereas if you close via the close button or Alt+F4, the application does have focus. I used a simple if check:
private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
if (this.ContainsFocus)
{
// Put user close code here
}
}
I'm writing a program that monitors state. It launches main window (LoginForm) to ask for user credentials, then hides the form. After that LoginForm inits NotifyIcon and all the remaining work is being done with LoginForm hidden. I've implemented all the clean-up work in FormClosing event of LoginForm. During normal exit process everything works perfectly.
The problem is that the program sits in tray all the time and I tend to forget to exit it before shutting down windows - program doesn't save the state on shutdown event.
I've read through many forums and docs, and from what I've read events FormClosing/FormClosed + SessionEnding/SessionEnded must fire anyway. But it looks like they just don't fire. Can't even cancel shutdown in SessionEnding (with stupid e.Cancel=true) - program disappears without reaching the place.
I've made myself a small debugging library to write out debug information into a file with instant flashing of cache. I've added debug messages to all the events. When I try to log off user in Windows (same as shutting down) for a test - I see no events being triggered usually, just the program vanishes. No exceptions I could catch, no events, etc. When exitting program manually or through "taskkill /IM " - I see all the expected debug printout. What's even more interesting - sometimes the program does reach closing events and does proper clean-up job during Windows shutdown.
Wasted a few days on this already. Overriden WndProc as suggested in MS article - program doesn't reach WndProc as well (to ensure it comes first before closing the form). Tried instead of FormClosing event to override OnClosing of LoginForm - no luck. Added UnhandledException handler, Microsoft.Win32.SessionEnding, Microsoft.Win32.SessionEnded, Form.FormClosing, Form.FormClosed event handlers - no luck.
I suspect this is either a problem of hidden forms or that some kind of exception is happening during shutdown only (resources disposed?). How can I find why that's happening? Is there some simple way to simulate Windows shutdown for single application to make debugging in VS possible? I've tried RMTool - for some reason it fails to simulate shutdown and program just ignores it.
Update: Program uses System.Timers.Timer to regularly poll server for any changes.
I've done some research into this, basically, after Windows XP they altered the way that shutdowns were handled.
You cannot block or capture the shutdown event reliably using the form_closing events etc.
You must use a new API to do so. There is a complete example here: http://bartdesmet.net/blogs/bart/archive/2006/10/25/Windows-Vista-2D00-ShutdownBlockReasonCreate-in-C_2300_.aspx
You should be able to call the function to block shutting down (display a message such as 'saving changes...') and then save and exit your application in the background. Once your program quits, it should allow windows to continue shutting down.
I think windows is simply configured to automatically shutdown all applications regardless and hence the application has no chance to catch SessionEnding events and so on : have a look at http://www.addictivetips.com/windows-tips/disable-automatic-termination-of-applications-during-shutdown-in-windows-7/ or check your configuration at Computer Configurations > Administrative Templates > System > Shutdown Options.
I have a simple WinForms application that runs in the system tray. Is it possible to password protect the program from closing if a user tries to close it from task manager?
Ideally I want to keep a user from closing the process but if windows is restarted, I want it to close without being prompted. Much like antivirus programs.
If a user has the correct permissions they will be able to kill your process from the Task Manager.
That said as #fujiFX mentions in his comment the FormClosing event is a good start and better than nothing.
The FormClosing event occurs as the form is being closed. When a form is closed, it is disposed, releasing all resources associated with the form. If you cancel this event, the form remains opened. To cancel the closure of a form, set the Cancel property of the FormClosingEventArgs passed to your event handler to true.
It's hard to do, but you can create two applications, one is main program and two is helper. If helper is killed, then main app restarts it. If main app is killed, then helper restarts main app.
You can make this verification on YourService.Stop method (assuming you're using a Windows Service thus inheriting from ServiceBase), but as far as I know you cannot prevent the user from killing the proccess, just to close the app (two different things in Windows).
I am using windows forms application, which runs from system tray. In ContextMenuStrip I have an Exit icon, which should be terminating my process, but it doesn't.
My process stays in task manager. So, if I run (and terminate) the applicaiton several times, then I have several processes in task manager, although none of them is reachable any more.
My code for exiting application is simple:
void exitOnClick(object sender, System.EventArgs e)
{
_notifyIcon.Visible = false;
Application.Exit();
}
I've checked with debugger - this code is triggered when I press Exit. Notify icon dissapears, but process remains in task manager. Also, if any of win forms are open, they are closed.
Try to use Environment.Exit static method. This method:
... terminates an application immediately, even if other threads are
running.
But it's better to find a code that is still running, as you was told above.
I am trying to figure out which I should be using. On closing my WinForm app fires of a Form in Dialog mode. That form runs a Background worker that Syncs the DB with the remote DB and displays it's progress on the "Splash Form."
I have a method like so:
private void CloseMyApp()
{
SaveUserSettings();
splashForm = new SplashForm();
splashForm.ShowDialog();
Application.ExitThread();
//Application.Exit();
}
which is what I call to close my app from Menu --> Exit and in the Form_FormClosing() event. Application.Exit() gives the following error -->
Collection was modified; enumeration operation may not execute.
Now I read that Environment.Exit() is brutal and means there is probably something wrong with your app (see here).
Application.ExitThread() works but I am concered that it may only be APPEARING to work and as I have never used it before I am not sure when it is normally appropriate to do so.
Unfortunately, the problem isn't caused by any of these, and really exists (even if you don't get the message) in all of these scenarios.
Your problem is this:
On closing my WinForm App fires of a Form in Dialog mode. That form runs a Background worker that Syncs the DB with the remote DB and displays it's progress on the "Splash Form."
Since you're not actually shutting down when you request a shutdown, all of the "Exit" functions are trying to tear down your background thread. Unfortunately, this is probably happening in the middle of your DB sync, and an enumeration working in the save logic is probably providing that error.
I would recommend not using any of these - just call myMainForm.Close() instead. That should close your main form, which will fire your closing logic appropriately. Once the main form in your application closes, it will shut down gracefully.
Environment.Exit() is used for console apps.
You want to use: System.Windows.Forms.Application.Exit()
By exiting thread, you are only exiting the current thread context, while leaving any started foreground threads running. I suspect the thread that is causing the error is still running, so you've essentially masked the problem, not worked around it. I would try and figure out why you are getting this error "Collection was modified; enumeration operation may not execute." on exit. It's being exposed by Application.Exit(), but it's not caused by it.