Jeremy’s Graceful Shutdown Braindump should really include another Use Case. How do you create a .NET application that never shuts down? Ever!
This is a common scenario for closed systems that only allow the user to interact with a predefined set of applications. In other words, the user is never able to utilize any of the Operating System functionality. In particular, they can not install new applications or update software components.
This situation is related to the issues discussed in Medical Device Software on Shared Computers. Creating a closed Windows-based system is not an easy task. For our XP Embedded system, here are some of the considerations:
- Prevent booting from a peripheral device (CD-ROM, USB stick, etc.).
- Prevent access to the BIOS so that #1 is enforced.
- Prevent plug-n-play devices from auto-starting installers.
- You can not run Explorer as the start-up shell — no desktop or Start menu.
- Prevent Ctrl-Alt-Del from activating Task Manager options.
- Disable the Alt-Tab selection window so the user can not switch application focus.
- Ensure that the primary user interface application is always running.
- All UI components must exit without user interaction when the system is powered down.
One of the challenges for .NET applications is how to handle unexpected exceptions. What you need first is a way to catch all exceptions. OK, so now you know your program is in serious distress. You may be able to recover some work (a la a “graceful shutdown”), but after that, it’s not a good idea keep the application running.
That means you have to restart the program. For a WinForms application, one option is:
Application.Restart();
Application.Restart()
essentially calls Application.Exit()
which tries to gracefully shutdown all UI threads. The problem with that is the application may appear to be hung if you have background worker threads that are monitoring hardware devices that are not currently responding.
Another issue is when the .NET application is doing interop with COM components. I’ve seen situations where all of the managed threads appear to exit properly via Application.Exit()
but an un-managed exception (and error window) still occurs. This behavior is unacceptable.
The way to ensure that the application restarts properly (simplified):
Process.Start(Application.ExecutablePath);
Environment.Exit(0);
The Environment.Exit()
call is harsh, but it is the only way I know of that guarantees that the application really exits. If you want a Windows Application event log and a dump of your application, you can use Environment.FailFast()
instead.