确定显示器的开/关(睡眠)状态
如何确定显示器是开启还是关闭,作为 Windows 电源计划操作的结果。
简介与背景
本文/项目是对 Michael Dunn 于 2006 年 12 月 29 日发表的文章 C++ 中的 Vista 好东西:监视计算机的电源状态 的扩展。Dunn 先生的文章重点在于确定电源、电源方案、电源情况和电源状态。我编写了一个桌面壁纸更改程序,并希望能够确定屏幕(显示器)是开还是处于睡眠模式,这样我的程序就不会在显示器关闭(睡眠模式)时更改壁纸,因为这样做毫无意义。以下是对 Dunn 先生方法的修改。
Using the Code
GUID_POWERSCHEME_PERSONALITY
、GUID_ACDC_POWER_SOURCE
和 GUID_BATTERY_PERCENTAGE_REMAINING
。 本项目仅使用 GUID_CONSOLE_DISPLAY_STATE
。该项目是一个简单的基于对话框的 MFC Windows 应用程序,使用 Visual Studio 2015 Community Edition 在运行 Windows 10 Creator's Update 的计算机上开发。 虽然未经测试,但该代码应该适用于 Windows Vista 或更高版本。 同样值得注意的是,我在台式计算机上使用此过程,而不是在笔记本电脑上使用。
我们需要捕获每当发生电源设置事件(例如关闭显示器)时生成的电源设置通知消息。 这是使用 RegisterPowerSettingNotification
函数完成的。 为了释放此捕获的通知,我们必须建立一个变量,以便我们取消注册该通知。
HPOWERNOTIFY m_hScreenStateNotify;
在程序的 OnInitDialog
函数中,我们插入代码
m_hScreenStateNotify = RegisterPowerSettingNotification
(this->m_hWnd, &GUID_CONSOLE_DISPLAY_STATE, DEVICE_NOTIFY_WINDOW_HANDLE);
在 OnDestroy
函数中,释放注册
void CDetectScreenSleepDlg::OnDestroy()
{
CDialogEx::OnDestroy();
UnregisterPowerSettingNotification(m_hScreenStateNotify);
}
与 Michael Dunn 的文章一样,扩展的核心包含在消息处理函数中。 在 VS 2015 的类视图窗口中单击主对话框类。接下来,单击“属性”窗口中的“消息”图标,并为 WM_POWERBROADCAST
消息添加消息处理程序。 它具有原型
UINT CDetectScreenSleepDlg::OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData)
LPARAM nEventData
变量包含我们需要处理的信息。 它被转换为 POWERBROADCAST_SETTING
。 该结构定义为typedef struct {
GUID PowerSetting;
DWORD DataLength;
UCHAR Data[1];
} POWERBROADCAST_SETTING, *PPOWERBROADCAST_SETTING;
Data
成员可能具有以下值之一
0x0 - The display is off
0x1 - The display is on.
0x2 - The display is dimmed. Because this program is developed for a desktop machine,
the "dimmed" value is returned when the lock screen is displayed prior to the monitor
being turned off.
消息处理程序是
ON_WM_POWERBROADCAST()
我使用列表控件来记录发送的消息。 当显示器关闭时,我们需要一些东西来记录这些消息(因为,当然,当显示器关闭时我们看不到它们 :-) )。
UINT CDetectScreenSleepDlg::OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData)
{
CString sMsg;
sMsg.Format(_T("Power Broadcast messages: %d"), m_nPowerMessages);
POWERBROADCAST_SETTING *pps = (POWERBROADCAST_SETTING*)nEventData;
if (GUID_CONSOLE_DISPLAY_STATE != pps->PowerSetting)
{
// If needed do something if we have a different message rather than the state of the monitor
return 0;
}
UINT uData = pps->Data[0];
// Do something based on the monitor status. For this demonstration project
// all I do is record the monitor status when it is on
// (when the program is first run and when the system is
// awakened, uData == 1),
// when it is dimmed (when the lock-screen is shown, uData == 2), and
// when the monitor is off (sleep mode, uData == 0)
int nMax = m_lcEvents.GetItemCount();
CTime tNow = CTime::GetCurrentTime();
sMsg.Format(_T("%u"), uData);
CString sStatus[3] = { _T("Off"), _T("On"), _T("Dimmed") };
int nItem = m_lcEvents.InsertItem(nMax, sMsg);
m_lcEvents.SetItemText(nItem, 1, sStatus[uData]);
m_lcEvents.SetItemText(nItem, 2, tNow.Format("%a %B %d, %y %I:%M:%S %p"));
return CDialogEx::OnPowerBroadcast(nPowerEvent, nEventData);
}
当我将此集成到我的壁纸设置程序中时,当显示器打开时,我将程序变量设置为 TRUE
(更改壁纸),当显示器状态为 OFF
或 DIMMED
时,我将程序变量设置为 FALSE
。
关注点
值得注意的是,当屏幕保护程序程序激活时,不会发布 POWERBROADCAST
消息。 我还尝试监视 GUID_SESSION_DISPLAY_STATUS
,但我没有看到它与 GUID_CONSOLE_DISPLAY_STATE
之间的差异。 如果有人知道这两个 GUID 有何不同,我将非常感兴趣。 当然,我也感谢所有反馈。
历史
这是本文的首次展示(即,尚无历史记录)。