close

最近的案子需要程式去偵測suspend resume

那這樣就要搞清楚測試機台的預設sleep模式是 S3 還是modern standby

因為偵測的方法不同

 

S3的方法我用的是 ↓

 SystemEvents.PowerModeChanged += OnPowerChange;

 

 private void OnPowerChange(object s, PowerModeChangedEventArgs e)
        {
            switch (e.Mode)
            {
                case PowerModes.Resume:                  
                    break;
                case PowerModes.Suspend:
                    break;
            }
        }

*此法在modern standby機台無效

也就是sleep模式採用modern standby的機台

PowerChange的Event不會被Trigger

-----------------------------------------------------------------------

測試機台的sleep模式是採用modern standby

Modern Standby的方法我用的是 ↓

      public MainWindow()
        {   ...
            this.SourceInitialized += MainWindow_SourceInitialized;

            ...
        }

      void MainWindow_SourceInitialized(object sender, EventArgs e)
        {
            RegisterSuspendResumeNotification();
            IntPtr hwnd = new WindowInteropHelper(this).Handle;
            HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc));
        }

 

       IntPtr hSLEEPRESUME

        [DllImport(@"User32", SetLastError = true, EntryPoint = "RegisterSuspendResumeNotification", CallingConvention = CallingConvention.StdCall)]
        private static extern IntPtr RegisterSuspendResumeNotification(IntPtr hRecipient, Int32 Flags);

       private void RegisterSuspendResumeNotification()
        {
            IntPtr handle = new WindowInteropHelper(System.Windows.Application.Current.Windows[0]).Handle;
            hSLEEPRESUME=RegisterSuspendResumeNotification(handle, DEVICE_NOTIFY_WINDOW_HANDLE);
        }

        IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case WM_POWERBROADCAST:
                    OnPowerBroadcast(wParam, lParam);
                    break;
                default:
                    break;
            }
            return IntPtr.Zero;
        }

        private void OnPowerBroadcast(IntPtr wParam, IntPtr lParam)
        {
           if ((int)wParam == PBT_APMSUSPEND)//系統暫停執行 
                ;
            else if ((int)wParam == PBT_APMRESUMEAUTOMATIC) //喚醒 
                ;
            else if ((int)wParam == PBT_APMRESUMESUSPEND)//喚醒 
                ;
        }

* 以下文字截自Windows休眠与唤醒事件

如果系统自动起来(非人为点击操作),会发送PBT_APMRESUMEAUTOMATIC事件

如果系统因人为唤醒(鼠标、键盘、电源键),会先发送PBT_APMRESUMEAUTOMATIC事件,再发送PBT_APMRESUMESUSPEND事件(休眠唤醒事件),同时系统点亮屏幕。这时你的程序需要重新打开因为系统睡眠时关闭的文件。

-----------------------------------------------------------------------

補充:節電模式開始與關閉的提醒

Windows桌面應用現在可以在節電模式開始與關閉時進行提醒。

通過改變節能模式,應用也可以在續航方面做出一定貢獻。

GUID_POWER_SAVING_STATUS:此全新GUID與RegisterPowerSettingNotification即可實現通知功能。

原文網址:Win10桌面/手機版最深層次開發功能挖掘  https://kknews.cc/tech/n36z5o5.html

 

程式實作:
 

public MainWindow()
{   ...
     this.SourceInitialized += MainWindow_SourceInitialized;

     ...
}

void MainWindow_SourceInitialized(object sender, EventArgs e)
 {
            RegisterForPowerNotifications();
            IntPtr hwnd = new WindowInteropHelper(this).Handle;
            HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc));
}

 IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case WM_POWERBROADCAST:
                    OnPowerBroadcast(wParam, lParam);
                    break;
                default:
                    break;
            }
            return IntPtr.Zero;
        }

Guid GUID_POWER_SAVING_STATUS = new Guid(0xE00958C0, 0xC213, 0x4ACE, 0xAC, 0x77, 0xFE, 0xCC, 0xED, 0x2E, 0xEE, 0xA5);

const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;

IntPtr hBATTERYSAVERCHANGE

private void RegisterForPowerNotifications()
{
            IntPtr handle = new WindowInteropHelper(System.Windows.Application.Current.Windows[0]).Handle;
            hBATTERYSAVERCHANGE = RegisterPowerSettingNotification(handle, ref GUID_POWER_SAVING_STATUS, DEVICE_NOTIFY_WINDOW_HANDLE);
}

 

internal struct POWERBROADCAST_SETTING
{
            public Guid PowerSetting;
            public uint DataLength;
            public byte Data;
}

const int PBT_POWERSETTINGCHANGE = 0x8013;

private void OnPowerBroadcast(IntPtr wParam, IntPtr lParam)
{
            if ((int)wParam == PBT_POWERSETTINGCHANGE)
            {
                POWERBROADCAST_SETTING ps = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(lParam, typeof(POWERBROADCAST_SETTING));
                if (ps.PowerSetting == GUID_POWER_SAVING_STATUS)
                {
                    if (ps.Data == 0)
                    {
                        Console.WriteLine("Disable Battery Saver Mode");
                        IsBatSaver = false;
                    }
                    else if (ps.Data == 1)
                    {
                        Console.WriteLine("Enable Battery Saver Mode");
                        IsBatSaver = true;
                    }
                }

}

-----------------------------------------------------------------------

*根據一起合作此案的bios team engineer所說

bios設定選單可以選要用S3 或 modern standby 進sleep

所以看起來兩者不會共存

 

後記:

因為我需要在機台resume的時候do something 

所以雖說客戶機台預設的模式是modern standby 

但為了保險起見

我的程式裡還是同時放了判斷S3 跟 modern standby  suspend resume的程式碼

 

參考資料

1. ModernStandby下获取系统电源消息 

 

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 iam9527 的頭像
    iam9527

    翁丸的育兒筆記

    iam9527 發表在 痞客邦 留言(0) 人氣()