VS2010中笔记本无法接收PBT_APMSUSPEND消息,如何获取睡眠通知?
解决VS2010中笔记本睡眠事件捕获问题
一、修复WM_POWERBROADCAST消息失效问题
你的现有代码在笔记本上失效,大概率是以下原因及对应修复方案:
消息处理逻辑错误
重点:你原代码中case WM_POWERBROADCAST的代码块末尾没有添加break,会导致该case执行完后继续进入default分支,这很可能是消息处理失效的核心原因! 修复后代码的WM_POWERBROADCASE分支需明确添加break。系统现代待机/快速启动影响
笔记本普遍启用现代待机(Modern Standby)或快速启动,传统的PBT_APMSUSPEND/PBT_APMRESUMEAUTOMATIC消息可能不会触发。需额外处理PBT_POWERSETTINGCHANGE事件,监测对应电源设置:
LRESULT Cttt1tDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_POWERBROADCAST: { switch (wParam) { case PBT_APMSUSPEND: MessageBox(_T("传统睡眠")); break; case PBT_APMRESUMEAUTOMATIC: MessageBox(_T("传统唤醒")); break; case PBT_POWERSETTINGCHANGE: { POWERBROADCAST_SETTING* pSetting = (POWERBROADCAST_SETTING*)lParam; // 监测现代待机(离开模式)状态 if (IsEqualGUID(pSetting->PowerSetting, GUID_SYSTEM_AWAYMODE)) { DWORD dwState = *(DWORD*)pSetting->Data; MessageBox(dwState == 1 ? _T("进入现代待机") : _T("退出现代待机")); } break; } default: break; } break; // 必须添加该break,避免逻辑混乱 } default: break; } return CDialogEx::WindowProc(message, wParam, lParam); }
- 窗口消息接收权限问题
确保你的对话框是顶层窗口,没有被其他消息拦截函数(如PreTranslateMessage)误处理WM_POWERBROADCAST消息。
二、兼容VS2010的替代方法
如果WM_POWERBROADCAST仍无法满足需求,可使用以下兼容Windows Vista及以上、支持VS2010的方案:
1. PowerSettingRegisterNotification注册电源通知
该函数包含在VS2010默认的Windows 7 SDK中,无需升级VS:
#include <powrprof.h> #pragma comment(lib, "powrprof.lib") // 全局保存通知句柄 HPOWERNOTIFY g_hPowerNotify = NULL; // 对话框初始化时注册通知 BOOL Cttt1tDlg::OnInitDialog() { CDialogEx::OnInitDialog(); g_hPowerNotify = PowerSettingRegisterNotification( m_hWnd, &GUID_SYSTEM_AWAYMODE, DEVICE_NOTIFY_WINDOW_HANDLE, NULL ); if (!g_hPowerNotify) { MessageBox(_T("电源通知注册失败")); } return TRUE; } // 对话框销毁时取消注册 void Cttt1tDlg::OnDestroy() { CDialogEx::OnDestroy(); if (g_hPowerNotify) { PowerSettingUnregisterNotification(g_hPowerNotify); g_hPowerNotify = NULL; } }
注册后,仍通过WM_POWERBROADCAST的PBT_POWERSETTINGCHANGE事件接收状态变更。
2. 旧版APM轮询方案(兼容Windows XP)
若需兼容更老系统,可通过定时器定期检查电源状态(效率较低,仅作备选):
// 定时器回调函数 VOID CALLBACK PowerStatusCheck(PVOID lpParam, BOOLEAN TimerFired) { SYSTEM_POWER_STATUS sps; if (GetSystemPowerStatus(&sps)) { // 0表示电池供电,可辅助判断睡眠前状态 if (sps.ACLineStatus == 0) { MessageBox(_T("切换至电池供电,可能即将进入睡眠")); } } } // 初始化时创建定时器 HANDLE hPowerTimer = CreateWaitableTimer(NULL, TRUE, NULL); LARGE_INTEGER liDueTime; liDueTime.QuadPart = -10000000; // 1秒后启动,每隔1秒触发 SetWaitableTimer(hPowerTimer, &liDueTime, 1000, PowerStatusCheck, NULL, FALSE);
内容的提问来源于stack exchange,提问作者ssroreo
相关产品推荐
相关产品推荐

