xref: /reactos/dll/win32/powrprof/powrprof.c (revision 7eead935)
1 /*
2  * Copyright (C) 2005 Benjamin Cutler
3  * Copyright (C) 2008 Dmitry Chapyshev
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 
21 #include <stdarg.h>
22 
23 #define WIN32_NO_STATUS
24 #include <windef.h>
25 #include <winbase.h>
26 #include <winreg.h>
27 #define NTOS_MODE_USER
28 #include <ndk/pofuncs.h>
29 #include <ndk/rtlfuncs.h>
30 #include <ndk/setypes.h>
31 #include <powrprof.h>
32 #include <wine/debug.h>
33 #include <wine/unicode.h>
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(powrprof);
36 
37 
38 static const WCHAR szPowerCfgSubKey[] =
39     L"Software\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg";
40 static const WCHAR szUserPowerConfigSubKey[] =
41     L"Control Panel\\PowerCfg";
42 static const WCHAR szCurrentPowerPolicies[] =
43     L"CurrentPowerPolicy";
44 static const WCHAR szPolicies[] = L"Policies";
45 static const WCHAR szName[] = L"Name";
46 static const WCHAR szDescription[] = L"Description";
47 static const WCHAR szSemaphoreName[] = L"PowerProfileRegistrySemaphore";
48 static const WCHAR szDiskMax[] = L"DiskSpindownMax";
49 static const WCHAR szDiskMin[] = L"DiskSpindownMin";
50 static const WCHAR szLastID[] = L"LastID";
51 
52 UINT g_LastID = (UINT)-1;
53 
54 BOOLEAN WINAPI WritePwrPolicy(PUINT puiID, PPOWER_POLICY pPowerPolicy);
55 
56 HANDLE PPRegSemaphore = NULL;
57 
58 NTSTATUS WINAPI
59 CallNtPowerInformation(POWER_INFORMATION_LEVEL InformationLevel,
60                        PVOID lpInputBuffer,
61                        ULONG nInputBufferSize,
62                        PVOID lpOutputBuffer,
63                        ULONG nOutputBufferSize)
64 {
65     BOOLEAN old;
66 
67 	//Lohnegrim: In order to get the right results, we have to adjust our Privileges
68     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &old);
69     RtlAdjustPrivilege(SE_CREATE_PAGEFILE_PRIVILEGE, TRUE, FALSE, &old);
70 
71     return NtPowerInformation(InformationLevel,
72                               lpInputBuffer,
73                               nInputBufferSize,
74                               lpOutputBuffer,
75                               nOutputBufferSize);
76 }
77 
78 BOOLEAN WINAPI
79 CanUserWritePwrScheme(VOID)
80 {
81     HKEY hKey = NULL;
82     LONG Ret;
83 
84     TRACE("()\n");
85 
86     Ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPowerCfgSubKey, 0, KEY_READ | KEY_WRITE, &hKey);
87     if (Ret != ERROR_SUCCESS)
88     {
89         TRACE("RegOpenKeyEx failed: %d\n", Ret);
90         SetLastError(Ret);
91         return FALSE;
92     }
93 
94     RegCloseKey(hKey);
95     return TRUE;
96 }
97 
98 BOOLEAN WINAPI
99 DeletePwrScheme(UINT uiIndex)
100 {
101     WCHAR Buf[MAX_PATH];
102     UINT Current;
103     LONG Err;
104 
105     swprintf(Buf, L"Control Panel\\PowerCfg\\PowerPolicies\\%d", uiIndex);
106 
107     if (!GetActivePwrScheme(&Current))
108         return FALSE;
109 
110     if (Current == uiIndex)
111     {
112         SetLastError(ERROR_ACCESS_DENIED);
113         return FALSE;
114     }
115 
116     Err = RegDeleteKey(HKEY_CURRENT_USER, (LPCTSTR)Buf);
117     if (Err != ERROR_SUCCESS)
118     {
119         TRACE("RegDeleteKey failed: %d\n", Err);
120         SetLastError(Err);
121         return FALSE;
122     }
123 
124     return TRUE;
125 }
126 
127 static BOOLEAN
128 POWRPROF_GetUserPowerPolicy(LPWSTR szNum,
129                             PUSER_POWER_POLICY puserPwrPolicy,
130                             DWORD cchName, LPWSTR szName,
131                             DWORD cchDesc, LPWSTR szDesc)
132 {
133     HKEY hSubKey = NULL;
134     DWORD dwSize;
135     LONG Err;
136     WCHAR szPath[MAX_PATH];
137     BOOL bRet = FALSE;
138 
139     swprintf(szPath, L"Control Panel\\PowerCfg\\PowerPolicies\\%s", szNum);
140 
141     Err = RegOpenKeyExW(HKEY_CURRENT_USER, szPath, 0, KEY_READ, &hSubKey);
142     if (Err != ERROR_SUCCESS)
143     {
144         ERR("RegOpenKeyExW failed: %d\n", Err);
145         SetLastError(Err);
146         return FALSE;
147     }
148 
149     dwSize = cchName * sizeof(WCHAR);
150     Err = RegQueryValueExW(hSubKey, L"Name", NULL, NULL, (LPBYTE)szName, &dwSize);
151     if (Err != ERROR_SUCCESS)
152     {
153         ERR("RegQueryValueExW failed: %d\n", Err);
154         SetLastError(Err);
155         goto cleanup;
156     }
157 
158     dwSize = cchDesc * sizeof(WCHAR);
159     Err = RegQueryValueExW(hSubKey, L"Description", NULL, NULL, (LPBYTE)szDesc, &dwSize);
160     if (Err != ERROR_SUCCESS)
161     {
162         ERR("RegQueryValueExW failed: %d\n", Err);
163         SetLastError(Err);
164         goto cleanup;
165     }
166 
167     dwSize = sizeof(USER_POWER_POLICY);
168     Err = RegQueryValueExW(hSubKey, L"Policies", NULL, NULL, (LPBYTE)puserPwrPolicy, &dwSize);
169     if (Err != ERROR_SUCCESS)
170     {
171         ERR("RegQueryValueExW failed: %d\n", Err);
172         SetLastError(Err);
173         goto cleanup;
174     }
175 
176     bRet = TRUE;
177 
178 cleanup:
179     RegCloseKey(hSubKey);
180 
181     return bRet;
182 }
183 
184 static BOOLEAN
185 POWRPROF_GetMachinePowerPolicy(LPWSTR szNum, PMACHINE_POWER_POLICY pmachinePwrPolicy)
186 {
187     HKEY hKey;
188     LONG Err;
189     WCHAR szPath[MAX_PATH];
190     DWORD dwSize;
191 
192     swprintf(szPath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg\\PowerPolicies\\%s", szNum);
193 
194     Err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPath, 0, KEY_READ, &hKey);
195     if (Err != ERROR_SUCCESS)
196     {
197         ERR("RegOpenKeyExW failed: %d\n", Err);
198         SetLastError(Err);
199         return FALSE;
200     }
201 
202     dwSize = sizeof(MACHINE_POWER_POLICY);
203     Err = RegQueryValueExW(hKey, L"Policies", NULL, NULL, (LPBYTE)pmachinePwrPolicy, &dwSize);
204 
205     if (Err != ERROR_SUCCESS)
206     {
207         ERR("RegQueryValueExW failed: %d\n", Err);
208         SetLastError(Err);
209         RegCloseKey(hKey);
210         return FALSE;
211     }
212 
213     RegCloseKey(hKey);
214 
215     return TRUE;
216 }
217 
218 BOOLEAN WINAPI
219 EnumPwrSchemes(PWRSCHEMESENUMPROC lpfnPwrSchemesEnumProc,
220                LPARAM lParam)
221 {
222     HKEY hKey;
223     LONG Err;
224     DWORD dwSize, dwNameSize = MAX_PATH, dwDescSize = MAX_PATH, dwIndex = 0;
225     WCHAR szNum[3 + 1], szName[MAX_PATH], szDesc[MAX_PATH];
226     POWER_POLICY PwrPolicy;
227     USER_POWER_POLICY userPwrPolicy;
228     MACHINE_POWER_POLICY machinePwrPolicy;
229     BOOLEAN bRet = FALSE;
230 
231     if (!lpfnPwrSchemesEnumProc)
232     {
233         SetLastError(ERROR_INVALID_PARAMETER);
234         return FALSE;
235     }
236 
237     Err = RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\PowerCfg\\PowerPolicies", 0, KEY_READ, &hKey);
238     if (Err != ERROR_SUCCESS)
239     {
240         ERR("RegOpenKeyW failed: %d\n", Err);
241         SetLastError(Err);
242         return FALSE;
243     }
244 
245     ReleaseSemaphore(PPRegSemaphore, 1, NULL);
246 
247     dwSize = sizeof(szNum) / sizeof(WCHAR);
248 
249     while (RegEnumKeyExW(hKey, dwIndex, szNum, &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
250     {
251         if (!POWRPROF_GetUserPowerPolicy(szNum, &userPwrPolicy,
252                                          dwNameSize, szName,
253                                          dwDescSize, szDesc))
254         {
255             WARN("POWRPROF_GetUserPowerPolicy failed\n");
256             goto cleanup;
257         }
258 
259         if (!POWRPROF_GetMachinePowerPolicy(szNum, &machinePwrPolicy))
260         {
261             WARN("POWRPROF_GetMachinePowerPolicy failed\n");
262             goto cleanup;
263         }
264 
265         memcpy(&PwrPolicy.user, &userPwrPolicy, sizeof(USER_POWER_POLICY));
266         memcpy(&PwrPolicy.mach, &machinePwrPolicy, sizeof(MACHINE_POWER_POLICY));
267 
268         if (!lpfnPwrSchemesEnumProc(_wtoi(szNum), (wcslen(szName) + 1) * sizeof(WCHAR), szName, (wcslen(szDesc) + 1) * sizeof(WCHAR), szDesc, &PwrPolicy, lParam))
269             goto cleanup;
270         else
271             bRet = TRUE;
272 
273         dwSize = sizeof(szNum) / sizeof(WCHAR);
274         dwIndex++;
275     }
276 
277 cleanup:
278     RegCloseKey(hKey);
279     ReleaseSemaphore(PPRegSemaphore, 1, NULL);
280 
281     return bRet;
282 }
283 
284 BOOLEAN WINAPI
285 GetActivePwrScheme(PUINT puiID)
286 {
287     HKEY hKey;
288     WCHAR szBuf[MAX_PATH];
289     DWORD dwSize;
290     LONG Err;
291 
292     TRACE("GetActivePwrScheme(%u)", puiID);
293 
294     Err = RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\PowerCfg", 0, KEY_READ, &hKey);
295     if (Err != ERROR_SUCCESS)
296     {
297         ERR("RegOpenKey failed: %d\n", Err);
298         SetLastError(Err);
299         return FALSE;
300     }
301 
302     dwSize = sizeof(szBuf);
303     Err = RegQueryValueExW(hKey, L"CurrentPowerPolicy",
304                            NULL, NULL,
305                            (LPBYTE)&szBuf, &dwSize);
306     if (Err != ERROR_SUCCESS)
307     {
308         ERR("RegQueryValueEx failed: %d\n", Err);
309         RegCloseKey(hKey);
310         SetLastError(Err);
311         return FALSE;
312     }
313 
314     RegCloseKey(hKey);
315     *puiID = _wtoi(szBuf);
316 
317     return TRUE;
318 }
319 
320 BOOLEAN WINAPI
321 GetCurrentPowerPolicies(PGLOBAL_POWER_POLICY pGlobalPowerPolicy,
322                         PPOWER_POLICY pPowerPolicy)
323 {
324     /*
325     SYSTEM_POWER_POLICY ACPower, DCPower;
326 
327     FIXME("(%p, %p) stub!\n", pGlobalPowerPolicy, pPowerPolicy);
328 
329     NtPowerInformation(SystemPowerPolicyAc, 0, 0, &ACPower, sizeof(SYSTEM_POWER_POLICY));
330     NtPowerInformation(SystemPowerPolicyDc, 0, 0, &DCPower, sizeof(SYSTEM_POWER_POLICY));
331 
332     return FALSE;
333     */
334 /*
335    Lohnegrim: I don't know why this Function should call NtPowerInformation, because as far as I know,
336       it simply returns the GlobalPowerPolicy and the AktivPowerScheme!
337  */
338     UINT uiID;
339 
340     if (pGlobalPowerPolicy != NULL)
341     {
342         if (!ReadGlobalPwrPolicy(pGlobalPowerPolicy))
343             return FALSE;
344     }
345     if (pPowerPolicy != NULL)
346     {
347         if (!GetActivePwrScheme(&uiID))
348             return FALSE;
349 
350         if (!ReadPwrScheme(uiID, pPowerPolicy))
351             return FALSE;
352     }
353 
354     return TRUE;
355 }
356 
357 BOOLEAN WINAPI
358 GetPwrCapabilities(PSYSTEM_POWER_CAPABILITIES lpSystemPowerCapabilities)
359 {
360     NTSTATUS Status;
361 
362     TRACE("(%p)\n", lpSystemPowerCapabilities);
363 
364     if (!lpSystemPowerCapabilities)
365     {
366         SetLastError(ERROR_INVALID_PARAMETER);
367         return FALSE;
368     }
369 
370     Status = NtPowerInformation(SystemPowerCapabilities, 0, 0, lpSystemPowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
371     if(!NT_SUCCESS(Status))
372     {
373         SetLastError(RtlNtStatusToDosError(Status));
374         return FALSE;
375     }
376 
377     return TRUE;
378 }
379 
380 BOOLEAN WINAPI
381 GetPwrDiskSpindownRange(PUINT RangeMax, PUINT RangeMin)
382 {
383     HKEY hKey;
384     BYTE lpValue[40];
385     LONG Ret;
386     DWORD cbValue = sizeof(lpValue);
387 
388     TRACE("(%p, %p)\n", RangeMax, RangeMin);
389 
390     if (RangeMax == NULL || RangeMin == NULL)
391     {
392         SetLastError(ERROR_INVALID_PARAMETER);
393         return FALSE;
394     }
395 
396     WaitForSingleObject(PPRegSemaphore, INFINITE);
397 
398     Ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPowerCfgSubKey, 0, KEY_READ, &hKey);
399     if (Ret != ERROR_SUCCESS)
400     {
401         TRACE("RegOpenKeyEx failed: %d\n", Ret);
402         TRACE("Using defaults: 3600, 3\n");
403         *RangeMax = 3600;
404         *RangeMin = 3;
405         ReleaseSemaphore(PPRegSemaphore, 1, NULL);
406         return TRUE;
407     }
408 
409     Ret = RegQueryValueExW(hKey, szDiskMax, 0, 0, lpValue, &cbValue);
410     if (Ret != ERROR_SUCCESS)
411     {
412         TRACE("Couldn't open DiskSpinDownMax: %d\n", Ret);
413         TRACE("Using default: 3600\n");
414         *RangeMax = 3600;
415     }
416     else
417     {
418         *RangeMax = _wtoi((LPCWSTR)lpValue);
419     }
420 
421     cbValue = sizeof(lpValue);
422 
423     Ret = RegQueryValueExW(hKey, szDiskMin, 0, 0, lpValue, &cbValue);
424     if (Ret != ERROR_SUCCESS)
425     {
426         TRACE("Couldn't open DiskSpinDownMin: %d\n", Ret);
427         TRACE("Using default: 3\n");
428         *RangeMin = 3;
429     }
430     else
431     {
432         *RangeMin = _wtoi((LPCWSTR)lpValue);
433     }
434 
435     RegCloseKey(hKey);
436 
437     ReleaseSemaphore(PPRegSemaphore, 1, NULL);
438 
439     return TRUE;
440 }
441 
442 BOOLEAN WINAPI
443 IsAdminOverrideActive(PADMINISTRATOR_POWER_POLICY p)
444 {
445     FIXME("( %p) stub!\n", p);
446     return FALSE;
447 }
448 
449 BOOLEAN WINAPI
450 IsPwrHibernateAllowed(VOID)
451 {
452     SYSTEM_POWER_CAPABILITIES PowerCaps;
453     NTSTATUS Status;
454     BOOLEAN old;
455 
456     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &old);
457 
458     Status = NtPowerInformation(SystemPowerCapabilities, NULL, 0, &PowerCaps, sizeof(PowerCaps));
459     if (!NT_SUCCESS(Status))
460     {
461         SetLastError(RtlNtStatusToDosError(Status));
462         return FALSE;
463     }
464 
465     return PowerCaps.SystemS4 && PowerCaps.HiberFilePresent; // IsHiberfilPresent();
466 }
467 
468 BOOLEAN WINAPI
469 IsPwrShutdownAllowed(VOID)
470 {
471     SYSTEM_POWER_CAPABILITIES PowerCaps;
472     NTSTATUS Status;
473     BOOLEAN old;
474 
475     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &old);
476 
477     Status = NtPowerInformation(SystemPowerCapabilities, NULL, 0, &PowerCaps, sizeof(PowerCaps));
478     if (!NT_SUCCESS(Status))
479     {
480         SetLastError(RtlNtStatusToDosError(Status));
481         return FALSE;
482     }
483 
484     return PowerCaps.SystemS5;
485 }
486 
487 BOOLEAN WINAPI
488 IsPwrSuspendAllowed(VOID)
489 {
490     SYSTEM_POWER_CAPABILITIES PowerCaps;
491     NTSTATUS Status;
492     BOOLEAN old;
493 
494     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &old);
495 
496     Status = NtPowerInformation(SystemPowerCapabilities, NULL, 0, &PowerCaps, sizeof(PowerCaps));
497     if (!NT_SUCCESS(Status))
498     {
499         SetLastError(RtlNtStatusToDosError(Status));
500         return FALSE;
501     }
502 
503     return PowerCaps.SystemS1 || PowerCaps.SystemS2 || PowerCaps.SystemS3;
504 }
505 
506 DWORD WINAPI
507 PowerGetActiveScheme(HKEY UserRootPowerKey, GUID **polguid)
508 {
509    FIXME("(%p,%p) stub!\n", UserRootPowerKey, polguid);
510    return ERROR_CALL_NOT_IMPLEMENTED;
511 }
512 
513 DWORD WINAPI
514 PowerReadDCValue(HKEY RootPowerKey, const GUID *Scheme, const GUID *SubGroup, const GUID *PowerSettings, PULONG Type, PUCHAR Buffer, DWORD *BufferSize)
515 {
516    FIXME("(%p,%s,%s,%s,%p,%p,%p) stub!\n", RootPowerKey, debugstr_guid(Scheme), debugstr_guid(SubGroup), debugstr_guid(PowerSettings), Type, Buffer, BufferSize);
517    return ERROR_CALL_NOT_IMPLEMENTED;
518 }
519 
520 BOOLEAN WINAPI
521 ReadGlobalPwrPolicy(PGLOBAL_POWER_POLICY pGlobalPowerPolicy)
522 {
523     GLOBAL_MACHINE_POWER_POLICY glMachPwrPolicy;
524     GLOBAL_USER_POWER_POLICY glUserPwrPolicy;
525     HKEY hKey = NULL;
526     DWORD dwSize;
527     LONG Err;
528     BOOL bRet = FALSE;
529 
530     ReleaseSemaphore(PPRegSemaphore, 1, NULL);
531 
532     // Getting user global power policy
533     Err = RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\PowerCfg\\GlobalPowerPolicy", 0, KEY_READ, &hKey);
534     if (Err != ERROR_SUCCESS)
535     {
536         ERR("RegOpenKeyW failed: %d\n", Err);
537         SetLastError(Err);
538         goto cleanup;
539     }
540 
541     dwSize = sizeof(glUserPwrPolicy);
542     Err = RegQueryValueExW(hKey, L"Policies", NULL, NULL, (LPBYTE)&glUserPwrPolicy, &dwSize);
543     if (Err != ERROR_SUCCESS)
544     {
545         ERR("RegQueryValueExW failed: %d\n", Err);
546         SetLastError(Err);
547         goto cleanup;
548     }
549 
550     RegCloseKey(hKey);
551 
552     // Getting machine global power policy
553     Err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg\\GlobalPowerPolicy", 0, KEY_READ, &hKey);
554     if (Err != ERROR_SUCCESS)
555     {
556         ERR("RegOpenKeyW failed: %d\n", Err);
557         SetLastError(Err);
558         goto cleanup;
559     }
560 
561     dwSize = sizeof(glMachPwrPolicy);
562     Err = RegQueryValueExW(hKey, L"Policies", NULL, NULL, (LPBYTE)&glMachPwrPolicy, &dwSize);
563     if (Err != ERROR_SUCCESS)
564     {
565         ERR("RegQueryValueExW failed: %d\n", Err);
566         SetLastError(Err);
567         goto cleanup;
568     }
569 
570     memcpy(&pGlobalPowerPolicy->user, &glUserPwrPolicy, sizeof(GLOBAL_USER_POWER_POLICY));
571     memcpy(&pGlobalPowerPolicy->mach, &glMachPwrPolicy, sizeof(GLOBAL_MACHINE_POWER_POLICY));
572     bRet = TRUE;
573 
574 cleanup:
575     if(hKey)
576         RegCloseKey(hKey);
577     ReleaseSemaphore(PPRegSemaphore, 1, NULL);
578 
579     return bRet;
580 }
581 
582 
583 BOOLEAN WINAPI
584 ReadProcessorPwrScheme(UINT uiID,
585                        PMACHINE_PROCESSOR_POWER_POLICY pMachineProcessorPowerPolicy)
586 {
587     HKEY hKey;
588     WCHAR szPath[MAX_PATH];
589     DWORD dwSize = sizeof(MACHINE_PROCESSOR_POWER_POLICY);
590 
591     swprintf(szPath, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg\\ProcessorPolicies\\%i", uiID);
592     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
593         return FALSE;
594 
595     if (RegQueryValueExW(hKey, szPolicies, NULL, 0, (LPBYTE)pMachineProcessorPowerPolicy, &dwSize) == ERROR_SUCCESS)
596     {
597         RegCloseKey(hKey);
598         return TRUE;
599     }
600 
601     RegCloseKey(hKey);
602     if (uiID != 0)
603         return ReadProcessorPwrScheme(0, pMachineProcessorPowerPolicy);
604 
605     return FALSE;
606 }
607 
608 
609 BOOLEAN WINAPI
610 ReadPwrScheme(UINT uiID,
611     PPOWER_POLICY pPowerPolicy)
612 {
613     USER_POWER_POLICY userPwrPolicy;
614     MACHINE_POWER_POLICY machinePwrPolicy;
615     WCHAR szNum[16]; // max number - 999
616 
617     ReleaseSemaphore(PPRegSemaphore, 1, NULL);
618 
619     swprintf(szNum, L"%d", uiID);
620 
621     if (!POWRPROF_GetUserPowerPolicy(szNum, &userPwrPolicy, 0, NULL, 0, NULL))
622     {
623         ReleaseSemaphore(PPRegSemaphore, 1, NULL);
624         return FALSE;
625     }
626 
627     if (!POWRPROF_GetMachinePowerPolicy(szNum, &machinePwrPolicy))
628     {
629         ReleaseSemaphore(PPRegSemaphore, 1, NULL);
630         return FALSE;
631     }
632 
633     memcpy(&pPowerPolicy->user, &userPwrPolicy, sizeof(userPwrPolicy));
634     memcpy(&pPowerPolicy->mach, &machinePwrPolicy, sizeof(machinePwrPolicy));
635 
636     ReleaseSemaphore(PPRegSemaphore, 1, NULL);
637 
638     return TRUE;
639 }
640 
641 BOOLEAN WINAPI
642 SetActivePwrScheme(UINT uiID,
643                    PGLOBAL_POWER_POLICY lpGlobalPowerPolicy,
644                    PPOWER_POLICY lpPowerPolicy)
645 {
646     POWER_POLICY tmp;
647     HKEY hKey;
648     WCHAR Buf[16];
649 
650     if (!ReadPwrScheme(uiID, &tmp))
651         return FALSE;
652 
653     if (RegOpenKeyEx(HKEY_CURRENT_USER, szUserPowerConfigSubKey, 0, KEY_WRITE, &hKey) != ERROR_SUCCESS)
654         return FALSE;
655 
656     swprintf(Buf, L"%i", uiID);
657 
658     if (RegSetValueExW(hKey, szCurrentPowerPolicies, 0, REG_SZ, (PBYTE)Buf, strlenW(Buf)*sizeof(WCHAR)) != ERROR_SUCCESS)
659     {
660         RegCloseKey(hKey);
661         return FALSE;
662     }
663     RegCloseKey(hKey);
664 
665     if (lpGlobalPowerPolicy != NULL || lpPowerPolicy != NULL)
666     {
667         if (!ValidatePowerPolicies(lpGlobalPowerPolicy, lpPowerPolicy))
668             return FALSE;
669 
670         if (lpGlobalPowerPolicy != NULL && !WriteGlobalPwrPolicy(lpGlobalPowerPolicy))
671             return FALSE;
672 
673         if (lpPowerPolicy != NULL && !WritePwrPolicy(&uiID,lpPowerPolicy))
674             return FALSE;
675     }
676 
677     return TRUE;
678 }
679 
680 BOOLEAN WINAPI
681 SetSuspendState(BOOLEAN Hibernate,
682                 BOOLEAN ForceCritical,
683                 BOOLEAN DisableWakeEvent)
684 {
685     FIXME("(%d, %d, %d) stub!\n", Hibernate, ForceCritical, DisableWakeEvent);
686     return TRUE;
687 }
688 
689 BOOLEAN WINAPI
690 WriteGlobalPwrPolicy(PGLOBAL_POWER_POLICY pGlobalPowerPolicy)
691 {
692     HKEY hKey;
693     GLOBAL_USER_POWER_POLICY gupp;
694     GLOBAL_MACHINE_POWER_POLICY gmpp;
695 
696     gupp = pGlobalPowerPolicy->user;
697     gmpp = pGlobalPowerPolicy->mach;
698 
699     if (RegOpenKeyEx(HKEY_CURRENT_USER,
700                     L"Control Panel\\PowerCfg\\GlobalPowerPolicy",
701                     0,
702                     KEY_WRITE,
703                     &hKey) != ERROR_SUCCESS)
704         return FALSE;
705 
706     if (RegSetValueExW(hKey, szPolicies, 0, REG_BINARY, (PBYTE)&gupp, sizeof(gupp)) != ERROR_SUCCESS)
707     {
708         RegCloseKey(hKey);
709         return FALSE;
710     }
711 
712     RegCloseKey(hKey);
713 
714     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
715                      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg\\GlobalPowerPolicy",
716                      0,
717                      KEY_ALL_ACCESS,
718                      &hKey))
719         return FALSE;
720 
721     if (RegSetValueExW(hKey,szPolicies, 0, REG_BINARY, (PBYTE)&gmpp, sizeof(gmpp)) != ERROR_SUCCESS)
722     {
723         RegCloseKey(hKey);
724         return FALSE;
725     }
726 
727     RegCloseKey(hKey);
728     return TRUE;
729 }
730 
731 BOOLEAN WINAPI
732 WriteProcessorPwrScheme(UINT ID,
733                         PMACHINE_PROCESSOR_POWER_POLICY pMachineProcessorPowerPolicy)
734 {
735     WCHAR Buf[MAX_PATH];
736     HKEY hKey;
737 
738     swprintf(Buf, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg\\ProcessorPolicies\\%i", ID);
739 
740     if (RegCreateKey(HKEY_LOCAL_MACHINE, Buf, &hKey) != ERROR_SUCCESS)
741         return FALSE;
742 
743     RegSetValueExW(hKey, szPolicies, 0, REG_BINARY, (PBYTE)pMachineProcessorPowerPolicy, sizeof(MACHINE_PROCESSOR_POWER_POLICY));
744     RegCloseKey(hKey);
745     return TRUE;
746 }
747 
748 static VOID
749 SetLastID(VOID)
750 {
751     WCHAR Buf[16];
752     HKEY hKey;
753 
754     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
755                     szPowerCfgSubKey,
756                     0,
757                     KEY_WRITE,
758                     &hKey) != ERROR_SUCCESS)
759         return;
760     swprintf(Buf, L"%i", g_LastID);
761     RegSetValueExW(hKey, szLastID, 0, REG_SZ, (PBYTE)Buf, strlenW(Buf)*sizeof(WCHAR));
762     RegCloseKey(hKey);
763 }
764 
765 BOOLEAN WINAPI
766 WritePwrScheme(PUINT puiID,
767                LPWSTR lpszName,
768                LPWSTR lpszDescription,
769                PPOWER_POLICY pPowerPolicy)
770 {
771     WCHAR Buf[MAX_PATH];
772     HKEY hKey;
773 
774     if (*puiID == -1)
775     {
776         g_LastID++;
777         *puiID = g_LastID;
778         SetLastID();
779     }
780 
781     swprintf(Buf, L"Control Panel\\PowerCfg\\PowerPolicies\\%i", *puiID);
782 
783     if (RegCreateKey(HKEY_CURRENT_USER, Buf, &hKey) != ERROR_SUCCESS)
784         return FALSE;
785 
786     RegSetValueExW(hKey, szName, 0, REG_SZ, (PBYTE)lpszName, strlenW(lpszName)*sizeof(WCHAR));
787     RegSetValueExW(hKey, szDescription, 0, REG_SZ, (PBYTE)lpszDescription, strlenW(lpszDescription)*sizeof(WCHAR));
788     RegCloseKey(hKey);
789     return WritePwrPolicy(puiID, pPowerPolicy);
790 }
791 
792 static BOOLEAN
793 CheckPowerActionPolicy(PPOWER_ACTION_POLICY pPAP, SYSTEM_POWER_CAPABILITIES PowerCaps)
794 {
795 /*
796    Lohnegrim: this is an Helper function, it checks if the POWERACTIONPOLICY is valid
797    Also, if the System doesn't support Hibernation, then change the PowerAction
798 */
799     switch (pPAP->Action)
800     {
801     case PowerActionNone:
802         return TRUE;
803     case PowerActionReserved:
804         if (PowerCaps.SystemS1 || PowerCaps.SystemS2 || PowerCaps.SystemS3)
805             pPAP->Action = PowerActionSleep;
806         else
807             pPAP->Action = PowerActionReserved;
808     case PowerActionSleep:
809         return TRUE;
810     case PowerActionHibernate:
811         if (!(PowerCaps.SystemS4 && PowerCaps.HiberFilePresent))
812         {
813             if (PowerCaps.SystemS1 || PowerCaps.SystemS2 || PowerCaps.SystemS3)
814                 pPAP->Action = PowerActionSleep;
815             else
816                 pPAP->Action = PowerActionReserved;
817         }
818     case PowerActionShutdown:
819     case PowerActionShutdownReset:
820     case PowerActionShutdownOff:
821     case PowerActionWarmEject:
822         return TRUE;
823     default:
824         SetLastError(ERROR_INVALID_DATA);
825         return FALSE;
826     };
827 }
828 
829 static VOID
830 FixSystemPowerState(PSYSTEM_POWER_STATE Psps, SYSTEM_POWER_CAPABILITIES PowerCaps)
831 {
832 	//Lohnegrim: If the System doesn't support the Powerstates, then we have to change them
833     if (!PowerCaps.SystemS1 && *Psps == PowerSystemSleeping1)
834         *Psps = PowerSystemSleeping2;
835     if (!PowerCaps.SystemS2 && *Psps == PowerSystemSleeping2)
836         *Psps = PowerSystemSleeping3;
837     if (!PowerCaps.SystemS3 && *Psps == PowerSystemSleeping3)
838         *Psps = PowerSystemHibernate;
839     if (!(PowerCaps.SystemS4 && PowerCaps.HiberFilePresent) && *Psps == PowerSystemHibernate)
840         *Psps = PowerSystemSleeping2;
841     if (!PowerCaps.SystemS1 && *Psps == PowerSystemSleeping1)
842         *Psps = PowerSystemSleeping2;
843     if (!PowerCaps.SystemS2 && *Psps == PowerSystemSleeping2)
844         *Psps = PowerSystemSleeping3;
845     if (!PowerCaps.SystemS3 && *Psps == PowerSystemSleeping3)
846         *Psps = PowerSystemShutdown;
847 
848 }
849 
850 BOOLEAN WINAPI
851 ValidatePowerPolicies(PGLOBAL_POWER_POLICY pGPP, PPOWER_POLICY pPP)
852 {
853     SYSTEM_POWER_CAPABILITIES PowerCaps;
854     NTSTATUS ret;
855     BOOLEAN old;
856 
857     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &old);
858     ret = NtPowerInformation(SystemPowerCapabilities, NULL, 0, &PowerCaps, sizeof(PowerCaps));
859     if (ret != STATUS_SUCCESS)
860     {
861         SetLastError(RtlNtStatusToDosError(ret));
862         return FALSE;
863     }
864 
865     if (pGPP)
866     {
867         if (pGPP->user.Revision != 1 || pGPP->mach.Revision != 1)
868         {
869             SetLastError(ERROR_REVISION_MISMATCH);
870             return FALSE;
871         }
872         if (pGPP->mach.LidOpenWakeAc == PowerSystemUnspecified)
873         {
874             SetLastError(ERROR_GEN_FAILURE);
875             return FALSE;
876         }
877         if ((int)pGPP->mach.LidOpenWakeAc > PowerSystemShutdown)
878         {
879             SetLastError(ERROR_GEN_FAILURE);
880             return FALSE;
881         }
882         if (pGPP->mach.LidOpenWakeDc < PowerSystemWorking)
883         {
884             SetLastError(ERROR_GEN_FAILURE);
885             return FALSE;
886         }
887         if ((int)pGPP->mach.LidOpenWakeDc > PowerSystemShutdown)
888         {
889             SetLastError(ERROR_GEN_FAILURE);
890             return FALSE;
891         }
892 		//Lohnegrim: unneeded
893         /*if ((pGPP->mach.LidOpenWakeDc < PowerSystemWorking) || (pGPP->mach.LidOpenWakeDc >= PowerSystemMaximum))
894         {
895             SetLastError(ERROR_GEN_FAILURE);
896             return FALSE;
897         }*/
898         if (!CheckPowerActionPolicy(&pGPP->user.LidCloseAc,PowerCaps))
899         {
900             return FALSE;
901         }
902         if (!CheckPowerActionPolicy(&pGPP->user.LidCloseDc,PowerCaps))
903         {
904             return FALSE;
905         }
906         if (!CheckPowerActionPolicy(&pGPP->user.PowerButtonAc,PowerCaps))
907         {
908             return FALSE;
909         }
910         if (!CheckPowerActionPolicy(&pGPP->user.PowerButtonDc,PowerCaps))
911         {
912             return FALSE;
913         }
914         if (!CheckPowerActionPolicy(&pGPP->user.SleepButtonAc,PowerCaps))
915         {
916             return FALSE;
917         }
918         if (!CheckPowerActionPolicy(&pGPP->user.SleepButtonDc,PowerCaps))
919         {
920             return FALSE;
921         }
922         //Lohnegrim: The BroadcastCapacityResolution presents the Powerlevel in Percent, if invalid set th 100 == FULL
923         if (pGPP->mach.BroadcastCapacityResolution > 100)
924             pGPP->mach.BroadcastCapacityResolution = 100;
925 
926 		//Lohnegrim: I have no idea, if they are really needed, or if they are specific for my System, or what they mean, so I removed them
927         //pGPP->user.DischargePolicy[1].PowerPolicy.EventCode = pGPP->user.DischargePolicy[1].PowerPolicy.EventCode | 0x010000;
928         //pGPP->user.DischargePolicy[2].PowerPolicy.EventCode = pGPP->user.DischargePolicy[2].PowerPolicy.EventCode | 0x020000;
929         //pGPP->user.DischargePolicy[3].PowerPolicy.EventCode = pGPP->user.DischargePolicy[3].PowerPolicy.EventCode | 0x030000;
930 
931         FixSystemPowerState(&pGPP->mach.LidOpenWakeAc,PowerCaps);
932         FixSystemPowerState(&pGPP->mach.LidOpenWakeDc,PowerCaps);
933 
934     }
935 
936     if (pPP)
937     {
938         if (pPP->user.Revision != 1 || pPP->mach.Revision != 1)
939         {
940             SetLastError(ERROR_REVISION_MISMATCH);
941             return FALSE;
942         }
943 
944 		//Lohnegrim: unneeded
945         //if (pPP->mach.MinSleepAc < PowerSystemWorking)
946         //{
947         //    SetLastError(ERROR_GEN_FAILURE);
948         //    return FALSE;
949         //}
950         if ((int)pPP->mach.MinSleepAc >= PowerSystemShutdown)
951         {
952             SetLastError(ERROR_GEN_FAILURE);
953             return FALSE;
954         }
955 		//Lohnegrim: unneeded
956         //if (pPP->mach.MinSleepDc < PowerSystemWorking)
957         //{
958         //    SetLastError(ERROR_GEN_FAILURE);
959         //    return FALSE;
960         //}
961         if ((int)pPP->mach.MinSleepDc >= PowerSystemShutdown)
962         {
963             SetLastError(ERROR_GEN_FAILURE);
964             return FALSE;
965         }
966         if ((int)pPP->mach.ReducedLatencySleepAc == PowerSystemUnspecified)
967         {
968             SetLastError(ERROR_GEN_FAILURE);
969             return FALSE;
970         }
971         if ((int)pPP->mach.ReducedLatencySleepAc > PowerSystemShutdown)
972         {
973             SetLastError(ERROR_GEN_FAILURE);
974             return FALSE;
975         }
976         if ((int)pPP->mach.ReducedLatencySleepDc < PowerSystemWorking)
977         {
978             SetLastError(ERROR_GEN_FAILURE);
979             return FALSE;
980         }
981         if ((int)pPP->mach.ReducedLatencySleepDc > PowerSystemShutdown)
982         {
983             SetLastError(ERROR_GEN_FAILURE);
984             return FALSE;
985         }
986 
987         if (!CheckPowerActionPolicy(&pPP->mach.OverThrottledAc,PowerCaps))
988         {
989             return FALSE;
990         }
991         if (!CheckPowerActionPolicy(&pPP->mach.OverThrottledDc,PowerCaps))
992         {
993             return FALSE;
994         }
995         if (!CheckPowerActionPolicy(&pPP->user.IdleAc,PowerCaps))
996         {
997             return FALSE;
998         }
999         if (!CheckPowerActionPolicy(&pPP->user.IdleDc,PowerCaps))
1000         {
1001             return FALSE;
1002         }
1003         if (pPP->user.MaxSleepAc < PowerSystemWorking)
1004         {
1005             SetLastError(ERROR_GEN_FAILURE);
1006             return FALSE;
1007         }
1008 		//Lohnegrim: unneeded
1009         /*if ((int)pPP->user.MaxSleepAc > PowerSystemShutdown)
1010         {
1011             SetLastError(ERROR_GEN_FAILURE);
1012             return FALSE;
1013         }*/
1014         if (pPP->user.MaxSleepDc < PowerSystemWorking)
1015         {
1016             SetLastError(ERROR_GEN_FAILURE);
1017             return FALSE;
1018         }
1019 		//Lohnegrim: unneeded
1020         /*if ((int)pPP->user.MaxSleepDc >= PowerSystemShutdown)
1021         {
1022             SetLastError(ERROR_GEN_FAILURE);
1023             return FALSE;
1024         }*/
1025         if (PowerCaps.SystemS1)
1026         {
1027             pPP->mach.MinSleepAc=PowerSystemSleeping1;
1028             pPP->mach.MinSleepDc=PowerSystemSleeping1;
1029         }
1030         else if (PowerCaps.SystemS2)
1031         {
1032             pPP->mach.MinSleepAc=PowerSystemSleeping2;
1033             pPP->mach.MinSleepDc=PowerSystemSleeping2;
1034         }
1035         else if (PowerCaps.SystemS3)
1036         {
1037             pPP->mach.MinSleepAc=PowerSystemSleeping3;
1038             pPP->mach.MinSleepDc=PowerSystemSleeping3;
1039         }
1040 
1041         if (PowerCaps.SystemS4)
1042         {
1043             pPP->user.MaxSleepAc=PowerSystemSleeping3;
1044             pPP->user.MaxSleepDc=PowerSystemSleeping3;
1045         }
1046         else if (PowerCaps.SystemS3)
1047         {
1048             pPP->user.MaxSleepAc=PowerSystemSleeping2;
1049             pPP->user.MaxSleepDc=PowerSystemSleeping2;
1050         }
1051         else if (PowerCaps.SystemS1)
1052         {
1053             pPP->user.MaxSleepAc=PowerSystemSleeping1;
1054             pPP->user.MaxSleepDc=PowerSystemSleeping1;
1055         }
1056 		//Lohnegrim: I don't know where to get this info from, so I removed it
1057         //pPP->user.OptimizeForPowerAc=TRUE;
1058         //pPP->user.OptimizeForPowerDc=TRUE;
1059 
1060         FixSystemPowerState(&pPP->mach.ReducedLatencySleepAc,PowerCaps);
1061         FixSystemPowerState(&pPP->mach.ReducedLatencySleepDc,PowerCaps);
1062     }
1063 
1064     SetLastError(ERROR_SUCCESS);
1065     return TRUE;
1066 }
1067 
1068 BOOLEAN WINAPI WritePwrPolicy(PUINT puiID, PPOWER_POLICY pPowerPolicy)
1069 {
1070     WCHAR Buf[MAX_PATH];
1071     HKEY hKey;
1072 
1073     swprintf(Buf, L"Control Panel\\PowerCfg\\PowerPolicies\\%i", *puiID);
1074 
1075     if (RegCreateKey(HKEY_CURRENT_USER, Buf, &hKey) != ERROR_SUCCESS)
1076         return FALSE;
1077 
1078     RegSetValueExW(hKey, szPolicies, 0, REG_BINARY, (const unsigned char *)&pPowerPolicy->user, sizeof(USER_POWER_POLICY));
1079     RegCloseKey(hKey);
1080 
1081     swprintf(Buf, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg\\PowerPolicies\\%i", *puiID);
1082 
1083     if (RegCreateKey(HKEY_LOCAL_MACHINE, Buf, &hKey) != ERROR_SUCCESS)
1084         return FALSE;
1085 
1086     RegSetValueExW(hKey, szPolicies, 0, REG_BINARY, (const unsigned char *)&pPowerPolicy->mach, sizeof(MACHINE_POWER_POLICY));
1087     RegCloseKey(hKey);
1088 
1089     return TRUE;
1090 }
1091 
1092 BOOL WINAPI
1093 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1094 {
1095     switch(fdwReason)
1096     {
1097         case DLL_PROCESS_ATTACH:
1098         {
1099             HKEY hKey;
1100             LONG Err;
1101 
1102             DisableThreadLibraryCalls(hinstDLL);
1103 
1104             Err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szPowerCfgSubKey, 0, KEY_READ, &hKey);
1105 
1106             if (Err != ERROR_SUCCESS)
1107             {
1108                 TRACE("Couldn't open registry key HKLM\\%s, using some sane(?) defaults\n", debugstr_w(szPowerCfgSubKey));
1109             }
1110             else
1111             {
1112                 WCHAR lpValue[MAX_PATH];
1113                 DWORD cbValue = sizeof(lpValue);
1114 
1115                 Err = RegQueryValueExW(hKey, szLastID, 0, 0, (BYTE*)lpValue, &cbValue);
1116                 if (Err == ERROR_SUCCESS)
1117                 {
1118                     g_LastID = _wtoi(lpValue);
1119                 }
1120                 else
1121                 {
1122                     TRACE("Couldn't open registry entry HKLM\\%s\\LastID, using some sane(?) defaults\n", debugstr_w(szPowerCfgSubKey));
1123                 }
1124                 RegCloseKey(hKey);
1125             }
1126 
1127             PPRegSemaphore = CreateSemaphoreW(NULL, 1, 1, szSemaphoreName);
1128             if (PPRegSemaphore == NULL)
1129             {
1130                 ERR("Couldn't create Semaphore: %d\n", GetLastError());
1131                 return FALSE;
1132             }
1133             break;
1134         }
1135         case DLL_PROCESS_DETACH:
1136             CloseHandle(PPRegSemaphore);
1137             break;
1138     }
1139     return TRUE;
1140 }
1141