You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
476 lines
14 KiB
476 lines
14 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devpopg.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements CDevicePowerMgmtPage -- device power management
|
|
property page
|
|
|
|
Author:
|
|
|
|
William Hsieh (williamh) created
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
// devdrvpg.cpp : implementation file
|
|
//
|
|
|
|
#include "devmgr.h"
|
|
#include "devpopg.h"
|
|
|
|
extern "C" {
|
|
#include <initguid.h>
|
|
#include <wdmguid.h>
|
|
#include <devguid.h>
|
|
}
|
|
|
|
|
|
//
|
|
// help topic ids
|
|
//
|
|
const DWORD g_a15HelpIDs[]=
|
|
{
|
|
IDC_DEVPOWER_DESC, IDH_DISABLEHELP,
|
|
IDC_DEVPOWER_ICON, IDH_DISABLEHELP,
|
|
IDC_DEVPOWER_WAKEENABLE, IDH_DEVMGR_PWRMGR_WAKEENABLE,
|
|
IDC_DEVPOWER_MGMT_WAKEENABLE, IDH_DEVMGR_PWRMGR_MGMT_WAKEENABLE,
|
|
IDC_DEVPOWER_DEVICEENABLE, IDH_DEVMGR_PWRMGR_DEVICEENABLE,
|
|
IDC_DEVPOWER_MESSAGE, IDH_DISABLEHELP,
|
|
0,0
|
|
|
|
};
|
|
|
|
BOOL
|
|
CDevicePowerMgmtPage::OnInitDialog(
|
|
LPPROPSHEETPAGE ppsp
|
|
)
|
|
{
|
|
//
|
|
// Notify CPropSheetData about the page creation
|
|
// the controls will be initialize in UpdateControls virtual function.
|
|
//
|
|
m_pDevice->m_psd.PageCreateNotify(m_hDlg);
|
|
|
|
BOOLEAN Enabled;
|
|
|
|
//
|
|
// First see if the device is able to wake the system
|
|
//
|
|
if (m_poWakeEnable.Open(m_pDevice->GetDeviceID())) {
|
|
|
|
m_poWakeEnable.Get(Enabled);
|
|
::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE), BM_SETCHECK,
|
|
Enabled ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), Enabled);
|
|
} else {
|
|
|
|
EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), FALSE);
|
|
ShowWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
|
|
}
|
|
|
|
//
|
|
// See if the device can be turned off to save power
|
|
//
|
|
if (m_poShutdownEnable.Open(m_pDevice->GetDeviceID())) {
|
|
|
|
m_poShutdownEnable.Get(Enabled);
|
|
::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE), BM_SETCHECK,
|
|
Enabled ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
} else {
|
|
|
|
EnableWindow(GetControl(IDC_DEVPOWER_DEVICEENABLE), FALSE);
|
|
}
|
|
|
|
//
|
|
// Special network card code.
|
|
//
|
|
GUID ClassGuid;
|
|
m_pDevice->ClassGuid(ClassGuid);
|
|
if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_NET)) {
|
|
|
|
if (m_poWakeMgmtEnable.Open(m_pDevice->GetDeviceID())) {
|
|
|
|
m_poWakeMgmtEnable.Get(Enabled);
|
|
::SendMessage(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), BM_SETCHECK,
|
|
Enabled ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
}
|
|
|
|
//
|
|
// This is a special case for network class devices. Wake on Lan will
|
|
// only work if the device is enabled for power management. So, if the
|
|
// user unchecks the 'power manage this device' then we need to disable
|
|
// the WOL and management stations controls.
|
|
//
|
|
if (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE),
|
|
BM_GETCHECK, 0, 0) ) {
|
|
|
|
if (m_poWakeEnable.IsOpened()) {
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), TRUE);
|
|
}
|
|
|
|
if (m_poWakeMgmtEnable.IsOpened()) {
|
|
//
|
|
// The 'allow management stations to bring the computer out of standby'
|
|
// option is only allowed if the 'Allow this device to bring the computer
|
|
// out of standby' option is checked.
|
|
//
|
|
if (m_poWakeEnable.IsOpened() &&
|
|
(BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
|
|
BM_GETCHECK, 0, 0))) {
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), TRUE);
|
|
} else {
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), FALSE);
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
|
|
}
|
|
} else {
|
|
|
|
ShowWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
|
|
EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
|
|
}
|
|
|
|
return CPropSheetPage::OnInitDialog(ppsp);
|
|
}
|
|
|
|
BOOL
|
|
CDevicePowerMgmtPage::OnCommand(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDC_DEVPOWER_WAKEENABLE:
|
|
if (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
|
|
BM_GETCHECK, 0, 0) ) {
|
|
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), TRUE);
|
|
|
|
} else {
|
|
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
|
|
}
|
|
break;
|
|
|
|
case IDC_DEVPOWER_DEVICEENABLE:
|
|
//
|
|
// This is a special case for network class devices. Wake on Lan will
|
|
// only work if the device is enabled for power management. So, if the
|
|
// user unchecks the 'power manage this device' then we need to disable
|
|
// the WOL and management stations controls.
|
|
//
|
|
GUID ClassGuid;
|
|
m_pDevice->ClassGuid(ClassGuid);
|
|
if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_NET)) {
|
|
|
|
if (BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE),
|
|
BM_GETCHECK, 0, 0) ) {
|
|
|
|
if (m_poWakeEnable.IsOpened()) {
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), TRUE);
|
|
}
|
|
|
|
if (m_poWakeMgmtEnable.IsOpened()) {
|
|
//
|
|
// The 'allow management stations to bring the computer out of standby'
|
|
// option is only allowed if the 'Allow this device to bring the computer
|
|
// out of standby' option is checked.
|
|
//
|
|
if (m_poWakeEnable.IsOpened() &&
|
|
(BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
|
|
BM_GETCHECK, 0, 0))) {
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), TRUE);
|
|
} else {
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_WAKEENABLE), FALSE);
|
|
::EnableWindow(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE), FALSE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// This function saves the settings(if any)
|
|
//
|
|
BOOL
|
|
CDevicePowerMgmtPage::OnApply()
|
|
{
|
|
BOOLEAN Enabled;
|
|
|
|
if (m_poWakeEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_WAKEENABLE))) {
|
|
|
|
Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_WAKEENABLE),
|
|
BM_GETCHECK, 0, 0);
|
|
m_poWakeEnable.Set(Enabled);
|
|
}
|
|
|
|
if (m_poWakeMgmtEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE))) {
|
|
|
|
Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_MGMT_WAKEENABLE),
|
|
BM_GETCHECK, 0, 0);
|
|
m_poWakeMgmtEnable.Set(Enabled);
|
|
}
|
|
|
|
if (m_poShutdownEnable.IsOpened() && IsWindowEnabled(GetControl(IDC_DEVPOWER_DEVICEENABLE))) {
|
|
|
|
Enabled = BST_CHECKED == ::SendMessage(GetControl(IDC_DEVPOWER_DEVICEENABLE),
|
|
BM_GETCHECK, 0, 0);
|
|
m_poShutdownEnable.Set(Enabled);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// This function refreshes every control in the dialog. It may be called
|
|
// when the dialog is being initialized
|
|
//
|
|
void
|
|
CDevicePowerMgmtPage::UpdateControls(
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
if (lParam) {
|
|
|
|
m_pDevice = (CDevice*) lParam;
|
|
}
|
|
|
|
try {
|
|
|
|
//
|
|
// Calling PropertyChanged() will update the display name for the device. We need
|
|
// to do this in case a 3rd party property sheet did something that could change
|
|
// the device's display name.
|
|
//
|
|
m_pDevice->PropertyChanged();
|
|
|
|
HICON hIconOld;
|
|
m_IDCicon = IDC_DEVPOWER_ICON; // Save for cleanup in OnDestroy.
|
|
hIconOld = (HICON)SendDlgItemMessage(m_hDlg, IDC_DEVPOWER_ICON, STM_SETICON,
|
|
(WPARAM)(m_pDevice->LoadClassIcon()),
|
|
0
|
|
);
|
|
if (hIconOld) {
|
|
DestroyIcon(hIconOld);
|
|
}
|
|
|
|
SetDlgItemText(m_hDlg, IDC_DEVPOWER_DESC, m_pDevice->GetDisplayName());
|
|
|
|
//
|
|
// Get any power message that the class installer might want to display
|
|
//
|
|
SP_POWERMESSAGEWAKE_PARAMS pmp;
|
|
DWORD RequiredSize;
|
|
|
|
pmp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
pmp.ClassInstallHeader.InstallFunction = DIF_POWERMESSAGEWAKE;
|
|
pmp.PowerMessageWake[0] = TEXT('\0');
|
|
|
|
m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
|
|
&pmp.ClassInstallHeader,
|
|
sizeof(pmp)
|
|
);
|
|
|
|
//
|
|
// If the class installer returns NO_ERROR and there is text to display in the
|
|
// PowerMessageWake field of the SP_POWERMESSAGEWAKE_PARAMS structure then display
|
|
// the text.
|
|
//
|
|
if ((m_pDevice->m_pMachine->DiCallClassInstaller(DIF_POWERMESSAGEWAKE, *m_pDevice)) &&
|
|
(m_pDevice->m_pMachine->DiGetClassInstallParams(*m_pDevice,
|
|
&pmp.ClassInstallHeader,
|
|
sizeof(pmp),
|
|
&RequiredSize)) &&
|
|
(pmp.PowerMessageWake[0] != TEXT('\0'))) {
|
|
|
|
SetDlgItemText(m_hDlg, IDC_DEVPOWER_MESSAGE, pmp.PowerMessageWake);
|
|
}
|
|
} catch (CMemoryException* e) {
|
|
e->Delete();
|
|
// report memory error
|
|
MsgBoxParam(m_hDlg, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CDevicePowerMgmtPage::OnHelp(
|
|
LPHELPINFO pHelpInfo
|
|
)
|
|
{
|
|
WinHelp((HWND)pHelpInfo->hItemHandle, DEVMGR_HELP_FILE_NAME, HELP_WM_HELP,
|
|
(ULONG_PTR)g_a15HelpIDs);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDevicePowerMgmtPage::OnContextMenu(
|
|
HWND hWnd,
|
|
WORD xPos,
|
|
WORD yPos
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(xPos);
|
|
UNREFERENCED_PARAMETER(yPos);
|
|
|
|
WinHelp(hWnd, DEVMGR_HELP_FILE_NAME, HELP_CONTEXTMENU,
|
|
(ULONG_PTR)g_a15HelpIDs);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// This function enables/disables the device power capability
|
|
// INPUT:
|
|
// fEnable -- TRUE to enable
|
|
// -- FALSE to disable
|
|
// OUTPUT:
|
|
// TRUE if the state is set
|
|
// FALSE if the state is not set.
|
|
BOOL
|
|
CPowerEnable::Set(
|
|
BOOLEAN fEnable
|
|
)
|
|
{
|
|
if (IsOpened()) {
|
|
|
|
DWORD Error;
|
|
BOOLEAN fNewValue = fEnable;
|
|
|
|
Error = WmiSetSingleInstance(m_hWmiBlock, m_DevInstId, m_Version,
|
|
sizeof(fNewValue), &fNewValue);
|
|
|
|
//
|
|
// Get the value back to see if the change is really succeeded.
|
|
//
|
|
if (ERROR_SUCCESS == Error && Get(fNewValue) && fNewValue == fEnable) {
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
CPowerEnable::Get(
|
|
BOOLEAN& fEnable
|
|
)
|
|
{
|
|
fEnable = FALSE;
|
|
|
|
if (IsOpened()) {
|
|
|
|
ULONG Size = m_WmiInstDataSize;
|
|
DWORD Error;
|
|
|
|
Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &Size, m_pWmiInstData);
|
|
|
|
if (ERROR_SUCCESS == Error && Size == m_WmiInstDataSize &&
|
|
m_DataBlockSize == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->SizeDataBlock &&
|
|
m_Version == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->WnodeHeader.Version) {
|
|
fEnable = *((BOOLEAN*)(m_pWmiInstData + ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->DataBlockOffset));
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Function to open the wmi block.
|
|
// INPUT:
|
|
// DeviceId -- the device id
|
|
// OUTPUT:
|
|
// TRUE if the device can be turned off
|
|
// FALSE if the device can not be turned off.
|
|
BOOL
|
|
CPowerEnable::Open(
|
|
LPCTSTR DeviceId
|
|
)
|
|
{
|
|
if (!DeviceId) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Do nothing if already opened
|
|
//
|
|
if (IsOpened()) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (lstrlen(DeviceId) >= ARRAYLEN(m_DevInstId) - 2) {
|
|
return FALSE;
|
|
}
|
|
|
|
WmiDevInstToInstanceName(m_DevInstId, ARRAYLEN(m_DevInstId), (PTCHAR)DeviceId, 0);
|
|
|
|
ULONG Error;
|
|
Error = WmiOpenBlock(&m_wmiGuid, 0, &m_hWmiBlock);
|
|
if (ERROR_SUCCESS == Error) {
|
|
//
|
|
// Get the required block size.
|
|
//
|
|
ULONG BufferSize = 0;
|
|
Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &BufferSize, NULL);
|
|
if (BufferSize && Error == ERROR_INSUFFICIENT_BUFFER) {
|
|
//
|
|
// The device does support the GUID, remember the size
|
|
// and allocate a buffer to the data block.
|
|
//
|
|
m_WmiInstDataSize = BufferSize;
|
|
m_pWmiInstData = new BYTE[BufferSize];
|
|
|
|
if (m_pWmiInstData) {
|
|
|
|
Error = WmiQuerySingleInstance(m_hWmiBlock, m_DevInstId, &BufferSize, m_pWmiInstData);
|
|
|
|
} else {
|
|
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == Error &&
|
|
m_DataBlockSize == ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->SizeDataBlock) {
|
|
//
|
|
// Remember the version
|
|
//
|
|
m_Version = ((PWNODE_SINGLE_INSTANCE)m_pWmiInstData)->WnodeHeader.Version;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
Close();
|
|
}
|
|
|
|
SetLastError(Error);
|
|
|
|
return FALSE;
|
|
}
|