xref: /reactos/dll/cpl/desk/screensaver.c (revision f7d612f3)
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 static const TCHAR szPreviewWndClass[] = TEXT("SSDemoParent");
16 
17 typedef struct
18 {
19     BOOL  bIsScreenSaver; /* Is this a valid screensaver */
20     TCHAR szFilename[MAX_PATH];
21     TCHAR szDisplayName[256];
22 } SCREEN_SAVER_ITEM;
23 
24 
25 typedef struct _DATA
26 {
27     SCREEN_SAVER_ITEM   ScreenSaverItems[MAX_SCREENSAVERS];
28     PROCESS_INFORMATION PrevWindowPi;
29     int                 Selection;
30     WNDPROC             OldPreviewProc;
31     UINT                ScreenSaverCount;
32     HWND                ScreenSaverPreviewParent;
33 } DATA, *PDATA;
34 
35 
36 static LPTSTR
37 GetCurrentScreenSaverValue(LPTSTR lpValue)
38 {
39     HKEY hKey;
40     LPTSTR lpBuf = NULL;
41     DWORD BufSize, Type = REG_SZ;
42     LONG Ret;
43 
44     Ret = RegOpenKeyEx(HKEY_CURRENT_USER,
45                        _T("Control Panel\\Desktop"),
46                        0,
47                        KEY_READ,
48                        &hKey);
49     if (Ret != ERROR_SUCCESS)
50         return NULL;
51 
52     Ret = RegQueryValueEx(hKey,
53                           lpValue,
54                           0,
55                           &Type,
56                           NULL,
57                           &BufSize);
58     if (Ret == ERROR_SUCCESS)
59     {
60         lpBuf = HeapAlloc(GetProcessHeap(), 0, BufSize);
61         if (lpBuf)
62         {
63             Ret = RegQueryValueEx(hKey,
64                                   lpValue,
65                                   0,
66                                   &Type,
67                                   (LPBYTE)lpBuf,
68                                   &BufSize);
69             if (Ret != ERROR_SUCCESS)
70             {
71                 HeapFree(GetProcessHeap(), 0, lpBuf);
72                 lpBuf = NULL;
73             }
74         }
75     }
76 
77     RegCloseKey(hKey);
78 
79     return lpBuf;
80 }
81 
82 
83 static VOID
84 SelectionChanged(HWND hwndDlg, PDATA pData)
85 {
86     HWND hwndCombo;
87     BOOL bEnable;
88     INT i;
89 
90     hwndCombo = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
91 
92     i = (INT)SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
93     i = (INT)SendMessage(hwndCombo, CB_GETITEMDATA, i, 0);
94 
95     pData->Selection = i;
96 
97     bEnable = (i != 0);
98 
99     EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_SETTINGS), bEnable);
100     EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TESTSC), bEnable);
101     EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_USEPASSCHK), bEnable);
102     EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TIMEDELAY), bEnable);
103     EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TIME), bEnable);
104     EnableWindow(GetDlgItem(hwndDlg, IDC_WAITTEXT), bEnable);
105     EnableWindow(GetDlgItem(hwndDlg, IDC_MINTEXT), bEnable);
106 }
107 
108 
109 LRESULT CALLBACK
110 RedrawSubclassProc(HWND hwndDlg,
111                    UINT uMsg,
112                    WPARAM wParam,
113                    LPARAM lParam)
114 {
115     HWND hwnd;
116     PDATA pData;
117     LRESULT Ret = FALSE;
118 
119     pData = (PDATA)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
120     if (!pData)
121         return Ret;
122 
123     Ret = CallWindowProc(pData->OldPreviewProc, hwndDlg, uMsg, wParam, lParam);
124 
125     if (uMsg == WM_PAINT)
126     {
127         hwnd = pData->ScreenSaverPreviewParent;
128         if (hwnd)
129             RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
130     }
131 
132     return Ret;
133 }
134 
135 
136 static VOID
137 ShowScreenSaverPreview(IN LPDRAWITEMSTRUCT draw, IN PDATA pData)
138 {
139     HBRUSH hBrush;
140     HDC hDC;
141     HGDIOBJ hOldObj;
142     RECT rcItem = {
143         MONITOR_LEFT,
144         MONITOR_TOP,
145         MONITOR_RIGHT,
146         MONITOR_BOTTOM
147     };
148 
149     hDC = CreateCompatibleDC(draw->hDC);
150     hOldObj = SelectObject(hDC, g_GlobalData.hMonitorBitmap);
151 
152     if (!IsWindowVisible(pData->ScreenSaverPreviewParent))
153     {
154         /* FIXME: Draw static bitmap inside monitor. */
155         hBrush = CreateSolidBrush(g_GlobalData.desktop_color);
156         FillRect(hDC, &rcItem, hBrush);
157         DeleteObject(hBrush);
158     }
159 
160     GdiTransparentBlt(draw->hDC,
161                       draw->rcItem.left, draw->rcItem.top,
162                       draw->rcItem.right - draw->rcItem.left + 1,
163                       draw->rcItem.bottom - draw->rcItem.top + 1,
164                       hDC,
165                       0, 0,
166                       g_GlobalData.bmMonWidth, g_GlobalData.bmMonHeight,
167                       MONITOR_ALPHA);
168 
169     SelectObject(hDC, hOldObj);
170     DeleteDC(hDC);
171 }
172 
173 
174 /*
175  * /p:<hwnd>    Run preview, hwnd is handle of calling window
176  */
177 static VOID
178 SetScreenSaverPreviewBox(HWND hwndDlg, PDATA pData)
179 {
180     HWND hPreview = pData->ScreenSaverPreviewParent;
181     HRESULT hr;
182     STARTUPINFO si;
183     TCHAR szCmdline[2048];
184 
185     /* Kill off the previous preview process */
186     if (pData->PrevWindowPi.hProcess)
187     {
188         TerminateProcess(pData->PrevWindowPi.hProcess, 0);
189         CloseHandle(pData->PrevWindowPi.hProcess);
190         CloseHandle(pData->PrevWindowPi.hThread);
191         pData->PrevWindowPi.hThread = pData->PrevWindowPi.hProcess = NULL;
192     }
193     ShowWindow(pData->ScreenSaverPreviewParent, SW_HIDE);
194 
195     if (pData->Selection < 1)
196         return;
197 
198     hr = StringCbPrintf(szCmdline, sizeof(szCmdline),
199                         TEXT("%s /p %Iu"),
200                         pData->ScreenSaverItems[pData->Selection].szFilename,
201                         (ULONG_PTR)hPreview);
202     if (FAILED(hr))
203         return;
204 
205     ZeroMemory(&si, sizeof(si));
206     si.cb = sizeof(si);
207     ZeroMemory(&pData->PrevWindowPi, sizeof(pData->PrevWindowPi));
208 
209     ShowWindow(pData->ScreenSaverPreviewParent, SW_SHOW);
210 
211     if (!CreateProcess(NULL,
212                        szCmdline,
213                        NULL,
214                        NULL,
215                        FALSE,
216                        0,
217                        NULL,
218                        NULL,
219                        &si,
220                        &pData->PrevWindowPi))
221     {
222         pData->PrevWindowPi.hThread = pData->PrevWindowPi.hProcess = NULL;
223     }
224 }
225 
226 static BOOL
227 WaitForSettingsDialog(HWND hwndDlg,
228                       HANDLE hProcess)
229 {
230     DWORD dwResult;
231     MSG msg;
232 
233     while (TRUE)
234     {
235         dwResult = MsgWaitForMultipleObjects(1,
236                                              &hProcess,
237                                              FALSE,
238                                              INFINITE,
239                                              QS_ALLINPUT);
240         if (dwResult == WAIT_OBJECT_0 + 1)
241         {
242             if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
243             {
244                 if (msg.message == WM_QUIT)
245                 {
246                     return FALSE;
247                 }
248                 if (IsDialogMessage(hwndDlg, &msg))
249                 {
250                     TranslateMessage(&msg);
251                     DispatchMessage(&msg);
252                 }
253             }
254         }
255         else if (dwResult == WAIT_OBJECT_0)
256         {
257             return TRUE;
258         }
259         else
260         {
261             return FALSE;
262         }
263     }
264 }
265 
266 
267 /*
268  * /c:<hwnd>    Run configuration, hwnd is handle of calling window
269  */
270 static VOID
271 ScreenSaverConfig(HWND hwndDlg, PDATA pData)
272 {
273     HRESULT hr;
274     STARTUPINFO si;
275     PROCESS_INFORMATION pi;
276     TCHAR szCmdline[2048];
277 
278     if (pData->Selection < 1)
279         return;
280 
281     hr = StringCbPrintf(szCmdline, sizeof(szCmdline),
282                         TEXT("%s /c:%Iu"),
283                         pData->ScreenSaverItems[pData->Selection].szFilename,
284                         (ULONG_PTR)hwndDlg);
285     if (FAILED(hr))
286         return;
287 
288     ZeroMemory(&si, sizeof(si));
289     si.cb = sizeof(si);
290     ZeroMemory(&pi, sizeof(pi));
291     if (CreateProcess(NULL,
292                       szCmdline,
293                       NULL,
294                       NULL,
295                       FALSE,
296                       0,
297                       NULL,
298                       NULL,
299                       &si,
300                       &pi))
301     {
302         /* Kill off the previous preview process */
303         if (pData->PrevWindowPi.hProcess)
304         {
305             TerminateProcess(pData->PrevWindowPi.hProcess, 0);
306             CloseHandle(pData->PrevWindowPi.hProcess);
307             CloseHandle(pData->PrevWindowPi.hThread);
308             pData->PrevWindowPi.hThread = pData->PrevWindowPi.hProcess = NULL;
309         }
310 
311         if (WaitForSettingsDialog(hwndDlg, pi.hProcess))
312             SetScreenSaverPreviewBox(hwndDlg, pData);
313 
314         CloseHandle(pi.hProcess);
315         CloseHandle(pi.hThread);
316     }
317 }
318 
319 /*
320  * /s   Run normal
321  */
322 static VOID
323 ScreenSaverPreview(HWND hwndDlg, PDATA pData)
324 {
325     HRESULT hr;
326     STARTUPINFO si;
327     PROCESS_INFORMATION pi;
328     TCHAR szCmdline[2048];
329 
330     if (pData->Selection < 1)
331         return;
332 
333     /* Kill off the previous preview process */
334     if (pData->PrevWindowPi.hProcess)
335     {
336         TerminateProcess(pData->PrevWindowPi.hProcess, 0);
337         CloseHandle(pData->PrevWindowPi.hProcess);
338         CloseHandle(pData->PrevWindowPi.hThread);
339         pData->PrevWindowPi.hThread = pData->PrevWindowPi.hProcess = NULL;
340     }
341 
342     hr = StringCbPrintf(szCmdline, sizeof(szCmdline),
343                         TEXT("%s /s"),
344                         pData->ScreenSaverItems[pData->Selection].szFilename);
345     if (FAILED(hr))
346         return;
347 
348     ZeroMemory(&si, sizeof(si));
349     si.cb = sizeof(si);
350     ZeroMemory(&pi, sizeof(pi));
351     if (CreateProcess(NULL,
352                       szCmdline,
353                       NULL,
354                       NULL,
355                       FALSE,
356                       0,
357                       NULL,
358                       NULL,
359                       &si,
360                       &pi))
361     {
362         WaitForSingleObject(pi.hProcess, INFINITE);
363         CloseHandle(pi.hProcess);
364         CloseHandle(pi.hThread);
365     }
366 }
367 
368 
369 static VOID
370 CheckRegScreenSaverIsSecure(HWND hwndDlg)
371 {
372     HKEY hKey;
373     TCHAR szBuffer[2];
374     DWORD bufferSize = sizeof(szBuffer);
375     DWORD varType = REG_SZ;
376     LONG result;
377 
378     if (RegOpenKeyEx(HKEY_CURRENT_USER,
379                      _T("Control Panel\\Desktop"),
380                      0,
381                      KEY_ALL_ACCESS,
382                      &hKey) == ERROR_SUCCESS)
383     {
384         result = RegQueryValueEx(hKey,
385                                 _T("ScreenSaverIsSecure"),
386                                 0,
387                                 &varType,
388                                 (LPBYTE)szBuffer,
389                                 &bufferSize);
390         RegCloseKey(hKey);
391 
392         if (result == ERROR_SUCCESS)
393         {
394             if (_ttoi(szBuffer) == 1)
395             {
396                 SendDlgItemMessage(hwndDlg,
397                                    IDC_SCREENS_USEPASSCHK,
398                                    BM_SETCHECK,
399                                    (WPARAM)BST_CHECKED,
400                                    0);
401                 return;
402             }
403         }
404 
405         SendDlgItemMessage(hwndDlg,
406                            IDC_SCREENS_USEPASSCHK,
407                            BM_SETCHECK,
408                            (WPARAM)BST_UNCHECKED,
409                            0);
410     }
411 }
412 
413 
414 static BOOL
415 AddScreenSaverItem(
416     _In_ HWND hwndScreenSavers,
417     _In_ PDATA pData,
418     _In_ SCREEN_SAVER_ITEM* ScreenSaverItem)
419 {
420     UINT i;
421 
422     if (pData->ScreenSaverCount >= MAX_SCREENSAVERS)
423         return FALSE;
424 
425     i = SendMessage(hwndScreenSavers,
426                     CB_ADDSTRING,
427                     0,
428                     (LPARAM)ScreenSaverItem->szDisplayName);
429     if ((i == CB_ERR) || (i == CB_ERRSPACE))
430         return FALSE;
431 
432     SendMessage(hwndScreenSavers,
433                 CB_SETITEMDATA,
434                 i,
435                 (LPARAM)pData->ScreenSaverCount);
436 
437     pData->ScreenSaverCount++;
438     return TRUE;
439 }
440 
441 static BOOL
442 AddScreenSaver(
443     _In_ HWND hwndScreenSavers,
444     _In_ PDATA pData,
445     _In_ LPCTSTR pszFilePath,
446     _In_ LPCTSTR pszFileName)
447 {
448     SCREEN_SAVER_ITEM* ScreenSaverItem;
449     HANDLE hModule;
450     HRESULT hr;
451 
452     if (pData->ScreenSaverCount >= MAX_SCREENSAVERS)
453         return FALSE;
454 
455     ScreenSaverItem = pData->ScreenSaverItems + pData->ScreenSaverCount;
456 
457     ScreenSaverItem->bIsScreenSaver = TRUE;
458 
459     hModule = LoadLibraryEx(pszFilePath,
460                             NULL,
461                             DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
462     if (hModule)
463     {
464         if (LoadString(hModule,
465                        1,
466                        ScreenSaverItem->szDisplayName,
467                        _countof(ScreenSaverItem->szDisplayName)) == 0)
468         {
469             /* If the string does not exist, copy the file name */
470             hr = StringCbCopy(ScreenSaverItem->szDisplayName,
471                               sizeof(ScreenSaverItem->szDisplayName),
472                               pszFileName);
473             if (FAILED(hr))
474             {
475                 FreeLibrary(hModule);
476                 return FALSE;
477             }
478             /* Remove the .scr extension */
479             ScreenSaverItem->szDisplayName[_tcslen(pszFileName)-4] = _T('\0');
480         }
481         FreeLibrary(hModule);
482     }
483     else
484     {
485         hr = StringCbCopy(ScreenSaverItem->szDisplayName,
486                           sizeof(ScreenSaverItem->szDisplayName),
487                           _T("Unknown"));
488         if (FAILED(hr))
489             return FALSE;
490     }
491 
492     hr = StringCbCopy(ScreenSaverItem->szFilename,
493                       sizeof(ScreenSaverItem->szFilename),
494                       pszFilePath);
495     if (FAILED(hr))
496         return FALSE;
497 
498     return AddScreenSaverItem(hwndScreenSavers, pData, ScreenSaverItem);
499 }
500 
501 static VOID
502 SearchScreenSavers(
503     _In_ HWND hwndScreenSavers,
504     _In_ PDATA pData,
505     _In_ LPCTSTR pszSearchPath)
506 {
507     HRESULT hr;
508     WIN32_FIND_DATA fd;
509     HANDLE hFind;
510     TCHAR szFilePath[MAX_PATH];
511 
512     hr = StringCbPrintf(szFilePath, sizeof(szFilePath),
513                         TEXT("%s\\*.scr"), pszSearchPath);
514     if (FAILED(hr))
515         return;
516 
517     hFind = FindFirstFile(szFilePath, &fd);
518     if (hFind == INVALID_HANDLE_VALUE)
519         return;
520 
521     do
522     {
523         /* Don't add any hidden screensavers */
524         if (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
525             continue;
526 
527         if (pData->ScreenSaverCount >= MAX_SCREENSAVERS)
528             break;
529 
530         hr = StringCbPrintf(szFilePath, sizeof(szFilePath),
531                             TEXT("%s\\%s"), pszSearchPath, fd.cFileName);
532         if (FAILED(hr))
533             break;
534 
535         if (!AddScreenSaver(hwndScreenSavers, pData, szFilePath, fd.cFileName))
536             break;
537 
538     } while (FindNextFile(hFind, &fd));
539 
540     FindClose(hFind);
541 }
542 
543 static VOID
544 EnumScreenSavers(
545     _In_ HWND hwndScreenSavers,
546     _In_ PDATA pData)
547 {
548     SCREEN_SAVER_ITEM* ScreenSaverItem;
549     PTCHAR pBackSlash;
550     TCHAR szSearchPath[MAX_PATH];
551     TCHAR szLocalPath[MAX_PATH];
552 
553     /* Initialize the number of list items */
554     pData->ScreenSaverCount = 0;
555 
556     /* Add the "(None)" item */
557     ScreenSaverItem = pData->ScreenSaverItems;
558 
559     ScreenSaverItem->bIsScreenSaver = FALSE;
560 
561     LoadString(hApplet,
562                IDS_NONE,
563                ScreenSaverItem->szDisplayName,
564                _countof(ScreenSaverItem->szDisplayName));
565 
566     AddScreenSaverItem(hwndScreenSavers, pData, ScreenSaverItem);
567 
568     /* Add all the screensavers where the applet is stored */
569     GetModuleFileName(hApplet, szLocalPath, _countof(szLocalPath));
570     pBackSlash = _tcsrchr(szLocalPath, _T('\\'));
571     if (pBackSlash != NULL)
572     {
573         *pBackSlash = _T('\0');
574         SearchScreenSavers(hwndScreenSavers, pData, szLocalPath);
575     }
576 
577     /* Add all the screensavers in the C:\ReactOS\System32 directory */
578     GetSystemDirectory(szSearchPath, _countof(szSearchPath));
579     if (pBackSlash != NULL && _tcsicmp(szSearchPath, szLocalPath) != 0)
580         SearchScreenSavers(hwndScreenSavers, pData, szSearchPath);
581 
582     /* Add all the screensavers in the C:\ReactOS directory */
583     GetWindowsDirectory(szSearchPath, _countof(szSearchPath));
584     if (pBackSlash != NULL && _tcsicmp(szSearchPath, szLocalPath) != 0)
585         SearchScreenSavers(hwndScreenSavers, pData, szSearchPath);
586 }
587 
588 
589 static VOID
590 SetScreenSaver(HWND hwndDlg, PDATA pData)
591 {
592     HKEY regKey;
593     BOOL DeleteMode = FALSE;
594 
595     DBG_UNREFERENCED_LOCAL_VARIABLE(DeleteMode);
596 
597     if (RegOpenKeyEx(HKEY_CURRENT_USER,
598                      _T("Control Panel\\Desktop"),
599                      0,
600                      KEY_ALL_ACCESS,
601                      &regKey) == ERROR_SUCCESS)
602     {
603         INT Time;
604         BOOL bRet;
605         TCHAR Sec;
606         UINT Ret;
607 
608         /* Set the screensaver */
609         if (pData->ScreenSaverItems[pData->Selection].bIsScreenSaver)
610         {
611             SIZE_T Length = (_tcslen(pData->ScreenSaverItems[pData->Selection].szFilename) + 1) * sizeof(TCHAR);
612             RegSetValueEx(regKey,
613                           _T("SCRNSAVE.EXE"),
614                           0,
615                           REG_SZ,
616                           (PBYTE)pData->ScreenSaverItems[pData->Selection].szFilename,
617                           (DWORD)Length);
618 
619             SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_UPDATEINIFILE);
620         }
621         else
622         {
623             /* Windows deletes the value if no screensaver is set */
624             RegDeleteValue(regKey, _T("SCRNSAVE.EXE"));
625             DeleteMode = TRUE;
626 
627             SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, SPIF_UPDATEINIFILE);
628         }
629 
630         /* Set the secure value */
631         Ret = SendDlgItemMessage(hwndDlg,
632                                  IDC_SCREENS_USEPASSCHK,
633                                  BM_GETCHECK,
634                                  0,
635                                  0);
636         Sec = (Ret == BST_CHECKED) ? _T('1') : _T('0');
637         RegSetValueEx(regKey,
638                       _T("ScreenSaverIsSecure"),
639                       0,
640                       REG_SZ,
641                       (PBYTE)&Sec,
642                       sizeof(TCHAR));
643 
644         /* Set the screensaver time delay */
645         Time = GetDlgItemInt(hwndDlg,
646                              IDC_SCREENS_TIMEDELAY,
647                              &bRet,
648                              FALSE);
649         if (Time == 0)
650             Time = 1;
651         Time *= 60; // Convert to seconds
652 
653         SystemParametersInfoW(SPI_SETSCREENSAVETIMEOUT, Time, 0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
654 
655         RegCloseKey(regKey);
656     }
657 }
658 
659 
660 static BOOL
661 OnInitDialog(HWND hwndDlg, PDATA pData)
662 {
663     HWND hwndSSCombo = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
664     LPTSTR pSsValue;
665     INT iCurSs;
666     WNDCLASS wc = {0};
667 
668     pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DATA));
669     if (!pData)
670     {
671         EndDialog(hwndDlg, -1);
672         return FALSE;
673     }
674 
675     wc.lpfnWndProc = DefWindowProc;
676     wc.hInstance = hApplet;
677     wc.hCursor = NULL;
678     wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
679     wc.lpszClassName = szPreviewWndClass;
680 
681     if (RegisterClass(&wc))
682     {
683         HWND hParent = GetDlgItem(hwndDlg, IDC_SCREENS_PREVIEW);
684         HWND hChild;
685 
686         if (hParent != NULL)
687         {
688             pData->OldPreviewProc = (WNDPROC)GetWindowLongPtr(hParent, GWLP_WNDPROC);
689             SetWindowLongPtr(hParent, GWLP_WNDPROC, (LONG_PTR)RedrawSubclassProc);
690             SetWindowLongPtr(hParent, GWLP_USERDATA, (LONG_PTR)pData);
691         }
692 
693         hChild = CreateWindowEx(0, szPreviewWndClass, NULL,
694                                 WS_CHILD | WS_CLIPCHILDREN,
695                                 0, 0, 0, 0, hParent,
696                                 NULL, hApplet, NULL);
697         if (hChild != NULL)
698         {
699             RECT rc;
700             GetClientRect(hParent, &rc);
701             rc.left += MONITOR_LEFT;
702             rc.top += MONITOR_TOP;
703             MoveWindow(hChild, rc.left, rc.top, MONITOR_WIDTH, MONITOR_HEIGHT, FALSE);
704         }
705 
706         pData->ScreenSaverPreviewParent = hChild;
707     }
708 
709     SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData);
710 
711     pData->Selection = -1;
712 
713     SendDlgItemMessage(hwndDlg,
714                        IDC_SCREENS_TIME,
715                        UDM_SETRANGE,
716                        0,
717                        MAKELONG(240, 1));
718 
719     EnumScreenSavers(hwndSSCombo, pData);
720 
721     CheckRegScreenSaverIsSecure(hwndDlg);
722 
723     /* Set the current screensaver in the combo box */
724     iCurSs = 0; // Default to "(None)"
725     pSsValue = GetCurrentScreenSaverValue(_T("SCRNSAVE.EXE"));
726     if (pSsValue)
727     {
728         BOOL bFound = FALSE;
729         INT i;
730 
731         /* Find whether the current screensaver is in the list */
732         for (i = 0; i < pData->ScreenSaverCount; i++)
733         {
734             if (!_tcsicmp(pSsValue, pData->ScreenSaverItems[i].szFilename))
735             {
736                 bFound = TRUE;
737                 break;
738             }
739         }
740 
741         if (!bFound)
742         {
743             /* The current screensaver is not in the list: add it */
744             // i = pData->ScreenSaverCount;
745             bFound = AddScreenSaver(hwndSSCombo, pData, pSsValue, _T("SCRNSAVE.EXE"));
746             if (bFound)
747                 i = pData->ScreenSaverCount - 1;
748         }
749 
750         HeapFree(GetProcessHeap(), 0, pSsValue);
751 
752         if (bFound)
753         {
754             /* The current screensaver should be in the list: select it */
755             iCurSs = SendMessage(hwndSSCombo,
756                                  CB_FINDSTRINGEXACT,
757                                  -1,
758                                  (LPARAM)pData->ScreenSaverItems[i].szDisplayName);
759             if (iCurSs == CB_ERR)
760                 iCurSs = 0; // Default to "(None)"
761         }
762     }
763     SendMessage(hwndSSCombo, CB_SETCURSEL, iCurSs, 0);
764 
765     /* Set the current timeout */
766     pSsValue = GetCurrentScreenSaverValue(_T("ScreenSaveTimeOut"));
767     if (pSsValue)
768     {
769         UINT Time = _ttoi(pSsValue) / 60;
770 
771         HeapFree(GetProcessHeap(), 0, pSsValue);
772 
773         SendDlgItemMessage(hwndDlg,
774                            IDC_SCREENS_TIME,
775                            UDM_SETPOS32,
776                            0,
777                            Time);
778     }
779 
780     SelectionChanged(hwndDlg, pData);
781 
782     return TRUE;
783 }
784 
785 
786 INT_PTR CALLBACK
787 ScreenSaverPageProc(HWND hwndDlg,
788                     UINT uMsg,
789                     WPARAM wParam,
790                     LPARAM lParam)
791 {
792     PDATA pData;
793 
794     pData = (PDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
795 
796     switch (uMsg)
797     {
798         case WM_INITDIALOG:
799         {
800             OnInitDialog(hwndDlg, pData);
801             break;
802         }
803 
804         case WM_DESTROY:
805         {
806             if (pData->ScreenSaverPreviewParent)
807             {
808                 SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SCREENS_PREVIEW),
809                                  GWLP_WNDPROC,
810                                  (LONG_PTR)pData->OldPreviewProc);
811                 DestroyWindow(pData->ScreenSaverPreviewParent);
812                 pData->ScreenSaverPreviewParent = NULL;
813             }
814             UnregisterClass(szPreviewWndClass, hApplet);
815             if (pData->PrevWindowPi.hProcess)
816             {
817                 TerminateProcess(pData->PrevWindowPi.hProcess, 0);
818                 CloseHandle(pData->PrevWindowPi.hProcess);
819                 CloseHandle(pData->PrevWindowPi.hThread);
820             }
821             HeapFree(GetProcessHeap(), 0, pData);
822             break;
823         }
824 
825         case WM_ENDSESSION:
826         {
827             SetScreenSaverPreviewBox(hwndDlg, pData);
828             break;
829         }
830 
831         case WM_DRAWITEM:
832         {
833             LPDRAWITEMSTRUCT lpDrawItem;
834             lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
835 
836             if (lpDrawItem->CtlID == IDC_SCREENS_PREVIEW)
837                 ShowScreenSaverPreview(lpDrawItem, pData);
838             break;
839         }
840 
841         case WM_COMMAND:
842         {
843             DWORD controlId = LOWORD(wParam);
844             DWORD command   = HIWORD(wParam);
845 
846             switch (controlId)
847             {
848                 case IDC_SCREENS_LIST:
849                 {
850                     if (HIWORD(wParam) == CBN_SELCHANGE)
851                     {
852                         SelectionChanged(hwndDlg, pData);
853                         SetScreenSaverPreviewBox(hwndDlg, pData);
854                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
855                     }
856                     break;
857                 }
858 
859                 case IDC_SCREENS_TIMEDELAY:
860                 {
861                     if (command == EN_CHANGE)
862                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
863                     break;
864                 }
865 
866                 case IDC_SCREENS_POWER_BUTTON: // Start Powercfg.Cpl
867                 {
868                     if (command == BN_CLICKED)
869                         WinExec("rundll32 shell32.dll,Control_RunDLL powercfg.cpl",SW_SHOWNORMAL);
870                     break;
871                 }
872 
873                 case IDC_SCREENS_TESTSC: // Screensaver Preview
874                 {
875                     if (command == BN_CLICKED)
876                     {
877                         ScreenSaverPreview(hwndDlg, pData);
878                         SetScreenSaverPreviewBox(hwndDlg, pData);
879                     }
880                     break;
881                 }
882 
883                 case IDC_SCREENS_SETTINGS: // Screensaver Settings
884                 {
885                     if (command == BN_CLICKED)
886                         ScreenSaverConfig(hwndDlg, pData);
887                     break;
888                 }
889 
890                 case IDC_SCREENS_USEPASSCHK: // Screensaver Is Secure
891                 {
892                     if (command == BN_CLICKED)
893                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
894                     break;
895                 }
896             }
897             break;
898         }
899 
900         case WM_NOTIFY:
901         {
902             LPNMHDR lpnm = (LPNMHDR)lParam;
903 
904             switch(lpnm->code)
905             {
906                 case PSN_APPLY:
907                 {
908                     SetScreenSaver(hwndDlg, pData);
909                     return TRUE;
910                 }
911 
912                 case PSN_SETACTIVE:
913                 {
914                     /* Enable screensaver preview support */
915                     SetScreenSaverPreviewBox(hwndDlg, pData);
916                     break;
917                 }
918 
919                 case PSN_KILLACTIVE:
920                 {
921                     /* Kill running preview screensaver */
922                     if (pData->PrevWindowPi.hProcess)
923                     {
924                         TerminateProcess(pData->PrevWindowPi.hProcess, 0);
925                         CloseHandle(pData->PrevWindowPi.hProcess);
926                         CloseHandle(pData->PrevWindowPi.hThread);
927                         pData->PrevWindowPi.hThread = pData->PrevWindowPi.hProcess = NULL;
928                     }
929                     break;
930                 }
931             }
932         }
933         break;
934     }
935 
936     return FALSE;
937 }
938