1+ using System ;
2+ using System . Diagnostics ;
3+ using System . Runtime . InteropServices ;
4+
5+ namespace HelloSwitcher . Models ;
6+
7+ public class PowerSuspendResumeWatcher : IDisposable
8+ {
9+ #region Win32
10+
11+ [ DllImport ( "Powrprof.dll" ) ]
12+ private static extern uint PowerRegisterSuspendResumeNotification (
13+ uint flags ,
14+ in DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient ,
15+ out IntPtr registrationHandle ) ;
16+
17+ [ DllImport ( "Powrprof.dll" ) ]
18+ private static extern uint PowerUnregisterSuspendResumeNotification (
19+ IntPtr registrationHandle ) ;
20+
21+ private const uint DEVICE_NOTIFY_CALLBACK = 2 ;
22+
23+ [ StructLayout ( LayoutKind . Sequential ) ]
24+ private struct DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
25+ {
26+ public DeviceNotifyCallbackRoutine callback ;
27+ public IntPtr context ;
28+ }
29+
30+ private delegate uint DeviceNotifyCallbackRoutine (
31+ IntPtr context ,
32+ int type ,
33+ IntPtr setting ) ;
34+
35+ private const uint ERROR_SUCCESS = 0 ;
36+
37+ #endregion
38+
39+ private DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS _recipient ;
40+ private IntPtr _registrationHandle ;
41+
42+ public PowerSuspendResumeWatcher ( )
43+ {
44+ _recipient = new DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
45+ {
46+ callback = new DeviceNotifyCallbackRoutine ( DeviceNotifyCallback ) ,
47+ context = IntPtr . Zero
48+ } ;
49+ uint result = PowerRegisterSuspendResumeNotification (
50+ DEVICE_NOTIFY_CALLBACK ,
51+ in _recipient ,
52+ out _registrationHandle ) ;
53+ if ( result != ERROR_SUCCESS )
54+ {
55+ Debug . WriteLine ( $ "Failed to register suspend resume notification. ({ result } )") ;
56+ }
57+ }
58+
59+ private uint DeviceNotifyCallback ( IntPtr context , int type , IntPtr setting )
60+ {
61+ if ( Enum . IsDefined ( typeof ( PowerStatus ) , type ) )
62+ {
63+ PowerStatusChanged ? . Invoke ( this , ( PowerStatus ) type ) ;
64+ }
65+ return 0 ;
66+ }
67+
68+ public event EventHandler < PowerStatus > PowerStatusChanged ;
69+
70+ #region IDisposable
71+
72+ private bool _isDisposed = false ;
73+
74+ public void Dispose ( )
75+ {
76+ Dispose ( true ) ;
77+ GC . SuppressFinalize ( this ) ;
78+ }
79+
80+ protected virtual void Dispose ( bool disposing )
81+ {
82+ if ( _isDisposed )
83+ return ;
84+
85+ if ( disposing )
86+ {
87+ // Free any other managed objects here.
88+ PowerStatusChanged = null ;
89+
90+ if ( _registrationHandle != IntPtr . Zero )
91+ {
92+ uint result = PowerUnregisterSuspendResumeNotification ( _registrationHandle ) ;
93+ if ( result != ERROR_SUCCESS )
94+ {
95+ Debug . WriteLine ( $ "Failed to unregister suspend resume notification. ({ result } )") ;
96+ }
97+ }
98+ }
99+
100+ // Free any unmanaged objects here.
101+ _isDisposed = true ;
102+ }
103+
104+ #endregion
105+ }
106+
107+ public enum PowerStatus
108+ {
109+ /// <summary>
110+ /// PBT_APMQUERYSUSPEND
111+ /// </summary>
112+ QuerySuspend = 0x0000 ,
113+
114+ /// <summary>
115+ /// PBT_APMQUERYSUSPENDFAILED
116+ /// </summary>
117+ QuerySuspendFailed = 0x0002 ,
118+
119+ /// <summary>
120+ /// PBT_APMSUSPEND
121+ /// </summary>
122+ Suspend = 0x0004 ,
123+
124+ /// <summary>
125+ /// PBT_APMRESUMECRITICAL
126+ /// </summary>
127+ ResumeCritical = 0x0006 ,
128+
129+ /// <summary>
130+ /// PBT_APMRESUMESUSPEND
131+ /// </summary>
132+ ResumeSuspend = 0x0007 ,
133+
134+ /// <summary>
135+ /// PBT_APMBATTERYLOW
136+ /// </summary>
137+ BatteryLow = 0x0009 ,
138+
139+ /// <summary>
140+ /// PBT_APMPOWERSTATUSCHANGE
141+ /// </summary>
142+ PowerStatusChange = 0x000A ,
143+
144+ /// <summary>
145+ /// PBT_APMOEMEVENT
146+ /// </summary>
147+ OemEvent = 0x000B ,
148+
149+ /// <summary>
150+ /// PBT_APMRESUMEAUTOMATIC
151+ /// </summary>
152+ ResumeAutomatic = 0x0012 ,
153+
154+ /// <summary>
155+ /// PBT_POWERSETTINGCHANGE
156+ /// </summary>
157+ PowerSettingChange = 0x8013
158+ }
0 commit comments