/******************************************************************************* * * (C) COPYRIGHT MICROSOFT CORP., 1998 * * TITLE: NTAPM.C * * VERSION: 2.0 * * AUTHOR: Patrickf * * DATE: 09 November, 1998 * * DESCRIPTION: * Implements the "APM" tab of the Power Management CPL Applet. * *******************************************************************************/ #ifdef WINNT #include #include #include #include #include #include #include #include #include #include #include #include "powercfg.h" #include "pwrresid.h" #include "PwrMn_cs.h" #include "ntapm.h" BOOL g_fDirty = FALSE; // Has state changed since last apply? CHAR RegPropBuff[MAX_PATH]; TCHAR CharBuffer[MAX_PATH]; TCHAR m_szApmActive[] = TEXT ("Start"); TCHAR m_szApmActiveKey[] = TEXT("System\\CurrentControlSet\\Services\\NtApm"); TCHAR m_szACPIActive[] = TEXT ("Start"); TCHAR m_szACPIActiveKey[] = TEXT("System\\CurrentControlSet\\Services\\ACPI"); extern HINSTANCE g_hInstance; // Global instance handle of this DLL. const DWORD g_NtApmHelpIDs[]= { IDC_APMENABLE, IDH_ENABLE_APM_SUPPORT, // Save Scheme: "Save Name Power scheme" 0, 0 }; /******************************************************************************* * * G L O B A L D A T A * *******************************************************************************/ /******************************************************************************* * * NtApmEnableAllPrivileges * * DESCRIPTION: This function is used to allow this thread to shudown the * system. * * PARAMETERS: * * *******************************************************************************/ BOOL NtApmEnableAllPrivileges() { BOOL Result = FALSE; ULONG ReturnLen; ULONG Index; HANDLE Token = NULL; PTOKEN_PRIVILEGES NewState = NULL; // // Open Process Token // Result = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token); if (Result) { ReturnLen = 4096; NewState = LocalAlloc(LMEM_FIXED, ReturnLen); if (NewState != NULL) { Result = GetTokenInformation(Token, TokenPrivileges, NewState, ReturnLen, &ReturnLen); if (Result) { if (NewState->PrivilegeCount > 0) { for (Index=0; Index < NewState->PrivilegeCount; Index++) { NewState->Privileges[Index].Attributes = SE_PRIVILEGE_ENABLED; } } Result = AdjustTokenPrivileges(Token, FALSE, NewState, ReturnLen, NULL, &ReturnLen); } } } if (NewState != NULL) { LocalFree(NewState); } if (Token != NULL) { CloseHandle(Token); } return(Result); } /******************************************************************************* * * NtApmACPIEnabled * * DESCRIPTION: This function gets called to determine if APM is present on * and started on the machine. If APM is present then the * tab needs to appear. * * This functions check for ACPI, MP and then if APM is actually * on the machine. If ACPI and MP then APM may be running but is * disabled. * * RETURNS: TRUE if APM is present, FALSE if APM is no present * *******************************************************************************/ BOOL NtApmACPIEnabled() { BOOL RetVal; DWORD CharBufferSize; DWORD ACPIStarted; HKEY hPortKey; // // Initialize - Assume the machine is not ACPI // RetVal = FALSE; // // Check if ACPI is Present on the machine. // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, m_szACPIActiveKey, 0, KEY_ALL_ACCESS, &hPortKey) != ERROR_SUCCESS) { } else if (RegQueryValueEx(hPortKey, m_szACPIActive, NULL, NULL, (PBYTE) CharBuffer, &CharBufferSize) != ERROR_SUCCESS) { RegCloseKey(hPortKey); } else { ACPIStarted = (DWORD) CharBuffer[0]; if (ACPIStarted == SERVICE_BOOT_START) { RetVal = TRUE; } RegCloseKey(hPortKey); } return(RetVal); } /******************************************************************************* * * NtApmTurnOnDiFlags * * DESCRIPTION: This function sets the DI flags * * PARAMETERS: * * *******************************************************************************/ BOOL NtApmTurnOnDiFlags ( HDEVINFO ApmDevInfo, PSP_DEVINFO_DATA ApmDevInfoData, DWORD FlagsMask) { BOOL RetVal; SP_DEVINSTALL_PARAMS DevParams; // // Turn on Device Interface flags // DevParams.cbSize = sizeof(DevParams); RetVal = SetupDiGetDeviceInstallParams(ApmDevInfo, ApmDevInfoData, &DevParams); if (RetVal) { DevParams.Flags |= FlagsMask; RetVal = SetupDiSetDeviceInstallParams(ApmDevInfoData, NULL, &DevParams); } return(RetVal); } /******************************************************************************* * * NtApmTurnOffDiFlags * * DESCRIPTION: This function sets the DI flags * * PARAMETERS: * * *******************************************************************************/ BOOL NtApmTurnOffDiFlags ( HDEVINFO ApmDevInfo, PSP_DEVINFO_DATA ApmDevInfoData, DWORD FlagsMask) { BOOL RetVal; SP_DEVINSTALL_PARAMS DevParams; // // Turn on Device Interface flags // DevParams.cbSize = sizeof(DevParams); RetVal = SetupDiGetDeviceInstallParams(ApmDevInfo, ApmDevInfoData, &DevParams); if (RetVal) { DevParams.Flags &= ~FlagsMask; RetVal = SetupDiSetDeviceInstallParams(ApmDevInfoData, NULL, &DevParams); } return(RetVal); } /******************************************************************************* * * NtApmGetHwProfile * * DESCRIPTION: This function is called to retrieve the current H/W Profile * * PARAMETERS: Pointer to store HW Profile Info * * *******************************************************************************/ BOOL NtApmGetHwProfile( DWORD ProfIdx, HWPROFILEINFO *NtApmHwProf) { CONFIGRET CmRetVal; CmRetVal = CM_Get_Hardware_Profile_Info_Ex(ProfIdx, NtApmHwProf, 0, NULL); if (CmRetVal == CR_SUCCESS) { return(TRUE); } else { return(FALSE); } } /******************************************************************************* * * NtApmCleanup * * DESCRIPTION: This function is called to Destroy the DevInfo and DevInfoData * list that were created. * * PARAMETERS: * * *******************************************************************************/ BOOL NtApmCleanup( HDEVINFO NtApmDevInfo, PSP_DEVINFO_DATA NtApmDevInfoData) { SetupDiDeleteDeviceInfo(NtApmDevInfo, NtApmDevInfoData); SetupDiDestroyDeviceInfoList(NtApmDevInfo); return(TRUE); } /******************************************************************************* * * NtApmGetDevInfo * * DESCRIPTION: This function is called to retrieve the HDEVINFO for NTAPM * * PARAMETERS: * * *******************************************************************************/ BOOL NtApmGetDevInfo( HDEVINFO *NtApmDevInfo, PSP_DEVINFO_DATA NtApmDevInfoData) { BOOL RetVal = FALSE; // Assume Failure *NtApmDevInfo = SetupDiGetClassDevsEx((LPGUID)&GUID_DEVCLASS_APMSUPPORT, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); if(*NtApmDevInfo != INVALID_HANDLE_VALUE) { // // Retrieve the DEVINFO_DATA for APM // NtApmDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA); if (!SetupDiEnumDeviceInfo(*NtApmDevInfo, 0, NtApmDevInfoData)) { SetupDiDestroyDeviceInfoList(*NtApmDevInfo); } else { RetVal = TRUE; } } return(RetVal); } /******************************************************************************* * * NtApmDisable * * DESCRIPTION: This function is called to Disable NT APM * * PARAMETERS: * * *******************************************************************************/ BOOL NtApmDisable() { DWORD ii; BOOL Canceled; SP_PROPCHANGE_PARAMS pcp; HDEVINFO NtApmDevInfo; SP_DEVINFO_DATA NtApmDevInfoData; HWPROFILEINFO NtApmHwProfile; // // Get handles to the device and the device information // If unable to get Device Info immediately return. // if (!NtApmGetDevInfo(&NtApmDevInfo, &NtApmDevInfoData)) { return(FALSE); } // // Turn on the Device Interface Flags // NtApmTurnOnDiFlags(NtApmDevInfo, &NtApmDevInfoData, DI_NODI_DEFAULTACTION); // // Ask the class installer if the device can be generally enabled/disabled // pcp.StateChange = DICS_DISABLE; pcp.Scope = DICS_FLAG_CONFIGGENERAL; pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; if (!SetupDiSetClassInstallParams(NtApmDevInfo, &NtApmDevInfoData, (PSP_CLASSINSTALL_HEADER)&pcp, sizeof(pcp))) { goto NtApmDisableError; } if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, NtApmDevInfo, &NtApmDevInfoData)) { goto NtApmDisableError; } Canceled = (ERROR_CANCELLED == GetLastError()); if (!Canceled) { pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.StateChange = DICS_DISABLE; for (ii=0; NtApmGetHwProfile(ii, &NtApmHwProfile); ii++) { pcp.HwProfile = NtApmHwProfile.HWPI_ulHWProfile; if (!SetupDiSetClassInstallParams(NtApmDevInfo, &NtApmDevInfoData, (PSP_CLASSINSTALL_HEADER)&pcp, sizeof(pcp))) { goto NtApmDisableError; } if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, NtApmDevInfo, &NtApmDevInfoData)) { goto NtApmDisableError; } Canceled = (ERROR_CANCELLED == GetLastError()); if (!Canceled) { if (!SetupDiSetClassInstallParams(NtApmDevInfo, &NtApmDevInfoData, (PSP_CLASSINSTALL_HEADER)&pcp, sizeof(pcp))) { goto NtApmDisableError; } if (!SetupDiChangeState(NtApmDevInfo, &NtApmDevInfoData)) { goto NtApmDisableError; } } } } // // Turn off Flags // NtApmTurnOnDiFlags(NtApmDevInfo, &NtApmDevInfoData, DI_PROPERTIES_CHANGE); if (!SetupDiSetClassInstallParams(NtApmDevInfo, NULL, NULL, 0)) { goto NtApmDisableError; } NtApmTurnOffDiFlags(NtApmDevInfo, &NtApmDevInfoData, DI_NODI_DEFAULTACTION); NtApmCleanup(NtApmDevInfo, &NtApmDevInfoData); return(TRUE); NtApmDisableError: NtApmCleanup(NtApmDevInfo, &NtApmDevInfoData); return (FALSE); } /******************************************************************************* * * NtApmEnable * * DESCRIPTION: This function is called to Enable NT APM * * PARAMETERS: * * *******************************************************************************/ BOOL NtApmEnable() { DWORD ii; BOOL Canceled; SP_PROPCHANGE_PARAMS pcp; HDEVINFO NtApmDevInfo; SP_DEVINFO_DATA NtApmDevInfoData; HWPROFILEINFO NtApmHwProfile; // // Get handles to the device and the device information // (If unable to get Device Info immediately return) // if (!NtApmGetDevInfo(&NtApmDevInfo, &NtApmDevInfoData)) { return(FALSE); } // // Turn on the Device Interface Flags // NtApmTurnOnDiFlags(NtApmDevInfo, &NtApmDevInfoData, DI_NODI_DEFAULTACTION); // // Ask the class installer if the device can be generally enabled/disabled // pcp.StateChange = DICS_ENABLE; pcp.Scope = DICS_FLAG_CONFIGGENERAL; pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; if (!SetupDiSetClassInstallParams(NtApmDevInfo, &NtApmDevInfoData, (PSP_CLASSINSTALL_HEADER)&pcp, sizeof(pcp))) { goto NtApmEnableError; } if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, NtApmDevInfo, &NtApmDevInfoData)) { goto NtApmEnableError; } Canceled = (ERROR_CANCELLED == GetLastError()); if (!Canceled) { pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.StateChange = DICS_ENABLE; for (ii=0; NtApmGetHwProfile(ii, &NtApmHwProfile); ii++) { pcp.HwProfile = NtApmHwProfile.HWPI_ulHWProfile; if (!SetupDiSetClassInstallParams(NtApmDevInfo, &NtApmDevInfoData, (PSP_CLASSINSTALL_HEADER)&pcp, sizeof(pcp))) { goto NtApmEnableError; } if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, NtApmDevInfo, &NtApmDevInfoData)) { goto NtApmEnableError; } Canceled = (ERROR_CANCELLED == GetLastError()); // // If still good, keep going // if (!Canceled) { if (!SetupDiSetClassInstallParams(NtApmDevInfo, &NtApmDevInfoData, (PSP_CLASSINSTALL_HEADER)&pcp, sizeof(pcp))) { goto NtApmEnableError; } if (!SetupDiChangeState(NtApmDevInfo, &NtApmDevInfoData)) { goto NtApmEnableError; } // // This call will start the device if it is not started // pcp.Scope = DICS_FLAG_GLOBAL; if (!SetupDiSetClassInstallParams(NtApmDevInfo, &NtApmDevInfoData, (PSP_CLASSINSTALL_HEADER)&pcp, sizeof(pcp))) { goto NtApmEnableError; } if (!SetupDiChangeState(NtApmDevInfo, &NtApmDevInfoData)) { goto NtApmEnableError; } } } } NtApmTurnOnDiFlags(NtApmDevInfo, &NtApmDevInfoData, DI_PROPERTIES_CHANGE); SetupDiSetClassInstallParams(NtApmDevInfo, NULL, NULL, 0); NtApmTurnOffDiFlags(NtApmDevInfo, &NtApmDevInfoData, DI_NODI_DEFAULTACTION); NtApmCleanup(NtApmDevInfo, &NtApmDevInfoData); return(TRUE); NtApmEnableError: NtApmCleanup(NtApmDevInfo, &NtApmDevInfoData); return (FALSE); } /******************************************************************************* * * NtApmEnabled * * DESCRIPTION: This function is used to determine if APM is actually * Enabled or Disabled. * * PARAMETERS: hDlg - handle to the dialog box. * fEnable - TRUE if APM is to be enabled, FALSE if APM is to * be disabled. * * *******************************************************************************/ NtApmEnabled() { DWORD Err; DWORD HwProf; DWORD pFlags; DWORD GlobalConfigFlags; SP_PROPCHANGE_PARAMS pcp; HDEVINFO NtApmDevInfo; SP_DEVINFO_DATA NtApmDevInfoData; CONFIGRET CmRetVal; HWPROFILEINFO HwProfileInfo; TCHAR DeviceId[MAX_DEVICE_ID_LEN + 1]; // // Registry Property Variables // DWORD RegProp; DWORD RegPropType; DWORD RegPropBuffSz; // // Retrieve the Handle the Device Information for APM. // if (!NtApmGetDevInfo(&NtApmDevInfo, &NtApmDevInfoData)) { return (FALSE); } // // Get the Global Flags (Just-in-case it is globally enabled) // RegProp = SPDRP_CONFIGFLAGS; RegPropBuffSz = sizeof(RegPropBuff) + 1; if (SetupDiGetDeviceRegistryProperty(NtApmDevInfo, &NtApmDevInfoData, RegProp, &RegPropType, RegPropBuff, RegPropBuffSz, 0)) { if (RegPropType != REG_DWORD) { GlobalConfigFlags = 0; } else { GlobalConfigFlags = (DWORD) RegPropBuff[0]; } // // Only Want the disabled bit // GlobalConfigFlags = GlobalConfigFlags & CONFIGFLAG_DISABLED; } // // Get the current HW Profile // if (!NtApmGetHwProfile(0xffffffff, &HwProfileInfo)) { goto NtApmEnabledError; } // // Get the Device ID for the given profile // HwProf = HwProfileInfo.HWPI_ulHWProfile; CmRetVal = CM_Get_Device_ID_Ex(NtApmDevInfoData.DevInst, DeviceId, sizeof(DeviceId), 0, NULL); if (CmRetVal != CR_SUCCESS) { Err = GetLastError(); goto NtApmEnabledError; } // // Now get the flags // CmRetVal = CM_Get_HW_Prof_Flags_Ex((LPTSTR)DeviceId, HwProf, &pFlags, 0, NULL); if (CmRetVal != CR_SUCCESS) { Err = GetLastError(); goto NtApmEnabledError; } NtApmCleanup(NtApmDevInfo, &NtApmDevInfoData); if (GlobalConfigFlags || (pFlags & CSCONFIGFLAG_DISABLED)) { return(FALSE); } else { return(TRUE); } NtApmEnabledError: NtApmCleanup(NtApmDevInfo, &NtApmDevInfoData); return(FALSE); } /******************************************************************************* * * NtApmToggle * * DESCRIPTION: This function gets called when the user clicks OK or Apply * and does the work of enabling or disabling APM support. * * PARAMETERS: fEnable - Indicates if APM is to enabled or disabled * SilentDisable - Do not put up dialog to reboot machine. * * *******************************************************************************/ BOOL NtApmToggle( IN BOOL fEnable, IN BOOL SilentDisable) { int MBoxRetVal; TCHAR Str1[2048]; TCHAR Str2[2048]; if (fEnable == APM_ENABLE) { NtApmEnable(); } else { if (NtApmDisable()) { if (!SilentDisable) { LoadString(g_hInstance, IDS_DEVCHANGE_RESTART, (LPTSTR) Str1, ARRAYSIZE(Str1)); LoadString(g_hInstance, IDS_DEVCHANGE_CAPTION, (LPTSTR) Str2, ARRAYSIZE(Str2)); MBoxRetVal = MessageBox(NULL, Str1, Str2, MB_ICONQUESTION | MB_YESNO); if (MBoxRetVal == IDYES) { NtApmEnableAllPrivileges(); ExitWindowsEx(EWX_REBOOT | EWX_FORCEIFHUNG, 0); } } } } // Return TRUE for success, FALSE for failure return(TRUE); } /******************************************************************************* * * APMDlgHandleInit * * DESCRIPTION: Handles WM_INITDIALOG messages sent to APMDlgProc * * PARAMETERS: * *******************************************************************************/ BOOL APMDlgHandleInit( IN HWND hDlg, IN WPARAM wParam, IN LPARAM lParam) { CheckDlgButton( hDlg, IDC_APMENABLE, NtApmEnabled() ? BST_CHECKED : BST_UNCHECKED); return(TRUE); } /******************************************************************************* * * APMDlgHandleCommand * * DESCRIPTION: Handles WM_COMMAND messages sent to APMDlgProc * * PARAMETERS: * *******************************************************************************/ BOOL APMDlgHandleCommand( IN HWND hDlg, IN WPARAM wParam, IN LPARAM lParam ) { BOOL RetVal; WORD idCtl = LOWORD(wParam); WORD wNotify = HIWORD(wParam); // // Assume there is nothing to do and return false; // RetVal = FALSE; switch (idCtl) { case IDC_APMENABLE: if (BN_CLICKED == wNotify) { // // State changed. Enable the Apply button. // g_fDirty = TRUE; PropSheet_Changed(GetParent(hDlg), hDlg); } RetVal = TRUE; break; default: break; } return(RetVal); } /******************************************************************************* * * APMDlgHandleNotify * * DESCRIPTION: Handles WM_NOTIFY messages sent to APMDlgProc * * PARAMETERS: * *******************************************************************************/ BOOL APMDlgHandleNotify( IN HWND hDlg, IN WPARAM wParam, IN LPARAM lParam ) { int idCtl = (int) wParam; LPNMHDR pnmhdr = (LPNMHDR) lParam; UINT uNotify = pnmhdr->code; BOOL fResult; switch (uNotify) { case PSN_APPLY: if (g_fDirty) { if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_APMENABLE)) { fResult = NtApmToggle(APM_ENABLE, FALSE); } else { fResult = NtApmToggle(APM_DISABLE, FALSE); } if (fResult) { g_fDirty = FALSE; } SetWindowLongPtr(hDlg, DWLP_MSGRESULT, fResult ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE); } return(TRUE); break; default: return(FALSE); break; } return(FALSE); } /******************************************************************************* * * IsNtApmPresent * * DESCRIPTION: This function gets called to determine if APM is present on * and started on the machine. If APM is present then the * tab needs to appear. * * This functions check for ACPI, MP and then if APM is actually * on the machine. If ACPI and MP then APM may be running but is * disabled. * * RETURNS: TRUE if APM is present, FALSE if APM is no present * * *******************************************************************************/ BOOLEAN IsNtApmPresent(PSYSTEM_POWER_CAPABILITIES pspc) { BOOLEAN RetVal; BOOL APMMachine; BOOL ACPIMachine; BOOL MPMachine; DWORD CharBufferSize; DWORD ApmStarted; HKEY hPortKey; SYSTEM_INFO SystemInfo; // // Assume nothing about the machine // ACPIMachine = FALSE; MPMachine = FALSE; APMMachine = FALSE; CharBufferSize = sizeof(CharBuffer); // // We do the following checks: // // * check for ACPI // * check for MP system // if (NtApmACPIEnabled()) { ACPIMachine = TRUE; } else { GetSystemInfo(&SystemInfo); if (SystemInfo.dwNumberOfProcessors > 1) { MPMachine = TRUE; } } // // If the machine is ACPI or MP we still need to check if APM // is enabled so that we can disable it. This is a bug in APM // code, but it is easiest to just fix it up here. // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, m_szApmActiveKey, 0, KEY_ALL_ACCESS, &hPortKey) != ERROR_SUCCESS) { } else if (RegQueryValueEx(hPortKey, m_szApmActive, NULL, NULL, (PBYTE) CharBuffer, &CharBufferSize) != ERROR_SUCCESS) { RegCloseKey(hPortKey); } else { if (CharBuffer[0] != (TCHAR) 0) { ApmStarted = (DWORD) CharBuffer[0]; if (ApmStarted != SERVICE_DISABLED) { APMMachine = TRUE; } } RegCloseKey(hPortKey); } // // If APM is Present and Enabled it needs to be // silently disabled if the machine is ACPI or MP. // if (ACPIMachine || MPMachine) { if (APMMachine && NtApmEnabled()) { NtApmToggle(APM_DISABLE, TRUE); } RetVal = FALSE; } else if (APMMachine) { RetVal = TRUE; } else { RetVal = FALSE; } return(RetVal); } /******************************************************************************* * * P U B L I C E N T R Y P O I N T S * *******************************************************************************/ /******************************************************************************* * * APMDlgProc * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/ INT_PTR CALLBACK APMDlgProc( IN HWND hDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: return(APMDlgHandleInit(hDlg, wParam, lParam)); break; case WM_COMMAND: return(APMDlgHandleCommand(hDlg, wParam, lParam)); break; case WM_NOTIFY: return(APMDlgHandleNotify(hDlg, wParam, lParam)); break; case WM_HELP: // F1 WinHelp(((LPHELPINFO)lParam)->hItemHandle, PWRMANHLP, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)g_NtApmHelpIDs); return TRUE; case WM_CONTEXTMENU: // right mouse click WinHelp((HWND)wParam, PWRMANHLP, HELP_CONTEXTMENU, (ULONG_PTR)(LPTSTR)g_NtApmHelpIDs); return TRUE; default: return(FALSE); break; } // switch (uMsg) return(FALSE); } #endif