admin 管理员组

文章数量: 887007

windows系统睡眠与合上盖子事件捕获

一、系统睡眠

1.1 睡眠事件

  • PBT_APMSUSPEND 事件
    通知应用程序计算机即将进入挂起状态。该事件通常在所有应用程序和可安装驱动程序返回TRUE给之前的PBT_APMQUERYSUSPEND 事件时传播。
    窗口通过WM_POWERBROADCAST消息接收这个事件。wParam和lParam参数的设置如下所示。
LRESULT 
CALLBACK 
WindowProc( HWND hwnd,      // handle to windowUINT uMsg,      // WM_POWERBROADCASTWPARAM wParam,  // PBT_APMSUSPENDLPARAM lParam); // zero

应用程序应该通过完成保存数据所需的所有任务来处理此事件。
系统允许应用程序大约两秒钟来处理此通知。过期后,如果应用仍在运行,可能会导致应用中断。

1.2 注册函数

  • PowerRegisterSuspendResumeNotification 注册(一个函数)来接受系统挂起或者恢复时的通知
DWORD PowerRegisterSuspendResumeNotification([in]  DWORD         Flags,[in]  HANDLE        Recipient,[out] PHPOWERNOTIFY RegistrationHandle
);

Parameters
[in] Flags
这个参数必须是 DEVICE_NOTIFY_CALLBACK.
[in] Recipient
这个参数是指向DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS结构的指针。在本例中,回调函数是DeviceNotifyCallbackRoutine。 当Callback函数执行时,将设置Type参数,指示所发生事件的类型。 可能的值包括PBT_APMSUSPEND, PBT_APMRESUMESUSPEND, PBT_APMRESUMEAUTOMATIC。

typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback;//指示应用程序接收到通知时将调用的回调函数。  PVOID                           Context;//注册通知的应用程序的上下文。  
} DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;DEVICE_NOTIFY_CALLBACK_ROUTINE DeviceNotifyCallbackRoutine;
ULONG DeviceNotifyCallbackRoutine(PVOID Context,ULONG Type,PVOID Setting
)
{...}

[out] RegistrationHandle
注册的返回的句柄,使用这个句柄来反注册以取消接受通知。
Return value
如果调用成功,返回ERROR_SUCCESS(零),如果调用失败,返回一个非零值。

  • RegisterSuspendResumeNotification 注册以便在系统暂停或恢复时接收通知。类似于PowerRegisterSuspendResumeNotification,但在用户模式下操作,可以接受一个窗口句柄
HPOWERNOTIFY RegisterSuspendResumeNotification([in] HANDLE hRecipient,[in] DWORD  Flags
);

Parameters
[in] hRecipient
此参数包含订阅电源通知或表示订阅过程的窗口句柄的参数。
如果Flags是DEVICE_NOTIFY_CALLBACK, hRecipient被解释为指向DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS结构体的指针。 在本例中,回调函数是DeviceNotifyCallbackRoutine。 当Callback函数执行时,将设置Type参数,指示所发生事件的类型。 可能的值包括PBT_APMSUSPEND, PBT_APMRESUMESUSPEND, PBT_APMRESUMEAUTOMATIC。
如果Flags是DEVICE_NOTIFY_WINDOW_HANDLE,则hreceiver是要传递事件的窗口句柄。
[in] Flags
这个参数可以是DEVICE_NOTIFY_WINDOW_HANDLE或者DEVICE_NOTIFY_CALLBACK。
Return value
注册的句柄。使用此句柄注销通知。
如果函数失败,返回值为NULL。要获得扩展的错误信息,请调用GetLastError。

1.3 PowerRegisterSuspendResumeNotification 示例

