参考链接
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 ", 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 }