/******************************************************************************* * * (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 #include #include #include #include #include #include #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; }