Introduction & Background
This article/project is an extension of Michael Dunn's December 29, 2006 article Vista Goodies in C++: Monitoring the Computer's Power Status Mr. Dunn's article focuses on determining the power source, power scheme, power situation and power status. I had written a desktop wallpaper change program and wanted to be able to determine whether the screen (monitor) was on or in sleep mode so my program would not change the wallpaper when the monitor was off (sleep mode) since that would be pointless. What follows is a modification of Mr. Dunn's approach.
Using the Code
Michael Dunn's article focuses on three power setting GUIDs: GUID_POWERSCHEME_PERSONALITY
, GUID_ACDC_POWER_SOURCE
, and GUID_BATTERY_PERCENTAGE_REMAINING
. This project uses only GUID_CONSOLE_DISPLAY_STATE
.
The full list of Power Setting GUIDs is provided by Microsoft
here.
The project is a simple dialog-based MFC Windows application, developed using Visual Studio 2015 Community Edition on a computer running Windows 10 Creator's Update. Although not tested, the code should work with Windows Vista or later. It is also worth noting that I am using this procedure on a desktop computer, not a laptop.
We need to capture the power setting notification messages generated whenever a power setting event, such as turning off the monitor takes place. This is done using the RegisterPowerSettingNotification
function. In order to release this captured notification, we must establish a variable that allows us to unregister the notification.
HPOWERNOTIFY m_hScreenStateNotify;
In the OnInitDialog
function of the program, we insert the code:
m_hScreenStateNotify = RegisterPowerSettingNotification
(this->m_hWnd, &GUID_CONSOLE_DISPLAY_STATE, DEVICE_NOTIFY_WINDOW_HANDLE);
In the OnDestroy
function, release the registration:
void CDetectScreenSleepDlg::OnDestroy()
{
CDialogEx::OnDestroy();
UnregisterPowerSettingNotification(m_hScreenStateNotify);
}
The meat of the extension, as with Michael Dunn's article, is contained in the message handler function. Click on the main dialog class in the Class View window of VS 2015. Next click on the Messages icon in the Properties window and add the message handler for the WM_POWERBROADCAST
message. It has the prototype:
UINT CDetectScreenSleepDlg::OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData)
The LPARAM nEventData
variable contains the information we need to process. It is cast to POWERBROADCAST_SETTING
. This structure is defined as:
typedef struct {
GUID PowerSetting;
DWORD DataLength;
UCHAR Data[1];
} POWERBROADCAST_SETTING, *PPOWERBROADCAST_SETTING;
The Data
member may have one of the following values:
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.
The message handler is:
ON_WM_POWERBROADCAST()
I have used a list control to record the messages sent. We need something to record these messages when the monitor is off (because, of course, we can't see them when the monitor is off :-) ).
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)
{
return 0;
}
UINT uData = pps->Data[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);
}
When I incorporated this into my wallpaper setting program, I set a program variable to TRUE
(make the wallpaper changes) when the monitor is ON and to FALSE
when the monitor status is either OFF
or DIMMED
.
Points of Interest
It is worth noting that a POWERBROADCAST
message is not posted when a screen saver program is activated. I have also tried monitoring the GUID_SESSION_DISPLAY_STATUS
, but I see no difference between it and GUID_CONSOLE_DISPLAY_STATE
. If anyone does know how these two GUIDs differ, I would be very interested in the feedback. Of course, I also appreciate all feedback.
History
This is the first presentation of this article (i.e., no history yet).