Recipe 20.1. Dealing with Operating System Shutdown, Power Management, or User Session ChangesProblemYou want to be notified whenever the operating system or a user has initiated an action that requires your application to shut down or be inactive (user logoff, remote session disconnect, system shutdown, hibernate/restore, etc.). This notification will allow you have your application respond gracefully to the changes. SolutionUse the Microsoft.Win32.SystemEvents class to get notification of operating system, user session change, and power management events. The RegisterForSystemEvents method shown next hooks up the five event handlers necessary to capture these events and would be placed in the initialization section for your code: public static void RegisterForSystemEvents( ) { // Always get the final notification when the event thread is shutting down // so we can unregister. SystemEvents.EventsThreadShutdown += new EventHandler(OnEventsThreadShutdown); SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(OnPowerModeChanged); SystemEvents.SessionSwitch += new SessionSwitchEventHandler(OnSessionSwitch); SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding); SystemEvents.SessionEnded += new SessionEndedEventHandler(OnSessionEnded); } The EventsThreadShutdown event notifies you of when the thread that is distributing the events from the SystemEvents class is shutting down so that you can unregister the events on the SystemEvents class if you have not already done so. The PowerModeChanged event triggers when the user suspends or resumes the system from a suspended state. The SessionSwitch event is triggered by a change in the logged-on user. The SessionEnding event is triggered when the user is trying to log off or shut down the system, and the SessionEnded event is triggered when the user is actually logging off or shutting down the system. The events can be unregistered using the UnregisterFromSystemEvents method. UnregisterFromSystemEvents should be called from the termination code of your Windows Form, user control, or any other class that may come and go, as well as from one other area shown later in the recipe: private static void UnregisterFromSystemEvents() { SystemEvents.EventsThreadShutdown -= new EventHandler(OnEventsThreadShutdown); SystemEvents.PowerModeChanged -= new PowerModeChangedEventHandler(OnPowerModeChanged); SystemEvents.SessionSwitch -= new SessionSwitchEventHandler(OnSessionSwitch); SystemEvents.SessionEnding -= new SessionEndingEventHandler(OnSessionEnding); SystemEvents.SessionEnded -= new SessionEndedEventHandler(OnSessionEnded); }
The SystemEvents handler methods are the individual event handlers for each of the events that have been subscribed to in RegisterForSystemEvents. The first handler to cover is the OnEventsThreadShutdown handler. It is essential that your handlers are unregistered if this event fires, as the notification thread for the SystemEvents class is going away and the class may be gone before your application is. If you haven't unregistered before that point, you will cause memory leaks, so add a call to UnregisterFromSystemEvents into this handler as shown here: private static void OnEventsThreadShutdown(object sender, EventArgs e) { Debug.WriteLine("System event thread is shutting down, no more notifications."); // Unregister all our events as the notification thread is going away. UnregisterFromSystemEvents(); } The next handler to explore is the OnPowerModeChanged method. This handler can report the type of power management event through the Mode property of the PowerModeEventChangedArgs parameter. The Mode property has the PowerMode enumeration type and specifies the event type through the enumeration value contained therein. private static void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e) { // Power mode is changing. switch (e.Mode) { case PowerModes.Resume: Debug.WriteLine("PowerMode: OS is resuming from suspended state"); break; case PowerModes.StatusChange: Debug.WriteLine("PowerMode: There was a change relating to the power" + " supply (weak battery, unplug, etc..)"); break; case PowerModes.Suspend: Debug.WriteLine("PowerMode: OS is about to be suspended"); break; } } The next three handlers all deal with operating system session states. They are OnSessionSwitch, OnSessionEnding, and OnSessionEnded. Handling all three of these events covers all of the operating system session state transitions that your application may need to worry about. In OnSessionEnding, there is a SessionEndingEventArgs parameter, which has a Cancel member. This Cancel member allows you to request that the session not end if set to false. Code for the three handlers is shown in Example 20-1. Example 20-1. OnSessionSwitch, OnSessionEnding, and OnSessionEnded handlers
DiscussionThe .NET Framework provides many opportunities to get feedback from the system when there are changes due to either user or system interactions. The SystemEvents class exposes more events than just the ones used in this recipe. For a full listing, see
The notifications from SystemEvents come on a dedicated thread for raising these events. In a Windows Forms application, you will need to get back on to the correct user interface thread before updating a UI with any of this information, using one of the various methods for doing so (Control.BeginInvoke, Control.Invoke, BackgroundWorker). See AlsoSee the "SystemEvents Class," "PowerModeChangedEventArgs Class," "SessionEndedEventArgs Class," "SessionEndingEventArgs Class," "SessionSwitchEventArgs Class," "TimerElapsedEventArgs Class," "UserPreferenceChangingEventArgs Class," and "UserPreferenceChangedEventArgs Class" topics in the MSDN documentation. |