514 lines
15 KiB
C
514 lines
15 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORP., 1996
|
|
*
|
|
* TITLE: HIBERNAT.C
|
|
*
|
|
* VERSION: 2.0
|
|
*
|
|
* AUTHOR: ReedB
|
|
*
|
|
* DATE: 17 Oct, 1996
|
|
*
|
|
* DESCRIPTION:
|
|
* Support for hibernate page of PowerCfg.Cpl.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
#include <help.h>
|
|
#include <powercfp.h>
|
|
|
|
#include "powercfg.h"
|
|
#include "pwrresid.h"
|
|
#include "PwrMn_cs.h"
|
|
|
|
// Private functions implemented in HIBERNAT.C
|
|
|
|
VOID SetNumberMB(LPTSTR, DWORD);
|
|
VOID InsertSeparators(LPTSTR);
|
|
UINT UpdateFreeSpace(HWND, UINT);
|
|
UINT UpdatePhysMem(void);
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* G L O B A L D A T A
|
|
*
|
|
*******************************************************************************/
|
|
|
|
// This structure is filled in by the Power Policy Manager at CPL_INIT time.
|
|
extern SYSTEM_POWER_CAPABILITIES g_SysPwrCapabilities;
|
|
extern BOOL g_bRunningUnderNT;
|
|
|
|
// A systary change requires PowerSchemeDlgProc re-init.
|
|
extern BOOL g_bSystrayChange;
|
|
|
|
// Persistant storage of this data is managed by POWRPROF.DLL API's.
|
|
extern GLOBAL_POWER_POLICY g_gpp;
|
|
|
|
// Power button power action string ID's. With and without hibernate.
|
|
UINT g_uiPwrActIDs[] =
|
|
{
|
|
IDS_NONE, PowerActionNone,
|
|
IDS_PROMPT, PowerActionNone,
|
|
IDS_STANDBY, PowerActionSleep,
|
|
IDS_HIBERNATE, PowerActionHibernate,
|
|
IDS_POWEROFF, PowerActionShutdownOff,
|
|
0, 0
|
|
};
|
|
|
|
// Lid action string ID's. With and without hibernate.
|
|
UINT g_uiLidActIDs[] =
|
|
{
|
|
IDS_NONE, PowerActionNone,
|
|
IDS_STANDBY, PowerActionSleep,
|
|
IDS_HIBERNATE, PowerActionHibernate,
|
|
IDS_POWEROFF, PowerActionShutdownOff,
|
|
0, 0
|
|
};
|
|
|
|
// UI state variables
|
|
TCHAR g_szRequiredSpace[128];
|
|
DWORD g_dwShowHibernate;
|
|
DWORD g_dwShowNoDiskSpace;
|
|
DWORD g_dwShowDiskSpace;
|
|
DWORD g_dwTrueFlag = (DWORD) TRUE;
|
|
BOOLEAN g_bHibernate;
|
|
|
|
// Globals for DoHibernateApply:
|
|
BOOL g_bHibernateDirty;
|
|
HWND g_hwndHibernateDlg;
|
|
UINT g_uiRequiredMB;
|
|
|
|
// Hibernate policies dialog controls descriptions:
|
|
|
|
#define NUM_HIBERNATE_POL_CONTROLS 7
|
|
|
|
// Handy indicies into our g_pcHibernatePol array:
|
|
#define ID_REQUIREDSPACE 0
|
|
#define ID_NOTENOUGHSPACE 1
|
|
#define ID_HIBERNATE 2
|
|
|
|
POWER_CONTROLS g_pcHibernatePol[NUM_HIBERNATE_POL_CONTROLS] =
|
|
{// Control ID Control Type Data Address Data Size Parameter Pointer Enable/Visible State Pointer
|
|
IDC_REQUIREDSPACE, EDIT_TEXT_RO, &g_szRequiredSpace, 0, NULL, &g_dwShowDiskSpace,
|
|
IDC_NOTENOUGHSPACE, STATIC_TEXT, NULL, 0, NULL, &g_dwShowNoDiskSpace,
|
|
IDC_HIBERNATE, CHECK_BOX, &g_bHibernate, sizeof(g_bHibernate), &g_dwTrueFlag, &g_dwShowHibernate,
|
|
IDC_DISKSPACEGROUPBOX, STATIC_TEXT, NULL, 0, NULL, &g_dwShowDiskSpace,
|
|
IDC_FREESPACETEXT, STATIC_TEXT, NULL, 0, NULL, &g_dwShowDiskSpace,
|
|
IDC_REQUIREDSPACETEXT, STATIC_TEXT, NULL, 0, NULL, &g_dwShowDiskSpace,
|
|
IDC_FREESPACE, STATIC_TEXT, NULL, 0, NULL, &g_dwShowDiskSpace,
|
|
};
|
|
|
|
// "Hibernate" Dialog Box (IDD_HIBERNATE == 105) help array:
|
|
|
|
const DWORD g_HibernateHelpIDs[]=
|
|
{
|
|
IDC_HIBERNATE, IDH_105_1400, // Hibernate: "After going on standby, &hibernate." (Button)
|
|
IDC_FREESPACE, IDH_105_1401, // Hibernate: "Free space" (Static)
|
|
IDC_REQUIREDSPACE, IDH_105_1402, // Hibernate: "Required space to hibernate" (Static)
|
|
IDC_NOTENOUGHSPACE, IDH_105_1403, // Hibernate: "You must free up some disk space before your computer can hibernate." (Static)
|
|
IDC_DISKSPACEGROUPBOX, IDH_105_1402,
|
|
IDC_FREESPACETEXT, IDH_105_1401,
|
|
IDC_REQUIREDSPACETEXT, IDH_105_1402,
|
|
IDC_HIBERNATEGROUPBOX, IDH_105_1400,
|
|
IDI_HIBERNATE, NO_HELP,
|
|
IDC_NO_HELP_6, NO_HELP,
|
|
IDI_PWRMNG, NO_HELP,
|
|
0, 0
|
|
};
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* P U B L I C E N T R Y P O I N T S
|
|
*
|
|
*******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* MapPwrAct
|
|
*
|
|
* DESCRIPTION:
|
|
* Map power action to one of a lesser number of UI supported actions.
|
|
* Depends on state of hibernate so implemented here.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL MapPwrAct(
|
|
PPOWER_ACTION ppa,
|
|
BOOL bNone
|
|
)
|
|
{
|
|
switch (*ppa) {
|
|
case PowerActionNone:
|
|
if (bNone) {
|
|
*ppa = PowerActionNone;
|
|
break;
|
|
}
|
|
case PowerActionReserved:
|
|
case PowerActionSleep:
|
|
*ppa = PowerActionSleep;
|
|
break;
|
|
|
|
case PowerActionHibernate:
|
|
if (g_SysPwrCapabilities.HiberFilePresent) {
|
|
*ppa = PowerActionHibernate;
|
|
}
|
|
else {
|
|
*ppa = PowerActionSleep;
|
|
}
|
|
break;
|
|
|
|
case PowerActionShutdown:
|
|
case PowerActionShutdownReset:
|
|
case PowerActionShutdownOff:
|
|
*ppa = PowerActionShutdownOff;
|
|
break;
|
|
|
|
default:
|
|
DebugPrint( "MapPwrAct, unknown power action: %X", *ppa);
|
|
*ppa = PowerActionShutdownOff;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* DoHibernateApply
|
|
*
|
|
* DESCRIPTION:
|
|
* Handle the WM_NOTIFY, PSN_APPLY message for HibernateDlgProc. Updates
|
|
* global hibernate state.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
void DoHibernateApply(void)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
// Only handle if hibernate page is dirty.
|
|
if (g_bHibernateDirty) {
|
|
// Fetch data from dialog controls.
|
|
GetControls(g_hwndHibernateDlg,
|
|
NUM_HIBERNATE_POL_CONTROLS,
|
|
g_pcHibernatePol);
|
|
|
|
status = CallNtPowerInformation(SystemReserveHiberFile,
|
|
&g_bHibernate,
|
|
sizeof(g_bHibernate),
|
|
NULL,
|
|
0);
|
|
if (status != STATUS_SUCCESS) {
|
|
ErrorMsgBox(g_hwndHibernateDlg,
|
|
#ifdef WINNT
|
|
RtlNtStatusToDosError(status),
|
|
#else
|
|
NO_ERROR,
|
|
#endif
|
|
IDS_UNABLETOSETHIBER);
|
|
}
|
|
|
|
// Get the current hibernate state from the PPM.
|
|
if (GetPwrCapabilities(&g_SysPwrCapabilities)) {
|
|
g_bHibernate = g_SysPwrCapabilities.HiberFilePresent;
|
|
|
|
// Map power actions to allowed UI values.
|
|
MapPwrAct(&g_gpp.user.LidCloseDc.Action, TRUE);
|
|
MapPwrAct(&g_gpp.user.PowerButtonDc.Action, FALSE);
|
|
MapPwrAct(&g_gpp.user.SleepButtonDc.Action, FALSE);
|
|
}
|
|
SetControls(g_hwndHibernateDlg, 1, &g_pcHibernatePol[ID_HIBERNATE]);
|
|
UpdateFreeSpace(g_hwndHibernateDlg, g_uiRequiredMB);
|
|
g_bHibernateDirty = FALSE;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* HibernateDlgProc
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
INT_PTR CALLBACK HibernateDlgProc(
|
|
HWND hWnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
NMHDR FAR *lpnm;
|
|
LPTSTR pszUPS;
|
|
|
|
switch (uMsg) {
|
|
case WM_INITDIALOG:
|
|
|
|
// Save the hibernate dialog hwnd for use by DoHibernateApply.
|
|
g_hwndHibernateDlg = hWnd;
|
|
|
|
// Get the current hibernate state from the PPM.
|
|
if (GetPwrCapabilities(&g_SysPwrCapabilities)) {
|
|
g_bHibernate = g_SysPwrCapabilities.HiberFilePresent;
|
|
}
|
|
|
|
// Get the disk free and required space only under NT.
|
|
if (g_bRunningUnderNT) {
|
|
g_dwShowDiskSpace = CONTROL_ENABLE;
|
|
|
|
// Get the required space from the power capabilities.
|
|
g_uiRequiredMB = UpdatePhysMem();
|
|
|
|
// Update the disk free space and enable/disable
|
|
// disk space warning and hibernate time out.
|
|
UpdateFreeSpace(hWnd, g_uiRequiredMB);
|
|
|
|
} else {
|
|
g_dwShowHibernate = CONTROL_ENABLE;
|
|
g_dwShowDiskSpace = CONTROL_HIDE;
|
|
g_dwShowNoDiskSpace = CONTROL_HIDE;
|
|
}
|
|
|
|
SetControls(hWnd, NUM_HIBERNATE_POL_CONTROLS, g_pcHibernatePol);
|
|
|
|
//
|
|
// Disable the checkbox is the user doesn't have permission to
|
|
// change it. We do this by trying to set the same value we
|
|
// retrieved earlier.
|
|
//
|
|
{
|
|
NTSTATUS status;
|
|
status = CallNtPowerInformation(SystemReserveHiberFile,
|
|
&g_bHibernate,
|
|
sizeof(g_bHibernate),
|
|
NULL,
|
|
0);
|
|
if ( ERROR_SUCCESS != status )
|
|
{
|
|
EnableWindow( GetDlgItem( hWnd, IDC_HIBERNATE ), FALSE );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
case WM_ACTIVATE:
|
|
// If user switches away, check the disk space when they come back.
|
|
if (g_bRunningUnderNT) {
|
|
GetControls(hWnd, NUM_HIBERNATE_POL_CONTROLS, g_pcHibernatePol);
|
|
UpdateFreeSpace(hWnd, g_uiRequiredMB);
|
|
SetControls(hWnd, NUM_HIBERNATE_POL_CONTROLS-1, g_pcHibernatePol);
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
lpnm = (NMHDR FAR *)lParam;
|
|
switch (lpnm->code) {
|
|
case PSN_APPLY:
|
|
DoHibernateApply();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
case IDC_HIBERNATE:
|
|
MarkSheetDirty(hWnd, &g_bHibernateDirty);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case PCWM_NOTIFYPOWER:
|
|
// Notification from systray, user has changed a PM UI setting.
|
|
g_bSystrayChange = TRUE;
|
|
break;
|
|
|
|
case WM_HELP: // F1
|
|
WinHelp(((LPHELPINFO)lParam)->hItemHandle, PWRMANHLP, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)g_HibernateHelpIDs);
|
|
return TRUE;
|
|
|
|
case WM_CONTEXTMENU: // right mouse click
|
|
WinHelp((HWND)wParam, PWRMANHLP, HELP_CONTEXTMENU, (ULONG_PTR)(LPTSTR)g_HibernateHelpIDs);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* P R I V A T E F U N C T I O N S
|
|
*
|
|
*******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SetNumberMB
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID SetNumberMB(LPTSTR psz, DWORD dwValue)
|
|
{
|
|
LPTSTR pszNumber;
|
|
TCHAR szBuf[128];
|
|
TCHAR szBufLow[64];
|
|
|
|
wsprintf(szBuf, TEXT("%u"), dwValue);
|
|
InsertSeparators(szBuf);
|
|
pszNumber = LoadDynamicString(IDS_MBYTES, szBuf);
|
|
if (pszNumber) {
|
|
lstrcpy(psz, pszNumber);
|
|
LocalFree(pszNumber);
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* InsertSeparators
|
|
*
|
|
* DESCRIPTION:
|
|
* Passed string must be large enough to hold seperators.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID InsertSeparators(LPTSTR pszNumber)
|
|
{
|
|
TCHAR szSeparator[10];
|
|
TCHAR Separator;
|
|
TCHAR szBuf[128];
|
|
ULONG cchNumber;
|
|
UINT Triples;
|
|
LPTSTR pch;
|
|
|
|
if (GetLocaleInfo(GetUserDefaultLCID(),
|
|
LOCALE_STHOUSAND,
|
|
szSeparator,
|
|
sizeof(szSeparator)/sizeof(TCHAR))) {
|
|
Separator = szSeparator[0];
|
|
cchNumber = lstrlen(pszNumber);
|
|
Triples = 0;
|
|
szBuf[127] = '\0';
|
|
pch = &szBuf[126];
|
|
while (cchNumber > 0) {
|
|
*pch-- = pszNumber[--cchNumber];
|
|
++Triples;
|
|
if ((0 == (Triples % 3)) && (cchNumber > 0)) {
|
|
*pch-- = Separator;
|
|
}
|
|
}
|
|
lstrcpy(pszNumber, pch + 1);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* UpdateFreeSpace
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
UINT UpdateFreeSpace(HWND hWnd, UINT uiRequiredMB)
|
|
{
|
|
DWORD dwSectorsPerCluster, dwBytesPerSector;
|
|
DWORD dwFreeClusters, dwTotalClusters;
|
|
ULONGLONG ullFreeBytes = 0;
|
|
UINT uiFreeMB = 0;
|
|
TCHAR szTmp[MAX_PATH];
|
|
|
|
// Get the free space on the system drive.
|
|
if (GetSystemDirectory(szTmp, sizeof(szTmp)/sizeof(TCHAR))) {
|
|
szTmp[3] = '\0';
|
|
if (GetDiskFreeSpace(szTmp,
|
|
&dwSectorsPerCluster,
|
|
&dwBytesPerSector,
|
|
&dwFreeClusters,
|
|
&dwTotalClusters)) {
|
|
ullFreeBytes = dwBytesPerSector * dwSectorsPerCluster;
|
|
ullFreeBytes *= dwFreeClusters;
|
|
uiFreeMB = (UINT) (ullFreeBytes /= 0x100000);
|
|
SetNumberMB(szTmp, uiFreeMB);
|
|
SetDlgItemText(hWnd, IDC_FREESPACE, szTmp);
|
|
|
|
// Logic to enable/disable disk space warning and hibernate time out.
|
|
if ((uiFreeMB >= uiRequiredMB) || g_bHibernate) {
|
|
g_dwShowHibernate = CONTROL_ENABLE;
|
|
g_dwShowNoDiskSpace = CONTROL_HIDE;
|
|
} else {
|
|
if (g_bHibernate) {
|
|
g_dwShowHibernate = CONTROL_ENABLE;
|
|
}
|
|
else {
|
|
g_dwShowHibernate = CONTROL_DISABLE;
|
|
}
|
|
g_dwShowNoDiskSpace = CONTROL_ENABLE;
|
|
}
|
|
|
|
}
|
|
}
|
|
return uiFreeMB;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* UpdatePhysMem
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
UINT UpdatePhysMem(void)
|
|
{
|
|
UINT uiPhysMemMB;
|
|
|
|
#ifdef WINNT
|
|
MEMORYSTATUSEX msex;
|
|
|
|
msex.dwLength = sizeof(msex);
|
|
|
|
GlobalMemoryStatusEx(&msex);
|
|
uiPhysMemMB = (UINT) (msex.ullTotalPhys / 0x100000);
|
|
|
|
if (msex.ullTotalPhys % 0x100000) {
|
|
uiPhysMemMB++;
|
|
}
|
|
#else
|
|
MEMORYSTATUS ms;
|
|
|
|
ms.dwLength = sizeof(ms);
|
|
|
|
GlobalMemoryStatus(&ms);
|
|
uiPhysMemMB = (UINT) (ms.dwTotalPhys / 0x100000);
|
|
|
|
if (ms.dwTotalPhys % 0x100000) {
|
|
uiPhysMemMB++;
|
|
}
|
|
#endif
|
|
|
|
SetNumberMB(g_szRequiredSpace, uiPhysMemMB);
|
|
return uiPhysMemMB;
|
|
}
|
|
|