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

一、系统睡眠

1.1 睡眠事件

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

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

1.2 注册函数

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 程序

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;
    }
    else
        return 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 class
    wc.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 computer
        NULL,                    // ServicesActive database 
        SC_MANAGER_ALL_ACCESS);  // full access rights 
 
    if (NULL == schSCManager) 
    {
        printf("OpenSCManager failed (%d)\n", GetLastError());
        return;
    }

    // Create the service

    schService = 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 service

    gSvcStatusHandle = RegisterServiceCtrlHandler( 
        SVCNAME, 
        SvcCtrlHandler);

    if( !gSvcStatusHandle )
    { 
        SvcReportEvent(TEXT("RegisterServiceCtrlHandler")); 
        return; 
    } 

    // These SERVICE_STATUS members remain as set here

    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 
    gSvcStatus.dwServiceSpecificExitCode = 0;    

    // Report initial status to the SCM

    ReportSvcStatus( 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 attributes
                         TRUE,    // manual reset event
                         FALSE,   // not signaled
                         NULL);   // no name

    if ( 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 handle
                    EVENTLOG_ERROR_TYPE, // event type
                    0,                   // event category
                    SVC_ERROR,           // event identifier
                    NULL,                // no security identifier
                    2,                   // size of lpszStrings array
                    0,                   // no binary data
                    lpszStrings,         // array of strings
                    NULL);               // no binary data

        DeregisterEventSource(hEventSource);
    }
}
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事件。

LRESULT 
CALLBACK 
WindowProc( HWND hwnd,      // handle to window
            UINT uMsg,      // WM_POWERBROADCAST
            WPARAM wParam,  // PBT_POWERSETTINGCHANGE
            LPARAM lParam); // Pointer to POWERBROADCAST_SETTING
typedef struct {
  GUID  PowerSetting;
  DWORD DataLength;
  UCHAR Data[1];
} POWERBROADCAST_SETTING, *PPOWERBROADCAST_SETTING;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值