mirror of
https://github.com/reactos/reactos.git
synced 2024-11-02 21:09:15 +00:00
389 lines
11 KiB
C
389 lines
11 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Winlogon
|
|
* FILE: base/system/winlogon/screensaver.c
|
|
* PURPOSE: Screen saver management
|
|
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "winlogon.h"
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
#ifndef USE_GETLASTINPUTINFO
|
|
static
|
|
LRESULT
|
|
CALLBACK
|
|
KeyboardActivityProc(
|
|
IN INT nCode,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
InterlockedExchange((LONG*)&WLSession->LastActivity, ((PKBDLLHOOKSTRUCT)lParam)->time);
|
|
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
|
}
|
|
|
|
|
|
static
|
|
LRESULT
|
|
CALLBACK
|
|
MouseActivityProc(
|
|
IN INT nCode,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
InterlockedExchange((LONG*)&WLSession->LastActivity, ((PMSLLHOOKSTRUCT)lParam)->time);
|
|
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
|
}
|
|
#endif
|
|
|
|
|
|
static
|
|
VOID
|
|
LoadScreenSaverParameters(
|
|
OUT LPDWORD Timeout)
|
|
{
|
|
BOOL Enabled;
|
|
|
|
if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT, 0, Timeout, 0))
|
|
{
|
|
WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
|
|
*Timeout = INFINITE;
|
|
}
|
|
else if (!SystemParametersInfoW(SPI_GETSCREENSAVEACTIVE, 0, &Enabled, 0))
|
|
{
|
|
WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
|
|
*Timeout = INFINITE;
|
|
}
|
|
else if (!Enabled)
|
|
{
|
|
TRACE("WL: Screen saver is disabled\n");
|
|
*Timeout = INFINITE;
|
|
}
|
|
else
|
|
{
|
|
TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout);
|
|
*Timeout *= 1000;
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
DWORD
|
|
WINAPI
|
|
ScreenSaverThreadMain(
|
|
IN LPVOID lpParameter)
|
|
{
|
|
PWLSESSION Session = (PWLSESSION)lpParameter;
|
|
HANDLE HandleArray[3];
|
|
#ifdef USE_GETLASTINPUTINFO
|
|
LASTINPUTINFO lastInputInfo;
|
|
#else
|
|
DWORD LastActivity;
|
|
#endif
|
|
DWORD TimeToWait;
|
|
DWORD Timeout; /* Timeout before screen saver starts, in milliseconds */
|
|
DWORD ret;
|
|
|
|
if (!ImpersonateLoggedOnUser(Session->UserToken))
|
|
{
|
|
ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
Session->hUserActivity = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
if (!Session->hUserActivity)
|
|
{
|
|
ERR("WL: Unable to create event (error %lu)\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
Session->hEndOfScreenSaver = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
if (!Session->hEndOfScreenSaver)
|
|
{
|
|
ERR("WL: Unable to create event (error %lu)\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
HandleArray[0] = Session->hEndOfScreenSaverThread;
|
|
HandleArray[1] = Session->hScreenSaverParametersChanged;
|
|
HandleArray[2] = Session->hEndOfScreenSaver;
|
|
|
|
LoadScreenSaverParameters(&Timeout);
|
|
|
|
#ifndef USE_GETLASTINPUTINFO
|
|
InterlockedExchange((LONG*)&Session->LastActivity, GetTickCount());
|
|
#else
|
|
lastInputInfo.cbSize = sizeof(LASTINPUTINFO);
|
|
#endif
|
|
for (;;)
|
|
{
|
|
/* See the time of last activity and calculate a timeout */
|
|
#ifndef USE_GETLASTINPUTINFO
|
|
LastActivity = InterlockedCompareExchange((LONG*)&Session->LastActivity, 0, 0);
|
|
TimeToWait = Timeout - (GetTickCount() - LastActivity);
|
|
#else
|
|
if (GetLastInputInfo(&lastInputInfo))
|
|
TimeToWait = Timeout - (GetTickCount() - lastInputInfo.dwTime);
|
|
else
|
|
{
|
|
WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
|
|
TimeToWait = 10; /* Try again in 10 ms */
|
|
}
|
|
#endif
|
|
|
|
if (TimeToWait > Timeout)
|
|
{
|
|
/* GetTickCount() got back to 0 */
|
|
TimeToWait = Timeout;
|
|
}
|
|
|
|
/* Wait for the timeout, or the end of this thread */
|
|
ret = WaitForMultipleObjects(2, HandleArray, FALSE, TimeToWait);
|
|
if (ret == WAIT_OBJECT_0)
|
|
break;
|
|
else if (ret == WAIT_OBJECT_0 + 1)
|
|
LoadScreenSaverParameters(&Timeout);
|
|
|
|
/* Check if we didn't had recent activity */
|
|
#ifndef USE_GETLASTINPUTINFO
|
|
LastActivity = InterlockedCompareExchange((LONG*)&Session->LastActivity, 0, 0);
|
|
if (LastActivity + Timeout > GetTickCount())
|
|
continue;
|
|
#else
|
|
if (!GetLastInputInfo(&lastInputInfo))
|
|
{
|
|
WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
|
|
continue;
|
|
}
|
|
|
|
if (lastInputInfo.dwTime + Timeout > GetTickCount())
|
|
continue;
|
|
#endif
|
|
|
|
/* Run screen saver */
|
|
PostMessageW(Session->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_SCRNSVR_TIMEOUT, 0);
|
|
|
|
/* Wait for the end of this thread or of the screen saver */
|
|
ret = WaitForMultipleObjects(3, HandleArray, FALSE, INFINITE);
|
|
if (ret == WAIT_OBJECT_0)
|
|
break;
|
|
else if (ret == WAIT_OBJECT_0 + 1)
|
|
LoadScreenSaverParameters(&Timeout);
|
|
else if (ret == WAIT_OBJECT_0 + 2)
|
|
SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING, FALSE, NULL, 0);
|
|
}
|
|
|
|
cleanup:
|
|
if (Session->hUserActivity)
|
|
CloseHandle(Session->hUserActivity);
|
|
|
|
if (Session->hEndOfScreenSaver)
|
|
CloseHandle(Session->hEndOfScreenSaver);
|
|
|
|
RevertToSelf();
|
|
|
|
#ifndef USE_GETLASTINPUTINFO
|
|
if (Session->KeyboardHook)
|
|
UnhookWindowsHookEx(Session->KeyboardHook);
|
|
|
|
if (Session->MouseHook)
|
|
UnhookWindowsHookEx(Session->MouseHook);
|
|
#endif
|
|
|
|
CloseHandle(Session->hEndOfScreenSaverThread);
|
|
CloseHandle(Session->hScreenSaverParametersChanged);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
InitializeScreenSaver(
|
|
IN OUT PWLSESSION Session)
|
|
{
|
|
HANDLE ScreenSaverThread;
|
|
|
|
#ifndef USE_GETLASTINPUTINFO
|
|
/* Register hooks to detect keyboard and mouse activity */
|
|
Session->KeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardActivityProc, hAppInstance, 0);
|
|
if (!Session->KeyboardHook)
|
|
{
|
|
ERR("WL: Unable to register keyboard hook\n");
|
|
return FALSE;
|
|
}
|
|
|
|
Session->MouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseActivityProc, hAppInstance, 0);
|
|
if (!Session->MouseHook)
|
|
{
|
|
ERR("WL: Unable to register mouse hook\n");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
Session->hScreenSaverParametersChanged = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
if (!Session->hScreenSaverParametersChanged)
|
|
{
|
|
WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
|
|
return TRUE;
|
|
}
|
|
|
|
Session->hEndOfScreenSaverThread = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
if (!Session->hEndOfScreenSaverThread)
|
|
{
|
|
WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
|
|
CloseHandle(Session->hScreenSaverParametersChanged);
|
|
return TRUE;
|
|
}
|
|
|
|
ScreenSaverThread = CreateThread(NULL,
|
|
0,
|
|
ScreenSaverThreadMain,
|
|
Session,
|
|
0,
|
|
NULL);
|
|
if (ScreenSaverThread)
|
|
CloseHandle(ScreenSaverThread);
|
|
else
|
|
ERR("WL: Unable to start screen saver thread\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
StartScreenSaver(
|
|
IN PWLSESSION Session)
|
|
{
|
|
HKEY hKey = NULL, hCurrentUser = NULL;
|
|
WCHAR szApplicationName[MAX_PATH];
|
|
WCHAR szCommandLine[MAX_PATH + 3];
|
|
DWORD bufferSize = sizeof(szApplicationName) - sizeof(WCHAR);
|
|
DWORD dwType;
|
|
STARTUPINFOW StartupInfo;
|
|
PROCESS_INFORMATION ProcessInformation;
|
|
HANDLE HandleArray[2];
|
|
LONG rc;
|
|
DWORD Status;
|
|
BOOL ret = FALSE;
|
|
|
|
if (!ImpersonateLoggedOnUser(Session->UserToken))
|
|
{
|
|
ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = RegOpenCurrentUser(KEY_READ,
|
|
&hCurrentUser);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
ERR("WL: RegOpenCurrentUser error %lu\n", rc);
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = RegOpenKeyExW(hCurrentUser,
|
|
L"Control Panel\\Desktop",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (rc != ERROR_SUCCESS)
|
|
{
|
|
ERR("WL: RegOpenKeyEx error %lu\n", rc);
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = RegQueryValueExW(hKey,
|
|
L"SCRNSAVE.EXE",
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)szApplicationName,
|
|
&bufferSize);
|
|
if (rc != ERROR_SUCCESS || dwType != REG_SZ)
|
|
{
|
|
if (rc != ERROR_FILE_NOT_FOUND)
|
|
ERR("WL: RegQueryValueEx error %lu\n", rc);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (bufferSize == 0)
|
|
{
|
|
ERR("WL: Buffer size is NULL!\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
szApplicationName[bufferSize / sizeof(WCHAR)] = 0; /* Terminate the string */
|
|
|
|
if (wcslen(szApplicationName) == 0)
|
|
{
|
|
ERR("WL: Application Name length is zero!\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
wsprintfW(szCommandLine, L"%s /s", szApplicationName);
|
|
TRACE("WL: Executing %S\n", szCommandLine);
|
|
|
|
ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
|
|
ZeroMemory(&ProcessInformation, sizeof(PROCESS_INFORMATION));
|
|
StartupInfo.cb = sizeof(STARTUPINFOW);
|
|
StartupInfo.dwFlags = STARTF_SCRNSAVER;
|
|
|
|
/* FIXME: run the screen saver on the screen saver desktop */
|
|
ret = CreateProcessW(szApplicationName,
|
|
szCommandLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&StartupInfo,
|
|
&ProcessInformation);
|
|
if (!ret)
|
|
{
|
|
ERR("WL: Unable to start %S, error %lu\n", szApplicationName, GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
CloseHandle(ProcessInformation.hThread);
|
|
|
|
SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING, TRUE, NULL, 0);
|
|
|
|
CallNotificationDlls(Session, StartScreenSaverHandler);
|
|
|
|
/* Wait the end of the process or some other activity */
|
|
ResetEvent(Session->hUserActivity);
|
|
HandleArray[0] = ProcessInformation.hProcess;
|
|
HandleArray[1] = Session->hUserActivity;
|
|
Status = WaitForMultipleObjects(2, HandleArray, FALSE, INFINITE);
|
|
if (Status == WAIT_OBJECT_0 + 1)
|
|
{
|
|
/* Kill the screen saver */
|
|
TerminateProcess(ProcessInformation.hProcess, 0);
|
|
}
|
|
|
|
SetEvent(Session->hEndOfScreenSaver);
|
|
|
|
CloseHandle(ProcessInformation.hProcess);
|
|
|
|
CallNotificationDlls(Session, StopScreenSaverHandler);
|
|
|
|
cleanup:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (hCurrentUser)
|
|
RegCloseKey(hCurrentUser);
|
|
|
|
RevertToSelf();
|
|
|
|
if (!ret)
|
|
{
|
|
PostMessageW(Session->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_SCRNSVR_ACTIVITY, 0);
|
|
#ifndef USE_GETLASTINPUTINFO
|
|
InterlockedExchange((LONG*)&Session->LastActivity, GetTickCount());
|
|
#endif
|
|
}
|
|
}
|