SystemEvents.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / CompMod / Microsoft / Win32 / SystemEvents.cs / 1305376 / SystemEvents.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace Microsoft.Win32 {
    using System; 
    using System.Diagnostics;
    using System.Security;
    using System.Security.Permissions;
    using System.Collections; 
    using System.Collections.Generic;
    using System.ComponentModel; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Reflection;
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Runtime.Versioning;
    using System.Text; 
    using System.Threading;
 
    ///  
    ///    
    ///       Provides a 
    ///       set of global system events to callers. This
    ///       class cannot be inherited.
    /// 
    [HostProtectionAttribute(MayLeakOnAbort = true)] 
    [
    // Disabling partial trust scenarios 
    PermissionSet(SecurityAction.LinkDemand, Name="FullTrust") 
    ]
    [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")] 
    public sealed class SystemEvents {
        // Almost all of our data is static.  We keep a single instance of
        // SystemEvents around so we can bind delegates to it.
        // Non-static methods in this class will only be called through 
        // one of the delegates.
        // 
        private static readonly object      eventLockObject = new object(); 
        private static readonly object      procLockObject = new object();
        private static SystemEvents         systemEvents; 
        private static Thread               windowThread;
        private static ManualResetEvent     eventWindowReady;
        private static Random               randomTimerId = new Random();
        private static bool                 startupRecreates; 
        private static bool                 registeredSessionNotification = false;
        private static int                  domainQualifier; 
        private static NativeMethods.WNDCLASS staticwndclass; 
        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        private static IntPtr               defWindowProc; 

        static string className = null;

        // cross-thread marshaling 
        private static Queue            threadCallbackList; // list of Delegates
        private static int threadCallbackMessage = 0; 
        private static ManualResetEvent eventThreadTerminated; 

        //Decide whether to marshal or use Everett-style non-marshaled calls 
        private static bool checkedThreadAffinity = false;
        private static bool useEverettThreadAffinity = false;
        private const string everettThreadAffinityValue = "EnableSystemEventsThreadAffinityCompatibility";
 
        // Per-instance data that is isolated to the window thread.
        // 
        private IntPtr                  windowHandle; 
        private NativeMethods.WndProc   windowProc;
        private NativeMethods.ConHndlr  consoleHandler; 

        // The set of events we respond to.
        //
        private static readonly object       OnUserPreferenceChangingEvent   = new object(); 
        private static readonly object       OnUserPreferenceChangedEvent    = new object();
        private static readonly object       OnSessionEndingEvent            = new object(); 
        private static readonly object       OnSessionEndedEvent             = new object(); 
        private static readonly object       OnPowerModeChangedEvent         = new object();
        private static readonly object       OnLowMemoryEvent                = new object(); 
        private static readonly object       OnDisplaySettingsChangingEvent  = new object();
        private static readonly object       OnDisplaySettingsChangedEvent   = new object();
        private static readonly object       OnInstalledFontsChangedEvent    = new object();
        private static readonly object       OnTimeChangedEvent              = new object(); 
        private static readonly object       OnTimerElapsedEvent             = new object();
        private static readonly object       OnPaletteChangedEvent           = new object(); 
        private static readonly object       OnEventsThreadShutdownEvent     = new object(); 
        private static readonly object       OnSessionSwitchEvent            = new object();
 

        // Our list of handler information.  This is a lookup of the above keys and objects that
        // match a delegate with a SyncronizationContext so we can fire on the proper thread.
        // 
        private static Dictionary>  _handlers;
 
 
        /// 
        ///     This class is static, there is no need to ever create it. 
        /// 
        private SystemEvents() {
        }
 

        // stole from SystemInformation... if we get SystemInformation moved 
        // to somewhere that we can use it... rip this! 
        //
        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] 
        private static IntPtr processWinStation = IntPtr.Zero;
        private static bool isUserInteractive = false;
        private static bool UserInteractive {
            [ResourceExposure(ResourceScope.None)] 
            [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
            get { 
                if (Environment.OSVersion.Platform == System.PlatformID.Win32NT) { 
                    IntPtr hwinsta = IntPtr.Zero;
 
                    hwinsta = UnsafeNativeMethods.GetProcessWindowStation();
                    if (hwinsta != IntPtr.Zero && processWinStation != hwinsta) {
                        isUserInteractive = true;
 
                        int lengthNeeded = 0;
                        NativeMethods.USEROBJECTFLAGS flags = new NativeMethods.USEROBJECTFLAGS(); 
 
                        if (UnsafeNativeMethods.GetUserObjectInformation(new HandleRef(null, hwinsta), NativeMethods.UOI_FLAGS, flags, Marshal.SizeOf(flags), ref lengthNeeded)) {
                            if ((flags.dwFlags & NativeMethods.WSF_VISIBLE) == 0) { 
                                isUserInteractive = false;
                            }
                        }
                        processWinStation = hwinsta; 
                    }
                } 
                else { 
                    isUserInteractive = true;
                } 
                return isUserInteractive;
            }
        }
 

        ///  
        ///    Occurs when the display settings are changing. 
        /// 
        public static event EventHandler DisplaySettingsChanging { 
            add {
                AddEventHandler(OnDisplaySettingsChangingEvent, value);
            }
            remove { 
                RemoveEventHandler(OnDisplaySettingsChangingEvent, value);
            } 
        } 

 
        /// 
        ///    Occurs when the user changes the display settings.
        /// 
        public static event EventHandler DisplaySettingsChanged { 
            add {
                AddEventHandler(OnDisplaySettingsChangedEvent, value); 
            } 
            remove {
                RemoveEventHandler(OnDisplaySettingsChangedEvent, value); 
            }
        }

 
        /// 
        ///    Occurs before the thread that listens for system events is terminated. 
        ///           Delegates will be invoked on the events thread. 
        /// 
        public static event EventHandler EventsThreadShutdown { 
            // Really only here for GDI+ initialization and shut down
            add {
                AddEventHandler(OnEventsThreadShutdownEvent, value);
            } 
            remove {
                RemoveEventHandler(OnEventsThreadShutdownEvent, value); 
            } 
        }
 

        /// 
        ///    Occurs when the user adds fonts to or removes fonts from the system.
        ///  
        public static event EventHandler InstalledFontsChanged {
            add { 
                AddEventHandler(OnInstalledFontsChangedEvent, value); 
            }
            remove { 
                RemoveEventHandler(OnInstalledFontsChangedEvent, value);
            }
        }
 

        ///  
        ///    Occurs when the system is running out of available RAM. 
        /// 
        [Obsolete("This event has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")] 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public static event EventHandler LowMemory
        {
            add { 
                EnsureSystemEvents(true, true);
                AddEventHandler(OnLowMemoryEvent, value); 
            } 
            remove {
                RemoveEventHandler(OnLowMemoryEvent, value); 
            }
        }

 
        /// 
        ///    Occurs when the user switches to an application that uses a different 
        ///       palette. 
        /// 
        public static event EventHandler PaletteChanged { 
            add {
                AddEventHandler(OnPaletteChangedEvent, value);
            }
            remove { 
                RemoveEventHandler(OnPaletteChangedEvent, value);
            } 
        } 

 
        /// 
        ///    Occurs when the user suspends or resumes the system.
        /// 
        public static event PowerModeChangedEventHandler PowerModeChanged { 
            add {
                EnsureSystemEvents(true, true); 
                AddEventHandler(OnPowerModeChangedEvent, value); 
            }
            remove { 
                RemoveEventHandler(OnPowerModeChangedEvent, value);
            }
        }
 

        ///  
        ///    Occurs when the user is logging off or shutting down the system. 
        /// 
        public static event SessionEndedEventHandler SessionEnded { 
            add {
                EnsureSystemEvents(true, false);
                AddEventHandler(OnSessionEndedEvent, value);
            } 
            remove {
                RemoveEventHandler(OnSessionEndedEvent, value); 
            } 
        }
 

        /// 
        ///    Occurs when the user is trying to log off or shutdown the system.
        ///  
        public static event SessionEndingEventHandler SessionEnding {
            add { 
                EnsureSystemEvents(true, false); 
                AddEventHandler(OnSessionEndingEvent, value);
            } 
            remove {
                RemoveEventHandler(OnSessionEndingEvent, value);
            }
        } 

        ///  
        ///    Occurs when a user session switches. 
        /// 
        public static event SessionSwitchEventHandler SessionSwitch { 
            add {
                EnsureSystemEvents(true, true);
                EnsureRegisteredSessionNotification();
                AddEventHandler(OnSessionSwitchEvent, value); 
            }
            remove { 
                RemoveEventHandler(OnSessionSwitchEvent, value); 
            }
        } 


        /// 
        ///    Occurs when the user changes the time on the system clock. 
        /// 
        public static event EventHandler TimeChanged { 
            add { 
                EnsureSystemEvents(true, false);
                AddEventHandler(OnTimeChangedEvent, value); 
            }
            remove {
                RemoveEventHandler(OnTimeChangedEvent, value);
            } 
        }
 
 
        /// 
        ///    Occurs when a windows timer interval has expired. 
        /// 
        public static event TimerElapsedEventHandler TimerElapsed {
            add {
                EnsureSystemEvents(true, false); 
                AddEventHandler(OnTimerElapsedEvent, value);
            } 
            remove { 
                RemoveEventHandler(OnTimerElapsedEvent, value);
            } 
        }


        ///  
        ///    Occurs when a user preference has changed.
        ///  
        public static event UserPreferenceChangedEventHandler UserPreferenceChanged { 
            add {
                AddEventHandler(OnUserPreferenceChangedEvent, value); 
            }
            remove {
                RemoveEventHandler(OnUserPreferenceChangedEvent, value);
            } 
        }
 
        ///  
        ///    Occurs when a user preference is changing.
        ///  
        public static event UserPreferenceChangingEventHandler UserPreferenceChanging {
            add {
                AddEventHandler(OnUserPreferenceChangingEvent, value);
            } 
            remove {
                RemoveEventHandler(OnUserPreferenceChangingEvent, value); 
            } 
        }
 
        [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity")]
        private static void AddEventHandler(object key, Delegate value) {
            lock (eventLockObject) {
 
               if (_handlers == null) {
                    _handlers = new Dictionary>(); 
                    EnsureSystemEvents(false, false); 
               }
 
               List invokeItems;

               if (!_handlers.TryGetValue(key, out invokeItems)) {
 
                    invokeItems = new List();
                    _handlers[key] = invokeItems; 
               } 
               else {
                    invokeItems = _handlers[key]; 
               }

               invokeItems.Add(new SystemEventInvokeInfo(value));
            } 
        }
 
        ///  
        ///      Console handler we add in case we are a console application or a service.
        ///      Without this we will not get end session events. 
        /// 
        private int ConsoleHandlerProc(int signalType) {

            switch (signalType) { 
                case NativeMethods.CTRL_LOGOFF_EVENT:
                    OnSessionEnded((IntPtr) 1, (IntPtr) NativeMethods.ENDSESSION_LOGOFF); 
                    break; 

                case NativeMethods.CTRL_SHUTDOWN_EVENT: 
                    OnSessionEnded((IntPtr) 1, (IntPtr) 0);
                    break;
            }
 
            return 0;
        } 
 
        private NativeMethods.WNDCLASS WndClass {
            [ResourceExposure(ResourceScope.AppDomain | ResourceScope.Assembly)] 
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.AppDomain | ResourceScope.Assembly)]
            get {
                if (staticwndclass == null) {
                    const string classNameFormat = ".NET-BroadcastEventWindow.{0}.{1}.{2}"; 

                    IntPtr hInstance = UnsafeNativeMethods.GetModuleHandle(null); 
 
                    className = string.Format(System.Globalization.CultureInfo.InvariantCulture,
                        classNameFormat, 
                        ThisAssembly.Version,
                        Convert.ToString(AppDomain.CurrentDomain.GetHashCode(), 16),
                        domainQualifier);
 
                    staticwndclass = new NativeMethods.WNDCLASS();
                    staticwndclass.hbrBackground = (IntPtr)(NativeMethods.COLOR_WINDOW + 1); 
                    staticwndclass.style = 0; 

                    windowProc = new NativeMethods.WndProc(this.WindowProc); 
                    staticwndclass.lpszClassName = className;
                    staticwndclass.lpfnWndProc = windowProc;
                    staticwndclass.hInstance = hInstance;
                } 
                return staticwndclass;
            } 
        } 

        private IntPtr DefWndProc { 
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
            get {
                if (defWindowProc == IntPtr.Zero) { 
                    string defproc = (Marshal.SystemDefaultCharSize == 1 ? "DefWindowProcA" : "DefWindowProcW");
 
                    defWindowProc = UnsafeNativeMethods.GetProcAddress(new HandleRef(this, UnsafeNativeMethods.GetModuleHandle("user32.dll")), defproc); 
                }
                return defWindowProc; 
            }
        }

        private void BumpQualifier() { 
            staticwndclass = null;
            domainQualifier++; 
        } 

        ///  
        /// 
        ///      Goes through the work to register and create a window.
        /// 
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private IntPtr CreateBroadcastWindow() { 
 
            // Register the window class.
            // 
            NativeMethods.WNDCLASS_I wndclassi = new NativeMethods.WNDCLASS_I();
            IntPtr hInstance = UnsafeNativeMethods.GetModuleHandle(null);

            if (!UnsafeNativeMethods.GetClassInfo(new HandleRef(this, hInstance), WndClass.lpszClassName, wndclassi)) { 

                if (UnsafeNativeMethods.RegisterClass(WndClass) == 0) { 
                    windowProc = null; 
                    Debug.Fail("Unable to register broadcast window class");
                    return IntPtr.Zero; 
                }
            }
            else {
                //lets double check the wndproc returned by getclassinfo for defwndproc. 
                if (wndclassi.lpfnWndProc == DefWndProc) {
 
                    //if we are in there, it means className belongs to an unloaded appdomain. 
                    short atom = 0;
 
                    //try to unregister it.
                    if (0 != UnsafeNativeMethods.UnregisterClass(WndClass.lpszClassName, new HandleRef(null, UnsafeNativeMethods.GetModuleHandle(null)))) {
                        atom = UnsafeNativeMethods.RegisterClass(WndClass);
                    } 

                    if (atom == 0) { 
                        do { 
                            BumpQualifier();
                            atom = UnsafeNativeMethods.RegisterClass(WndClass); 
                        } while (atom == 0 && Marshal.GetLastWin32Error() == NativeMethods.ERROR_CLASS_ALREADY_EXISTS);
                    }
                }
            } 

            // And create an instance of the window. 
            // 
            IntPtr hwnd = UnsafeNativeMethods.CreateWindowEx(
                                                            0, 
                                                            WndClass.lpszClassName,
                                                            WndClass.lpszClassName,
                                                            NativeMethods.WS_POPUP,
                                                            0, 0, 0, 0, NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, 
                                                            new HandleRef(this, hInstance), null);
            return hwnd; 
        } 

        ///  
        /// 
        ///    Creates a new window timer asociated with the
        ///       system events window.
        ///  
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        public static IntPtr CreateTimer(int interval) { 
            if (interval <= 0) {
                throw new ArgumentException(SR.GetString(SR.InvalidLowBoundArgument, "interval", interval.ToString(System.Threading.Thread.CurrentThread.CurrentCulture), "0")); 
            }

            EnsureSystemEvents(true, true);
            IntPtr timerId = UnsafeNativeMethods.SendMessage(new HandleRef(systemEvents, systemEvents.windowHandle), 
                                                             NativeMethods.WM_CREATETIMER, (IntPtr)interval, IntPtr.Zero);
 
            if (timerId == IntPtr.Zero) { 
                throw new ExternalException(SR.GetString(SR.ErrorCreateTimer));
            } 
            return timerId;
        }

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private void Dispose() { 
            if (windowHandle != IntPtr.Zero) { 

                if (registeredSessionNotification) { 
                    UnsafeNativeMethods.WTSUnRegisterSessionNotification(new HandleRef(systemEvents, systemEvents.windowHandle));
                }

                IntPtr handle = windowHandle; 
                windowHandle = IntPtr.Zero;
 
                HandleRef href = new HandleRef(this, handle); 

                //we check IsWindow because Application may have rudely destroyed our broadcast window. 
                //if this were true, we want to unregister the class.
                if (UnsafeNativeMethods.IsWindow(href) && DefWndProc != IntPtr.Zero) {
                    UnsafeNativeMethods.SetWindowLong(href, NativeMethods.GWL_WNDPROC, new HandleRef(this, DefWndProc));
 
                    //set our sentinel value that we will look for upon initialization to indicate
                    //the window class belongs to an unloaded appdomain and therefore should not be used. 
                    UnsafeNativeMethods.SetClassLong(href, NativeMethods.GCL_WNDPROC, DefWndProc); 
                }
 
                // If DestroyWindow failed, it is because we're being
                // shutdown from another thread.  In this case, locate the
                // DefWindowProc call in User32, sling the window back to it,
                // and post a nice fat WM_CLOSE 
                //
                if (UnsafeNativeMethods.IsWindow(href) && !UnsafeNativeMethods.DestroyWindow(href)) { 
                    UnsafeNativeMethods.PostMessage(href, NativeMethods.WM_CLOSE, IntPtr.Zero, IntPtr.Zero); 
                }
                else { 
                    IntPtr hInstance = UnsafeNativeMethods.GetModuleHandle(null);
                    UnsafeNativeMethods.UnregisterClass(className, new HandleRef(this, hInstance));
                }
            } 

            if (consoleHandler != null) { 
                UnsafeNativeMethods.SetConsoleCtrlHandler(consoleHandler, 0); 
                consoleHandler = null;
            } 
        }

        /// 
        ///  Creates the static resources needed by 
        ///  system events.
        ///  
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
        private static void EnsureSystemEvents(bool requireHandle, bool throwOnRefusal) { 

            // The secondary check here is to detect asp.net.  Asp.net uses multiple
            // app domains to field requests and we do not want to gobble up an
            // additional thread per domain.  So under this scenario SystemEvents 
            // becomes a nop.
            // 
            if (systemEvents == null) { 
                lock (procLockObject) {
                    if (systemEvents == null) { 
                        if (Thread.GetDomain().GetData(".appDomain") != null) {
                            if (throwOnRefusal) {
                                throw new InvalidOperationException(SR.GetString(SR.ErrorSystemEventsNotSupported));
                            } 
                            return;
                        } 
 
                        // If we are creating system events on a thread declared as STA, then
                        // just share the thread. 
                        //
                        if (!UserInteractive || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) {
                            systemEvents = new SystemEvents();
                            systemEvents.Initialize(); 
                        }
                        else { 
                            eventWindowReady = new ManualResetEvent(false); 
                            systemEvents = new SystemEvents();
                            windowThread = new Thread(new ThreadStart(systemEvents.WindowThreadProc)); 
                            windowThread.IsBackground = true;
                            windowThread.Name = ".NET SystemEvents";
                            windowThread.Start();
                            eventWindowReady.WaitOne(); 
                        }
 
                        if (requireHandle && systemEvents.windowHandle == IntPtr.Zero) { 
                            // In theory, it's not the end of the world that
                            // we don't get system events.  Unfortunately, the main reason windowHandle == 0 
                            // is CreateWindowEx failed for mysterious reasons, and when that happens,
                            // subsequent (and more important) CreateWindowEx calls also fail.
                            // See ASURT #44424 for a rather lengthy discussion of this.
                            throw new ExternalException(SR.GetString(SR.ErrorCreateSystemEvents)); 
                        }
 
                        startupRecreates = false; 
                    }
                } 
            }
        }

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static void EnsureRegisteredSessionNotification() { 
            if (!registeredSessionNotification) { 
                IntPtr retval = SafeNativeMethods.LoadLibrary(ExternDll.Wtsapi32);
 
                if (retval != IntPtr.Zero) {
                    UnsafeNativeMethods.WTSRegisterSessionNotification(new HandleRef(systemEvents, systemEvents.windowHandle), NativeMethods.NOTIFY_FOR_THIS_SESSION);
                    registeredSessionNotification = true;
                    SafeNativeMethods.FreeLibrary(new HandleRef(null, retval)); 
                }
            } 
        } 

        [SuppressMessage("Microsoft.Performance", "CA1801:AvoidUnusedParameters")] 
        private UserPreferenceCategory GetUserPreferenceCategory(int msg, IntPtr wParam, IntPtr lParam) {

            UserPreferenceCategory pref = UserPreferenceCategory.General;
 
            if (msg == NativeMethods.WM_SETTINGCHANGE) {
 
                if (lParam != IntPtr.Zero && Marshal.PtrToStringAuto(lParam).Equals("Policy")) { 
                    pref = UserPreferenceCategory.Policy;
                } 
                else if (lParam != IntPtr.Zero && Marshal.PtrToStringAuto(lParam).Equals("intl")) {
                    pref = UserPreferenceCategory.Locale;
                }
                else { 
                    switch ((int) wParam) {
                        case NativeMethods.SPI_SETACCESSTIMEOUT: 
                        case NativeMethods.SPI_SETFILTERKEYS: 
                        case NativeMethods.SPI_SETHIGHCONTRAST:
                        case NativeMethods.SPI_SETMOUSEKEYS: 
                        case NativeMethods.SPI_SETSCREENREADER:
                        case NativeMethods.SPI_SETSERIALKEYS:
                        case NativeMethods.SPI_SETSHOWSOUNDS:
                        case NativeMethods.SPI_SETSOUNDSENTRY: 
                        case NativeMethods.SPI_SETSTICKYKEYS:
                        case NativeMethods.SPI_SETTOGGLEKEYS: 
                            pref = UserPreferenceCategory.Accessibility; 
                            break;
 
                        case NativeMethods.SPI_SETDESKWALLPAPER:
                        case NativeMethods.SPI_SETFONTSMOOTHING:
                        case NativeMethods.SPI_SETCURSORS:
                        case NativeMethods.SPI_SETDESKPATTERN: 
                        case NativeMethods.SPI_SETGRIDGRANULARITY:
                        case NativeMethods.SPI_SETWORKAREA: 
                            pref = UserPreferenceCategory.Desktop; 
                            break;
 
                        case NativeMethods.SPI_ICONHORIZONTALSPACING:
                        case NativeMethods.SPI_ICONVERTICALSPACING:
                        case NativeMethods.SPI_SETICONMETRICS:
                        case NativeMethods.SPI_SETICONS: 
                        case NativeMethods.SPI_SETICONTITLELOGFONT:
                        case NativeMethods.SPI_SETICONTITLEWRAP: 
                            pref = UserPreferenceCategory.Icon; 
                            break;
 
                        case NativeMethods.SPI_SETDOUBLECLICKTIME:
                        case NativeMethods.SPI_SETDOUBLECLKHEIGHT:
                        case NativeMethods.SPI_SETDOUBLECLKWIDTH:
                        case NativeMethods.SPI_SETMOUSE: 
                        case NativeMethods.SPI_SETMOUSEBUTTONSWAP:
                        case NativeMethods.SPI_SETMOUSEHOVERHEIGHT: 
                        case NativeMethods.SPI_SETMOUSEHOVERTIME: 
                        case NativeMethods.SPI_SETMOUSESPEED:
                        case NativeMethods.SPI_SETMOUSETRAILS: 
                        case NativeMethods.SPI_SETSNAPTODEFBUTTON:
                        case NativeMethods.SPI_SETWHEELSCROLLLINES:
                        case NativeMethods.SPI_SETCURSORSHADOW:
                        case NativeMethods.SPI_SETHOTTRACKING: 
                        case NativeMethods.SPI_SETTOOLTIPANIMATION:
                        case NativeMethods.SPI_SETTOOLTIPFADE: 
                            pref = UserPreferenceCategory.Mouse; 
                            break;
 
                        case NativeMethods.SPI_SETKEYBOARDDELAY:
                        case NativeMethods.SPI_SETKEYBOARDPREF:
                        case NativeMethods.SPI_SETKEYBOARDSPEED:
                        case NativeMethods.SPI_SETLANGTOGGLE: 
                            pref = UserPreferenceCategory.Keyboard;
                            break; 
 
                        case NativeMethods.SPI_SETMENUDROPALIGNMENT:
                        case NativeMethods.SPI_SETMENUFADE: 
                        case NativeMethods.SPI_SETMENUSHOWDELAY:
                        case NativeMethods.SPI_SETMENUANIMATION:
                        case NativeMethods.SPI_SETSELECTIONFADE:
                            pref = UserPreferenceCategory.Menu; 
                            break;
 
                        case NativeMethods.SPI_SETLOWPOWERACTIVE: 
                        case NativeMethods.SPI_SETLOWPOWERTIMEOUT:
                        case NativeMethods.SPI_SETPOWEROFFACTIVE: 
                        case NativeMethods.SPI_SETPOWEROFFTIMEOUT:
                            pref = UserPreferenceCategory.Power;
                            break;
 
                        case NativeMethods.SPI_SETSCREENSAVEACTIVE:
                        case NativeMethods.SPI_SETSCREENSAVERRUNNING: 
                        case NativeMethods.SPI_SETSCREENSAVETIMEOUT: 
                            pref = UserPreferenceCategory.Screensaver;
                            break; 

                        case NativeMethods.SPI_SETKEYBOARDCUES:
                        case NativeMethods.SPI_SETCOMBOBOXANIMATION:
                        case NativeMethods.SPI_SETLISTBOXSMOOTHSCROLLING: 
                        case NativeMethods.SPI_SETGRADIENTCAPTIONS:
                        case NativeMethods.SPI_SETUIEFFECTS: 
                        case NativeMethods.SPI_SETACTIVEWINDOWTRACKING: 
                        case NativeMethods.SPI_SETACTIVEWNDTRKZORDER:
                        case NativeMethods.SPI_SETACTIVEWNDTRKTIMEOUT: 
                        case NativeMethods.SPI_SETANIMATION:
                        case NativeMethods.SPI_SETBORDER:
                        case NativeMethods.SPI_SETCARETWIDTH:
                        case NativeMethods.SPI_SETDRAGFULLWINDOWS: 
                        case NativeMethods.SPI_SETDRAGHEIGHT:
                        case NativeMethods.SPI_SETDRAGWIDTH: 
                        case NativeMethods.SPI_SETFOREGROUNDFLASHCOUNT: 
                        case NativeMethods.SPI_SETFOREGROUNDLOCKTIMEOUT:
                        case NativeMethods.SPI_SETMINIMIZEDMETRICS: 
                        case NativeMethods.SPI_SETNONCLIENTMETRICS:
                        case NativeMethods.SPI_SETSHOWIMEUI:
                            pref = UserPreferenceCategory.Window;
                            break; 
                    }
                } 
            } 
            else if (msg == NativeMethods.WM_SYSCOLORCHANGE) {
                pref = UserPreferenceCategory.Color; 
            }
            else {
                Debug.Fail("Unrecognized message passed to UserPreferenceCategory");
            } 

            return pref; 
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private void Initialize() {
            consoleHandler = new NativeMethods.ConHndlr(this.ConsoleHandlerProc);
            if (!UnsafeNativeMethods.SetConsoleCtrlHandler(consoleHandler, 1)) { 
                Debug.Fail("Failed to install console handler.");
                consoleHandler = null; 
            } 

            windowHandle = CreateBroadcastWindow(); 
            Debug.Assert(windowHandle != IntPtr.Zero, "CreateBroadcastWindow failed");

            AppDomain.CurrentDomain.ProcessExit += new EventHandler(SystemEvents.Shutdown);
            AppDomain.CurrentDomain.DomainUnload += new EventHandler(SystemEvents.Shutdown); 
        }
 
        ///  
        ///     Called on the control's owning thread to perform the actual callback.
        ///     This empties this control's callback queue, propagating any excpetions 
        ///     back as needed.
        /// 
        [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 
        private void InvokeMarshaledCallbacks() {
            Debug.Assert(threadCallbackList != null, "Invoking marshaled callbacks before there are any"); 
 
            Delegate current = null;
            lock (threadCallbackList) { 
                if (threadCallbackList.Count > 0) {
                    current = (Delegate)threadCallbackList.Dequeue();
                }
            } 

            // Now invoke on all the queued items. 
            // 
            while (current != null) {
                try { 
                    // Optimize a common case of using EventHandler. This allows us to invoke
                    // early bound, which is a bit more efficient.
                    //
                    EventHandler c = current as EventHandler; 
                    if (c != null) {
                        c(null, EventArgs.Empty); 
                    } 
                    else {
                        current.DynamicInvoke(new object[0]); 
                    }
                }
                catch (Exception t) {
                    Debug.Fail("SystemEvents marshaled callback failed:" + t); 
                }
                lock (threadCallbackList) { 
                    if (threadCallbackList.Count > 0) { 
                        current = (Delegate)threadCallbackList.Dequeue();
                    } 
                    else {
                        current = null;
                    }
                } 
            }
        } 
 
        /// 
        ///     Executes the given delegate on the thread that listens for system events.  Similar to Control.Invoke(). 
        /// 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        public static void InvokeOnEventsThread(Delegate method) { 
            // This method is really only here for GDI+ initialization/shutdown
            EnsureSystemEvents(true, true); 
 
#if DEBUG
            int pid; 
            int thread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(systemEvents, systemEvents.windowHandle), out pid);
            Debug.Assert(windowThread == null || thread != SafeNativeMethods.GetCurrentThreadId(), "Don't call MarshaledInvoke on the system events thread");
#endif
 
            if (threadCallbackList == null) {
                lock (eventLockObject) { 
                    if (threadCallbackList == null) { 
                        threadCallbackList = new Queue();
                        threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage("SystemEventsThreadCallbackMessage"); 
                    }
                }
            }
 
            Debug.Assert(threadCallbackMessage != 0, "threadCallbackList initialized but threadCallbackMessage not?");
 
            lock (threadCallbackList) { 
                threadCallbackList.Enqueue(method);
            } 

            UnsafeNativeMethods.PostMessage(new HandleRef(systemEvents, systemEvents.windowHandle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
        }
 
        /// 
        ///  
        ///    Kills the timer specified by the given id. 
        /// 
        public static void KillTimer(IntPtr timerId) { 
            EnsureSystemEvents(true, true);
            if (systemEvents.windowHandle != IntPtr.Zero) {
                int res = (int) UnsafeNativeMethods.SendMessage(new HandleRef(systemEvents, systemEvents.windowHandle),
                                                                NativeMethods.WM_KILLTIMER, timerId, IntPtr.Zero); 

                if (res == 0) 
                    throw new ExternalException(SR.GetString(SR.ErrorKillTimer)); 
            }
        } 

        /// 
        ///      Callback that handles the create timer
        ///      user message. 
        /// 
        private IntPtr OnCreateTimer(IntPtr wParam) { 
            IntPtr timerId = (IntPtr) randomTimerId.Next(); 
            IntPtr res = UnsafeNativeMethods.SetTimer(new HandleRef(this, windowHandle), new HandleRef(this, timerId), (int) wParam, NativeMethods.NullHandleRef);
            return(res == IntPtr.Zero ? IntPtr.Zero: timerId); 
        }

        /// 
        ///      Handler that raises the DisplaySettings changing event 
        /// 
        private void OnDisplaySettingsChanging() { 
            RaiseEvent(OnDisplaySettingsChangingEvent, this, EventArgs.Empty); 
        }
 
        /// 
        ///      Handler that raises the DisplaySettings changed event
        /// 
        private void OnDisplaySettingsChanged() { 
            RaiseEvent(OnDisplaySettingsChangedEvent, this, EventArgs.Empty);
        } 
 
        /// 
        ///      Handler for any event that fires a standard EventHandler delegate. 
        /// 
        private void OnGenericEvent(object eventKey) {
            RaiseEvent(eventKey, this, EventArgs.Empty);
        } 

        private void OnShutdown(object eventKey) { 
            RaiseEvent(false, eventKey, this, EventArgs.Empty); 
        }
 
        /// 
        ///      Callback that handles the KillTimer
        ///      user message.
        ///  
        private bool OnKillTimer(IntPtr wParam) {
            bool res = UnsafeNativeMethods.KillTimer(new HandleRef(this, windowHandle), new HandleRef(this, wParam)); 
            return res; 
        }
 
        /// 
        ///      Handler for WM_POWERBROADCAST.
        /// 
        private void OnPowerModeChanged(IntPtr wParam) { 

            PowerModes mode; 
 
            switch ((int)wParam)
            { 
                case NativeMethods.PBT_APMSUSPEND:
                case NativeMethods.PBT_APMSTANDBY:
                    mode = PowerModes.Suspend;
                    break; 

                case NativeMethods.PBT_APMRESUMECRITICAL: 
                case NativeMethods.PBT_APMRESUMESUSPEND: 
                case NativeMethods.PBT_APMRESUMESTANDBY:
                    mode = PowerModes.Resume; 
                    break;

                case NativeMethods.PBT_APMBATTERYLOW:
                case NativeMethods.PBT_APMPOWERSTATUSCHANGE: 
                case NativeMethods.PBT_APMOEMEVENT:
                    mode = PowerModes.StatusChange; 
                    break; 

                default: 
                    return;
            }

            RaiseEvent(OnPowerModeChangedEvent ,this, new PowerModeChangedEventArgs (mode)); 

        } 
 
        /// 
        ///      Handler for WM_ENDSESSION. 
        /// 
        private void OnSessionEnded(IntPtr wParam, IntPtr lParam) {

            // wParam will be nonzero if the session is actually ending.  If 
            // it was canceled then we do not want to raise the event.
            // 
            if (wParam != (IntPtr) 0) { 

                SessionEndReasons reason = SessionEndReasons.SystemShutdown; 

                if (((unchecked ((int)(long) lParam)) & NativeMethods.ENDSESSION_LOGOFF) != 0) {
                    reason = SessionEndReasons.Logoff;
                } 

                SessionEndedEventArgs endEvt = new SessionEndedEventArgs(reason); 
 
                RaiseEvent(OnSessionEndedEvent, this, endEvt);
            } 
        }

        /// 
        ///      Handler for WM_QUERYENDSESSION. 
        /// 
        private int OnSessionEnding(IntPtr lParam) { 
            int endOk = 1; 

            SessionEndReasons reason = SessionEndReasons.SystemShutdown; 

            //Casting to (int) is bad if we're 64-bit; casting to (long) is ok whether we're 64- or 32-bit.
            if ((((long)lParam) & NativeMethods.ENDSESSION_LOGOFF) != 0) {
                reason = SessionEndReasons.Logoff; 
            }
 
            SessionEndingEventArgs endEvt = new SessionEndingEventArgs(reason); 

            RaiseEvent(OnSessionEndingEvent, this, endEvt); 
            endOk = (endEvt.Cancel ? 0 : 1);

            return endOk;
        } 

        private void OnSessionSwitch(int wParam) { 
            SessionSwitchEventArgs switchEventArgs = new SessionSwitchEventArgs((SessionSwitchReason)wParam); 

            RaiseEvent (OnSessionSwitchEvent, this, switchEventArgs); 
        }

        /// 
        ///      Handler for WM_THEMECHANGED 
        ///      Whidbey note: Before Whidbey, we used to fire UserPreferenceChanged with category
        ///      set to Window. In Whidbey, we support visual styles and need a new category Theme 
        ///      since Window is too general. We fire UserPreferenceChanged with this category, but 
        ///      for backward compat, we also fire it with category set to Window.
        ///  
        private void OnThemeChanged() {
            //we need to fire a changing event handler for Themes.
            //note that it needs to be documented that accessing theme information during the changing event is forbidden.
            RaiseEvent(OnUserPreferenceChangingEvent, this, new UserPreferenceChangingEventArgs(UserPreferenceCategory.VisualStyle)); 

            UserPreferenceCategory pref = UserPreferenceCategory.Window; 
 
            RaiseEvent (OnUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs (pref));
 
            pref = UserPreferenceCategory.VisualStyle;

            RaiseEvent(OnUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs (pref));
        } 

        ///  
        ///      Handler for WM_SETTINGCHANGE and WM_SYSCOLORCHANGE. 
        /// 
        private void OnUserPreferenceChanged(int msg, IntPtr wParam, IntPtr lParam) { 
            UserPreferenceCategory pref = GetUserPreferenceCategory(msg, wParam, lParam);

            RaiseEvent(OnUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs (pref));
        } 

        private void OnUserPreferenceChanging(int msg, IntPtr wParam, IntPtr lParam) { 
 
            UserPreferenceCategory pref = GetUserPreferenceCategory(msg, wParam, lParam);
 
            RaiseEvent(OnUserPreferenceChangingEvent, this, new UserPreferenceChangingEventArgs(pref));
        }

        ///  
        ///      Handler for WM_TIMER.
        ///  
        private void OnTimerElapsed(IntPtr wParam) { 
            RaiseEvent(OnTimerElapsedEvent, this, new TimerElapsedEventArgs (wParam));
        } 

        #region EverettThreadAffinity
        //VSWhidbey 470990: we need a backdoor to allow applications to enable the old, broken
        //behavior for SystemEvents, where we fire them on whichever thread they end up on. 
        //It's unlikely that someone's depending on this behavior, but we want to avoid a QFE if
        //they are.  Unfortunately, all of CommonAppDataRegistry's friends are on 
        //System.Windows.Forms.Application, and we can't take a dependency to windows forms from here. 
        internal static bool UseEverettThreadAffinity {
            [ResourceExposure(ResourceScope.None)] 
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            get {
                if (!checkedThreadAffinity) {
                    //No point in locking if we don't have to... 
                    lock (eventLockObject) {
                        //...but now that we have the lock, make sure nobody else just beat us here. 
                        if (!checkedThreadAffinity) { 
                            checkedThreadAffinity = true;
                            string template = @"Software\{0}\{1}\{2}"; 
                            try {
                                //We need access to be able to read from the registry here.  We're not creating a
                                //registry key, nor are we returning information from the registry to the user.
                                new RegistryPermission(PermissionState.Unrestricted).Assert(); 
                                RegistryKey key = Registry.LocalMachine.OpenSubKey(string.Format(System.Globalization.CultureInfo.CurrentCulture,
                                    template, CompanyNameInternal, ProductNameInternal, ProductVersionInternal)); 
                                if (key != null) { 
                                    object value = key.GetValue(everettThreadAffinityValue);
                                    if (value != null && (int)value != 0) { 
                                        useEverettThreadAffinity = true;
                                    }
                                }
                            } 
                            catch (SecurityException) {
                                // Can't read the key: use default value (false) 
                            } 
                            catch (InvalidCastException) {
                                // Key is of wrong type: use default value (false) 
                            }
                        }
                    }
                } 
                return useEverettThreadAffinity;
            } 
        } 

        private static string CompanyNameInternal { 
            //No point in caching the value: we're only using it once.
            get {
                string companyName = null;
                // custom attribute 
                //
                Assembly entryAssembly = Assembly.GetEntryAssembly(); 
                if (entryAssembly != null) { 
                    object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
                    if (attrs != null && attrs.Length > 0) { 
                        companyName = ((AssemblyCompanyAttribute)attrs[0]).Company;
                    }
                }
 
                // win32 version
                // 
                if (companyName == null || companyName.Length == 0) { 
                    companyName = GetAppFileVersionInfo().CompanyName;
                    if (companyName != null) { 
                        companyName = companyName.Trim();
                    }
                }
 
                // fake it with a namespace
                // won't work with MC++ see GetAppMainType. 
                if (companyName == null || companyName.Length == 0) { 
                    Type t = GetAppMainType();
 
                    if (t != null) {
                        string ns = t.Namespace;

                        if (!string.IsNullOrEmpty(ns)) { 
                            int firstDot = ns.IndexOf(".", StringComparison.Ordinal);
                            if (firstDot != -1) { 
                                companyName = ns.Substring(0, firstDot); 
                            }
                            else { 
                                companyName = ns;
                            }
                        }
                        else { 
                            // last ditch... no namespace, use product name...
                            // 
                            companyName = ProductNameInternal; 
                        }
                    } 
                }
                return companyName;
            }
        } 

        private static string ProductNameInternal { 
            get { 
                string productName = null;
                // custom attribute 
                //
                Assembly entryAssembly = Assembly.GetEntryAssembly();
                if (entryAssembly != null) {
                    object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false); 
                    if (attrs != null && attrs.Length > 0) {
                        productName = ((AssemblyProductAttribute)attrs[0]).Product; 
                    } 
                }
 
                // win32 version info
                //
                if (productName == null || productName.Length == 0) {
                    productName = GetAppFileVersionInfo().ProductName; 
                    if (productName != null) {
                        productName = productName.Trim(); 
                    } 
                }
 
                // fake it with namespace
                // won't work with MC++ see GetAppMainType.
                if (productName == null || productName.Length == 0) {
                    Type t = GetAppMainType(); 

                    if (t != null) { 
                        string ns = t.Namespace; 

                        if (!string.IsNullOrEmpty(ns)) { 
                            int lastDot = ns.LastIndexOf(".", StringComparison.Ordinal);
                            if (lastDot != -1 && lastDot < ns.Length - 1) {
                                productName = ns.Substring(lastDot + 1);
                            } 
                            else {
                                productName = ns; 
                            } 
                        }
                        else { 
                            // last ditch... use the main type
                            //
                            productName = t.Name;
                        } 
                    }
                } 
                return productName; 
            }
        } 

        private static string ProductVersionInternal {
            get {
                string productVersion = null; 
                // custom attribute
                // 
                Assembly entryAssembly = Assembly.GetEntryAssembly(); 
                if (entryAssembly != null) {
                    object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); 
                    if (attrs != null && attrs.Length > 0) {
                        productVersion = ((AssemblyInformationalVersionAttribute)attrs[0]).InformationalVersion;
                    }
                } 

                // win32 version info 
                // 
                if (productVersion == null || productVersion.Length == 0) {
                    productVersion = GetAppFileVersionInfo().ProductVersion; 
                    if (productVersion != null) {
                        productVersion = productVersion.Trim();
                    }
                } 

                // fake it 
                // 
                if (productVersion == null || productVersion.Length == 0) {
                    productVersion = "1.0.0.0"; 
                }
                return productVersion;
            }
        } 

        private static object appFileVersion; 
        [ResourceExposure(ResourceScope.Machine)]  // Let's review who calls this, and why. 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static FileVersionInfo GetAppFileVersionInfo() { 
            if (appFileVersion == null) {
                Type t = GetAppMainType();
                if (t != null) {
                    // SECREVIEW : This Assert is ok, getting the module's version is a safe operation, 
                    //             the result is provided by the system.
                    // 
                    FileIOPermission fiop = new FileIOPermission(PermissionState.None); 
                    fiop.AllFiles = FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read;
                    fiop.Assert(); 

                    try {
                        appFileVersion = FileVersionInfo.GetVersionInfo(t.Module.FullyQualifiedName);
                    } 
                    finally {
                        CodeAccessPermission.RevertAssert(); 
                    } 
                }
                else { 
                    appFileVersion = FileVersionInfo.GetVersionInfo(ExecutablePath);
                }
            }
 
            return (FileVersionInfo)appFileVersion;
        } 
 
        /// 
        ///  
        ///     Retrieves the Type that contains the "Main" method.
        /// 
        private static Type mainType;
        private static Type GetAppMainType() { 
            if (mainType == null) {
                Assembly exe = Assembly.GetEntryAssembly(); 
 
                // Get Main type...This doesn't work in MC++ because Main is a global function and not
                // a class static method (it doesn't belong to a Type). 
                if (exe != null) {
                    mainType = exe.EntryPoint.ReflectedType;
                }
            } 

            return mainType; 
        } 

        private static string executablePath = null; 
        private static string ExecutablePath {
            [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)] 
            get {
                if (executablePath == null) { 
                    Assembly asm = Assembly.GetEntryAssembly(); 
                    if (asm == null) {
                        StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); 
                        UnsafeNativeMethods.GetModuleFileName(NativeMethods.NullHandleRef, sb, sb.Capacity);

                        executablePath = IntSecurity.UnsafeGetFullPath(sb.ToString());
                    } 
                    else {
                        String ecb = asm.EscapedCodeBase; 
                        Uri codeBase = new Uri(ecb); 
                        if (codeBase.Scheme == "file") {
                            executablePath = NativeMethods.GetLocalPath(ecb); 
                        }
                        else {
                            executablePath = codeBase.ToString();
                        } 
                    }
                } 
                Uri exeUri = new Uri(executablePath); 
                if (exeUri.Scheme == "file") {
                    new FileIOPermission(FileIOPermissionAccess.PathDiscovery, executablePath).Demand(); 
                }
                return executablePath;
            }
        } 
        #endregion
 
        private static void RaiseEvent(object key, params object[] args) { 
            RaiseEvent(true, key, args);
        } 

        [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private static void RaiseEvent(bool checkFinalization, object key, params object[] args) { 
            //If the AppDomain's unloading, we shouldn't fire SystemEvents other than Shutdown.
            if (checkFinalization && AppDomain.CurrentDomain.IsFinalizingForUnload()) { 
                return; 
            }
 
            SystemEventInvokeInfo[] invokeItemArray = null;

            lock (eventLockObject) {
 
                if (_handlers != null && _handlers.ContainsKey(key)) {
                    List invokeItems = _handlers[key]; 
 
                    // clone the list so we don't have this type locked and cause
                    // a deadlock if someone tries to modify handlers during an invoke. 
                    //
                    if (invokeItems != null) {
                        invokeItemArray = invokeItems.ToArray();
                    } 
                }
 
            } 

            if (invokeItemArray != null) { 
                for (int i = 0; i < invokeItemArray.Length; i++) {
                    try
                    {
                        SystemEventInvokeInfo info = invokeItemArray[i]; 
                        info.Invoke(checkFinalization, args);
                        invokeItemArray[i] = null; // clear it if it's valid 
                    } 
                    catch (Exception)
                    { 
                        //Eat exceptions (Everett compat)
                    }
                }
 
                // clean out any that are dead.
                // 
                lock (eventLockObject) { 
                    List invokeItems = null;
 
                    for (int i = 0; i < invokeItemArray.Length; i++) {
                        SystemEventInvokeInfo info = invokeItemArray[i];
                        if (info != null) {
                            if (invokeItems == null) { 
                                if (!_handlers.TryGetValue(key, out invokeItems)) {
                                    // weird.  just to be safe. 
                                    // 
                                    return;
                                } 
                            }

                            invokeItems.Remove(info);
                        } 
                    }
                } 
 
            }
        } 

        [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity")]
        private static void RemoveEventHandler(object key, Delegate value) {
            lock (eventLockObject) { 

                if (_handlers != null && _handlers.ContainsKey(key)) { 
                    List invokeItems = (List)_handlers[key]; 

                    invokeItems.Remove(new SystemEventInvokeInfo(value)); 
                }
            }
        }
 
        /// 
        ///     This method is invoked via reflection from windows forms.  Why?  Because when the runtime is hosted in IE, 
        ///     IE doesn't tell it when to shut down.  The first notification the runtime gets is 
        ///     DLL_PROCESS_DETACH, at which point it is too late for us to run any managed code.  But,
        ///     if we don't destroy our system events window the HWND will fault if it 
        ///     receives a message after the runtime shuts down.  So it is imparative that
        ///     we destroy the window, but it is also necessary to recreate the window on demand.
        ///     That's hard to do, because we originally created it in response to an event
        ///     wire-up, but that event is still bound so technically we should still have the 
        ///     window around.  To work around this crashing fiasco, we have special code
        ///     in the ActiveXImpl class within Control.  This code checks to see if it is running 
        ///     inside of IE, and if so, it will invoke these methods via private reflection. 
        ///     It will invoke Shutdown when the last active X control is destroyed, and then
        ///     call Startup with the first activeX control is recreated. 
        /// 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        private static void Startup() {
            if (startupRecreates) { 
                EnsureSystemEvents(false, false);
            } 
        } 

        ///  
        ///     This method is invoked via reflection from windows forms.  Why?  Because when the runtime is hosted in IE,
        ///     IE doesn't tell it when to shut down.  The first notification the runtime gets is
        ///     DLL_PROCESS_DETACH, at which point it is too late for us to run any managed code.  But,
        ///     if we don't destroy our system events window the HWND will fault if it 
        ///     receives a message after the runtime shuts down.  So it is imparative that
        ///     we destroy the window, but it is also necessary to recreate the window on demand. 
        ///     That's hard to do, because we originally created it in response to an event 
        ///     wire-up, but that event is still bound so technically we should still have the
        ///     window around.  To work around this crashing fiasco, we have special code 
        ///     in the ActiveXImpl class within Control.  This code checks to see if it is running
        ///     inside of IE, and if so, it will invoke these methods via private reflection.
        ///     It will invoke Shutdown when the last active X control is destroyed, and then
        ///     call Startup with the first activeX control is recreated. 
        /// 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private static void Shutdown() { 
            if (systemEvents != null && systemEvents.windowHandle != IntPtr.Zero) {
                lock(procLockObject) {
                    if (systemEvents != null) {
                        startupRecreates = true; 

                        // If we are using system events from another thread, request that it terminate 
                        // 
                        if (windowThread != null) {
                            eventThreadTerminated = new ManualResetEvent(false); 

#if DEBUG
                            int pid;
                            int thread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(systemEvents, systemEvents.windowHandle), out pid); 
                            Debug.Assert(thread != SafeNativeMethods.GetCurrentThreadId(), "Don't call Shutdown on the system events thread");
#endif 
                            UnsafeNativeMethods.PostMessage(new HandleRef(systemEvents, systemEvents.windowHandle), NativeMethods.WM_QUIT, IntPtr.Zero, IntPtr.Zero); 

                            eventThreadTerminated.WaitOne(); 
                            windowThread.Join(); //avoids an AppDomainUnloaded exception on our background thread.
                        }
                        else {
                            systemEvents.Dispose(); 
                            systemEvents = null;
                        } 
                    } 
                }
            } 
        }

        [PrePrepareMethod]
        private static void Shutdown(object sender, EventArgs e) { 
            Shutdown();
        } 
 
        /// 
        ///      A standard Win32 window proc for our broadcast window. 
        /// 
        [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private IntPtr WindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam) { 

            switch (msg) { 
                case NativeMethods.WM_SETTINGCHANGE: 
                    string newString;
                    IntPtr newStringPtr = lParam; 
                    if (lParam != IntPtr.Zero) {
                        newString = Marshal.PtrToStringAuto(lParam);
                        if (newString != null) {
                            newStringPtr = Marshal.StringToHGlobalAuto(newString); 
                        }
                    } 
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, windowHandle), NativeMethods.WM_REFLECT + msg, wParam, newStringPtr); 
                    break;
                case NativeMethods.WM_WTSSESSION_CHANGE: 
                    OnSessionSwitch((int)wParam);
                    break;
                case NativeMethods.WM_SYSCOLORCHANGE:
                case NativeMethods.WM_COMPACTING: 
                case NativeMethods.WM_DISPLAYCHANGE:
                case NativeMethods.WM_FONTCHANGE: 
                case NativeMethods.WM_PALETTECHANGED: 
                case NativeMethods.WM_TIMECHANGE:
                case NativeMethods.WM_TIMER: 
                case NativeMethods.WM_THEMECHANGED:
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, windowHandle), NativeMethods.WM_REFLECT + msg, wParam, lParam);
                    break;
 
                case NativeMethods.WM_CREATETIMER:
                    return OnCreateTimer(wParam); 
 
                case NativeMethods.WM_KILLTIMER:
                    return (IntPtr)(OnKillTimer(wParam) ? 1 : 0); 

                case NativeMethods.WM_REFLECT + NativeMethods.WM_SETTINGCHANGE:
                    try {
                        OnUserPreferenceChanging(msg - NativeMethods.WM_REFLECT, wParam, lParam); 
                        OnUserPreferenceChanged(msg - NativeMethods.WM_REFLECT, wParam, lParam);
                    } 
                    finally { 
                        try {
                            if (lParam != IntPtr.Zero) { 
                                Marshal.FreeHGlobal(lParam);
                            }
                        }
                        catch (Exception e) { 
                            Debug.Assert(false, "Exception occurred while freeing memory: " + e.ToString());
                        } 
                    } 
                    break;
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_SYSCOLORCHANGE:
                    OnUserPreferenceChanging(msg - NativeMethods.WM_REFLECT, wParam, lParam);
                    OnUserPreferenceChanged(msg - NativeMethods.WM_REFLECT, wParam, lParam);
                    break; 

                case NativeMethods.WM_REFLECT + NativeMethods.WM_THEMECHANGED: 
                    OnThemeChanged(); 
                    break;
 
                case NativeMethods.WM_QUERYENDSESSION:
                    return(IntPtr) OnSessionEnding(lParam);

                case NativeMethods.WM_ENDSESSION: 
                    OnSessionEnded(wParam, lParam);
                    break; 
 
                case NativeMethods.WM_POWERBROADCAST:
                    OnPowerModeChanged(wParam); 
                    break;

                    // WM_HIBERNATE on WinCE
                case NativeMethods.WM_REFLECT + NativeMethods.WM_COMPACTING: 
                    OnGenericEvent(OnLowMemoryEvent);
                    break; 
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_DISPLAYCHANGE:
                    OnDisplaySettingsChanging(); 
                    OnDisplaySettingsChanged();
                    break;

                case NativeMethods.WM_REFLECT + NativeMethods.WM_FONTCHANGE: 
                    OnGenericEvent(OnInstalledFontsChangedEvent);
                    break; 
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_PALETTECHANGED:
                    OnGenericEvent(OnPaletteChangedEvent); 
                    break;

                case NativeMethods.WM_REFLECT + NativeMethods.WM_TIMECHANGE:
                    OnGenericEvent(OnTimeChangedEvent); 
                    break;
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_TIMER: 
                    OnTimerElapsed(wParam);
                    break; 

                default:
                    // If we received a thread execute message, then execute it.
                    // 
                    if (msg == threadCallbackMessage && msg != 0) {
                        InvokeMarshaledCallbacks(); 
                        return IntPtr.Zero; 
                    }
 		    break; 
            }

            return UnsafeNativeMethods.DefWindowProc(hWnd, msg, wParam, lParam);
        } 

        ///  
        ///      This is the method that runs our window thread.  This method 
        ///      creates a window and spins up a message loop.  The window
        ///      is made visible with a size of 0, 0, so that it will trap 
        ///      global broadcast messages.
        /// 
        [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 
        private void WindowThreadProc() {
            try { 
                Initialize(); 
                eventWindowReady.Set();
 
                if (windowHandle != IntPtr.Zero) {
                    NativeMethods.MSG msg = new NativeMethods.MSG();

                    bool keepRunning = true; 

                    // Blocking on a GetMessage() call prevents the EE from being able to unwind 
                    // this thread properly (e.g. during AppDomainUnload). So, we use PeekMessage() 
                    // and sleep so we always block in managed code instead.
                    // 
                    while (keepRunning) {
                        int ret = UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, NativeMethods.QS_ALLINPUT, NativeMethods.MWMO_INPUTAVAILABLE);

                        if (ret == NativeMethods.WAIT_TIMEOUT) { 
                            Thread.Sleep(1);
                        } 
                        else { 
                            while (UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_REMOVE))
                            { 
                                if (msg.message == NativeMethods.WM_QUIT) {
                                    keepRunning = false;
                                    break;
                                } 

                                UnsafeNativeMethods.TranslateMessage(ref msg); 
                                UnsafeNativeMethods.DispatchMessage(ref msg); 
                            }
                        } 
                    }
                }

                OnShutdown(OnEventsThreadShutdownEvent); 
            }
            catch (Exception e) { 
                // In case something very very wrong happend during the creation action. 
                // This will unblock the calling thread.
                // 
                eventWindowReady.Set();

                if (!((e is ThreadInterruptedException) || (e is ThreadAbortException))) {
                    Debug.Fail("Unexpected thread exception in system events window thread proc", e.ToString()); 
                }
            } 
 
            Dispose();
            if (eventThreadTerminated != null) { 
                eventThreadTerminated.Set();
            }
        }
 
        // A class that helps fire events on the right thread.
        // 
        private class SystemEventInvokeInfo { 

            private SynchronizationContext _syncContext; // the context that we'll use to fire against. 
            private Delegate    _delegate;     // the delegate we'll fire.  This is a weak ref so we don't hold object in memory.
            public SystemEventInvokeInfo(Delegate d) {

                _delegate = d; 
                _syncContext = AsyncOperationManager.SynchronizationContext;
            } 
 
            // fire the given event with the given params.
            // 
            public void Invoke(bool checkFinalization, params object[] args) {
                try {
                    // If we didn't get call back, or if we're using Everett threading, invoke directly.
                    // 
                    if (_syncContext == null || SystemEvents.UseEverettThreadAffinity) {
                        InvokeCallback(args); 
                    } 
                    else {
                        // otherwise tell the context to do it for us. 
                        //
                        _syncContext.Send(new SendOrPostCallback(InvokeCallback), args);
                    }
                } 
                catch (InvalidAsynchronousStateException) {
                    //if the synch context is invalid -- do the invoke directly for app compat. 
                    //If the app's shutting down, don't fire the event (unless it's shutdown). 
                    if (!checkFinalization || !AppDomain.CurrentDomain.IsFinalizingForUnload()) {
                        InvokeCallback(args); 
                    }
                }
            }
 
            // our delegate method that the SyncContext will call on.
            // 
            private void InvokeCallback(object arg) { 

                _delegate.DynamicInvoke((object[])arg); 
            }

            public override bool Equals(object other) {
                SystemEventInvokeInfo otherInvoke = other as SystemEventInvokeInfo; 

                if (otherInvoke == null) { 
                    return false; 
                }
                return otherInvoke._delegate.Equals(_delegate); 
            }

            public override int GetHashCode() {
                return base.GetHashCode(); 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace Microsoft.Win32 {
    using System; 
    using System.Diagnostics;
    using System.Security;
    using System.Security.Permissions;
    using System.Collections; 
    using System.Collections.Generic;
    using System.ComponentModel; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Reflection;
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Runtime.Versioning;
    using System.Text; 
    using System.Threading;
 
    ///  
    ///    
    ///       Provides a 
    ///       set of global system events to callers. This
    ///       class cannot be inherited.
    /// 
    [HostProtectionAttribute(MayLeakOnAbort = true)] 
    [
    // Disabling partial trust scenarios 
    PermissionSet(SecurityAction.LinkDemand, Name="FullTrust") 
    ]
    [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")] 
    public sealed class SystemEvents {
        // Almost all of our data is static.  We keep a single instance of
        // SystemEvents around so we can bind delegates to it.
        // Non-static methods in this class will only be called through 
        // one of the delegates.
        // 
        private static readonly object      eventLockObject = new object(); 
        private static readonly object      procLockObject = new object();
        private static SystemEvents         systemEvents; 
        private static Thread               windowThread;
        private static ManualResetEvent     eventWindowReady;
        private static Random               randomTimerId = new Random();
        private static bool                 startupRecreates; 
        private static bool                 registeredSessionNotification = false;
        private static int                  domainQualifier; 
        private static NativeMethods.WNDCLASS staticwndclass; 
        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        private static IntPtr               defWindowProc; 

        static string className = null;

        // cross-thread marshaling 
        private static Queue            threadCallbackList; // list of Delegates
        private static int threadCallbackMessage = 0; 
        private static ManualResetEvent eventThreadTerminated; 

        //Decide whether to marshal or use Everett-style non-marshaled calls 
        private static bool checkedThreadAffinity = false;
        private static bool useEverettThreadAffinity = false;
        private const string everettThreadAffinityValue = "EnableSystemEventsThreadAffinityCompatibility";
 
        // Per-instance data that is isolated to the window thread.
        // 
        private IntPtr                  windowHandle; 
        private NativeMethods.WndProc   windowProc;
        private NativeMethods.ConHndlr  consoleHandler; 

        // The set of events we respond to.
        //
        private static readonly object       OnUserPreferenceChangingEvent   = new object(); 
        private static readonly object       OnUserPreferenceChangedEvent    = new object();
        private static readonly object       OnSessionEndingEvent            = new object(); 
        private static readonly object       OnSessionEndedEvent             = new object(); 
        private static readonly object       OnPowerModeChangedEvent         = new object();
        private static readonly object       OnLowMemoryEvent                = new object(); 
        private static readonly object       OnDisplaySettingsChangingEvent  = new object();
        private static readonly object       OnDisplaySettingsChangedEvent   = new object();
        private static readonly object       OnInstalledFontsChangedEvent    = new object();
        private static readonly object       OnTimeChangedEvent              = new object(); 
        private static readonly object       OnTimerElapsedEvent             = new object();
        private static readonly object       OnPaletteChangedEvent           = new object(); 
        private static readonly object       OnEventsThreadShutdownEvent     = new object(); 
        private static readonly object       OnSessionSwitchEvent            = new object();
 

        // Our list of handler information.  This is a lookup of the above keys and objects that
        // match a delegate with a SyncronizationContext so we can fire on the proper thread.
        // 
        private static Dictionary>  _handlers;
 
 
        /// 
        ///     This class is static, there is no need to ever create it. 
        /// 
        private SystemEvents() {
        }
 

        // stole from SystemInformation... if we get SystemInformation moved 
        // to somewhere that we can use it... rip this! 
        //
        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] 
        private static IntPtr processWinStation = IntPtr.Zero;
        private static bool isUserInteractive = false;
        private static bool UserInteractive {
            [ResourceExposure(ResourceScope.None)] 
            [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
            get { 
                if (Environment.OSVersion.Platform == System.PlatformID.Win32NT) { 
                    IntPtr hwinsta = IntPtr.Zero;
 
                    hwinsta = UnsafeNativeMethods.GetProcessWindowStation();
                    if (hwinsta != IntPtr.Zero && processWinStation != hwinsta) {
                        isUserInteractive = true;
 
                        int lengthNeeded = 0;
                        NativeMethods.USEROBJECTFLAGS flags = new NativeMethods.USEROBJECTFLAGS(); 
 
                        if (UnsafeNativeMethods.GetUserObjectInformation(new HandleRef(null, hwinsta), NativeMethods.UOI_FLAGS, flags, Marshal.SizeOf(flags), ref lengthNeeded)) {
                            if ((flags.dwFlags & NativeMethods.WSF_VISIBLE) == 0) { 
                                isUserInteractive = false;
                            }
                        }
                        processWinStation = hwinsta; 
                    }
                } 
                else { 
                    isUserInteractive = true;
                } 
                return isUserInteractive;
            }
        }
 

        ///  
        ///    Occurs when the display settings are changing. 
        /// 
        public static event EventHandler DisplaySettingsChanging { 
            add {
                AddEventHandler(OnDisplaySettingsChangingEvent, value);
            }
            remove { 
                RemoveEventHandler(OnDisplaySettingsChangingEvent, value);
            } 
        } 

 
        /// 
        ///    Occurs when the user changes the display settings.
        /// 
        public static event EventHandler DisplaySettingsChanged { 
            add {
                AddEventHandler(OnDisplaySettingsChangedEvent, value); 
            } 
            remove {
                RemoveEventHandler(OnDisplaySettingsChangedEvent, value); 
            }
        }

 
        /// 
        ///    Occurs before the thread that listens for system events is terminated. 
        ///           Delegates will be invoked on the events thread. 
        /// 
        public static event EventHandler EventsThreadShutdown { 
            // Really only here for GDI+ initialization and shut down
            add {
                AddEventHandler(OnEventsThreadShutdownEvent, value);
            } 
            remove {
                RemoveEventHandler(OnEventsThreadShutdownEvent, value); 
            } 
        }
 

        /// 
        ///    Occurs when the user adds fonts to or removes fonts from the system.
        ///  
        public static event EventHandler InstalledFontsChanged {
            add { 
                AddEventHandler(OnInstalledFontsChangedEvent, value); 
            }
            remove { 
                RemoveEventHandler(OnInstalledFontsChangedEvent, value);
            }
        }
 

        ///  
        ///    Occurs when the system is running out of available RAM. 
        /// 
        [Obsolete("This event has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")] 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public static event EventHandler LowMemory
        {
            add { 
                EnsureSystemEvents(true, true);
                AddEventHandler(OnLowMemoryEvent, value); 
            } 
            remove {
                RemoveEventHandler(OnLowMemoryEvent, value); 
            }
        }

 
        /// 
        ///    Occurs when the user switches to an application that uses a different 
        ///       palette. 
        /// 
        public static event EventHandler PaletteChanged { 
            add {
                AddEventHandler(OnPaletteChangedEvent, value);
            }
            remove { 
                RemoveEventHandler(OnPaletteChangedEvent, value);
            } 
        } 

 
        /// 
        ///    Occurs when the user suspends or resumes the system.
        /// 
        public static event PowerModeChangedEventHandler PowerModeChanged { 
            add {
                EnsureSystemEvents(true, true); 
                AddEventHandler(OnPowerModeChangedEvent, value); 
            }
            remove { 
                RemoveEventHandler(OnPowerModeChangedEvent, value);
            }
        }
 

        ///  
        ///    Occurs when the user is logging off or shutting down the system. 
        /// 
        public static event SessionEndedEventHandler SessionEnded { 
            add {
                EnsureSystemEvents(true, false);
                AddEventHandler(OnSessionEndedEvent, value);
            } 
            remove {
                RemoveEventHandler(OnSessionEndedEvent, value); 
            } 
        }
 

        /// 
        ///    Occurs when the user is trying to log off or shutdown the system.
        ///  
        public static event SessionEndingEventHandler SessionEnding {
            add { 
                EnsureSystemEvents(true, false); 
                AddEventHandler(OnSessionEndingEvent, value);
            } 
            remove {
                RemoveEventHandler(OnSessionEndingEvent, value);
            }
        } 

        ///  
        ///    Occurs when a user session switches. 
        /// 
        public static event SessionSwitchEventHandler SessionSwitch { 
            add {
                EnsureSystemEvents(true, true);
                EnsureRegisteredSessionNotification();
                AddEventHandler(OnSessionSwitchEvent, value); 
            }
            remove { 
                RemoveEventHandler(OnSessionSwitchEvent, value); 
            }
        } 


        /// 
        ///    Occurs when the user changes the time on the system clock. 
        /// 
        public static event EventHandler TimeChanged { 
            add { 
                EnsureSystemEvents(true, false);
                AddEventHandler(OnTimeChangedEvent, value); 
            }
            remove {
                RemoveEventHandler(OnTimeChangedEvent, value);
            } 
        }
 
 
        /// 
        ///    Occurs when a windows timer interval has expired. 
        /// 
        public static event TimerElapsedEventHandler TimerElapsed {
            add {
                EnsureSystemEvents(true, false); 
                AddEventHandler(OnTimerElapsedEvent, value);
            } 
            remove { 
                RemoveEventHandler(OnTimerElapsedEvent, value);
            } 
        }


        ///  
        ///    Occurs when a user preference has changed.
        ///  
        public static event UserPreferenceChangedEventHandler UserPreferenceChanged { 
            add {
                AddEventHandler(OnUserPreferenceChangedEvent, value); 
            }
            remove {
                RemoveEventHandler(OnUserPreferenceChangedEvent, value);
            } 
        }
 
        ///  
        ///    Occurs when a user preference is changing.
        ///  
        public static event UserPreferenceChangingEventHandler UserPreferenceChanging {
            add {
                AddEventHandler(OnUserPreferenceChangingEvent, value);
            } 
            remove {
                RemoveEventHandler(OnUserPreferenceChangingEvent, value); 
            } 
        }
 
        [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity")]
        private static void AddEventHandler(object key, Delegate value) {
            lock (eventLockObject) {
 
               if (_handlers == null) {
                    _handlers = new Dictionary>(); 
                    EnsureSystemEvents(false, false); 
               }
 
               List invokeItems;

               if (!_handlers.TryGetValue(key, out invokeItems)) {
 
                    invokeItems = new List();
                    _handlers[key] = invokeItems; 
               } 
               else {
                    invokeItems = _handlers[key]; 
               }

               invokeItems.Add(new SystemEventInvokeInfo(value));
            } 
        }
 
        ///  
        ///      Console handler we add in case we are a console application or a service.
        ///      Without this we will not get end session events. 
        /// 
        private int ConsoleHandlerProc(int signalType) {

            switch (signalType) { 
                case NativeMethods.CTRL_LOGOFF_EVENT:
                    OnSessionEnded((IntPtr) 1, (IntPtr) NativeMethods.ENDSESSION_LOGOFF); 
                    break; 

                case NativeMethods.CTRL_SHUTDOWN_EVENT: 
                    OnSessionEnded((IntPtr) 1, (IntPtr) 0);
                    break;
            }
 
            return 0;
        } 
 
        private NativeMethods.WNDCLASS WndClass {
            [ResourceExposure(ResourceScope.AppDomain | ResourceScope.Assembly)] 
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.AppDomain | ResourceScope.Assembly)]
            get {
                if (staticwndclass == null) {
                    const string classNameFormat = ".NET-BroadcastEventWindow.{0}.{1}.{2}"; 

                    IntPtr hInstance = UnsafeNativeMethods.GetModuleHandle(null); 
 
                    className = string.Format(System.Globalization.CultureInfo.InvariantCulture,
                        classNameFormat, 
                        ThisAssembly.Version,
                        Convert.ToString(AppDomain.CurrentDomain.GetHashCode(), 16),
                        domainQualifier);
 
                    staticwndclass = new NativeMethods.WNDCLASS();
                    staticwndclass.hbrBackground = (IntPtr)(NativeMethods.COLOR_WINDOW + 1); 
                    staticwndclass.style = 0; 

                    windowProc = new NativeMethods.WndProc(this.WindowProc); 
                    staticwndclass.lpszClassName = className;
                    staticwndclass.lpfnWndProc = windowProc;
                    staticwndclass.hInstance = hInstance;
                } 
                return staticwndclass;
            } 
        } 

        private IntPtr DefWndProc { 
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
            get {
                if (defWindowProc == IntPtr.Zero) { 
                    string defproc = (Marshal.SystemDefaultCharSize == 1 ? "DefWindowProcA" : "DefWindowProcW");
 
                    defWindowProc = UnsafeNativeMethods.GetProcAddress(new HandleRef(this, UnsafeNativeMethods.GetModuleHandle("user32.dll")), defproc); 
                }
                return defWindowProc; 
            }
        }

        private void BumpQualifier() { 
            staticwndclass = null;
            domainQualifier++; 
        } 

        ///  
        /// 
        ///      Goes through the work to register and create a window.
        /// 
        [ResourceExposure(ResourceScope.Process)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private IntPtr CreateBroadcastWindow() { 
 
            // Register the window class.
            // 
            NativeMethods.WNDCLASS_I wndclassi = new NativeMethods.WNDCLASS_I();
            IntPtr hInstance = UnsafeNativeMethods.GetModuleHandle(null);

            if (!UnsafeNativeMethods.GetClassInfo(new HandleRef(this, hInstance), WndClass.lpszClassName, wndclassi)) { 

                if (UnsafeNativeMethods.RegisterClass(WndClass) == 0) { 
                    windowProc = null; 
                    Debug.Fail("Unable to register broadcast window class");
                    return IntPtr.Zero; 
                }
            }
            else {
                //lets double check the wndproc returned by getclassinfo for defwndproc. 
                if (wndclassi.lpfnWndProc == DefWndProc) {
 
                    //if we are in there, it means className belongs to an unloaded appdomain. 
                    short atom = 0;
 
                    //try to unregister it.
                    if (0 != UnsafeNativeMethods.UnregisterClass(WndClass.lpszClassName, new HandleRef(null, UnsafeNativeMethods.GetModuleHandle(null)))) {
                        atom = UnsafeNativeMethods.RegisterClass(WndClass);
                    } 

                    if (atom == 0) { 
                        do { 
                            BumpQualifier();
                            atom = UnsafeNativeMethods.RegisterClass(WndClass); 
                        } while (atom == 0 && Marshal.GetLastWin32Error() == NativeMethods.ERROR_CLASS_ALREADY_EXISTS);
                    }
                }
            } 

            // And create an instance of the window. 
            // 
            IntPtr hwnd = UnsafeNativeMethods.CreateWindowEx(
                                                            0, 
                                                            WndClass.lpszClassName,
                                                            WndClass.lpszClassName,
                                                            NativeMethods.WS_POPUP,
                                                            0, 0, 0, 0, NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, 
                                                            new HandleRef(this, hInstance), null);
            return hwnd; 
        } 

        ///  
        /// 
        ///    Creates a new window timer asociated with the
        ///       system events window.
        ///  
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        public static IntPtr CreateTimer(int interval) { 
            if (interval <= 0) {
                throw new ArgumentException(SR.GetString(SR.InvalidLowBoundArgument, "interval", interval.ToString(System.Threading.Thread.CurrentThread.CurrentCulture), "0")); 
            }

            EnsureSystemEvents(true, true);
            IntPtr timerId = UnsafeNativeMethods.SendMessage(new HandleRef(systemEvents, systemEvents.windowHandle), 
                                                             NativeMethods.WM_CREATETIMER, (IntPtr)interval, IntPtr.Zero);
 
            if (timerId == IntPtr.Zero) { 
                throw new ExternalException(SR.GetString(SR.ErrorCreateTimer));
            } 
            return timerId;
        }

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private void Dispose() { 
            if (windowHandle != IntPtr.Zero) { 

                if (registeredSessionNotification) { 
                    UnsafeNativeMethods.WTSUnRegisterSessionNotification(new HandleRef(systemEvents, systemEvents.windowHandle));
                }

                IntPtr handle = windowHandle; 
                windowHandle = IntPtr.Zero;
 
                HandleRef href = new HandleRef(this, handle); 

                //we check IsWindow because Application may have rudely destroyed our broadcast window. 
                //if this were true, we want to unregister the class.
                if (UnsafeNativeMethods.IsWindow(href) && DefWndProc != IntPtr.Zero) {
                    UnsafeNativeMethods.SetWindowLong(href, NativeMethods.GWL_WNDPROC, new HandleRef(this, DefWndProc));
 
                    //set our sentinel value that we will look for upon initialization to indicate
                    //the window class belongs to an unloaded appdomain and therefore should not be used. 
                    UnsafeNativeMethods.SetClassLong(href, NativeMethods.GCL_WNDPROC, DefWndProc); 
                }
 
                // If DestroyWindow failed, it is because we're being
                // shutdown from another thread.  In this case, locate the
                // DefWindowProc call in User32, sling the window back to it,
                // and post a nice fat WM_CLOSE 
                //
                if (UnsafeNativeMethods.IsWindow(href) && !UnsafeNativeMethods.DestroyWindow(href)) { 
                    UnsafeNativeMethods.PostMessage(href, NativeMethods.WM_CLOSE, IntPtr.Zero, IntPtr.Zero); 
                }
                else { 
                    IntPtr hInstance = UnsafeNativeMethods.GetModuleHandle(null);
                    UnsafeNativeMethods.UnregisterClass(className, new HandleRef(this, hInstance));
                }
            } 

            if (consoleHandler != null) { 
                UnsafeNativeMethods.SetConsoleCtrlHandler(consoleHandler, 0); 
                consoleHandler = null;
            } 
        }

        /// 
        ///  Creates the static resources needed by 
        ///  system events.
        ///  
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
        private static void EnsureSystemEvents(bool requireHandle, bool throwOnRefusal) { 

            // The secondary check here is to detect asp.net.  Asp.net uses multiple
            // app domains to field requests and we do not want to gobble up an
            // additional thread per domain.  So under this scenario SystemEvents 
            // becomes a nop.
            // 
            if (systemEvents == null) { 
                lock (procLockObject) {
                    if (systemEvents == null) { 
                        if (Thread.GetDomain().GetData(".appDomain") != null) {
                            if (throwOnRefusal) {
                                throw new InvalidOperationException(SR.GetString(SR.ErrorSystemEventsNotSupported));
                            } 
                            return;
                        } 
 
                        // If we are creating system events on a thread declared as STA, then
                        // just share the thread. 
                        //
                        if (!UserInteractive || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) {
                            systemEvents = new SystemEvents();
                            systemEvents.Initialize(); 
                        }
                        else { 
                            eventWindowReady = new ManualResetEvent(false); 
                            systemEvents = new SystemEvents();
                            windowThread = new Thread(new ThreadStart(systemEvents.WindowThreadProc)); 
                            windowThread.IsBackground = true;
                            windowThread.Name = ".NET SystemEvents";
                            windowThread.Start();
                            eventWindowReady.WaitOne(); 
                        }
 
                        if (requireHandle && systemEvents.windowHandle == IntPtr.Zero) { 
                            // In theory, it's not the end of the world that
                            // we don't get system events.  Unfortunately, the main reason windowHandle == 0 
                            // is CreateWindowEx failed for mysterious reasons, and when that happens,
                            // subsequent (and more important) CreateWindowEx calls also fail.
                            // See ASURT #44424 for a rather lengthy discussion of this.
                            throw new ExternalException(SR.GetString(SR.ErrorCreateSystemEvents)); 
                        }
 
                        startupRecreates = false; 
                    }
                } 
            }
        }

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static void EnsureRegisteredSessionNotification() { 
            if (!registeredSessionNotification) { 
                IntPtr retval = SafeNativeMethods.LoadLibrary(ExternDll.Wtsapi32);
 
                if (retval != IntPtr.Zero) {
                    UnsafeNativeMethods.WTSRegisterSessionNotification(new HandleRef(systemEvents, systemEvents.windowHandle), NativeMethods.NOTIFY_FOR_THIS_SESSION);
                    registeredSessionNotification = true;
                    SafeNativeMethods.FreeLibrary(new HandleRef(null, retval)); 
                }
            } 
        } 

        [SuppressMessage("Microsoft.Performance", "CA1801:AvoidUnusedParameters")] 
        private UserPreferenceCategory GetUserPreferenceCategory(int msg, IntPtr wParam, IntPtr lParam) {

            UserPreferenceCategory pref = UserPreferenceCategory.General;
 
            if (msg == NativeMethods.WM_SETTINGCHANGE) {
 
                if (lParam != IntPtr.Zero && Marshal.PtrToStringAuto(lParam).Equals("Policy")) { 
                    pref = UserPreferenceCategory.Policy;
                } 
                else if (lParam != IntPtr.Zero && Marshal.PtrToStringAuto(lParam).Equals("intl")) {
                    pref = UserPreferenceCategory.Locale;
                }
                else { 
                    switch ((int) wParam) {
                        case NativeMethods.SPI_SETACCESSTIMEOUT: 
                        case NativeMethods.SPI_SETFILTERKEYS: 
                        case NativeMethods.SPI_SETHIGHCONTRAST:
                        case NativeMethods.SPI_SETMOUSEKEYS: 
                        case NativeMethods.SPI_SETSCREENREADER:
                        case NativeMethods.SPI_SETSERIALKEYS:
                        case NativeMethods.SPI_SETSHOWSOUNDS:
                        case NativeMethods.SPI_SETSOUNDSENTRY: 
                        case NativeMethods.SPI_SETSTICKYKEYS:
                        case NativeMethods.SPI_SETTOGGLEKEYS: 
                            pref = UserPreferenceCategory.Accessibility; 
                            break;
 
                        case NativeMethods.SPI_SETDESKWALLPAPER:
                        case NativeMethods.SPI_SETFONTSMOOTHING:
                        case NativeMethods.SPI_SETCURSORS:
                        case NativeMethods.SPI_SETDESKPATTERN: 
                        case NativeMethods.SPI_SETGRIDGRANULARITY:
                        case NativeMethods.SPI_SETWORKAREA: 
                            pref = UserPreferenceCategory.Desktop; 
                            break;
 
                        case NativeMethods.SPI_ICONHORIZONTALSPACING:
                        case NativeMethods.SPI_ICONVERTICALSPACING:
                        case NativeMethods.SPI_SETICONMETRICS:
                        case NativeMethods.SPI_SETICONS: 
                        case NativeMethods.SPI_SETICONTITLELOGFONT:
                        case NativeMethods.SPI_SETICONTITLEWRAP: 
                            pref = UserPreferenceCategory.Icon; 
                            break;
 
                        case NativeMethods.SPI_SETDOUBLECLICKTIME:
                        case NativeMethods.SPI_SETDOUBLECLKHEIGHT:
                        case NativeMethods.SPI_SETDOUBLECLKWIDTH:
                        case NativeMethods.SPI_SETMOUSE: 
                        case NativeMethods.SPI_SETMOUSEBUTTONSWAP:
                        case NativeMethods.SPI_SETMOUSEHOVERHEIGHT: 
                        case NativeMethods.SPI_SETMOUSEHOVERTIME: 
                        case NativeMethods.SPI_SETMOUSESPEED:
                        case NativeMethods.SPI_SETMOUSETRAILS: 
                        case NativeMethods.SPI_SETSNAPTODEFBUTTON:
                        case NativeMethods.SPI_SETWHEELSCROLLLINES:
                        case NativeMethods.SPI_SETCURSORSHADOW:
                        case NativeMethods.SPI_SETHOTTRACKING: 
                        case NativeMethods.SPI_SETTOOLTIPANIMATION:
                        case NativeMethods.SPI_SETTOOLTIPFADE: 
                            pref = UserPreferenceCategory.Mouse; 
                            break;
 
                        case NativeMethods.SPI_SETKEYBOARDDELAY:
                        case NativeMethods.SPI_SETKEYBOARDPREF:
                        case NativeMethods.SPI_SETKEYBOARDSPEED:
                        case NativeMethods.SPI_SETLANGTOGGLE: 
                            pref = UserPreferenceCategory.Keyboard;
                            break; 
 
                        case NativeMethods.SPI_SETMENUDROPALIGNMENT:
                        case NativeMethods.SPI_SETMENUFADE: 
                        case NativeMethods.SPI_SETMENUSHOWDELAY:
                        case NativeMethods.SPI_SETMENUANIMATION:
                        case NativeMethods.SPI_SETSELECTIONFADE:
                            pref = UserPreferenceCategory.Menu; 
                            break;
 
                        case NativeMethods.SPI_SETLOWPOWERACTIVE: 
                        case NativeMethods.SPI_SETLOWPOWERTIMEOUT:
                        case NativeMethods.SPI_SETPOWEROFFACTIVE: 
                        case NativeMethods.SPI_SETPOWEROFFTIMEOUT:
                            pref = UserPreferenceCategory.Power;
                            break;
 
                        case NativeMethods.SPI_SETSCREENSAVEACTIVE:
                        case NativeMethods.SPI_SETSCREENSAVERRUNNING: 
                        case NativeMethods.SPI_SETSCREENSAVETIMEOUT: 
                            pref = UserPreferenceCategory.Screensaver;
                            break; 

                        case NativeMethods.SPI_SETKEYBOARDCUES:
                        case NativeMethods.SPI_SETCOMBOBOXANIMATION:
                        case NativeMethods.SPI_SETLISTBOXSMOOTHSCROLLING: 
                        case NativeMethods.SPI_SETGRADIENTCAPTIONS:
                        case NativeMethods.SPI_SETUIEFFECTS: 
                        case NativeMethods.SPI_SETACTIVEWINDOWTRACKING: 
                        case NativeMethods.SPI_SETACTIVEWNDTRKZORDER:
                        case NativeMethods.SPI_SETACTIVEWNDTRKTIMEOUT: 
                        case NativeMethods.SPI_SETANIMATION:
                        case NativeMethods.SPI_SETBORDER:
                        case NativeMethods.SPI_SETCARETWIDTH:
                        case NativeMethods.SPI_SETDRAGFULLWINDOWS: 
                        case NativeMethods.SPI_SETDRAGHEIGHT:
                        case NativeMethods.SPI_SETDRAGWIDTH: 
                        case NativeMethods.SPI_SETFOREGROUNDFLASHCOUNT: 
                        case NativeMethods.SPI_SETFOREGROUNDLOCKTIMEOUT:
                        case NativeMethods.SPI_SETMINIMIZEDMETRICS: 
                        case NativeMethods.SPI_SETNONCLIENTMETRICS:
                        case NativeMethods.SPI_SETSHOWIMEUI:
                            pref = UserPreferenceCategory.Window;
                            break; 
                    }
                } 
            } 
            else if (msg == NativeMethods.WM_SYSCOLORCHANGE) {
                pref = UserPreferenceCategory.Color; 
            }
            else {
                Debug.Fail("Unrecognized message passed to UserPreferenceCategory");
            } 

            return pref; 
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private void Initialize() {
            consoleHandler = new NativeMethods.ConHndlr(this.ConsoleHandlerProc);
            if (!UnsafeNativeMethods.SetConsoleCtrlHandler(consoleHandler, 1)) { 
                Debug.Fail("Failed to install console handler.");
                consoleHandler = null; 
            } 

            windowHandle = CreateBroadcastWindow(); 
            Debug.Assert(windowHandle != IntPtr.Zero, "CreateBroadcastWindow failed");

            AppDomain.CurrentDomain.ProcessExit += new EventHandler(SystemEvents.Shutdown);
            AppDomain.CurrentDomain.DomainUnload += new EventHandler(SystemEvents.Shutdown); 
        }
 
        ///  
        ///     Called on the control's owning thread to perform the actual callback.
        ///     This empties this control's callback queue, propagating any excpetions 
        ///     back as needed.
        /// 
        [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 
        private void InvokeMarshaledCallbacks() {
            Debug.Assert(threadCallbackList != null, "Invoking marshaled callbacks before there are any"); 
 
            Delegate current = null;
            lock (threadCallbackList) { 
                if (threadCallbackList.Count > 0) {
                    current = (Delegate)threadCallbackList.Dequeue();
                }
            } 

            // Now invoke on all the queued items. 
            // 
            while (current != null) {
                try { 
                    // Optimize a common case of using EventHandler. This allows us to invoke
                    // early bound, which is a bit more efficient.
                    //
                    EventHandler c = current as EventHandler; 
                    if (c != null) {
                        c(null, EventArgs.Empty); 
                    } 
                    else {
                        current.DynamicInvoke(new object[0]); 
                    }
                }
                catch (Exception t) {
                    Debug.Fail("SystemEvents marshaled callback failed:" + t); 
                }
                lock (threadCallbackList) { 
                    if (threadCallbackList.Count > 0) { 
                        current = (Delegate)threadCallbackList.Dequeue();
                    } 
                    else {
                        current = null;
                    }
                } 
            }
        } 
 
        /// 
        ///     Executes the given delegate on the thread that listens for system events.  Similar to Control.Invoke(). 
        /// 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        public static void InvokeOnEventsThread(Delegate method) { 
            // This method is really only here for GDI+ initialization/shutdown
            EnsureSystemEvents(true, true); 
 
#if DEBUG
            int pid; 
            int thread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(systemEvents, systemEvents.windowHandle), out pid);
            Debug.Assert(windowThread == null || thread != SafeNativeMethods.GetCurrentThreadId(), "Don't call MarshaledInvoke on the system events thread");
#endif
 
            if (threadCallbackList == null) {
                lock (eventLockObject) { 
                    if (threadCallbackList == null) { 
                        threadCallbackList = new Queue();
                        threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage("SystemEventsThreadCallbackMessage"); 
                    }
                }
            }
 
            Debug.Assert(threadCallbackMessage != 0, "threadCallbackList initialized but threadCallbackMessage not?");
 
            lock (threadCallbackList) { 
                threadCallbackList.Enqueue(method);
            } 

            UnsafeNativeMethods.PostMessage(new HandleRef(systemEvents, systemEvents.windowHandle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
        }
 
        /// 
        ///  
        ///    Kills the timer specified by the given id. 
        /// 
        public static void KillTimer(IntPtr timerId) { 
            EnsureSystemEvents(true, true);
            if (systemEvents.windowHandle != IntPtr.Zero) {
                int res = (int) UnsafeNativeMethods.SendMessage(new HandleRef(systemEvents, systemEvents.windowHandle),
                                                                NativeMethods.WM_KILLTIMER, timerId, IntPtr.Zero); 

                if (res == 0) 
                    throw new ExternalException(SR.GetString(SR.ErrorKillTimer)); 
            }
        } 

        /// 
        ///      Callback that handles the create timer
        ///      user message. 
        /// 
        private IntPtr OnCreateTimer(IntPtr wParam) { 
            IntPtr timerId = (IntPtr) randomTimerId.Next(); 
            IntPtr res = UnsafeNativeMethods.SetTimer(new HandleRef(this, windowHandle), new HandleRef(this, timerId), (int) wParam, NativeMethods.NullHandleRef);
            return(res == IntPtr.Zero ? IntPtr.Zero: timerId); 
        }

        /// 
        ///      Handler that raises the DisplaySettings changing event 
        /// 
        private void OnDisplaySettingsChanging() { 
            RaiseEvent(OnDisplaySettingsChangingEvent, this, EventArgs.Empty); 
        }
 
        /// 
        ///      Handler that raises the DisplaySettings changed event
        /// 
        private void OnDisplaySettingsChanged() { 
            RaiseEvent(OnDisplaySettingsChangedEvent, this, EventArgs.Empty);
        } 
 
        /// 
        ///      Handler for any event that fires a standard EventHandler delegate. 
        /// 
        private void OnGenericEvent(object eventKey) {
            RaiseEvent(eventKey, this, EventArgs.Empty);
        } 

        private void OnShutdown(object eventKey) { 
            RaiseEvent(false, eventKey, this, EventArgs.Empty); 
        }
 
        /// 
        ///      Callback that handles the KillTimer
        ///      user message.
        ///  
        private bool OnKillTimer(IntPtr wParam) {
            bool res = UnsafeNativeMethods.KillTimer(new HandleRef(this, windowHandle), new HandleRef(this, wParam)); 
            return res; 
        }
 
        /// 
        ///      Handler for WM_POWERBROADCAST.
        /// 
        private void OnPowerModeChanged(IntPtr wParam) { 

            PowerModes mode; 
 
            switch ((int)wParam)
            { 
                case NativeMethods.PBT_APMSUSPEND:
                case NativeMethods.PBT_APMSTANDBY:
                    mode = PowerModes.Suspend;
                    break; 

                case NativeMethods.PBT_APMRESUMECRITICAL: 
                case NativeMethods.PBT_APMRESUMESUSPEND: 
                case NativeMethods.PBT_APMRESUMESTANDBY:
                    mode = PowerModes.Resume; 
                    break;

                case NativeMethods.PBT_APMBATTERYLOW:
                case NativeMethods.PBT_APMPOWERSTATUSCHANGE: 
                case NativeMethods.PBT_APMOEMEVENT:
                    mode = PowerModes.StatusChange; 
                    break; 

                default: 
                    return;
            }

            RaiseEvent(OnPowerModeChangedEvent ,this, new PowerModeChangedEventArgs (mode)); 

        } 
 
        /// 
        ///      Handler for WM_ENDSESSION. 
        /// 
        private void OnSessionEnded(IntPtr wParam, IntPtr lParam) {

            // wParam will be nonzero if the session is actually ending.  If 
            // it was canceled then we do not want to raise the event.
            // 
            if (wParam != (IntPtr) 0) { 

                SessionEndReasons reason = SessionEndReasons.SystemShutdown; 

                if (((unchecked ((int)(long) lParam)) & NativeMethods.ENDSESSION_LOGOFF) != 0) {
                    reason = SessionEndReasons.Logoff;
                } 

                SessionEndedEventArgs endEvt = new SessionEndedEventArgs(reason); 
 
                RaiseEvent(OnSessionEndedEvent, this, endEvt);
            } 
        }

        /// 
        ///      Handler for WM_QUERYENDSESSION. 
        /// 
        private int OnSessionEnding(IntPtr lParam) { 
            int endOk = 1; 

            SessionEndReasons reason = SessionEndReasons.SystemShutdown; 

            //Casting to (int) is bad if we're 64-bit; casting to (long) is ok whether we're 64- or 32-bit.
            if ((((long)lParam) & NativeMethods.ENDSESSION_LOGOFF) != 0) {
                reason = SessionEndReasons.Logoff; 
            }
 
            SessionEndingEventArgs endEvt = new SessionEndingEventArgs(reason); 

            RaiseEvent(OnSessionEndingEvent, this, endEvt); 
            endOk = (endEvt.Cancel ? 0 : 1);

            return endOk;
        } 

        private void OnSessionSwitch(int wParam) { 
            SessionSwitchEventArgs switchEventArgs = new SessionSwitchEventArgs((SessionSwitchReason)wParam); 

            RaiseEvent (OnSessionSwitchEvent, this, switchEventArgs); 
        }

        /// 
        ///      Handler for WM_THEMECHANGED 
        ///      Whidbey note: Before Whidbey, we used to fire UserPreferenceChanged with category
        ///      set to Window. In Whidbey, we support visual styles and need a new category Theme 
        ///      since Window is too general. We fire UserPreferenceChanged with this category, but 
        ///      for backward compat, we also fire it with category set to Window.
        ///  
        private void OnThemeChanged() {
            //we need to fire a changing event handler for Themes.
            //note that it needs to be documented that accessing theme information during the changing event is forbidden.
            RaiseEvent(OnUserPreferenceChangingEvent, this, new UserPreferenceChangingEventArgs(UserPreferenceCategory.VisualStyle)); 

            UserPreferenceCategory pref = UserPreferenceCategory.Window; 
 
            RaiseEvent (OnUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs (pref));
 
            pref = UserPreferenceCategory.VisualStyle;

            RaiseEvent(OnUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs (pref));
        } 

        ///  
        ///      Handler for WM_SETTINGCHANGE and WM_SYSCOLORCHANGE. 
        /// 
        private void OnUserPreferenceChanged(int msg, IntPtr wParam, IntPtr lParam) { 
            UserPreferenceCategory pref = GetUserPreferenceCategory(msg, wParam, lParam);

            RaiseEvent(OnUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs (pref));
        } 

        private void OnUserPreferenceChanging(int msg, IntPtr wParam, IntPtr lParam) { 
 
            UserPreferenceCategory pref = GetUserPreferenceCategory(msg, wParam, lParam);
 
            RaiseEvent(OnUserPreferenceChangingEvent, this, new UserPreferenceChangingEventArgs(pref));
        }

        ///  
        ///      Handler for WM_TIMER.
        ///  
        private void OnTimerElapsed(IntPtr wParam) { 
            RaiseEvent(OnTimerElapsedEvent, this, new TimerElapsedEventArgs (wParam));
        } 

        #region EverettThreadAffinity
        //VSWhidbey 470990: we need a backdoor to allow applications to enable the old, broken
        //behavior for SystemEvents, where we fire them on whichever thread they end up on. 
        //It's unlikely that someone's depending on this behavior, but we want to avoid a QFE if
        //they are.  Unfortunately, all of CommonAppDataRegistry's friends are on 
        //System.Windows.Forms.Application, and we can't take a dependency to windows forms from here. 
        internal static bool UseEverettThreadAffinity {
            [ResourceExposure(ResourceScope.None)] 
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            get {
                if (!checkedThreadAffinity) {
                    //No point in locking if we don't have to... 
                    lock (eventLockObject) {
                        //...but now that we have the lock, make sure nobody else just beat us here. 
                        if (!checkedThreadAffinity) { 
                            checkedThreadAffinity = true;
                            string template = @"Software\{0}\{1}\{2}"; 
                            try {
                                //We need access to be able to read from the registry here.  We're not creating a
                                //registry key, nor are we returning information from the registry to the user.
                                new RegistryPermission(PermissionState.Unrestricted).Assert(); 
                                RegistryKey key = Registry.LocalMachine.OpenSubKey(string.Format(System.Globalization.CultureInfo.CurrentCulture,
                                    template, CompanyNameInternal, ProductNameInternal, ProductVersionInternal)); 
                                if (key != null) { 
                                    object value = key.GetValue(everettThreadAffinityValue);
                                    if (value != null && (int)value != 0) { 
                                        useEverettThreadAffinity = true;
                                    }
                                }
                            } 
                            catch (SecurityException) {
                                // Can't read the key: use default value (false) 
                            } 
                            catch (InvalidCastException) {
                                // Key is of wrong type: use default value (false) 
                            }
                        }
                    }
                } 
                return useEverettThreadAffinity;
            } 
        } 

        private static string CompanyNameInternal { 
            //No point in caching the value: we're only using it once.
            get {
                string companyName = null;
                // custom attribute 
                //
                Assembly entryAssembly = Assembly.GetEntryAssembly(); 
                if (entryAssembly != null) { 
                    object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
                    if (attrs != null && attrs.Length > 0) { 
                        companyName = ((AssemblyCompanyAttribute)attrs[0]).Company;
                    }
                }
 
                // win32 version
                // 
                if (companyName == null || companyName.Length == 0) { 
                    companyName = GetAppFileVersionInfo().CompanyName;
                    if (companyName != null) { 
                        companyName = companyName.Trim();
                    }
                }
 
                // fake it with a namespace
                // won't work with MC++ see GetAppMainType. 
                if (companyName == null || companyName.Length == 0) { 
                    Type t = GetAppMainType();
 
                    if (t != null) {
                        string ns = t.Namespace;

                        if (!string.IsNullOrEmpty(ns)) { 
                            int firstDot = ns.IndexOf(".", StringComparison.Ordinal);
                            if (firstDot != -1) { 
                                companyName = ns.Substring(0, firstDot); 
                            }
                            else { 
                                companyName = ns;
                            }
                        }
                        else { 
                            // last ditch... no namespace, use product name...
                            // 
                            companyName = ProductNameInternal; 
                        }
                    } 
                }
                return companyName;
            }
        } 

        private static string ProductNameInternal { 
            get { 
                string productName = null;
                // custom attribute 
                //
                Assembly entryAssembly = Assembly.GetEntryAssembly();
                if (entryAssembly != null) {
                    object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false); 
                    if (attrs != null && attrs.Length > 0) {
                        productName = ((AssemblyProductAttribute)attrs[0]).Product; 
                    } 
                }
 
                // win32 version info
                //
                if (productName == null || productName.Length == 0) {
                    productName = GetAppFileVersionInfo().ProductName; 
                    if (productName != null) {
                        productName = productName.Trim(); 
                    } 
                }
 
                // fake it with namespace
                // won't work with MC++ see GetAppMainType.
                if (productName == null || productName.Length == 0) {
                    Type t = GetAppMainType(); 

                    if (t != null) { 
                        string ns = t.Namespace; 

                        if (!string.IsNullOrEmpty(ns)) { 
                            int lastDot = ns.LastIndexOf(".", StringComparison.Ordinal);
                            if (lastDot != -1 && lastDot < ns.Length - 1) {
                                productName = ns.Substring(lastDot + 1);
                            } 
                            else {
                                productName = ns; 
                            } 
                        }
                        else { 
                            // last ditch... use the main type
                            //
                            productName = t.Name;
                        } 
                    }
                } 
                return productName; 
            }
        } 

        private static string ProductVersionInternal {
            get {
                string productVersion = null; 
                // custom attribute
                // 
                Assembly entryAssembly = Assembly.GetEntryAssembly(); 
                if (entryAssembly != null) {
                    object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); 
                    if (attrs != null && attrs.Length > 0) {
                        productVersion = ((AssemblyInformationalVersionAttribute)attrs[0]).InformationalVersion;
                    }
                } 

                // win32 version info 
                // 
                if (productVersion == null || productVersion.Length == 0) {
                    productVersion = GetAppFileVersionInfo().ProductVersion; 
                    if (productVersion != null) {
                        productVersion = productVersion.Trim();
                    }
                } 

                // fake it 
                // 
                if (productVersion == null || productVersion.Length == 0) {
                    productVersion = "1.0.0.0"; 
                }
                return productVersion;
            }
        } 

        private static object appFileVersion; 
        [ResourceExposure(ResourceScope.Machine)]  // Let's review who calls this, and why. 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static FileVersionInfo GetAppFileVersionInfo() { 
            if (appFileVersion == null) {
                Type t = GetAppMainType();
                if (t != null) {
                    // SECREVIEW : This Assert is ok, getting the module's version is a safe operation, 
                    //             the result is provided by the system.
                    // 
                    FileIOPermission fiop = new FileIOPermission(PermissionState.None); 
                    fiop.AllFiles = FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read;
                    fiop.Assert(); 

                    try {
                        appFileVersion = FileVersionInfo.GetVersionInfo(t.Module.FullyQualifiedName);
                    } 
                    finally {
                        CodeAccessPermission.RevertAssert(); 
                    } 
                }
                else { 
                    appFileVersion = FileVersionInfo.GetVersionInfo(ExecutablePath);
                }
            }
 
            return (FileVersionInfo)appFileVersion;
        } 
 
        /// 
        ///  
        ///     Retrieves the Type that contains the "Main" method.
        /// 
        private static Type mainType;
        private static Type GetAppMainType() { 
            if (mainType == null) {
                Assembly exe = Assembly.GetEntryAssembly(); 
 
                // Get Main type...This doesn't work in MC++ because Main is a global function and not
                // a class static method (it doesn't belong to a Type). 
                if (exe != null) {
                    mainType = exe.EntryPoint.ReflectedType;
                }
            } 

            return mainType; 
        } 

        private static string executablePath = null; 
        private static string ExecutablePath {
            [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)] 
            get {
                if (executablePath == null) { 
                    Assembly asm = Assembly.GetEntryAssembly(); 
                    if (asm == null) {
                        StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); 
                        UnsafeNativeMethods.GetModuleFileName(NativeMethods.NullHandleRef, sb, sb.Capacity);

                        executablePath = IntSecurity.UnsafeGetFullPath(sb.ToString());
                    } 
                    else {
                        String ecb = asm.EscapedCodeBase; 
                        Uri codeBase = new Uri(ecb); 
                        if (codeBase.Scheme == "file") {
                            executablePath = NativeMethods.GetLocalPath(ecb); 
                        }
                        else {
                            executablePath = codeBase.ToString();
                        } 
                    }
                } 
                Uri exeUri = new Uri(executablePath); 
                if (exeUri.Scheme == "file") {
                    new FileIOPermission(FileIOPermissionAccess.PathDiscovery, executablePath).Demand(); 
                }
                return executablePath;
            }
        } 
        #endregion
 
        private static void RaiseEvent(object key, params object[] args) { 
            RaiseEvent(true, key, args);
        } 

        [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private static void RaiseEvent(bool checkFinalization, object key, params object[] args) { 
            //If the AppDomain's unloading, we shouldn't fire SystemEvents other than Shutdown.
            if (checkFinalization && AppDomain.CurrentDomain.IsFinalizingForUnload()) { 
                return; 
            }
 
            SystemEventInvokeInfo[] invokeItemArray = null;

            lock (eventLockObject) {
 
                if (_handlers != null && _handlers.ContainsKey(key)) {
                    List invokeItems = _handlers[key]; 
 
                    // clone the list so we don't have this type locked and cause
                    // a deadlock if someone tries to modify handlers during an invoke. 
                    //
                    if (invokeItems != null) {
                        invokeItemArray = invokeItems.ToArray();
                    } 
                }
 
            } 

            if (invokeItemArray != null) { 
                for (int i = 0; i < invokeItemArray.Length; i++) {
                    try
                    {
                        SystemEventInvokeInfo info = invokeItemArray[i]; 
                        info.Invoke(checkFinalization, args);
                        invokeItemArray[i] = null; // clear it if it's valid 
                    } 
                    catch (Exception)
                    { 
                        //Eat exceptions (Everett compat)
                    }
                }
 
                // clean out any that are dead.
                // 
                lock (eventLockObject) { 
                    List invokeItems = null;
 
                    for (int i = 0; i < invokeItemArray.Length; i++) {
                        SystemEventInvokeInfo info = invokeItemArray[i];
                        if (info != null) {
                            if (invokeItems == null) { 
                                if (!_handlers.TryGetValue(key, out invokeItems)) {
                                    // weird.  just to be safe. 
                                    // 
                                    return;
                                } 
                            }

                            invokeItems.Remove(info);
                        } 
                    }
                } 
 
            }
        } 

        [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity")]
        private static void RemoveEventHandler(object key, Delegate value) {
            lock (eventLockObject) { 

                if (_handlers != null && _handlers.ContainsKey(key)) { 
                    List invokeItems = (List)_handlers[key]; 

                    invokeItems.Remove(new SystemEventInvokeInfo(value)); 
                }
            }
        }
 
        /// 
        ///     This method is invoked via reflection from windows forms.  Why?  Because when the runtime is hosted in IE, 
        ///     IE doesn't tell it when to shut down.  The first notification the runtime gets is 
        ///     DLL_PROCESS_DETACH, at which point it is too late for us to run any managed code.  But,
        ///     if we don't destroy our system events window the HWND will fault if it 
        ///     receives a message after the runtime shuts down.  So it is imparative that
        ///     we destroy the window, but it is also necessary to recreate the window on demand.
        ///     That's hard to do, because we originally created it in response to an event
        ///     wire-up, but that event is still bound so technically we should still have the 
        ///     window around.  To work around this crashing fiasco, we have special code
        ///     in the ActiveXImpl class within Control.  This code checks to see if it is running 
        ///     inside of IE, and if so, it will invoke these methods via private reflection. 
        ///     It will invoke Shutdown when the last active X control is destroyed, and then
        ///     call Startup with the first activeX control is recreated. 
        /// 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        private static void Startup() {
            if (startupRecreates) { 
                EnsureSystemEvents(false, false);
            } 
        } 

        ///  
        ///     This method is invoked via reflection from windows forms.  Why?  Because when the runtime is hosted in IE,
        ///     IE doesn't tell it when to shut down.  The first notification the runtime gets is
        ///     DLL_PROCESS_DETACH, at which point it is too late for us to run any managed code.  But,
        ///     if we don't destroy our system events window the HWND will fault if it 
        ///     receives a message after the runtime shuts down.  So it is imparative that
        ///     we destroy the window, but it is also necessary to recreate the window on demand. 
        ///     That's hard to do, because we originally created it in response to an event 
        ///     wire-up, but that event is still bound so technically we should still have the
        ///     window around.  To work around this crashing fiasco, we have special code 
        ///     in the ActiveXImpl class within Control.  This code checks to see if it is running
        ///     inside of IE, and if so, it will invoke these methods via private reflection.
        ///     It will invoke Shutdown when the last active X control is destroyed, and then
        ///     call Startup with the first activeX control is recreated. 
        /// 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
        private static void Shutdown() { 
            if (systemEvents != null && systemEvents.windowHandle != IntPtr.Zero) {
                lock(procLockObject) {
                    if (systemEvents != null) {
                        startupRecreates = true; 

                        // If we are using system events from another thread, request that it terminate 
                        // 
                        if (windowThread != null) {
                            eventThreadTerminated = new ManualResetEvent(false); 

#if DEBUG
                            int pid;
                            int thread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(systemEvents, systemEvents.windowHandle), out pid); 
                            Debug.Assert(thread != SafeNativeMethods.GetCurrentThreadId(), "Don't call Shutdown on the system events thread");
#endif 
                            UnsafeNativeMethods.PostMessage(new HandleRef(systemEvents, systemEvents.windowHandle), NativeMethods.WM_QUIT, IntPtr.Zero, IntPtr.Zero); 

                            eventThreadTerminated.WaitOne(); 
                            windowThread.Join(); //avoids an AppDomainUnloaded exception on our background thread.
                        }
                        else {
                            systemEvents.Dispose(); 
                            systemEvents = null;
                        } 
                    } 
                }
            } 
        }

        [PrePrepareMethod]
        private static void Shutdown(object sender, EventArgs e) { 
            Shutdown();
        } 
 
        /// 
        ///      A standard Win32 window proc for our broadcast window. 
        /// 
        [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private IntPtr WindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam) { 

            switch (msg) { 
                case NativeMethods.WM_SETTINGCHANGE: 
                    string newString;
                    IntPtr newStringPtr = lParam; 
                    if (lParam != IntPtr.Zero) {
                        newString = Marshal.PtrToStringAuto(lParam);
                        if (newString != null) {
                            newStringPtr = Marshal.StringToHGlobalAuto(newString); 
                        }
                    } 
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, windowHandle), NativeMethods.WM_REFLECT + msg, wParam, newStringPtr); 
                    break;
                case NativeMethods.WM_WTSSESSION_CHANGE: 
                    OnSessionSwitch((int)wParam);
                    break;
                case NativeMethods.WM_SYSCOLORCHANGE:
                case NativeMethods.WM_COMPACTING: 
                case NativeMethods.WM_DISPLAYCHANGE:
                case NativeMethods.WM_FONTCHANGE: 
                case NativeMethods.WM_PALETTECHANGED: 
                case NativeMethods.WM_TIMECHANGE:
                case NativeMethods.WM_TIMER: 
                case NativeMethods.WM_THEMECHANGED:
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, windowHandle), NativeMethods.WM_REFLECT + msg, wParam, lParam);
                    break;
 
                case NativeMethods.WM_CREATETIMER:
                    return OnCreateTimer(wParam); 
 
                case NativeMethods.WM_KILLTIMER:
                    return (IntPtr)(OnKillTimer(wParam) ? 1 : 0); 

                case NativeMethods.WM_REFLECT + NativeMethods.WM_SETTINGCHANGE:
                    try {
                        OnUserPreferenceChanging(msg - NativeMethods.WM_REFLECT, wParam, lParam); 
                        OnUserPreferenceChanged(msg - NativeMethods.WM_REFLECT, wParam, lParam);
                    } 
                    finally { 
                        try {
                            if (lParam != IntPtr.Zero) { 
                                Marshal.FreeHGlobal(lParam);
                            }
                        }
                        catch (Exception e) { 
                            Debug.Assert(false, "Exception occurred while freeing memory: " + e.ToString());
                        } 
                    } 
                    break;
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_SYSCOLORCHANGE:
                    OnUserPreferenceChanging(msg - NativeMethods.WM_REFLECT, wParam, lParam);
                    OnUserPreferenceChanged(msg - NativeMethods.WM_REFLECT, wParam, lParam);
                    break; 

                case NativeMethods.WM_REFLECT + NativeMethods.WM_THEMECHANGED: 
                    OnThemeChanged(); 
                    break;
 
                case NativeMethods.WM_QUERYENDSESSION:
                    return(IntPtr) OnSessionEnding(lParam);

                case NativeMethods.WM_ENDSESSION: 
                    OnSessionEnded(wParam, lParam);
                    break; 
 
                case NativeMethods.WM_POWERBROADCAST:
                    OnPowerModeChanged(wParam); 
                    break;

                    // WM_HIBERNATE on WinCE
                case NativeMethods.WM_REFLECT + NativeMethods.WM_COMPACTING: 
                    OnGenericEvent(OnLowMemoryEvent);
                    break; 
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_DISPLAYCHANGE:
                    OnDisplaySettingsChanging(); 
                    OnDisplaySettingsChanged();
                    break;

                case NativeMethods.WM_REFLECT + NativeMethods.WM_FONTCHANGE: 
                    OnGenericEvent(OnInstalledFontsChangedEvent);
                    break; 
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_PALETTECHANGED:
                    OnGenericEvent(OnPaletteChangedEvent); 
                    break;

                case NativeMethods.WM_REFLECT + NativeMethods.WM_TIMECHANGE:
                    OnGenericEvent(OnTimeChangedEvent); 
                    break;
 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_TIMER: 
                    OnTimerElapsed(wParam);
                    break; 

                default:
                    // If we received a thread execute message, then execute it.
                    // 
                    if (msg == threadCallbackMessage && msg != 0) {
                        InvokeMarshaledCallbacks(); 
                        return IntPtr.Zero; 
                    }
 		    break; 
            }

            return UnsafeNativeMethods.DefWindowProc(hWnd, msg, wParam, lParam);
        } 

        ///  
        ///      This is the method that runs our window thread.  This method 
        ///      creates a window and spins up a message loop.  The window
        ///      is made visible with a size of 0, 0, so that it will trap 
        ///      global broadcast messages.
        /// 
        [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 
        private void WindowThreadProc() {
            try { 
                Initialize(); 
                eventWindowReady.Set();
 
                if (windowHandle != IntPtr.Zero) {
                    NativeMethods.MSG msg = new NativeMethods.MSG();

                    bool keepRunning = true; 

                    // Blocking on a GetMessage() call prevents the EE from being able to unwind 
                    // this thread properly (e.g. during AppDomainUnload). So, we use PeekMessage() 
                    // and sleep so we always block in managed code instead.
                    // 
                    while (keepRunning) {
                        int ret = UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, NativeMethods.QS_ALLINPUT, NativeMethods.MWMO_INPUTAVAILABLE);

                        if (ret == NativeMethods.WAIT_TIMEOUT) { 
                            Thread.Sleep(1);
                        } 
                        else { 
                            while (UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_REMOVE))
                            { 
                                if (msg.message == NativeMethods.WM_QUIT) {
                                    keepRunning = false;
                                    break;
                                } 

                                UnsafeNativeMethods.TranslateMessage(ref msg); 
                                UnsafeNativeMethods.DispatchMessage(ref msg); 
                            }
                        } 
                    }
                }

                OnShutdown(OnEventsThreadShutdownEvent); 
            }
            catch (Exception e) { 
                // In case something very very wrong happend during the creation action. 
                // This will unblock the calling thread.
                // 
                eventWindowReady.Set();

                if (!((e is ThreadInterruptedException) || (e is ThreadAbortException))) {
                    Debug.Fail("Unexpected thread exception in system events window thread proc", e.ToString()); 
                }
            } 
 
            Dispose();
            if (eventThreadTerminated != null) { 
                eventThreadTerminated.Set();
            }
        }
 
        // A class that helps fire events on the right thread.
        // 
        private class SystemEventInvokeInfo { 

            private SynchronizationContext _syncContext; // the context that we'll use to fire against. 
            private Delegate    _delegate;     // the delegate we'll fire.  This is a weak ref so we don't hold object in memory.
            public SystemEventInvokeInfo(Delegate d) {

                _delegate = d; 
                _syncContext = AsyncOperationManager.SynchronizationContext;
            } 
 
            // fire the given event with the given params.
            // 
            public void Invoke(bool checkFinalization, params object[] args) {
                try {
                    // If we didn't get call back, or if we're using Everett threading, invoke directly.
                    // 
                    if (_syncContext == null || SystemEvents.UseEverettThreadAffinity) {
                        InvokeCallback(args); 
                    } 
                    else {
                        // otherwise tell the context to do it for us. 
                        //
                        _syncContext.Send(new SendOrPostCallback(InvokeCallback), args);
                    }
                } 
                catch (InvalidAsynchronousStateException) {
                    //if the synch context is invalid -- do the invoke directly for app compat. 
                    //If the app's shutting down, don't fire the event (unless it's shutdown). 
                    if (!checkFinalization || !AppDomain.CurrentDomain.IsFinalizingForUnload()) {
                        InvokeCallback(args); 
                    }
                }
            }
 
            // our delegate method that the SyncContext will call on.
            // 
            private void InvokeCallback(object arg) { 

                _delegate.DynamicInvoke((object[])arg); 
            }

            public override bool Equals(object other) {
                SystemEventInvokeInfo otherInvoke = other as SystemEventInvokeInfo; 

                if (otherInvoke == null) { 
                    return false; 
                }
                return otherInvoke._delegate.Equals(_delegate); 
            }

            public override int GetHashCode() {
                return base.GetHashCode(); 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK