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)
9 /* INCLUDES *****************************************************************/
13 /* FUNCTIONS ****************************************************************/
15 #ifndef USE_GETLASTINPUTINFO
24 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PKBDLLHOOKSTRUCT
)lParam
)->time
);
25 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
37 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PMSLLHOOKSTRUCT
)lParam
)->time
);
38 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
45 LoadScreenSaverParameters(
50 if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT
, 0, Timeout
, 0))
52 WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
55 else if (!SystemParametersInfoW(SPI_GETSCREENSAVEACTIVE
, 0, &Enabled
, 0))
57 WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
62 TRACE("WL: Screen saver is disabled\n");
67 TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout
);
76 ScreenSaverThreadMain(
77 IN LPVOID lpParameter
)
79 PWLSESSION Session
= (PWLSESSION
)lpParameter
;
80 HANDLE HandleArray
[3];
81 #ifdef USE_GETLASTINPUTINFO
82 LASTINPUTINFO lastInputInfo
;
87 DWORD Timeout
; /* Timeout before screen saver starts, in milliseconds */
90 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
92 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
96 Session
->hUserActivity
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
97 if (!Session
->hUserActivity
)
99 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
103 Session
->hEndOfScreenSaver
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
104 if (!Session
->hEndOfScreenSaver
)
106 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
110 HandleArray
[0] = Session
->hEndOfScreenSaverThread
;
111 HandleArray
[1] = Session
->hScreenSaverParametersChanged
;
112 HandleArray
[2] = Session
->hEndOfScreenSaver
;
114 LoadScreenSaverParameters(&Timeout
);
116 #ifndef USE_GETLASTINPUTINFO
117 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());
119 lastInputInfo
.cbSize
= sizeof(LASTINPUTINFO
);
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
);
128 if (GetLastInputInfo(&lastInputInfo
))
129 TimeToWait
= Timeout
- (GetTickCount() - lastInputInfo
.dwTime
);
132 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
133 TimeToWait
= 10; /* Try again in 10 ms */
137 if (TimeToWait
> Timeout
)
139 /* GetTickCount() got back to 0 */
140 TimeToWait
= Timeout
;
143 /* Wait for the timeout, or the end of this thread */
144 ret
= WaitForMultipleObjects(2, HandleArray
, FALSE
, TimeToWait
);
145 if (ret
== WAIT_OBJECT_0
)
147 else if (ret
== WAIT_OBJECT_0
+ 1)
148 LoadScreenSaverParameters(&Timeout
);
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())
156 if (!GetLastInputInfo(&lastInputInfo
))
158 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
162 if (lastInputInfo
.dwTime
+ Timeout
> GetTickCount())
166 /* Run screen saver */
167 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
, 0);
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
)
173 else if (ret
== WAIT_OBJECT_0
+ 1)
174 LoadScreenSaverParameters(&Timeout
);
175 else if (ret
== WAIT_OBJECT_0
+ 2)
176 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, FALSE
, NULL
, 0);
180 if (Session
->hUserActivity
)
181 CloseHandle(Session
->hUserActivity
);
183 if (Session
->hEndOfScreenSaver
)
184 CloseHandle(Session
->hEndOfScreenSaver
);
188 #ifndef USE_GETLASTINPUTINFO
189 if (Session
->KeyboardHook
)
190 UnhookWindowsHookEx(Session
->KeyboardHook
);
192 if (Session
->MouseHook
)
193 UnhookWindowsHookEx(Session
->MouseHook
);
196 CloseHandle(Session
->hEndOfScreenSaverThread
);
197 CloseHandle(Session
->hScreenSaverParametersChanged
);
204 InitializeScreenSaver(
205 IN OUT PWLSESSION Session
)
207 HANDLE ScreenSaverThread
;
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
)
214 ERR("WL: Unable to register keyboard hook\n");
218 Session
->MouseHook
= SetWindowsHookEx(WH_MOUSE_LL
, MouseActivityProc
, hAppInstance
, 0);
219 if (!Session
->MouseHook
)
221 ERR("WL: Unable to register mouse hook\n");
226 Session
->hScreenSaverParametersChanged
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
227 if (!Session
->hScreenSaverParametersChanged
)
229 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
233 Session
->hEndOfScreenSaverThread
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
234 if (!Session
->hEndOfScreenSaverThread
)
236 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
237 CloseHandle(Session
->hScreenSaverParametersChanged
);
241 ScreenSaverThread
= CreateThread(NULL
,
243 ScreenSaverThreadMain
,
247 if (ScreenSaverThread
)
248 CloseHandle(ScreenSaverThread
);
250 ERR("WL: Unable to start screen saver thread\n");
258 IN PWLSESSION Session
)
260 HKEY hKey
= NULL
, hCurrentUser
= NULL
;
261 WCHAR szApplicationName
[MAX_PATH
];
262 WCHAR szCommandLine
[MAX_PATH
+ 3];
263 DWORD bufferSize
= sizeof(szApplicationName
) - sizeof(WCHAR
);
265 STARTUPINFOW StartupInfo
;
266 PROCESS_INFORMATION ProcessInformation
;
267 HANDLE HandleArray
[2];
272 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
274 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
278 rc
= RegOpenCurrentUser(KEY_READ
,
280 if (rc
!= ERROR_SUCCESS
)
282 ERR("WL: RegOpenCurrentUser error %lu\n", rc
);
286 rc
= RegOpenKeyExW(hCurrentUser
,
287 L
"Control Panel\\Desktop",
291 if (rc
!= ERROR_SUCCESS
)
293 ERR("WL: RegOpenKeyEx error %lu\n", rc
);
297 rc
= RegQueryValueExW(hKey
,
301 (LPBYTE
)szApplicationName
,
303 if (rc
!= ERROR_SUCCESS
|| dwType
!= REG_SZ
)
305 if (rc
!= ERROR_FILE_NOT_FOUND
)
306 ERR("WL: RegQueryValueEx error %lu\n", rc
);
312 ERR("WL: Buffer size is NULL!\n");
316 szApplicationName
[bufferSize
/ sizeof(WCHAR
)] = 0; /* Terminate the string */
318 if (wcslen(szApplicationName
) == 0)
320 ERR("WL: Application Name length is zero!\n");
324 wsprintfW(szCommandLine
, L
"%s /s", szApplicationName
);
325 TRACE("WL: Executing %S\n", szCommandLine
);
327 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
328 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
329 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
330 StartupInfo
.dwFlags
= STARTF_SCREENSAVER
;
332 /* FIXME: Run the screen saver on the secure screen saver desktop if required */
333 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
335 ret
= CreateProcessAsUserW(Session
->UserToken
,
345 &ProcessInformation
);
348 ERR("WL: Unable to start %S, error %lu\n", szApplicationName
, GetLastError());
352 CloseHandle(ProcessInformation
.hThread
);
354 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, TRUE
, NULL
, 0);
356 CallNotificationDlls(Session
, StartScreenSaverHandler
);
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)
365 /* Kill the screen saver */
366 TerminateProcess(ProcessInformation
.hProcess
, 0);
369 SetEvent(Session
->hEndOfScreenSaver
);
371 CloseHandle(ProcessInformation
.hProcess
);
373 CallNotificationDlls(Session
, StopScreenSaverHandler
);
380 RegCloseKey(hCurrentUser
);
386 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_ACTIVITY
, 0);
387 #ifndef USE_GETLASTINPUTINFO
388 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());