65.9K
CodeProject 正在变化。 阅读更多。
Home

确定显示器的开/关(睡眠)状态

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (19投票s)

2017年6月24日

CPOL

2分钟阅读

viewsIcon

28438

downloadIcon

2331

如何确定显示器是开启还是关闭,作为 Windows 电源计划操作的结果。

简介与背景

本文/项目是对 Michael Dunn 于 2006 年 12 月 29 日发表的文章 C++ 中的 Vista 好东西:监视计算机的电源状态 的扩展。Dunn 先生的文章重点在于确定电源、电源方案、电源情况和电源状态。我编写了一个桌面壁纸更改程序,并希望能够确定屏幕(显示器)是开还是处于睡眠模式,这样我的程序就不会在显示器关闭(睡眠模式)时更改壁纸,因为这样做毫无意义。以下是对 Dunn 先生方法的修改。

Using the Code

Michael Dunn 的文章重点关注三个电源设置 GUID:GUID_POWERSCHEME_PERSONALITYGUID_ACDC_POWER_SOURCEGUID_BATTERY_PERCENTAGE_REMAINING。 本项目仅使用 GUID_CONSOLE_DISPLAY_STATE
 
Microsoft 在此 提供了电源设置 GUID 的完整列表。

该项目是一个简单的基于对话框的 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(更改壁纸),当显示器状态为 OFFDIMMED 时,我将程序变量设置为 FALSE

关注点

值得注意的是,当屏幕保护程序程序激活时,不会发布 POWERBROADCAST 消息。 我还尝试监视 GUID_SESSION_DISPLAY_STATUS,但我没有看到它与 GUID_CONSOLE_DISPLAY_STATE 之间的差异。 如果有人知道这两个 GUID 有何不同,我将非常感兴趣。 当然,我也感谢所有反馈。

历史

这是本文的首次展示(即,尚无历史记录)。

© . All rights reserved.