void ReigsterSleepNotify(std::function<void (int)> cb) {DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS  dnsp{ [](PVOID Context, ULONG Type, PVOID Setting) noexcept -> ULONG {std::function<void(int)>* pCB = reinterpret_cast<std::function<void(int)>*>(Context);if (Type == PBT_APMSUSPEND) {std::cout << "PBT_APMSUSPEND" << std::endl;if (pCB) {(*pCB)(1);}}else if (Type == PBT_APMRESUMESUSPEND) {std::cout << "PBT_APMRESUMESUSPEND" << std::endl;if (pCB) {(*pCB)(0);}}else if (Type == PBT_APMRESUMEAUTOMATIC) {std::cout << "PBT_APMRESUMEAUTOMATIC" << std::endl;}else {std::cout << "Event type:" << Type << std::endl;}return TRUE;},&cb };HPOWERNOTIFY pRhBak;PowerRegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK, &dnsp, &pRhBak);
}

二、合上盖子

2.1 GUI 程序

  • RegisterPowerSettingNotification
HPOWERNOTIFY RegisterPowerSettingNotification([in] HANDLE  hRecipient,[in] LPCGUID PowerSettingGuid,[in] DWORD   Flags
);
  • 示例
#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <winnt.h>
#include <sstream>
#include <powrprof.h>
#include <powerbase.h>#pragma comment(lib,"Powrprof.lib")static long FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{if (message == WM_POWERBROADCAST){std::cout << "WM_POWERBROADCAST" << std::endl;DWORD dwWParam = (DWORD)wParam;if (dwWParam == PBT_POWERSETTINGCHANGE) {//std::cout << "PBT_POWERSETTINGCHANGE" << std::endl;PPOWERBROADCAST_SETTING dwLParam = (PPOWERBROADCAST_SETTING)lParam;if (dwLParam->PowerSetting == GUID_LIDSWITCH_STATE_CHANGE) {//std::cout << "GUID_LIDSWITCH_STATE_CHANGE." << std::endl;if ((char)dwLParam->Data == '0') {std::cout << "lid close" << std::endl;}else if ((char)dwLParam->Data == '\x1') {std::cout << "lid open" << std::endl;}else {std::cout << "no lid open neither close" << std::endl;}}}return TRUE;}elsereturn DefWindowProc(hWnd, message, wParam, lParam);
}int main()
{std::cout << "Hello World!\n";MSG msg;BOOL bRet = FALSE;HWND hwnd = GetWindowHwndByPID(dsPID);NDCLASS wc = { 0 };// Set up and register window classwc.lpfnWndProc = WindowProc;wc.lpszClassName = _T("SomeNameYouInvented");RegisterClass(&wc);HWND hWin = CreateWindow(_T("SomeNameYouInvented"), _T(""), 0, 0, 0, 0, 0, NULL, NULL, NULL, 0);RegisterPowerSettingNotification(hWin, &GUID_LIDSWITCH_STATE_CHANGE, DEVICE_NOTIFY_WINDOW_HANDLE);//RegisterSuspendResumeNotification(hWin, DEVICE_NOTIFY_WINDOW_HANDLE);while ((bRet = GetMessage(&msg, hWin, 0, 0)) != 0){if (bRet == -1){// handle the error and possibly exit}else{TranslateMessage(&msg);DispatchMessage(&msg);}}   Sleep(1000000);
}

