c# 监听 Modern Standby 下的电源状态(Sleep mode)
Windows 8.1之后,winows系統(tǒng)引入一種叫Connected Standby power model。其目的在于模擬手機關(guān)屏后能夠省電,而開屏時又能快速響應(yīng)的特點。在windows 10中,又擴展了這種模式。有了conneted standby mode 和DisConnected standby mode.(https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby)
最主要的意思是睡眠的時候仍然聯(lián)網(wǎng),比如:收郵件。進入CS 之后后臺仍然能夠收郵件,conneted standby 最主要的意思是睡眠的時候仍然聯(lián)網(wǎng),比如:收郵件。進入CS 之后后臺仍然能夠收郵件,喚醒之后馬上就能看到新郵件。還有一種是 Disconnected Standby,就是睡眠的時候斷網(wǎng)(Modern Standby簡介 - WWW.LAB-Z.COM (lab-z.com))。
聽起來這都是windows的改善行為。但是對于傳統(tǒng)的windows api,或者從windows 7遷移過來的app,這是有影響。很多程序在用戶進入sleep的時候,會監(jiān)聽 SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged 做一些保存的動作。但是在windows 10中,如果電源模式為Modern standby 的話,那么這個事件失效的。
?
原來windows OS 引入 Desktop Activity Moderator? PowerRegisterSuspendResumeNotification 這個API來處理這個問題。
https://docs.microsoft.com/en-us/windows/win32/w8cookbook/desktop-activity-moderator? 來處理這個問題。
以下演示在代碼展示c#程序中如何使用這種方法。
using System; using System.Runtime.InteropServices; namespace PowerStatusChanged {class Program{static void Main(string[] args){IntPtr registrationHandle = new IntPtr();DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient = new DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS();recipient.Callback = new DeviceNotifyCallbackRoutine(DeviceNotifyCallback);recipient.Context = IntPtr.Zero;IntPtr pRecipient = Marshal.AllocHGlobal(Marshal.SizeOf(recipient));Marshal.StructureToPtr(recipient, pRecipient, false);uint result = PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, ref recipient, ref registrationHandle);if (result != 0)Console.WriteLine("Error registering for power notifications: " + Marshal.GetLastWin32Error());elseConsole.WriteLine("Successfully Registered for power notifications!");Console.ReadKey();}private static int DeviceNotifyCallback(IntPtr context, int type, IntPtr setting){Console.WriteLine("Device notify callback called: ");switch (type){case PBT_APMPOWERSTATUSCHANGE:Console.WriteLine("\tPower status has changed.");break;case PBT_APMRESUMEAUTOMATIC:Console.WriteLine("\tOperation is resuming automatically from a low-power state.This message is sent every time the system resumes.");break;case PBT_APMRESUMESUSPEND:Console.WriteLine("\tOperation is resuming from a low-power state.This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.");break;case PBT_APMSUSPEND:Console.WriteLine("\tSystem is suspending operation.");break;case PBT_POWERSETTINGCHANGE:Console.WriteLine("\tA power setting change event has been received. ");break;default:Console.WriteLine("unknown");break;}// do something herereturn 0;}private const int WM_POWERBROADCAST = 536; // (0x218)private const int PBT_APMPOWERSTATUSCHANGE = 10; // (0xA) - Power status has changed.private const int PBT_APMRESUMEAUTOMATIC = 18; // (0x12) - Operation is resuming automatically from a low-power state.This message is sent every time the system resumes.private const int PBT_APMRESUMESUSPEND = 7; // (0x7) - Operation is resuming from a low-power state.This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.private const int PBT_APMSUSPEND = 4; // (0x4) - System is suspending operation.private const int PBT_POWERSETTINGCHANGE = 32787; // (0x8013) - A power setting change event has been received.private const int DEVICE_NOTIFY_CALLBACK = 2;/// <summary>/// OS callback delegate definition/// </summary>/// <param name="context">The context for the callback</param>/// <param name="type">The type of the callback...for power notifcation it's a PBT_ message</param>/// <param name="setting">A structure related to the notification, depends on type parameter</param>/// <returns></returns>public delegate int DeviceNotifyCallbackRoutine(IntPtr context, int type, IntPtr setting);/// <summary>/// A callback definition/// </summary>[StructLayout(LayoutKind.Sequential)]public struct DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{public DeviceNotifyCallbackRoutine Callback;public IntPtr Context;}[DllImport("Powrprof.dll", SetLastError = true)]static extern uint PowerRegisterSuspendResumeNotification(uint flags, ref DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS receipient, ref IntPtr registrationHandle);} }源碼下載
https://download.csdn.net/download/mochounv/15728042
運行以上程序,點擊開始-->休眠,喚醒回來后,可以看到以下結(jié)果:
?
以上代碼方案參考
ModernStandby下獲取系統(tǒng)電源消息_wayyt_新浪博客 (sina.com.cn)
pinvoke.net: PowerRegisterSuspendResumeNotification (powrprof)
值得分享的是:
1)以上程序在傳統(tǒng)的S3, S4電源模式下,也能響應(yīng)系統(tǒng)Sleep事件。當將這代碼移到GUI程序(如wpf winform等程序時,需要將 registrationHandle,recipient 和 pRecipient 設(shè)置為 static 的成員,否則因為生命周期的問題,回調(diào)會找不到部分數(shù)據(jù),而導致程序在OS resume 回來時掛掉)
2)這里想強調(diào)的時,雖然這里監(jiān)聽的是PBT_APMSUSPEND事件,但是千萬不要在桌面程序的窗口事件WndindowProc來監(jiān)聽,盡管有這樣一套接口官網(wǎng)有這樣一套接口
?https://docs.microsoft.com/en-us/windows/win32/power/wm-powerbroadcast#:~:text=WM_POWERBROADCAST%20messages%20do%20not%20distinguish%20between%20different%20low-power,state%20transitions%20in%20the%20Windows%20System%20event%20log.
但是我測下來,只能收到插播電源的事件。從以上鏈接看不出來為什么不行。
?
?
?
一點擴展:
如何查看系統(tǒng)的電源模式呢,在cmd窗口中,使用powercfg -a 可以查看。
比如以下模式,就是一個傳統(tǒng)的電源模式, S3 (Sleep), S4(Hibernate).
而以下模式
S0 Low Power Idle表示 Modern standby 模式。
?
?
至于什么是Modern standby 模式以及它跟傳統(tǒng)的 S3(Sleep), S4(Hibernate)有的區(qū)別可以查看
https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-vs-s3。
?
?
總結(jié)
以上是生活随笔為你收集整理的c# 监听 Modern Standby 下的电源状态(Sleep mode)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 家庭和办公路由器被劫持以发动DDoS攻击
- 下一篇: SQL必知必会第4版读书笔记