using System; using System.Collections.Generic; using Microsoft.Win32; using Win32_SystemEvents = Microsoft.Win32.SystemEvents; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Threading; using System.ComponentModel; using Trigger.Classes.Power; using Trigger.Classes.System; namespace Trigger.Events { /// /// A that provides events for Power stuff /// It catches changes in the PowerMode (Battery Status, Battery Availability, PowerLine Status), Suspend and Resumes and a change of the active /// public class Power : EventPlugin { #region Dll Imports [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal extern static IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, int Flags); [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal extern static IntPtr UnregisterPowerSettingNotification(IntPtr Handle); #endregion #region Constants, Structs & Enums internal enum EventType : byte { PowerModeChanged, PowerLineStatusChanged, BatteryStatusChanged, PowerSchemeChanged, } #endregion #region Properties internal static Main Main; internal Dictionary oldValues = new Dictionary(); internal static Dictionary oldStaticValues = new Dictionary(); #region Register Parent Events internal byte powerModeChangedEnabled; internal bool PowerModeChangedEnabled { get { return powerModeChangedEnabled > 0; } set { if (value) powerModeChangedEnabled++; else powerModeChangedEnabled--; if (value && powerModeChangedEnabled == 1) Win32_SystemEvents.PowerModeChanged += Win32_SystemEvents_PowerModeChanged; else if (powerModeChangedEnabled == 0) Win32_SystemEvents.PowerModeChanged -= Win32_SystemEvents_PowerModeChanged; } } internal static byte powerBroadcastChangedEnabled; internal static IntPtr powerBroadcastChangedHandle = IntPtr.Zero; internal static bool PowerBroadcastChangedEnabled { get { return powerBroadcastChangedEnabled > 0; } set { if (value) powerBroadcastChangedEnabled++; else powerBroadcastChangedEnabled--; if (value && powerBroadcastChangedEnabled == 1) { powerBroadcastChangedHandle = RegisterPowerSettingNotification(Main.Handle, ref Classes.Power.PowerScheme.GUID_POWERSCHEME_PERSONALITY, Main.DEVICE_NOTIFY_WINDOW_HANDLE); Main.RegisterEventForMessage(Classes.System.WindowsMessages.WM_POWERBROADCAST); Main.MessageReceived += Main_MessageReceived; } else if (powerBroadcastChangedEnabled == 0) { UnregisterPowerSettingNotification(powerBroadcastChangedHandle); powerBroadcastChangedHandle = IntPtr.Zero; Main.UnregisterEventForMessage(Classes.System.WindowsMessages.WM_POWERBROADCAST); Main.MessageReceived -= Main_MessageReceived; } } } #endregion #region Events #region PowerModeChanged internal EventPlugin.EventValue OnPowerModeChanged; /// Occurs when the user suspends or resumes the system. public event EventPlugin.EventValue PowerModeChanged { add { this.OnPowerModeChanged += value; PowerModeChangedEnabled = true; } remove { this.OnPowerModeChanged -= value; PowerModeChangedEnabled = false; } } #endregion #region - Suspend internal EventPlugin.Event OnSuspend; /// Occurs when the user suspends the system. public event EventPlugin.Event Suspend { add { this.OnSuspend += value; PowerModeChangedEnabled = true; } remove { this.OnSuspend -= value; PowerModeChangedEnabled = false; } } #endregion #region - Resume internal EventPlugin.Event OnResume; /// Occurs when the user resumes the system. public event EventPlugin.Event Resume { add { this.OnResume += value; PowerModeChangedEnabled = true; } remove { this.OnResume -= value; PowerModeChangedEnabled = false; } } #endregion #region - PowerLineStatusChanged internal EventPlugin.EventValues OnPowerLineStatusChanged; /// Occurs when the user connects or disconnects the system from/to the power network. public event EventPlugin.EventValues PowerLineStatusChanged { add { if (!oldValues.ContainsKey(EventType.PowerLineStatusChanged)) oldValues[EventType.PowerLineStatusChanged] = Status.Power.PowerLineStatus; this.OnPowerLineStatusChanged += value; PowerModeChangedEnabled = true; } remove { this.OnPowerLineStatusChanged -= value; PowerModeChangedEnabled = false; } } #endregion #region - BatteryAvailabilityChanged internal EventPlugin.EventValue OnBatteryAvailabilityChanged; /// Occurs when the user connects or disconnects the computer from the battery. public event EventPlugin.EventValue BatteryAvailabilityChanged { add { if (!oldValues.ContainsKey(EventType.BatteryStatusChanged)) oldValues[EventType.BatteryStatusChanged] = Status.Power.BatteryChargeStatus; this.OnBatteryAvailabilityChanged += value; PowerModeChangedEnabled = true; } remove { this.OnBatteryAvailabilityChanged -= value; PowerModeChangedEnabled = false; } } #endregion #region - BatteryStatusChanged internal EventPlugin.EventValues OnBatteryStatusChanged; /// Occurs when the user connects or disconnects the computer from the battery. public event EventPlugin.EventValues BatteryStatusChanged { add { if (!oldValues.ContainsKey(EventType.BatteryStatusChanged)) oldValues[EventType.BatteryStatusChanged] = Status.Power.BatteryChargeStatus; this.OnBatteryStatusChanged += value; PowerModeChangedEnabled = true; } remove { this.OnBatteryStatusChanged -= value; PowerModeChangedEnabled = false; } } #endregion #region PowerSchemeChanged internal static EventPlugin.EventValues OnPowerSchemeChanged; /// Occurs when the user selects antoher power plan. public event EventPlugin.EventValues PowerSchemeChanged { add { if (!oldStaticValues.ContainsKey(EventType.PowerSchemeChanged)) oldStaticValues[EventType.PowerSchemeChanged] = Status.Power.ActivePowerScheme; OnPowerSchemeChanged += value; PowerBroadcastChangedEnabled = true; } remove { OnPowerSchemeChanged -= value; PowerBroadcastChangedEnabled = false; } } #endregion #endregion #endregion #region Constructor & Destructor /// /// Creates an instance of this class /// /// public Power(Main main) { Main = main; } /// /// Disables all SystemEvents because they are static /// /// http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents.displaysettingschanged%28v=vs.110%29.aspx ~Power() { if (PowerModeChangedEnabled) Win32_SystemEvents.PowerModeChanged -= Win32_SystemEvents_PowerModeChanged; if (PowerBroadcastChangedEnabled) { UnregisterPowerSettingNotification(powerBroadcastChangedHandle); Main.MessageReceived -= Main_MessageReceived; } } #endregion #region Methods /// /// /// public override EventList EventNames() { EventList list = new EventList(); EventListRow row = list.NewEventListRow(); row.Name = "PowerModeChanged"; row.Text = "Power mode changed"; row.Description = "The user suspends or resumes the system"; row.Type = Manager.EventTypes.SingleValue; list.AddEventListRow(row); row = list.NewEventListRow(); row.Name = "Suspend"; row.Text = "Suspend"; row.Description = "The user suspends the system"; row.Type = Manager.EventTypes.Simple; list.AddEventListRow(row); row = list.NewEventListRow(); row.Name = "Resume"; row.Text = "Resume"; row.Description = "The user resumes the system"; row.Type = Manager.EventTypes.Simple; list.AddEventListRow(row); return list; } /// /// /// public override TreeNode GetStatus() { TreeNode tnMain = new TreeNode("Power"); TreeNode tnEvents = tnMain.Nodes.Add("Registered events"); if (PowerModeChangedEnabled) { TreeNode tnEvent = tnEvents.Nodes.Add("PowerModeChanged"); tnEvent.ToolTipText = "Microsoft.Win32.SystemEvents.PowerModeChanged"; } if (PowerBroadcastChangedEnabled) { TreeNode tnEvent = tnEvents.Nodes.Add("PowerBroadcastChanged"); tnEvent.ToolTipText = "Registered in Win32 message service (WM_POWERBROADCAST)"; } return tnMain; } #endregion #region Event Handler internal void Win32_SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) { if (OnPowerModeChanged != null) OnPowerModeChanged(this, new EventArgsValue(e.Mode)); switch (e.Mode) { case PowerModes.Resume: if (OnResume != null) OnResume(this, new EventArgs()); break; case PowerModes.Suspend: if (OnSuspend != null) OnSuspend(this, new EventArgs()); break; case PowerModes.StatusChange: if (OnPowerLineStatusChanged != null) { PowerLineStatus oldValuePLS = (PowerLineStatus)oldValues[EventType.PowerLineStatusChanged]; PowerLineStatus newValuePLS = Status.Power.PowerLineStatus; if (oldValuePLS != newValuePLS) { OnPowerLineStatusChanged(this, new EventArgsValues(oldValuePLS, newValuePLS)); oldValues[EventType.PowerLineStatusChanged] = newValuePLS; } } BatteryChargeStatus oldValueBCS = (BatteryChargeStatus)oldValues[EventType.BatteryStatusChanged]; BatteryChargeStatus newValueBCS = Status.Power.BatteryChargeStatus; if (OnBatteryStatusChanged != null) { if (oldValueBCS != newValueBCS) { OnBatteryStatusChanged(this, new EventArgsValues(oldValueBCS, newValueBCS)); oldValues[EventType.BatteryStatusChanged] = newValueBCS; } } if (OnBatteryAvailabilityChanged != null) { bool? oldValueBCSb = null, newValueBCSb = null; if (oldValueBCS == BatteryChargeStatus.NoSystemBattery) oldValueBCSb = false; else if (oldValueBCS != BatteryChargeStatus.Unknown) oldValueBCSb = true; if (newValueBCS == BatteryChargeStatus.NoSystemBattery) newValueBCSb = false; else if (newValueBCS != BatteryChargeStatus.Unknown) newValueBCSb = true; if (oldValueBCSb != newValueBCSb) { OnBatteryAvailabilityChanged(this, new EventArgsValue(newValueBCSb)); } } break; } } internal static void Main_MessageReceived(object sender, EventArgsValue e) { if (e.Value.Msg != (int)Classes.System.WindowsMessages.WM_POWERBROADCAST) return; PBT wParam = (PBT)e.Value.WParam.ToInt32(); switch (wParam) { case PBT.POWERSETTINGCHANGE: PowerBroadcast_Setting pbs = (PowerBroadcast_Setting)Marshal.PtrToStructure(e.Value.LParam, typeof(PowerBroadcast_Setting)); PowerScheme oldPlan = (PowerScheme)oldStaticValues[EventType.PowerSchemeChanged]; PowerScheme newPlan = Status.Power.ActivePowerScheme; if (oldPlan == newPlan) return; if (OnPowerSchemeChanged != null) OnPowerSchemeChanged(null, new EventArgsValues(oldPlan, newPlan)); oldStaticValues[EventType.PowerSchemeChanged] = newPlan; break; } } #endregion } }