| /* |
| * Copyright (C) 2005 Benjamin Cutler |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| |
| #include <stdarg.h> |
| |
| #include "ntstatus.h" |
| #define WIN32_NO_STATUS |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winnt.h" |
| #include "winreg.h" |
| #include "winternl.h" |
| #include "powrprof.h" |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(powrprof); |
| |
| /* Notes to implementors: |
| * #1: The native implementation of these functions attempted to read in |
| * registry entries that I was unable to locate on any of the Windows |
| * machines I checked, but I only had desktops available, so maybe |
| * laptop users will have better luck. They return FNF errors because |
| * that's what the native DLL was returning during my tests. |
| * #2: These functions call NtPowerInformation but I don't know what they |
| * do with the results, and NtPowerInformation doesn't do much in WINE yet |
| * anyway. |
| * #3: Since I can't get several other functions working (see note #1), |
| * implementing these functions is going to have to wait until somebody can |
| * cobble together some sane test input. */ |
| |
| static const WCHAR szPowerCfgSubKey[] = { 'S', 'o', 'f', 't', 'w', 'a', 'r', 'e', |
| '\\', 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\', 'W', 'i', |
| 'n', 'd', 'o', 'w', 's', '\\', 'C', 'u', 'r', 'r', 'e', 'n', 't', |
| 'V', 'e', 'r', 's', 'i', 'o', 'n', '\\', 'C', 'o', 'n', 't', 'r', |
| 'o', 'l', 's', ' ', 'F', 'o', 'l', 'd', 'e', 'r', '\\', 'P', 'o', |
| 'w', 'e', 'r', 'C', 'f', 'g', 0 }; |
| static const WCHAR szSemaphoreName[] = { 'P', 'o', 'w', 'e', 'r', 'P', 'r', 'o', |
| 'f', 'i', 'l', 'e', 'R', 'e', 'g', 'i', 's', 't', 'r', 'y', 'S', |
| 'e', 'm', 'a', 'p', 'h', 'o', 'r', 'e', 0 }; |
| static const WCHAR szDiskMax[] = { 'D', 'i', 's', 'k', 'S', 'p', 'i', 'n', 'd', |
| 'o', 'w', 'n', 'M', 'a', 'x', 0 }; |
| static const WCHAR szDiskMin[] = { 'D', 'i', 's', 'k', 'S', 'p', 'i', 'n', 'd', |
| 'o', 'w', 'n', 'M', 'i', 'n', 0 }; |
| static const WCHAR szLastID[] = { 'L', 'a', 's', 't', 'I', 'D', 0 }; |
| static HANDLE PPRegSemaphore = NULL; |
| |
| NTSTATUS WINAPI CallNtPowerInformation( |
| POWER_INFORMATION_LEVEL InformationLevel, |
| PVOID lpInputBuffer, ULONG nInputBufferSize, |
| PVOID lpOutputBuffer, ULONG nOutputBufferSize) |
| { |
| return NtPowerInformation(InformationLevel, lpInputBuffer, |
| nInputBufferSize, lpOutputBuffer, nOutputBufferSize); |
| } |
| |
| BOOLEAN WINAPI CanUserWritePwrScheme(VOID) |
| { |
| HKEY hKey = NULL; |
| LONG r; |
| BOOLEAN bSuccess = TRUE; |
| |
| TRACE("()\n"); |
| |
| r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPowerCfgSubKey, 0, KEY_READ | KEY_WRITE, &hKey); |
| |
| if (r != ERROR_SUCCESS) { |
| TRACE("RegOpenKeyEx failed: %d\n", r); |
| bSuccess = FALSE; |
| } |
| |
| SetLastError(r); |
| RegCloseKey(hKey); |
| return bSuccess; |
| } |
| |
| BOOLEAN WINAPI DeletePwrScheme(UINT uiIndex) |
| { |
| /* FIXME: See note #1 */ |
| FIXME("(%d) stub!\n", uiIndex); |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI EnumPwrSchemes(PWRSCHEMESENUMPROC lpfnPwrSchemesEnumProc, |
| LPARAM lParam) |
| { |
| /* FIXME: See note #1 */ |
| FIXME("(%p, %ld) stub!\n", lpfnPwrSchemesEnumProc, lParam); |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI GetActivePwrScheme(PUINT puiID) |
| { |
| /* FIXME: See note #1 */ |
| FIXME("(%p) stub!\n", puiID); |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI GetCurrentPowerPolicies( |
| PGLOBAL_POWER_POLICY pGlobalPowerPolicy, |
| PPOWER_POLICY pPowerPolicy) |
| { |
| /* FIXME: See note #2 */ |
| SYSTEM_POWER_POLICY ACPower, DCPower; |
| |
| FIXME("(%p, %p) stub!\n", pGlobalPowerPolicy, pPowerPolicy); |
| |
| NtPowerInformation(SystemPowerPolicyAc, 0, 0, &ACPower, sizeof(SYSTEM_POWER_POLICY)); |
| NtPowerInformation(SystemPowerPolicyDc, 0, 0, &DCPower, sizeof(SYSTEM_POWER_POLICY)); |
| |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI GetPwrCapabilities( |
| PSYSTEM_POWER_CAPABILITIES lpSystemPowerCapabilities) |
| { |
| NTSTATUS r; |
| |
| TRACE("(%p)\n", lpSystemPowerCapabilities); |
| |
| r = NtPowerInformation(SystemPowerCapabilities, 0, 0, lpSystemPowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES)); |
| |
| SetLastError(RtlNtStatusToDosError(r)); |
| |
| return r == STATUS_SUCCESS; |
| } |
| |
| BOOLEAN WINAPI GetPwrDiskSpindownRange(PUINT RangeMax, PUINT RangeMin) |
| { |
| HKEY hKey; |
| BYTE lpValue[40]; |
| LONG r; |
| DWORD cbValue = sizeof(lpValue); |
| |
| TRACE("(%p, %p)\n", RangeMax, RangeMin); |
| |
| if (RangeMax == NULL || RangeMin == NULL) { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| |
| SetLastError(ERROR_SUCCESS); |
| |
| WaitForSingleObject(PPRegSemaphore, INFINITE); |
| |
| r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPowerCfgSubKey, 0, KEY_READ, &hKey); |
| if (r != ERROR_SUCCESS) { |
| TRACE("RegOpenKeyEx failed: %d\n", r); |
| TRACE("Using defaults: 3600, 3\n"); |
| *RangeMax = 3600; |
| *RangeMin = 3; |
| ReleaseSemaphore(PPRegSemaphore, 1, NULL); |
| return TRUE; |
| } |
| |
| r = RegQueryValueExW(hKey, szDiskMax, 0, 0, lpValue, &cbValue); |
| if (r != ERROR_SUCCESS) { |
| TRACE("Couldn't open DiskSpinDownMax: %d\n", r); |
| TRACE("Using default: 3600\n"); |
| *RangeMax = 3600; |
| } else { |
| *RangeMax = atoiW((LPCWSTR)lpValue); |
| } |
| |
| cbValue = sizeof(lpValue); |
| |
| r = RegQueryValueExW(hKey, szDiskMin, 0, 0, lpValue, &cbValue); |
| if (r != ERROR_SUCCESS) { |
| TRACE("Couldn't open DiskSpinDownMin: %d\n", r); |
| TRACE("Using default: 3\n"); |
| *RangeMin = 3; |
| } else { |
| *RangeMin = atoiW((LPCWSTR)lpValue); |
| } |
| |
| RegCloseKey(hKey); |
| |
| ReleaseSemaphore(PPRegSemaphore, 1, NULL); |
| |
| return TRUE; |
| } |
| |
| BOOLEAN WINAPI IsAdminOverrideActive(PADMINISTRATOR_POWER_POLICY p) |
| { |
| FIXME("( %p) stub!\n", p); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI IsPwrHibernateAllowed(VOID) |
| { |
| SYSTEM_POWER_CAPABILITIES PowerCaps; |
| NtPowerInformation(SystemPowerCapabilities, NULL, 0, &PowerCaps, sizeof(PowerCaps)); |
| return PowerCaps.SystemS4 && PowerCaps.HiberFilePresent; |
| } |
| |
| BOOLEAN WINAPI IsPwrShutdownAllowed(VOID) |
| { |
| SYSTEM_POWER_CAPABILITIES PowerCaps; |
| NtPowerInformation(SystemPowerCapabilities, NULL, 0, &PowerCaps, sizeof(PowerCaps)); |
| return PowerCaps.SystemS5; |
| } |
| |
| BOOLEAN WINAPI IsPwrSuspendAllowed(VOID) |
| { |
| SYSTEM_POWER_CAPABILITIES PowerCaps; |
| NtPowerInformation(SystemPowerCapabilities, NULL, 0, &PowerCaps, sizeof(PowerCaps)); |
| return PowerCaps.SystemS1 && PowerCaps.SystemS2 && PowerCaps.SystemS3; |
| } |
| |
| BOOLEAN WINAPI ReadGlobalPwrPolicy(PGLOBAL_POWER_POLICY pGlobalPowerPolicy) |
| { |
| /* FIXME: See note #1 */ |
| FIXME("(%p) stub!\n", pGlobalPowerPolicy); |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI ReadProcessorPwrScheme(UINT uiID, |
| PMACHINE_PROCESSOR_POWER_POLICY pMachineProcessorPowerPolicy) |
| { |
| /* FIXME: See note #1 */ |
| FIXME("(%d, %p) stub!\n", uiID, pMachineProcessorPowerPolicy); |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI ReadPwrScheme(UINT uiID, |
| PPOWER_POLICY pPowerPolicy) |
| { |
| /* FIXME: See note #1 */ |
| FIXME("(%d, %p) stub!\n", uiID, pPowerPolicy); |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI SetActivePwrScheme(UINT uiID, |
| PGLOBAL_POWER_POLICY lpGlobalPowerPolicy, |
| PPOWER_POLICY lpPowerPolicy) |
| { |
| /* FIXME: See note #1 */ |
| FIXME("(%d, %p, %p) stub!\n", uiID, lpGlobalPowerPolicy, lpPowerPolicy); |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI SetSuspendState(BOOLEAN Hibernate, BOOLEAN ForceCritical, |
| BOOLEAN DisableWakeEvent) |
| { |
| /* FIXME: I have NO idea how you're supposed to call NtInitiatePowerAction |
| * here, because it's not a documented function that I can find */ |
| FIXME("(%d, %d, %d) stub!\n", Hibernate, ForceCritical, DisableWakeEvent); |
| return TRUE; |
| } |
| |
| BOOLEAN WINAPI WriteGlobalPwrPolicy(PGLOBAL_POWER_POLICY pGlobalPowerPolicy) |
| { |
| /* FIXME: See note #3 */ |
| FIXME("(%p) stub!\n", pGlobalPowerPolicy); |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI WriteProcessorPwrScheme(UINT ID, |
| PMACHINE_PROCESSOR_POWER_POLICY pMachineProcessorPowerPolicy) |
| { |
| /* FIXME: See note #3 */ |
| FIXME("(%d, %p) stub!\n", ID, pMachineProcessorPowerPolicy); |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| return FALSE; |
| } |
| |
| BOOLEAN WINAPI WritePwrScheme(PUINT puiID, LPWSTR lpszName, LPWSTR lpszDescription, |
| PPOWER_POLICY pPowerPolicy) |
| { |
| /* FIXME: See note #3 */ |
| FIXME("(%p, %s, %s, %p) stub!\n", puiID, debugstr_w(lpszName), debugstr_w(lpszDescription), pPowerPolicy); |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| return FALSE; |
| } |
| |
| DWORD WINAPI PowerGetActiveScheme(HKEY UserRootPowerKey, GUID **polguid) |
| { |
| FIXME("(%p,%p) stub!\n", UserRootPowerKey, polguid); |
| return ERROR_CALL_NOT_IMPLEMENTED; |
| } |
| |
| DWORD WINAPI PowerReadDCValue(HKEY RootPowerKey, const GUID *Scheme, const GUID *SubGroup, const GUID *PowerSettings, PULONG Type, PUCHAR Buffer, DWORD *BufferSize) |
| { |
| FIXME("(%p,%s,%s,%s,%p,%p,%p) stub!\n", RootPowerKey, debugstr_guid(Scheme), debugstr_guid(SubGroup), debugstr_guid(PowerSettings), Type, Buffer, BufferSize); |
| return ERROR_CALL_NOT_IMPLEMENTED; |
| } |
| |
| BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) |
| { |
| switch(fdwReason) { |
| case DLL_PROCESS_ATTACH: { |
| |
| HKEY hKey; |
| LONG r; |
| |
| DisableThreadLibraryCalls(hinstDLL); |
| |
| r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPowerCfgSubKey, 0, KEY_READ | KEY_WRITE, &hKey); |
| |
| if (r != ERROR_SUCCESS) { |
| TRACE("Couldn't open registry key HKLM\\%s, using some sane(?) defaults\n", debugstr_w(szPowerCfgSubKey)); |
| } else { |
| BYTE lpValue[40]; |
| DWORD cbValue = sizeof(lpValue); |
| r = RegQueryValueExW(hKey, szLastID, 0, 0, lpValue, &cbValue); |
| if (r != ERROR_SUCCESS) { |
| TRACE("Couldn't open registry entry HKLM\\%s\\LastID, using some sane(?) defaults\n", debugstr_w(szPowerCfgSubKey)); |
| } |
| RegCloseKey(hKey); |
| } |
| |
| PPRegSemaphore = CreateSemaphoreW(NULL, 1, 1, szSemaphoreName); |
| if (PPRegSemaphore == NULL) { |
| ERR("Couldn't create Semaphore: %d\n", GetLastError()); |
| return FALSE; |
| } |
| break; |
| } |
| case DLL_PROCESS_DETACH: |
| if (lpvReserved) break; |
| CloseHandle(PPRegSemaphore); |
| break; |
| } |
| return TRUE; |
| } |