ReactOS 0.4.16-dev-319-g6cf4263
screensaver.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winlogon
4 * FILE: base/system/winlogon/screensaver.c
5 * PURPOSE: Screen saver management
6 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9/* INCLUDES *****************************************************************/
10
11#include "winlogon.h"
12
13/* FUNCTIONS ****************************************************************/
14
15#ifndef USE_GETLASTINPUTINFO
16static
19KeyboardActivityProc(
20 IN INT nCode,
23{
24 InterlockedExchange((LONG*)&WLSession->LastActivity, ((PKBDLLHOOKSTRUCT)lParam)->time);
25 return CallNextHookEx(NULL, nCode, wParam, lParam);
26}
27
28
29static
32MouseActivityProc(
33 IN INT nCode,
36{
37 InterlockedExchange((LONG*)&WLSession->LastActivity, ((PMSLLHOOKSTRUCT)lParam)->time);
38 return CallNextHookEx(NULL, nCode, wParam, lParam);
39}
40#endif
41
42
43static
44VOID
47{
49
51 {
52 WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
54 }
56 {
57 WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
59 }
60 else if (!Enabled)
61 {
62 TRACE("WL: Screen saver is disabled\n");
64 }
65 else
66 {
67 TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout);
68 *Timeout *= 1000;
69 }
70}
71
72
73static
77 IN LPVOID lpParameter)
78{
79 PWLSESSION Session = (PWLSESSION)lpParameter;
80 HANDLE HandleArray[3];
81#ifdef USE_GETLASTINPUTINFO
82 LASTINPUTINFO lastInputInfo;
83#else
84 DWORD LastActivity;
85#endif
86 DWORD TimeToWait;
87 DWORD Timeout; /* Timeout before screen saver starts, in milliseconds */
88 DWORD ret;
89
91 {
92 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
93 return 0;
94 }
95
97 if (!Session->hUserActivity)
98 {
99 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
100 goto cleanup;
101 }
102
104 if (!Session->hEndOfScreenSaver)
105 {
106 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
107 goto cleanup;
108 }
109
110 HandleArray[0] = Session->hEndOfScreenSaverThread;
111 HandleArray[1] = Session->hScreenSaverParametersChanged;
112 HandleArray[2] = Session->hEndOfScreenSaver;
113
115
116#ifndef USE_GETLASTINPUTINFO
117 InterlockedExchange((LONG*)&Session->LastActivity, GetTickCount());
118#else
119 lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
120#endif
121 for (;;)
122 {
123 /* See the time of last activity and calculate a timeout */
124#ifndef USE_GETLASTINPUTINFO
125 LastActivity = InterlockedCompareExchange((LONG*)&Session->LastActivity, 0, 0);
126 TimeToWait = Timeout - (GetTickCount() - LastActivity);
127#else
128 if (GetLastInputInfo(&lastInputInfo))
129 TimeToWait = Timeout - (GetTickCount() - lastInputInfo.dwTime);
130 else
131 {
132 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
133 TimeToWait = 10; /* Try again in 10 ms */
134 }
135#endif
136
137 if (TimeToWait > Timeout)
138 {
139 /* GetTickCount() got back to 0 */
140 TimeToWait = Timeout;
141 }
142
143 /* Wait for the timeout, or the end of this thread */
144 ret = WaitForMultipleObjects(2, HandleArray, FALSE, TimeToWait);
145 if (ret == WAIT_OBJECT_0)
146 break;
147 else if (ret == WAIT_OBJECT_0 + 1)
149
150 /* Check if we didn't had recent activity */
151#ifndef USE_GETLASTINPUTINFO
152 LastActivity = InterlockedCompareExchange((LONG*)&Session->LastActivity, 0, 0);
153 if (LastActivity + Timeout > GetTickCount())
154 continue;
155#else
156 if (!GetLastInputInfo(&lastInputInfo))
157 {
158 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
159 continue;
160 }
161
162 if (lastInputInfo.dwTime + Timeout > GetTickCount())
163 continue;
164#endif
165
166 /* Run screen saver */
168
169 /* Wait for the end of this thread or of the screen saver */
170 ret = WaitForMultipleObjects(3, HandleArray, FALSE, INFINITE);
171 if (ret == WAIT_OBJECT_0)
172 break;
173 else if (ret == WAIT_OBJECT_0 + 1)
175 else if (ret == WAIT_OBJECT_0 + 2)
176 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING, FALSE, NULL, 0);
177 }
178
179cleanup:
180 if (Session->hUserActivity)
181 CloseHandle(Session->hUserActivity);
182
183 if (Session->hEndOfScreenSaver)
185
186 RevertToSelf();
187
188#ifndef USE_GETLASTINPUTINFO
189 if (Session->KeyboardHook)
190 UnhookWindowsHookEx(Session->KeyboardHook);
191
192 if (Session->MouseHook)
193 UnhookWindowsHookEx(Session->MouseHook);
194#endif
195
198
199 return 0;
200}
201
202
203BOOL
205 IN OUT PWLSESSION Session)
206{
207 HANDLE ScreenSaverThread;
208
209#ifndef USE_GETLASTINPUTINFO
210 /* Register hooks to detect keyboard and mouse activity */
211 Session->KeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardActivityProc, hAppInstance, 0);
212 if (!Session->KeyboardHook)
213 {
214 ERR("WL: Unable to register keyboard hook\n");
215 return FALSE;
216 }
217
218 Session->MouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseActivityProc, hAppInstance, 0);
219 if (!Session->MouseHook)
220 {
221 ERR("WL: Unable to register mouse hook\n");
222 return FALSE;
223 }
224#endif
225
226 Session->hScreenSaverParametersChanged = CreateEventW(NULL, FALSE, FALSE, NULL);
227 if (!Session->hScreenSaverParametersChanged)
228 {
229 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
230 return TRUE;
231 }
232
233 Session->hEndOfScreenSaverThread = CreateEventW(NULL, FALSE, FALSE, NULL);
234 if (!Session->hEndOfScreenSaverThread)
235 {
236 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
237 CloseHandle(Session->hScreenSaverParametersChanged);
238 return TRUE;
239 }
240
241 ScreenSaverThread = CreateThread(NULL,
242 0,
244 Session,
245 0,
246 NULL);
247 if (ScreenSaverThread)
248 CloseHandle(ScreenSaverThread);
249 else
250 ERR("WL: Unable to start screen saver thread\n");
251
252 return TRUE;
253}
254
255
256VOID
258 IN PWLSESSION Session)
259{
260 HKEY hKey = NULL, hCurrentUser = NULL;
261 WCHAR szApplicationName[MAX_PATH];
262 WCHAR szCommandLine[MAX_PATH + 3];
263 DWORD bufferSize = sizeof(szApplicationName) - sizeof(WCHAR);
264 DWORD dwType;
265 STARTUPINFOW StartupInfo;
266 PROCESS_INFORMATION ProcessInformation;
267 HANDLE HandleArray[2];
268 LONG rc;
270 BOOL ret = FALSE;
271
272 if (!ImpersonateLoggedOnUser(Session->UserToken))
273 {
274 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
275 goto cleanup;
276 }
277
279 &hCurrentUser);
280 if (rc != ERROR_SUCCESS)
281 {
282 ERR("WL: RegOpenCurrentUser error %lu\n", rc);
283 goto cleanup;
284 }
285
286 rc = RegOpenKeyExW(hCurrentUser,
287 L"Control Panel\\Desktop",
288 0,
290 &hKey);
291 if (rc != ERROR_SUCCESS)
292 {
293 ERR("WL: RegOpenKeyEx error %lu\n", rc);
294 goto cleanup;
295 }
296
298 L"SCRNSAVE.EXE",
299 0,
300 &dwType,
301 (LPBYTE)szApplicationName,
302 &bufferSize);
303 if (rc != ERROR_SUCCESS || dwType != REG_SZ)
304 {
305 if (rc != ERROR_FILE_NOT_FOUND)
306 ERR("WL: RegQueryValueEx error %lu\n", rc);
307 goto cleanup;
308 }
309
310 if (bufferSize == 0)
311 {
312 ERR("WL: Buffer size is NULL!\n");
313 goto cleanup;
314 }
315
316 szApplicationName[bufferSize / sizeof(WCHAR)] = 0; /* Terminate the string */
317
318 if (wcslen(szApplicationName) == 0)
319 {
320 ERR("WL: Application Name length is zero!\n");
321 goto cleanup;
322 }
323
324 wsprintfW(szCommandLine, L"%s /s", szApplicationName);
325 TRACE("WL: Executing %S\n", szCommandLine);
326
327 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
328 ZeroMemory(&ProcessInformation, sizeof(PROCESS_INFORMATION));
329 StartupInfo.cb = sizeof(STARTUPINFOW);
330 StartupInfo.dwFlags = STARTF_SCREENSAVER;
331
332 /* FIXME: Run the screen saver on the secure screen saver desktop if required */
333 StartupInfo.lpDesktop = L"WinSta0\\Default";
334
335 ret = CreateProcessAsUserW(Session->UserToken,
336 szApplicationName,
337 szCommandLine,
338 NULL,
339 NULL,
340 FALSE,
342 NULL,
343 NULL,
344 &StartupInfo,
345 &ProcessInformation);
346 if (!ret)
347 {
348 ERR("WL: Unable to start %S, error %lu\n", szApplicationName, GetLastError());
349 goto cleanup;
350 }
351
352 CloseHandle(ProcessInformation.hThread);
353
354 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING, TRUE, NULL, 0);
355
357
358 /* Wait the end of the process or some other activity */
359 ResetEvent(Session->hUserActivity);
360 HandleArray[0] = ProcessInformation.hProcess;
361 HandleArray[1] = Session->hUserActivity;
362 Status = WaitForMultipleObjects(2, HandleArray, FALSE, INFINITE);
363 if (Status == WAIT_OBJECT_0 + 1)
364 {
365 /* Kill the screen saver */
366 TerminateProcess(ProcessInformation.hProcess, 0);
367 }
368
369 SetEvent(Session->hEndOfScreenSaver);
370
371 CloseHandle(ProcessInformation.hProcess);
372
374
375cleanup:
376 if (hKey)
378
379 if (hCurrentUser)
380 RegCloseKey(hCurrentUser);
381
382 RevertToSelf();
383
384 if (!ret)
385 {
387#ifndef USE_GETLASTINPUTINFO
388 InterlockedExchange((LONG*)&Session->LastActivity, GetTickCount());
389#endif
390 }
391}
#define InterlockedExchange
Definition: armddk.h:54
HINSTANCE hAppInstance
Definition: mmc.c:23
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
VOID CallNotificationDlls(PWLSESSION pSession, NOTIFICATION_TYPE Type)
Definition: notify.c:390
static DWORD WINAPI ScreenSaverThreadMain(IN LPVOID lpParameter)
Definition: screensaver.c:76
static VOID LoadScreenSaverParameters(OUT LPDWORD Timeout)
Definition: screensaver.c:45
BOOL InitializeScreenSaver(IN OUT PWLSESSION Session)
Definition: screensaver.c:204
VOID StartScreenSaver(IN PWLSESSION Session)
Definition: screensaver.c:257
#define RegCloseKey(hKey)
Definition: registry.h:49
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserW(_In_opt_ HANDLE hToken, _In_opt_ LPCWSTR lpApplicationName, _Inout_opt_ LPWSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCWSTR lpCurrentDirectory, _In_ LPSTARTUPINFOW lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation)
Definition: logon.c:993
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3333
LONG WINAPI RegOpenCurrentUser(IN REGSAM samDesired, OUT PHKEY phkResult)
Definition: reg.c:3209
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4103
BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken)
Definition: misc.c:152
#define CloseHandle
Definition: compat.h:739
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
static void cleanup(void)
Definition: main.c:1335
BOOL WINAPI TerminateProcess(IN HANDLE hProcess, IN UINT uExitCode)
Definition: proc.c:1532
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
#define INFINITE
Definition: serial.h:102
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxAutoRegKey hKey
size_t bufferSize
Status
Definition: gdiplustypes.h:25
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define InterlockedCompareExchange
Definition: interlocked.h:104
#define REG_SZ
Definition: layer.c:22
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
@ Enabled
Definition: mountmgr.h:179
#define KEY_READ
Definition: nt_native.h:1023
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
static ULONG Timeout
Definition: ping.c:61
#define TRACE(s)
Definition: solgame.cpp:4
LPWSTR lpDesktop
Definition: winbase.h:879
DWORD cb
Definition: winbase.h:877
DWORD dwFlags
Definition: winbase.h:888
HANDLE hUserActivity
Definition: winlogon.h:244
HANDLE hScreenSaverParametersChanged
Definition: winlogon.h:243
HANDLE hEndOfScreenSaver
Definition: winlogon.h:245
HANDLE UserToken
Definition: winlogon.h:232
HANDLE hEndOfScreenSaverThread
Definition: winlogon.h:242
HWND SASWindow
Definition: winlogon.h:225
DWORD WINAPI WaitForMultipleObjects(IN DWORD nCount, IN CONST HANDLE *lpHandles, IN BOOL bWaitAll, IN DWORD dwMilliseconds)
Definition: synch.c:151
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:651
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
BOOL WINAPI DECLSPEC_HOTPATCH ResetEvent(IN HANDLE hEvent)
Definition: synch.c:714
unsigned char * LPBYTE
Definition: typedefs.h:53
uint32_t * LPDWORD
Definition: typedefs.h:59
int32_t INT
Definition: typedefs.h:58
#define IN
Definition: typedefs.h:39
#define OUT
Definition: typedefs.h:40
#define STARTF_SCREENSAVER
Definition: undocuser.h:165
int ret
#define ZeroMemory
Definition: winbase.h:1737
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define WAIT_OBJECT_0
Definition: winbase.h:432
#define IDLE_PRIORITY_CLASS
Definition: winbase.h:185
BOOL WINAPI RevertToSelf(void)
Definition: security.c:1608
struct _STARTUPINFOW STARTUPINFOW
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
#define WINAPI
Definition: msvc.h:6
PWLSESSION WLSession
Definition: winlogon.c:20
struct _WLSESSION * PWLSESSION
@ StopScreenSaverHandler
Definition: winlogon.h:265
@ StartScreenSaverHandler
Definition: winlogon.h:264
BOOL WINAPI GetLastInputInfo(_Out_ PLASTINPUTINFO)
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
#define SetWindowsHookEx
Definition: winuser.h:5868
#define WH_MOUSE_LL
Definition: winuser.h:44
BOOL WINAPI UnhookWindowsHookEx(_In_ HHOOK)
#define WH_KEYBOARD_LL
Definition: winuser.h:43
BOOL WINAPI SystemParametersInfoW(_In_ UINT uiAction, _In_ UINT uiParam, _Inout_opt_ PVOID pvParam, _In_ UINT fWinIni)
LRESULT WINAPI CallNextHookEx(_In_opt_ HHOOK, _In_ int, _In_ WPARAM, _In_ LPARAM)
#define SPI_GETSCREENSAVETIMEOUT
Definition: winuser.h:1366
#define SPI_GETSCREENSAVEACTIVE
Definition: winuser.h:1368
struct tagLASTINPUTINFO LASTINPUTINFO
#define WLX_WM_SAS
Definition: winwlx.h:71
#define WLX_SAS_TYPE_SCRNSVR_TIMEOUT
Definition: winwlx.h:37
#define WLX_SAS_TYPE_SCRNSVR_ACTIVITY
Definition: winwlx.h:38
__wchar_t WCHAR
Definition: xmlstorage.h:180