Load correct screensaver's name patch by piulachs (marc dot piulachs at codexchange...
[reactos.git] / reactos / dll / cpl / desk / screensaver.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Display Control Panel
4 * FILE: dll/cpl/desk/screensaver.c
5 * PURPOSE: Screen saver property page
6 *
7 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
8 * Ged Murphy (gedmurphy@reactos.org)
9 */
10
11 #include "desk.h"
12
13 #define MAX_SCREENSAVERS 100
14
15 typedef struct
16 {
17 BOOL bIsScreenSaver; /* Is this background a wallpaper */
18 TCHAR szFilename[MAX_PATH];
19 TCHAR szDisplayName[256];
20 } ScreenSaverItem;
21
22
23 typedef struct _GLOBAL_DATA
24 {
25 ScreenSaverItem ScreenSaverItems[MAX_SCREENSAVERS];
26 PROCESS_INFORMATION PrevWindowPi;
27 int Selection;
28 } GLOBAL_DATA, *PGLOBAL_DATA;
29
30
31 static LPTSTR
32 GetCurrentScreenSaverValue(LPTSTR lpValue)
33 {
34 HKEY hKey;
35 LPTSTR lpBuf = NULL;
36 DWORD BufSize, Type = REG_SZ;
37 LONG Ret;
38
39 Ret = RegOpenKeyEx(HKEY_CURRENT_USER,
40 _T("Control Panel\\Desktop"),
41 0,
42 KEY_READ,
43 &hKey);
44 if (Ret != ERROR_SUCCESS)
45 return NULL;
46
47 Ret = RegQueryValueEx(hKey,
48 lpValue,
49 0,
50 &Type,
51 NULL,
52 &BufSize);
53 if (Ret == ERROR_SUCCESS)
54 {
55 lpBuf = HeapAlloc(GetProcessHeap(),
56 0,
57 BufSize);
58 if (lpBuf)
59 {
60 Ret = RegQueryValueEx(hKey,
61 lpValue,
62 0,
63 &Type,
64 (LPBYTE)lpBuf,
65 &BufSize);
66 if (Ret != ERROR_SUCCESS)
67 lpBuf = NULL;
68 }
69 }
70
71 RegCloseKey(hKey);
72
73 return lpBuf;
74 }
75
76
77 static VOID
78 SelectionChanged(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
79 {
80 HWND hwndCombo;
81 BOOL bEnable;
82 INT i;
83
84 hwndCombo = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
85
86 i = (INT)SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
87 i = (INT)SendMessage(hwndCombo, CB_GETITEMDATA, i, 0);
88
89 pGlobalData->Selection = i;
90
91 bEnable = (i != 0);
92
93 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_SETTINGS), bEnable);
94 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TESTSC), bEnable);
95 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_USEPASSCHK), bEnable);
96 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TIMEDELAY), bEnable);
97 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TIME), bEnable);
98 EnableWindow(GetDlgItem(hwndDlg, IDC_WAITTEXT), bEnable);
99 EnableWindow(GetDlgItem(hwndDlg, IDC_MINTEXT), bEnable);
100 }
101
102
103 static VOID
104 SetScreenSaverPreviewBox(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
105 {
106 HWND hPreview = GetDlgItem(hwndDlg, IDC_SCREENS_PREVIEW);
107 STARTUPINFO si;
108 TCHAR szCmdline[2048];
109
110 /* kill off the previous preview process*/
111 if (pGlobalData->PrevWindowPi.hProcess)
112 {
113 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
114 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
115 CloseHandle(pGlobalData->PrevWindowPi.hThread);
116 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
117 }
118
119 if (pGlobalData->Selection > 0)
120 {
121 _stprintf(szCmdline,
122 _T("%s /p %u"),
123 pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename,
124 hPreview);
125
126 ZeroMemory(&si, sizeof(si));
127 si.cb = sizeof(si);
128 ZeroMemory(&pGlobalData->PrevWindowPi, sizeof(pGlobalData->PrevWindowPi));
129
130 if (!CreateProcess(NULL,
131 szCmdline,
132 NULL,
133 NULL,
134 FALSE,
135 0,
136 NULL,
137 NULL,
138 &si,
139 &pGlobalData->PrevWindowPi))
140 {
141 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
142 }
143 }
144 }
145
146 static BOOL
147 WaitForSettingsDialog(HWND hwndDlg,
148 HANDLE hProcess)
149 {
150 while (TRUE)
151 {
152 DWORD Ret;
153 MSG msg;
154
155 while (PeekMessage(&msg,
156 NULL,
157 0,
158 0,
159 PM_REMOVE))
160 {
161 if (msg.message == WM_QUIT)
162 return FALSE;
163
164 if (IsDialogMessage(hwndDlg, &msg))
165 {
166 TranslateMessage(&msg);
167 DispatchMessage(&msg);
168 }
169 }
170
171 Ret = MsgWaitForMultipleObjects(1,
172 &hProcess,
173 FALSE,
174 INFINITE,
175 QS_ALLINPUT);
176 if (Ret == (WAIT_OBJECT_0))
177 {
178 return TRUE;
179 }
180 }
181 }
182
183
184 static VOID
185 ScreensaverConfig(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
186 {
187 /*
188 /c:<hwnd> Run configuration, hwnd is handle of calling window
189 */
190
191 TCHAR szCmdline[2048];
192 STARTUPINFO si;
193 PROCESS_INFORMATION pi;
194
195 if (pGlobalData->Selection < 1)
196 return;
197
198 _stprintf(szCmdline,
199 _T("%s /c:%u"),
200 pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename,
201 hwndDlg);
202
203 ZeroMemory(&si, sizeof(si));
204 si.cb = sizeof(si);
205 ZeroMemory(&pi, sizeof(pi));
206 if(CreateProcess(NULL,
207 szCmdline,
208 NULL,
209 NULL,
210 FALSE,
211 0,
212 NULL,
213 NULL,
214 &si,
215 &pi))
216 {
217 /* kill off the previous preview process */
218 if (pGlobalData->PrevWindowPi.hProcess)
219 {
220 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
221 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
222 CloseHandle(pGlobalData->PrevWindowPi.hThread);
223 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
224 }
225
226 if (WaitForSettingsDialog(hwndDlg, pi.hProcess))
227 SetScreenSaverPreviewBox(hwndDlg, pGlobalData);
228 }
229 }
230
231
232 static VOID
233 ScreensaverPreview(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
234 {
235 /*
236 /s Run normal
237 */
238
239 WCHAR szCmdline[2048];
240 STARTUPINFO si;
241 PROCESS_INFORMATION pi;
242
243 if (pGlobalData->Selection < 1)
244 return;
245
246 /* kill off the previous preview process*/
247 if (pGlobalData->PrevWindowPi.hProcess)
248 {
249 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
250 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
251 CloseHandle(pGlobalData->PrevWindowPi.hThread);
252 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
253 }
254
255 _stprintf(szCmdline,
256 _T("%s /s"),
257 pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename);
258
259 ZeroMemory(&si, sizeof(si));
260 si.cb = sizeof(si);
261 ZeroMemory(&pi, sizeof(pi));
262 if(CreateProcess(NULL,
263 szCmdline,
264 NULL,
265 NULL,
266 FALSE,
267 0,
268 NULL,
269 NULL,
270 &si,
271 &pi))
272 {
273 WaitForSingleObject(pi.hProcess, INFINITE);
274 CloseHandle(pi.hProcess);
275 CloseHandle(pi.hThread);
276 }
277 }
278
279
280 static VOID
281 CheckRegScreenSaverIsSecure(HWND hwndDlg)
282 {
283 HKEY hKey;
284 TCHAR szBuffer[2];
285 DWORD bufferSize = sizeof(szBuffer);
286 DWORD varType = REG_SZ;
287 LONG result;
288
289 if (RegOpenKeyEx(HKEY_CURRENT_USER,
290 _T("Control Panel\\Desktop"),
291 0,
292 KEY_ALL_ACCESS,
293 &hKey) == ERROR_SUCCESS)
294 {
295 result = RegQueryValueEx(hKey,
296 _T("ScreenSaverIsSecure"),
297 0,
298 &varType,
299 (LPBYTE)szBuffer,
300 &bufferSize);
301 RegCloseKey(hKey);
302
303 if (result == ERROR_SUCCESS)
304 {
305 if (_ttoi(szBuffer) == 1)
306 {
307 SendDlgItemMessage(hwndDlg,
308 IDC_SCREENS_USEPASSCHK,
309 BM_SETCHECK,
310 (WPARAM)BST_CHECKED,
311 0);
312 return;
313 }
314 }
315
316 SendDlgItemMessage(hwndDlg,
317 IDC_SCREENS_USEPASSCHK,
318 BM_SETCHECK,
319 (WPARAM)BST_UNCHECKED,
320 0);
321 }
322 }
323
324
325 static VOID
326 AddScreenSavers(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
327 {
328 HWND hwndScreenSavers = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
329 WIN32_FIND_DATA fd;
330 HANDLE hFind;
331 TCHAR szSearchPath[MAX_PATH];
332 INT i;
333 int ScreenSaverCount = 0;
334 ScreenSaverItem *ScreenSaverItem = NULL;
335 HANDLE hModule = NULL;
336
337 /* Add the "None" item */
338 ScreenSaverItem = &pGlobalData->ScreenSaverItems[ScreenSaverCount];
339
340 ScreenSaverItem->bIsScreenSaver = FALSE;
341
342 LoadString(hApplet,
343 IDS_NONE,
344 ScreenSaverItem->szDisplayName,
345 sizeof(ScreenSaverItem->szDisplayName) / sizeof(TCHAR));
346
347 i = SendMessage(hwndScreenSavers,
348 CB_ADDSTRING,
349 0,
350 (LPARAM)ScreenSaverItem->szDisplayName);
351
352 SendMessage(hwndScreenSavers,
353 CB_SETITEMDATA,
354 i,
355 (LPARAM)ScreenSaverCount);
356
357 ScreenSaverCount++;
358
359 /* Add all the screensavers in the C:\ReactOS\System32 directory. */
360
361 GetSystemDirectory(szSearchPath, MAX_PATH);
362 _tcscat(szSearchPath, TEXT("\\*.scr"));
363
364 hFind = FindFirstFile(szSearchPath, &fd);
365 while (ScreenSaverCount < MAX_SCREENSAVERS-1 &&
366 hFind != INVALID_HANDLE_VALUE)
367 {
368 /* Don't add any hidden screensavers */
369 if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0)
370 {
371 TCHAR filename[MAX_PATH];
372
373 GetSystemDirectory(filename, MAX_PATH);
374
375 _tcscat(filename, TEXT("\\"));
376 _tcscat(filename, fd.cFileName);
377
378 ScreenSaverItem = &pGlobalData->ScreenSaverItems[ScreenSaverCount];
379
380 ScreenSaverItem->bIsScreenSaver = TRUE;
381
382 hModule = LoadLibraryEx(filename,
383 NULL,
384 DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
385 if (hModule)
386 {
387 LoadString(hModule,
388 1,
389 ScreenSaverItem->szDisplayName,
390 sizeof(ScreenSaverItem->szDisplayName) / sizeof(TCHAR));
391 FreeLibrary(hModule);
392 }
393 else
394 {
395 _tcscpy(ScreenSaverItem->szDisplayName, _T("Unknown"));
396 }
397
398 _tcscpy(ScreenSaverItem->szFilename, filename);
399
400 i = SendMessage(hwndScreenSavers,
401 CB_ADDSTRING,
402 0,
403 (LPARAM)ScreenSaverItem->szDisplayName);
404
405 SendMessage(hwndScreenSavers,
406 CB_SETITEMDATA,
407 i,
408 (LPARAM)ScreenSaverCount);
409
410 ScreenSaverCount++;
411 }
412
413 if (!FindNextFile(hFind, &fd))
414 hFind = INVALID_HANDLE_VALUE;
415 }
416 }
417
418
419 static VOID
420 SetScreenSaver(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
421 {
422 HKEY regKey;
423
424 if (RegOpenKeyEx(HKEY_CURRENT_USER,
425 _T("Control Panel\\Desktop"),
426 0,
427 KEY_ALL_ACCESS,
428 &regKey) == ERROR_SUCCESS)
429 {
430 INT Time;
431 BOOL bRet;
432 TCHAR szTime[256], Sec;
433 UINT Ret;
434
435 /* set the screensaver */
436 if (pGlobalData->ScreenSaverItems[pGlobalData->Selection].bIsScreenSaver)
437 {
438 RegSetValueEx(regKey,
439 _T("SCRNSAVE.EXE"),
440 0,
441 REG_SZ,
442 (PBYTE)pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename,
443 _tcslen(pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename) * sizeof(TCHAR));
444 }
445 else
446 {
447 /* Windows deletes the value if no screensaver is set */
448 RegDeleteValue(regKey, _T("SCRNSAVE.EXE"));
449 }
450
451 /* set the screensaver time delay */
452 Time = GetDlgItemInt(hwndDlg,
453 IDC_SCREENS_TIMEDELAY,
454 &bRet,
455 FALSE);
456 if (Time == 0)
457 Time = 60;
458 else
459 Time *= 60;
460
461 _itot(Time, szTime, 10);
462 RegSetValueEx(regKey,
463 _T("ScreenSaveTimeOut"),
464 0,
465 REG_SZ,
466 (PBYTE)szTime,
467 _tcslen(szTime) * sizeof(TCHAR));
468
469 /* set the secure value */
470 Ret = SendDlgItemMessage(hwndDlg,
471 IDC_SCREENS_USEPASSCHK,
472 BM_GETCHECK,
473 0,
474 0);
475 Sec = (Ret == BST_CHECKED) ? _T('1') : _T('0');
476 RegSetValueEx(regKey,
477 _T("ScreenSaverIsSecure"),
478 0,
479 REG_SZ,
480 (PBYTE)&Sec,
481 sizeof(TCHAR));
482
483 RegCloseKey(regKey);
484 }
485 }
486
487
488 static BOOL
489 OnInitDialog(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
490 {
491 LPTSTR lpCurSs;
492 HWND hwndSSCombo = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
493 INT Num;
494
495 pGlobalData = HeapAlloc(GetProcessHeap(),
496 HEAP_ZERO_MEMORY,
497 sizeof(GLOBAL_DATA));
498 if (!pGlobalData)
499 {
500 EndDialog(hwndDlg, -1);
501 return FALSE;
502 }
503
504 SetWindowLongPtr(hwndDlg,
505 DWLP_USER,
506 (LONG_PTR)pGlobalData);
507
508 pGlobalData->Selection = -1;
509
510 SendDlgItemMessage(hwndDlg,
511 IDC_SCREENS_TIME,
512 UDM_SETRANGE,
513 0,
514 MAKELONG
515 ((short) 240, (short) 1));
516
517 AddScreenSavers(hwndDlg,
518 pGlobalData);
519
520 CheckRegScreenSaverIsSecure(hwndDlg);
521
522 /* set the current screensaver in the combo box */
523 lpCurSs = GetCurrentScreenSaverValue(_T("SCRNSAVE.EXE"));
524 if (lpCurSs)
525 {
526 BOOL bFound = FALSE;
527 INT i;
528
529 for (i = 0; i < MAX_SCREENSAVERS; i++)
530 {
531 if (!_tcscmp(lpCurSs, pGlobalData->ScreenSaverItems[i].szFilename))
532 {
533 bFound = TRUE;
534 break;
535 }
536 }
537
538 if (bFound)
539 {
540 Num = SendMessage(hwndSSCombo,
541 CB_FINDSTRINGEXACT,
542 -1,
543 (LPARAM)pGlobalData->ScreenSaverItems[i].szDisplayName);
544 if (Num != CB_ERR)
545 SendMessage(hwndSSCombo,
546 CB_SETCURSEL,
547 Num,
548 0);
549 }
550 else
551 {
552 SendMessage(hwndSSCombo,
553 CB_SETCURSEL,
554 0,
555 0);
556 }
557
558 HeapFree(GetProcessHeap(),
559 0,
560 lpCurSs);
561 }
562 else
563 {
564 /* set screensaver to (none) */
565 SendMessage(hwndSSCombo,
566 CB_SETCURSEL,
567 0,
568 0);
569 }
570
571 /* set the current timeout */
572 lpCurSs = GetCurrentScreenSaverValue(_T("ScreenSaveTimeOut"));
573 if (lpCurSs)
574 {
575 UINT Time = _ttoi(lpCurSs);
576
577 Time /= 60;
578
579 SendDlgItemMessage(hwndDlg,
580 IDC_SCREENS_TIME,
581 UDM_SETPOS32,
582 0,
583 Time);
584
585 HeapFree(GetProcessHeap(),
586 0,
587 lpCurSs);
588
589 }
590
591 SelectionChanged(hwndDlg,
592 pGlobalData);
593
594 return TRUE;
595 }
596
597
598 INT_PTR CALLBACK
599 ScreenSaverPageProc(HWND hwndDlg,
600 UINT uMsg,
601 WPARAM wParam,
602 LPARAM lParam)
603 {
604 PGLOBAL_DATA pGlobalData;
605
606 pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
607
608 switch (uMsg)
609 {
610 case WM_INITDIALOG:
611 {
612 OnInitDialog(hwndDlg, pGlobalData);
613 break;
614 }
615
616 case WM_DESTROY:
617 {
618 if (pGlobalData->PrevWindowPi.hProcess)
619 {
620 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
621 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
622 CloseHandle(pGlobalData->PrevWindowPi.hThread);
623 }
624 HeapFree(GetProcessHeap(),
625 0,
626 pGlobalData);
627 break;
628 }
629
630 case WM_ENDSESSION:
631 {
632 SetScreenSaverPreviewBox(hwndDlg,
633 pGlobalData);
634 break;
635 }
636
637 case WM_COMMAND:
638 {
639 DWORD controlId = LOWORD(wParam);
640 DWORD command = HIWORD(wParam);
641
642 switch (controlId)
643 {
644 case IDC_SCREENS_LIST:
645 {
646 if (HIWORD(wParam) == CBN_SELCHANGE)
647 {
648 SelectionChanged(hwndDlg, pGlobalData);
649 SetScreenSaverPreviewBox(hwndDlg, pGlobalData);
650 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
651 }
652 break;
653 }
654
655 case IDC_SCREENS_TIMEDELAY:
656 {
657 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
658 break;
659 }
660
661 case IDC_SCREENS_POWER_BUTTON: // Start Powercfg.Cpl
662 {
663 if (command == BN_CLICKED)
664 WinExec("rundll32 shell32.dll,Control_RunDLL powercfg.cpl",SW_SHOWNORMAL);
665 break;
666 }
667
668 case IDC_SCREENS_TESTSC: // Screensaver Preview
669 {
670 if(command == BN_CLICKED)
671 {
672 ScreensaverPreview(hwndDlg, pGlobalData);
673 SetScreenSaverPreviewBox(hwndDlg, pGlobalData);
674 }
675 break;
676 }
677
678 case IDC_SCREENS_SETTINGS: // Screensaver Settings
679 {
680 if (command == BN_CLICKED)
681 ScreensaverConfig(hwndDlg, pGlobalData);
682 break;
683 }
684
685 case IDC_SCREENS_USEPASSCHK: // Screensaver Is Secure
686 {
687 if (command == BN_CLICKED)
688 {
689 MessageBox(NULL, TEXT("Feature not yet implemented"), TEXT("Sorry"), MB_OK);
690 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
691 }
692 break;
693 }
694 }
695 break;
696 }
697
698 case WM_NOTIFY:
699 {
700 LPNMHDR lpnm = (LPNMHDR)lParam;
701
702 switch(lpnm->code)
703 {
704 case PSN_APPLY:
705 {
706 SetScreenSaver(hwndDlg, pGlobalData);
707 return TRUE;
708 }
709
710 case PSN_SETACTIVE:
711 {
712 /* activate screen saver support */
713 SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_SENDCHANGE);
714 SetScreenSaverPreviewBox(hwndDlg, pGlobalData);
715 break;
716 }
717
718 case PSN_KILLACTIVE:
719 {
720 /* Disable screensaver support */
721 SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, FALSE, 0, SPIF_SENDCHANGE);
722 if (pGlobalData->PrevWindowPi.hProcess)
723 {
724 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
725 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
726 CloseHandle(pGlobalData->PrevWindowPi.hThread);
727 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
728 }
729 break;
730 }
731 }
732 }
733 break;
734 }
735
736 return FALSE;
737 }