2.2 非GUI程序

  • 服务示例
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include "sample.h"#pragma comment(lib, "advapi32.lib")#define SVCNAME TEXT("SvcName")SERVICE_STATUS          gSvcStatus; 
SERVICE_STATUS_HANDLE   gSvcStatusHandle; 
HANDLE                  ghSvcStopEvent = NULL;VOID SvcInstall(void);
VOID WINAPI SvcCtrlHandler( DWORD ); 
VOID WINAPI SvcMain( DWORD, LPTSTR * ); VOID ReportSvcStatus( DWORD, DWORD, DWORD );
VOID SvcInit( DWORD, LPTSTR * ); 
VOID SvcReportEvent( LPTSTR );//
// Purpose: 
//   Entry point for the process
//
// Parameters:
//   None
// 
// Return value:
//   None, defaults to 0 (zero)
//
int __cdecl _tmain(int argc, TCHAR *argv[]) 
{ // If command-line parameter is "install", install the service. // Otherwise, the service is probably being started by the SCM.if( lstrcmpi( argv[1], TEXT("install")) == 0 ){SvcInstall();return 0;}// TO_DO: Add any additional services for the process to this table.SERVICE_TABLE_ENTRY DispatchTable[] = { { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain }, { NULL, NULL } }; // This call returns when the service has stopped. // The process should simply terminate when the call returns.if (!StartServiceCtrlDispatcher( DispatchTable )) { SvcReportEvent(TEXT("StartServiceCtrlDispatcher")); } 
} //
// Purpose: 
//   Installs a service in the SCM database
//
// Parameters:
//   None
// 
// Return value:
//   None
//
VOID SvcInstall()
{SC_HANDLE schSCManager;SC_HANDLE schService;TCHAR szUnquotedPath[MAX_PATH];if( !GetModuleFileName( NULL, szUnquotedPath, MAX_PATH ) ){printf("Cannot install service (%d)\n", GetLastError());return;}// In case the path contains a space, it must be quoted so that// it is correctly interpreted. For example,// "d:\my share\myservice.exe" should be specified as// ""d:\my share\myservice.exe"".TCHAR szPath[MAX_PATH];StringCbPrintf(szPath, MAX_PATH, TEXT("\"%s\""), szUnquotedPath);// Get a handle to the SCM database. schSCManager = OpenSCManager( NULL,                    // local computerNULL,                    // ServicesActive database SC_MANAGER_ALL_ACCESS);  // full access rights if (NULL == schSCManager) {printf("OpenSCManager failed (%d)\n", GetLastError());return;}// Create the serviceschService = CreateService( schSCManager,              // SCM database SVCNAME,                   // name of service SVCNAME,                   // service name to display SERVICE_ALL_ACCESS,        // desired access SERVICE_WIN32_OWN_PROCESS, // service type SERVICE_DEMAND_START,      // start type SERVICE_ERROR_NORMAL,      // error control type szPath,                    // path to service's binary NULL,                      // no load ordering group NULL,                      // no tag identifier NULL,                      // no dependencies NULL,                      // LocalSystem account NULL);                     // no password if (schService == NULL) {printf("CreateService failed (%d)\n", GetLastError()); CloseServiceHandle(schSCManager);return;}else printf("Service installed successfully\n"); CloseServiceHandle(schService); CloseServiceHandle(schSCManager);
}//
// Purpose: 
//   Entry point for the service
//
// Parameters:
//   dwArgc - Number of arguments in the lpszArgv array
//   lpszArgv - Array of strings. The first string is the name of
//     the service and subsequent strings are passed by the process
//     that called the StartService function to start the service.
// 
// Return value:
//   None.
//
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{// Register the handler function for the servicegSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, SvcCtrlHandler);if( !gSvcStatusHandle ){ SvcReportEvent(TEXT("RegisterServiceCtrlHandler")); return; } // These SERVICE_STATUS members remain as set heregSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; gSvcStatus.dwServiceSpecificExitCode = 0;    // Report initial status to the SCMReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );// Perform service-specific initialization and work.SvcInit( dwArgc, lpszArgv );
}//
// Purpose: 
//   The service code
//
// Parameters:
//   dwArgc - Number of arguments in the lpszArgv array
//   lpszArgv - Array of strings. The first string is the name of
//     the service and subsequent strings are passed by the process
//     that called the StartService function to start the service.
// 
// Return value:
//   None
//
VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)
{// TO_DO: Declare and set any required variables.//   Be sure to periodically call ReportSvcStatus() with //   SERVICE_START_PENDING. If initialization fails, call//   ReportSvcStatus with SERVICE_STOPPED.// Create an event. The control handler function, SvcCtrlHandler,// signals this event when it receives the stop control code.ghSvcStopEvent = CreateEvent(NULL,    // default security attributesTRUE,    // manual reset eventFALSE,   // not signaledNULL);   // no nameif ( ghSvcStopEvent == NULL){ReportSvcStatus( SERVICE_STOPPED, GetLastError(), 0 );return;}// Report running status when initialization is complete.ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );// TO_DO: Perform work until service stops.while(1){// Check whether to stop the service.WaitForSingleObject(ghSvcStopEvent, INFINITE);ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );return;}
}//
// Purpose: 
//   Sets the current service status and reports it to the SCM.
//
// Parameters:
//   dwCurrentState - The current state (see SERVICE_STATUS)
//   dwWin32ExitCode - The system error code
//   dwWaitHint - Estimated time for pending operation, 
//     in milliseconds
// 
// Return value:
//   None
//
VOID ReportSvcStatus( DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint)
{static DWORD dwCheckPoint = 1;// Fill in the SERVICE_STATUS structure.gSvcStatus.dwCurrentState = dwCurrentState;gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;gSvcStatus.dwWaitHint = dwWaitHint;if (dwCurrentState == SERVICE_START_PENDING)gSvcStatus.dwControlsAccepted = 0;else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;if ( (dwCurrentState == SERVICE_RUNNING) ||(dwCurrentState == SERVICE_STOPPED) )gSvcStatus.dwCheckPoint = 0;else gSvcStatus.dwCheckPoint = dwCheckPoint++;// Report the status of the service to the SCM.SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
}//
// Purpose: 
//   Called by SCM whenever a control code is sent to the service
//   using the ControlService function.
//
// Parameters:
//   dwCtrl - control code
// 
// Return value:
//   None
//
VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
{// Handle the requested control code. switch(dwCtrl) {  case SERVICE_CONTROL_STOP: ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);// Signal the service to stop.SetEvent(ghSvcStopEvent);ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);return;case SERVICE_CONTROL_INTERROGATE: break; default: break;} }//
// Purpose: 
//   Logs messages to the event log
//
// Parameters:
//   szFunction - name of function that failed
// 
// Return value:
//   None
//
// Remarks:
//   The service must have an entry in the Application event log.
//
VOID SvcReportEvent(LPTSTR szFunction) 
{ HANDLE hEventSource;LPCTSTR lpszStrings[2];TCHAR Buffer[80];hEventSource = RegisterEventSource(NULL, SVCNAME);if( NULL != hEventSource ){StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());lpszStrings[0] = SVCNAME;lpszStrings[1] = Buffer;ReportEvent(hEventSource,        // event log handleEVENTLOG_ERROR_TYPE, // event type0,                   // event categorySVC_ERROR,           // event identifierNULL,                // no security identifier2,                   // size of lpszStrings array0,                   // no binary datalpszStrings,         // array of stringsNULL);               // no binary dataDeregisterEventSource(hEventSource);}
}
  • RegisterServiceCtrlHandlerExA
SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerExA([in]           LPCSTR                lpServiceName,[in]           LPHANDLER_FUNCTION_EX lpHandlerProc,[in, optional] LPVOID                lpContext
);LPHANDLER_FUNCTION_EX LphandlerFunctionEx;DWORD LphandlerFunctionEx([in] DWORD dwControl,[in] DWORD dwEventType,[in] LPVOID lpEventData,[in] LPVOID lpContext
)
{...}

[in] dwControl
控制代码。如SERVICE_CONTROL_POWEREVENT。
[in] dwEventType
如果dwControl是SERVICE_CONTROL_POWEREVENT,这个参数可以是WM_POWERBROADCAST消息的wParam参数中指定的值之一。见下面的PBT_POWERSETTINGCHANGE事件。

  • SERVICE_CONTROL_POWEREVENT事件
    SERVICE_CONTROL_POWEREVENT 0x0000000D 通知服务系统电源事件。dwEventType参数包含其他信息。如果dwEventType是PBT_POWERSETTINGCHANGE, lpEventData参数还包含额外的信息。

  • PBT_POWERSETTINGCHANGE事件

LRESULT 
CALLBACK 
WindowProc( HWND hwnd,      // handle to windowUINT uMsg,      // WM_POWERBROADCASTWPARAM wParam,  // PBT_POWERSETTINGCHANGELPARAM lParam); // Pointer to POWERBROADCAST_SETTING
typedef struct {GUID  PowerSetting;DWORD DataLength;UCHAR Data[1];
} POWERBROADCAST_SETTING, *PPOWERBROADCAST_SETTING;

本文标签: windows系统睡眠与合上盖子事件捕获