ReactOS  0.4.14-dev-41-g31d7680
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
16 static
17 LRESULT
19 KeyboardActivityProc(
20  IN INT nCode,
23 {
24  InterlockedExchange((LONG*)&WLSession->LastActivity, ((PKBDLLHOOKSTRUCT)lParam)->time);
25  return CallNextHookEx(NULL, nCode, wParam, lParam);
26 }
27 
28 
29 static
30 LRESULT
32 MouseActivityProc(
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 
43 static
44 VOID
47 {
48  BOOL Enabled;
49 
51  {
52  WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
53  *Timeout = INFINITE;
54  }
56  {
57  WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
58  *Timeout = INFINITE;
59  }
60  else if (!Enabled)
61  {
62  TRACE("WL: Screen saver is disabled\n");
63  *Timeout = INFINITE;
64  }
65  else
66  {
67  TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout);
68  *Timeout *= 1000;
69  }
70 }
71 
72 
73 static
74 DWORD
75 WINAPI
78 {
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 
90  if (!ImpersonateLoggedOnUser(Session->UserToken))
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 
179 cleanup:
180  if (Session->hUserActivity)
181  CloseHandle(Session->hUserActivity);
182 
183  if (Session->hEndOfScreenSaver)
184  CloseHandle(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 
203 BOOL
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 
256 VOID
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;
269  DWORD Status;
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 
297  rc = RegQueryValueExW(hKey,
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 screen saver desktop */
333  ret = CreateProcessW(szApplicationName,
334  szCommandLine,
335  NULL,
336  NULL,
337  FALSE,
338  0,
339  NULL,
340  NULL,
341  &StartupInfo,
342  &ProcessInformation);
343  if (!ret)
344  {
345  ERR("WL: Unable to start %S, error %lu\n", szApplicationName, GetLastError());
346  goto cleanup;
347  }
348 
349  CloseHandle(ProcessInformation.hThread);
350 
351  SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING, TRUE, NULL, 0);
352 
354 
355  /* Wait the end of the process or some other activity */
356  ResetEvent(Session->hUserActivity);
357  HandleArray[0] = ProcessInformation.hProcess;
358  HandleArray[1] = Session->hUserActivity;
359  Status = WaitForMultipleObjects(2, HandleArray, FALSE, INFINITE);
360  if (Status == WAIT_OBJECT_0 + 1)
361  {
362  /* Kill the screen saver */
363  TerminateProcess(ProcessInformation.hProcess, 0);
364  }
365 
366  SetEvent(Session->hEndOfScreenSaver);
367 
368  CloseHandle(ProcessInformation.hProcess);
369 
371 
372 cleanup:
373  if (hKey)
374  RegCloseKey(hKey);
375 
376  if (hCurrentUser)
377  RegCloseKey(hCurrentUser);
378 
379  RevertToSelf();
380 
381  if (!ret)
382  {
383  PostMessageW(Session->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_SCRNSVR_ACTIVITY, 0);
384 #ifndef USE_GETLASTINPUTINFO
385  InterlockedExchange((LONG*)&Session->LastActivity, GetTickCount());
386 #endif
387  }
388 }
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
PWLSESSION WLSession
Definition: winlogon.c:20
#define IN
Definition: typedefs.h:38
#define WLX_WM_SAS
Definition: winwlx.h:71
#define TRUE
Definition: types.h:120
struct _WLSESSION * PWLSESSION
#define CloseHandle
Definition: compat.h:398
HANDLE hScreenSaverParametersChanged
Definition: winlogon.h:238
#define ERROR_SUCCESS
Definition: deptool.c:10
#define WLX_SAS_TYPE_SCRNSVR_ACTIVITY
Definition: winwlx.h:38
#define KEY_READ
Definition: nt_native.h:1023
struct tagLASTINPUTINFO LASTINPUTINFO
BOOL WINAPI RevertToSelf(VOID)
Definition: security.c:1487
HWND SASWindow
Definition: winlogon.h:220
struct _STARTUPINFOW STARTUPINFOW
#define WARN(fmt,...)
Definition: debug.h:111
VOID StartScreenSaver(IN PWLSESSION Session)
Definition: screensaver.c:257
HANDLE UserToken
Definition: winlogon.h:227
#define SPI_GETSCREENSAVETIMEOUT
Definition: winuser.h:1345
#define CALLBACK
Definition: compat.h:27
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
#define InterlockedCompareExchange
Definition: interlocked.h:104
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1635
UINT_PTR WPARAM
Definition: windef.h:207
DWORD WINAPI WaitForMultipleObjects(IN DWORD nCount, IN CONST HANDLE *lpHandles, IN BOOL bWaitAll, IN DWORD dwMilliseconds)
Definition: synch.c:151
int32_t INT
Definition: typedefs.h:56
WPARAM wParam
Definition: combotst.c:138
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:651
HANDLE hEndOfScreenSaver
Definition: winlogon.h:240
#define WLX_SAS_TYPE_SCRNSVR_TIMEOUT
Definition: winwlx.h:37
#define WH_MOUSE_LL
Definition: winuser.h:44
HANDLE hUserActivity
Definition: winlogon.h:239
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:52
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
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:136
smooth NULL
Definition: ftsmooth.c:416
LONG_PTR LPARAM
Definition: windef.h:208
BOOL WINAPI GetLastInputInfo(_Out_ PLASTINPUTINFO)
BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken)
Definition: misc.c:152
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
Definition: proc.c:4593
BOOL WINAPI SystemParametersInfoW(_In_ UINT, _In_ UINT, _Inout_opt_ PVOID, _In_ UINT)
#define TRACE(s)
Definition: solgame.cpp:4
#define WAIT_OBJECT_0
Definition: winbase.h:387
DWORD cb
Definition: winbase.h:817
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4116
#define WH_KEYBOARD_LL
Definition: winuser.h:43
__wchar_t WCHAR
Definition: xmlstorage.h:180
BOOL InitializeScreenSaver(IN OUT PWLSESSION Session)
Definition: screensaver.c:204
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
#define SetWindowsHookEx
Definition: winuser.h:5757
unsigned long DWORD
Definition: ntddk_ex.h:95
int ret
static const WCHAR L[]
Definition: oid.c:1250
LPVOID lpParameter
Definition: kernel32.h:241
#define InterlockedExchange
Definition: armddk.h:54
BOOL WINAPI UnhookWindowsHookEx(_In_ HHOOK)
Status
Definition: gdiplustypes.h:24
#define ERR(fmt,...)
Definition: debug.h:109
VOID CallNotificationDlls(PWLSESSION pSession, NOTIFICATION_TYPE Type)
Definition: notify.c:304
HANDLE hEndOfScreenSaverThread
Definition: winlogon.h:237
LRESULT WINAPI CallNextHookEx(_In_opt_ HHOOK, _In_ int, _In_ WPARAM, _In_ LPARAM)
static ULONG Timeout
Definition: ping.c:61
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
BOOL WINAPI TerminateProcess(IN HANDLE hProcess, IN UINT uExitCode)
Definition: proc.c:1532
#define STARTF_SCREENSAVER
Definition: undocuser.h:163
static DWORD WINAPI ScreenSaverThreadMain(IN LPVOID lpParameter)
Definition: screensaver.c:76
BOOL WINAPI DECLSPEC_HOTPATCH ResetEvent(IN HANDLE hEvent)
Definition: synch.c:714
static VOID LoadScreenSaverParameters(OUT LPDWORD Timeout)
Definition: screensaver.c:45
#define SPI_GETSCREENSAVEACTIVE
Definition: winuser.h:1347
LONG WINAPI RegOpenCurrentUser(IN REGSAM samDesired, OUT PHKEY phkResult)
Definition: reg.c:3232
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define OUT
Definition: typedefs.h:39
uint32_t * LPDWORD
Definition: typedefs.h:57
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3366
char * cleanup(char *str)
Definition: wpickclick.c:99
DWORD dwFlags
Definition: winbase.h:828
LONG_PTR LRESULT
Definition: windef.h:209
#define INFINITE
Definition: serial.h:102
LPARAM lParam
Definition: combotst.c:139
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
HINSTANCE hAppInstance
Definition: mmc.c:23
#define REG_SZ
Definition: layer.c:22