c# 监听 Modern Standby 下的电源状态(Sleep mode)

Windows 8.1之后,winows系统引入一种叫Connected Standby power model。其目的在于模拟手机关屏后能够省电,而开屏时又能快速响应的特点。在windows 10中,又扩展了这种模式。有了conneted standby mode 和DisConnected standby mode.(https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby)

最主要的意思是睡眠的时候仍然联网,比如:收邮件。进入CS 之后后台仍然能够收邮件,conneted standby 最主要的意思是睡眠的时候仍然联网,比如:收邮件。进入CS 之后后台仍然能够收邮件,唤醒之后马上就能看到新邮件。还有一种是 Disconnected Standby,就是睡眠的时候断网(Modern Standby简介 - WWW.LAB-Z.COM (lab-z.com))。

听起来这都是windows的改善行为。但是对于传统的windows api,或者从windows 7迁移过来的app,这是有影响。很多程序在用户进入sleep的时候,会监听 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());
            else
                Console.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 here
            return 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

运行以上程序,点击开始-->休眠,唤醒回来后,可以看到以下结果:

 

以上代码方案参考

ModernStandby下获取系统电源消息_wayyt_新浪博客 (sina.com.cn)

pinvoke.net: PowerRegisterSuspendResumeNotification (powrprof)

值得分享的是:

1)以上程序在传统的S3, S4电源模式下,也能响应系统Sleep事件。当将这代码移到GUI程序(如wpf winform等程序时,需要将 registrationHandle,recipient 和 pRecipient 设置为 static 的成员,否则因为生命周期的问题,回调会找不到部分数据,而导致程序在OS resume 回来时挂掉)

2)这里想强调的时,虽然这里监听的是PBT_APMSUSPEND事件,但是千万不要在桌面程序的窗口事件WndindowProc来监听,尽管有这样一套接口官网有这样一套接口

 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.

但是我测下来,只能收到插播电源的事件。从以上链接看不出来为什么不行。

 

 

 

一点扩展:

如何查看系统的电源模式呢,在cmd窗口中,使用powercfg -a 可以查看。

比如以下模式,就是一个传统的电源模式, S3 (Sleep), S4(Hibernate).

而以下模式

S0 Low Power Idle表示 Modern standby 模式。

 

 

至于什么是Modern standby 模式以及它跟传统的 S3(Sleep), S4(Hibernate)有的区别可以查看

https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-vs-s3

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值