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);
181 if (Session
->hUserActivity
)
182 CloseHandle(Session
->hUserActivity
);
184 if (Session
->hEndOfScreenSaver
)
185 CloseHandle(Session
->hEndOfScreenSaver
);
187 #ifndef USE_GETLASTINPUTINFO
188 if (Session
->KeyboardHook
)
189 UnhookWindowsHookEx(Session
->KeyboardHook
);
191 if (Session
->MouseHook
)
192 UnhookWindowsHookEx(Session
->MouseHook
);
195 CloseHandle(Session
->hEndOfScreenSaverThread
);
196 CloseHandle(Session
->hScreenSaverParametersChanged
);
202 InitializeScreenSaver(
203 IN OUT PWLSESSION Session
)
205 HANDLE ScreenSaverThread
;
207 #ifndef USE_GETLASTINPUTINFO
208 /* Register hooks to detect keyboard and mouse activity */
209 Session
->KeyboardHook
= SetWindowsHookEx(WH_KEYBOARD_LL
, KeyboardActivityProc
, hAppInstance
, 0);
210 if (!Session
->KeyboardHook
)
212 ERR("WL: Unable to register keyboard hook\n");
216 Session
->MouseHook
= SetWindowsHookEx(WH_MOUSE_LL
, MouseActivityProc
, hAppInstance
, 0);
217 if (!Session
->MouseHook
)
219 ERR("WL: Unable to register mouse hook\n");
224 Session
->hScreenSaverParametersChanged
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
225 if (!Session
->hScreenSaverParametersChanged
)
227 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
231 Session
->hEndOfScreenSaverThread
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
232 if (!Session
->hEndOfScreenSaverThread
)
234 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
235 CloseHandle(Session
->hScreenSaverParametersChanged
);
239 ScreenSaverThread
= CreateThread(NULL
,
241 ScreenSaverThreadMain
,
245 if (ScreenSaverThread
)
246 CloseHandle(ScreenSaverThread
);
248 ERR("WL: Unable to start screen saver thread\n");
256 IN PWLSESSION Session
)
258 HKEY hKey
= NULL
, hCurrentUser
= NULL
;
259 WCHAR szApplicationName
[MAX_PATH
];
260 WCHAR szCommandLine
[MAX_PATH
+ 3];
261 DWORD bufferSize
= sizeof(szApplicationName
) - sizeof(WCHAR
);
263 STARTUPINFOW StartupInfo
;
264 PROCESS_INFORMATION ProcessInformation
;
265 HANDLE HandleArray
[2];
270 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
272 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
276 rc
= RegOpenCurrentUser(KEY_READ
,
278 if (rc
!= ERROR_SUCCESS
)
280 ERR("WL: RegOpenCurrentUser Error!\n");
284 rc
= RegOpenKeyExW(hCurrentUser
,
285 L
"Control Panel\\Desktop",
289 if (rc
!= ERROR_SUCCESS
)
291 ERR("WL: RegOpenKeyEx Error!\n");
295 rc
= RegQueryValueExW(hKey
,
299 (LPBYTE
)szApplicationName
,
301 if (rc
!= ERROR_SUCCESS
|| dwType
!= REG_SZ
)
303 ERR("WL: RegQueryValueEx Error!\n");
309 ERR("WL: Buffer size is NULL!\n");
313 szApplicationName
[bufferSize
/ sizeof(WCHAR
)] = 0; /* Terminate the string */
315 if (wcslen(szApplicationName
) == 0)
317 ERR("WL: Application Name length is zero!\n");
321 wsprintfW(szCommandLine
, L
"%s /s", szApplicationName
);
322 TRACE("WL: Executing %S\n", szCommandLine
);
324 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
325 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
326 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
327 StartupInfo
.dwFlags
= STARTF_SCRNSAVER
;
329 /* FIXME: run the screen saver on the screen saver desktop */
330 ret
= CreateProcessW(szApplicationName
,
339 &ProcessInformation
);
342 ERR("WL: Unable to start %S, error %lu\n", szApplicationName
, GetLastError());
346 CloseHandle(ProcessInformation
.hThread
);
348 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, TRUE
, NULL
, 0);
350 /* Wait the end of the process or some other activity */
351 ResetEvent(Session
->hUserActivity
);
352 HandleArray
[0] = ProcessInformation
.hProcess
;
353 HandleArray
[1] = Session
->hUserActivity
;
354 Status
= WaitForMultipleObjects(2, HandleArray
, FALSE
, INFINITE
);
355 if (Status
== WAIT_OBJECT_0
+ 1)
357 /* Kill the screen saver */
358 TerminateProcess(ProcessInformation
.hProcess
, 0);
361 SetEvent(Session
->hEndOfScreenSaver
);
363 CloseHandle(ProcessInformation
.hProcess
);
371 RegCloseKey(hCurrentUser
);
375 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_ACTIVITY
, 0);
376 #ifndef USE_GETLASTINPUTINFO
377 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());