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 WINE_DEFAULT_DEBUG_CHANNEL(winlogon
);
15 /* FUNCTIONS ****************************************************************/
17 #ifndef USE_GETLASTINPUTINFO
18 static LRESULT CALLBACK
24 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PKBDLLHOOKSTRUCT
)lParam
)->time
);
25 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
28 static LRESULT CALLBACK
34 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PMSLLHOOKSTRUCT
)lParam
)->time
);
35 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
40 LoadScreenSaverParameters(
45 if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT
, 0, Timeout
, 0))
47 WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
50 else if (!SystemParametersInfoW(SPI_GETSCREENSAVEACTIVE
, 0, &Enabled
, 0))
52 WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
57 TRACE("WL: Screen saver is disabled\n");
62 TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout
);
68 ScreenSaverThreadMain(
69 IN LPVOID lpParameter
)
71 PWLSESSION Session
= (PWLSESSION
)lpParameter
;
72 HANDLE HandleArray
[3];
73 #ifdef USE_GETLASTINPUTINFO
74 LASTINPUTINFO lastInputInfo
;
79 DWORD Timeout
; /* Timeout before screen saver starts, in milliseconds */
82 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
84 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
88 Session
->hUserActivity
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
89 if (!Session
->hUserActivity
)
91 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
95 Session
->hEndOfScreenSaver
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
96 if (!Session
->hEndOfScreenSaver
)
98 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
102 HandleArray
[0] = Session
->hEndOfScreenSaverThread
;
103 HandleArray
[1] = Session
->hScreenSaverParametersChanged
;
104 HandleArray
[2] = Session
->hEndOfScreenSaver
;
106 LoadScreenSaverParameters(&Timeout
);
108 #ifndef USE_GETLASTINPUTINFO
109 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());
111 lastInputInfo
.cbSize
= sizeof(LASTINPUTINFO
);
115 /* See the time of last activity and calculate a timeout */
116 #ifndef USE_GETLASTINPUTINFO
117 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
118 TimeToWait
= Timeout
- (GetTickCount() - LastActivity
);
120 if (GetLastInputInfo(&lastInputInfo
))
121 TimeToWait
= Timeout
- (GetTickCount() - lastInputInfo
.dwTime
);
124 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
125 TimeToWait
= 10; /* Try again in 10 ms */
128 if (TimeToWait
> Timeout
)
130 /* GetTickCount() got back to 0 */
131 TimeToWait
= Timeout
;
134 /* Wait for the timeout, or the end of this thread */
135 ret
= WaitForMultipleObjects(2, HandleArray
, FALSE
, TimeToWait
);
136 if (ret
== WAIT_OBJECT_0
)
138 else if (ret
== WAIT_OBJECT_0
+ 1)
139 LoadScreenSaverParameters(&Timeout
);
141 /* Check if we didn't had recent activity */
142 #ifndef USE_GETLASTINPUTINFO
143 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
144 if (LastActivity
+ Timeout
> GetTickCount())
147 if (!GetLastInputInfo(&lastInputInfo
))
149 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
152 if (lastInputInfo
.dwTime
+ Timeout
> GetTickCount())
156 /* Run screen saver */
157 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
, 0);
159 /* Wait for the end of this thread or of the screen saver */
160 ret
= WaitForMultipleObjects(3, HandleArray
, FALSE
, INFINITE
);
161 if (ret
== WAIT_OBJECT_0
)
163 else if (ret
== WAIT_OBJECT_0
+ 1)
164 LoadScreenSaverParameters(&Timeout
);
165 else if (ret
== WAIT_OBJECT_0
+ 2)
166 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, FALSE
, NULL
, 0);
171 if (Session
->hUserActivity
)
172 CloseHandle(Session
->hUserActivity
);
173 if (Session
->hEndOfScreenSaver
)
174 CloseHandle(Session
->hEndOfScreenSaver
);
175 #ifndef USE_GETLASTINPUTINFO
176 if (Session
->KeyboardHook
)
177 UnhookWindowsHookEx(Session
->KeyboardHook
);
178 if (Session
->MouseHook
)
179 UnhookWindowsHookEx(Session
->MouseHook
);
181 CloseHandle(Session
->hEndOfScreenSaverThread
);
182 CloseHandle(Session
->hScreenSaverParametersChanged
);
187 InitializeScreenSaver(
188 IN OUT PWLSESSION Session
)
190 HANDLE ScreenSaverThread
;
192 #ifndef USE_GETLASTINPUTINFO
193 /* Register hooks to detect keyboard and mouse activity */
194 Session
->KeyboardHook
= SetWindowsHookEx(WH_KEYBOARD_LL
, KeyboardActivityProc
, hAppInstance
, 0);
195 if (!Session
->KeyboardHook
)
197 ERR("WL: Unable to register keyboard hook\n");
200 Session
->MouseHook
= SetWindowsHookEx(WH_MOUSE_LL
, MouseActivityProc
, hAppInstance
, 0);
201 if (!Session
->MouseHook
)
203 ERR("WL: Unable to register mouse hook\n");
208 Session
->hScreenSaverParametersChanged
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
209 if (!Session
->hScreenSaverParametersChanged
)
211 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
214 Session
->hEndOfScreenSaverThread
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
215 if (!Session
->hEndOfScreenSaverThread
)
217 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
218 CloseHandle(Session
->hScreenSaverParametersChanged
);
222 ScreenSaverThread
= CreateThread(
225 ScreenSaverThreadMain
,
229 if (ScreenSaverThread
)
230 CloseHandle(ScreenSaverThread
);
232 ERR("WL: Unable to start screen saver thread\n");
239 IN PWLSESSION Session
)
241 HKEY hKey
= NULL
, hCurrentUser
= NULL
;
242 WCHAR szApplicationName
[MAX_PATH
];
243 WCHAR szCommandLine
[MAX_PATH
+ 3];
244 DWORD bufferSize
= sizeof(szApplicationName
) - sizeof(WCHAR
);
246 STARTUPINFOW StartupInfo
;
247 PROCESS_INFORMATION ProcessInformation
;
248 HANDLE HandleArray
[2];
253 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
255 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
259 rc
= RegOpenCurrentUser(
262 if (rc
!= ERROR_SUCCESS
)
264 ERR("WL: RegOpenCurrentUser Error!\n");
270 L
"Control Panel\\Desktop",
274 if (rc
!= ERROR_SUCCESS
)
276 ERR("WL: RegOpenKeyEx Error!\n");
280 rc
= RegQueryValueExW(
285 (LPBYTE
)szApplicationName
,
287 if (rc
!= ERROR_SUCCESS
|| dwType
!= REG_SZ
)
289 ERR("WL: RegQueryValueEx Error!\n");
295 ERR("WL: Buffer size is NULL!\n");
299 szApplicationName
[bufferSize
/ sizeof(WCHAR
)] = 0; /* Terminate the string */
301 if (wcslen(szApplicationName
) == 0)
303 ERR("WL: Application Name length is zero!\n");
307 wsprintfW(szCommandLine
, L
"%s /s", szApplicationName
);
308 TRACE("WL: Executing %S\n", szCommandLine
);
310 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
311 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
312 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
313 StartupInfo
.dwFlags
= STARTF_SCRNSAVER
;
314 /* FIXME: run the screen saver on the screen saver desktop */
315 ret
= CreateProcessW(
325 &ProcessInformation
);
328 ERR("WL: Unable to start %S, error %lu\n", szApplicationName
, GetLastError());
331 CloseHandle(ProcessInformation
.hThread
);
333 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, TRUE
, NULL
, 0);
335 /* Wait the end of the process or some other activity */
336 ResetEvent(Session
->hUserActivity
);
337 HandleArray
[0] = ProcessInformation
.hProcess
;
338 HandleArray
[1] = Session
->hUserActivity
;
339 Status
= WaitForMultipleObjects(2, HandleArray
, FALSE
, INFINITE
);
340 if (Status
== WAIT_OBJECT_0
+ 1)
342 /* Kill the screen saver */
343 TerminateProcess(ProcessInformation
.hProcess
, 0);
345 SetEvent(Session
->hEndOfScreenSaver
);
347 CloseHandle(ProcessInformation
.hProcess
);
354 RegCloseKey(hCurrentUser
);
357 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_ACTIVITY
, 0);
358 #ifndef USE_GETLASTINPUTINFO
359 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());