參考鏈接
https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby
https://blogs.msdn.microsoft.com/winsdk/2014/12/02/how-to-get-notified-when-going-in-and-out-of-connected-standby-from-a-windows-service/
一 介紹
低功耗聯網狀態, win8 win8.1叫connected standby, win10 對win8的connected standby 進行了擴展, 並起了一個新名字,叫modern-standby
進入這種狀態時,Windows Store Applications以及傳統桌面程序會被暫停, session 0中的服務程序不會被暫停, 但是會受到一些限制(目前沒有詳細測試, 會受到哪些限制)
只有硬件跟系統都支持的時候, 這台機器才支持這種狀態
二 查看是否支持這種狀態
以win10為例, 使用命令powercfg /a之后, 如果有 so 低電量待機字樣的說明當前機器支持這種狀態
三 查看當前系統何時進入這種狀態
還是以win10為例, 使用命令 powercfg /batteryreport, 成功執行后會在當前目錄生成一份電池使用報告, 部分報告如下所示
四 程序感知系統進入跟離開這種狀態
在第二個url中有詳細的方法, 測試服務通知的時候發現有一些細節需要注意, 參見代碼中的注釋, 關鍵代碼如下:
1 #include <PowrProf.h> 2 #pragma comment(lib,"PowrProf.lib") 3 #include <WinNT.h>
1 SERVICE_STATUS_HANDLE hStatus = NULL; 2 VOID WINAPI ServiceMain(DWORD dwNumServicesArgs, LPWSTR *lpServiceArgVectors) 3 { 4 //省略的代碼 5 6 7 //為服務注冊控制處理器 8 hStatus = RegisterServiceCtrlHandlerEx(L"aaa", Ctrlhandler, NULL);//服務名,指向controlhandlefunction指針 9 if (!hStatus) 10 { 11 return; 12 } 13 14 //省略的代碼 15 16 WriteLog("service start"); 17 // 針對connected standby的特殊處理 18 HPOWERNOTIFY hNotify = NULL; 19 if (IsSupportConnectedStandby()) 20 { 21 hNotify =RegisterPowerSettingNotification(hStatus, &GUID_MONITOR_POWER_ON, DEVICE_NOTIFY_SERVICE_HANDLE); 22 if (!hNotify) 23 WriteLog("register err!!!!"); 24 else 25 WriteLog("register success"); 26 } 27 28 29 //省略的代碼 30 31 32 // 服務主線程結束時, 要取消掉通知回調 33 if (hNotify) 34 UnregisterPowerSettingNotification(hNotify);
35 }
1 bool IsSupportConnectedStandby()//S0 low power idle 2 { 3 bool result = false; 4 do 5 { 6 SYSTEM_POWER_CAPABILITIES info = { 0 }; 7 NTSTATUS ret = CallNtPowerInformation(SystemPowerCapabilities, NULL, 0, &info, sizeof(info)); 8 if (ret != 0)//STATUS_SUCCESS 用戶層沒有這個宏, 所以直接用數值進行比較 9 { 10 printf("get info error: %x\n", ret); 11 break; 12 } 13 if (info.AoAc == TRUE) 14 result = true; 15 } while (false); 16 17 return result; 18 }
1 DWORD WINAPI Ctrlhandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) 2 { 3 switch (dwControl) 4 { 5 case SERVICE_CONTROL_STOP: 6 brun = false; 7 ServiceStatus.dwCurrentState = SERVICE_STOPPED; 8 WriteLog("SERVICE_CONTROL_STOP"); 9 break; 10 case SERVICE_CONTROL_SHUTDOWN: 11 brun = false; 12 ServiceStatus.dwCurrentState = SERVICE_STOPPED; 13 WriteLog("SERVICE_CONTROL_SHUTDOWN"); 14 break; 15 case SERVICE_CONTROL_PAUSE: 16 brun = false; 17 ServiceStatus.dwCurrentState = SERVICE_PAUSED; 18 WriteLog("SERVICE_CONTROL_SHUTDOWN"); 19 break; 20 case SERVICE_CONTROL_CONTINUE: 21 brun = false; 22 ServiceStatus.dwCurrentState = SERVICE_RUNNING; 23 break; 24 case SERVICE_CONTROL_POWEREVENT: 25 switch (dwEventType) 26 { 27 case PBT_APMRESUMEAUTOMATIC: 28 { 29 WriteLog("PBT_APMRESUMEAUTOMATIC"); 30 break; 31 } 32 case PBT_APMRESUMESUSPEND: 33 { 34 WriteLog("PBT_APMRESUMESUSPEND"); 35 break; 36 } 37 case PBT_APMSUSPEND: 38 { 39 WriteLog("PBT_APMSUSPEND"); 40 break; 41 } 42 case PBT_APMPOWERSTATUSCHANGE: // 交流變電池 或者電池變交流 43 { 44 WriteLog("PBT_APMPOWERSTATUSCHANGE"); 45 break; 46 } 47 case PBT_POWERSETTINGCHANGE: 48 { 49 WriteLog("PBT_POWERSETTINGCHANGE"); 50 PPOWERBROADCAST_SETTING setting = (PPOWERBROADCAST_SETTING)lpEventData; 51 if(setting->PowerSetting == GUID_MONITOR_POWER_ON) 52 { 53 std::string str("GUID_MONITOR_POWER_ON "); 54 55 if(setting->DataLength == 4) 56 { 57 // MONITOR_POWER_OFF(data ==0)-->進入 connected standby狀態 58 // MONITOR_POWER_ON(data ==1)-->進入 active狀態 59 // MONITOR_POWER_OFF對應於設置里面睡眠進入的時間, 而不是根據字面意思對應設置里面的屏幕關閉時間, 這個要注意!!! 60 // 剛剛注冊GUID_MONITOR_POWER_ON成功后會立刻收到一次該事件, 報告data ==1 61 DWORD data = *(DWORD*)(setting->Data); 62 str += std::to_string(data); 63 } 64 else 65 { 66 str += "len: "; 67 str += std::to_string(setting->DataLength); 68 } 69 WriteLog(str); 70 } 71 break; 72 } 73 74 default: 75 break; 76 } 77 break; 78 case SERVICE_CONTROL_SESSIONCHANGE: 79 { 80 std::string str("SERVICE_CONTROL_SESSIONCHANGE: "); 81 str+= std::to_string(dwEventType); 82 83 PWTSSESSION_NOTIFICATION Notification = (PWTSSESSION_NOTIFICATION)lpEventData; 84 str += " "; 85 str += std::to_string(Notification->dwSessionId); 86 WriteLog(str.c_str()); 87 88 switch (dwEventType) 89 { 90 case WTS_CONSOLE_CONNECT: 91 break; 92 case WTS_CONSOLE_DISCONNECT: 93 break; 94 case WTS_SESSION_LOGON: 95 break; 96 case WTS_SESSION_LOGOFF: 97 break; 98 case WTS_SESSION_LOCK: 99 break; 100 case WTS_SESSION_UNLOCK: 101 break; 102 default: 103 ; 104 } 105 } 106 break; 107 default: 108 break; 109 } 110 //向SCM報告“SERVICE_STOPPED”狀態 111 SetServiceStatus(hStatus, &ServiceStatus); 112 return NO_ERROR; 113 }