Add code to start the screensaver from winlogon

This code should replace the existing one in win32k/csrss, but is not activated (yet) due to some bugs:
- Calling SetWindowsHookEx with WH_KEYBOARD_LL gives a BSOD when pressing a key
- Time field in PKBDLLHOOKSTRUCT/PMSLLHOOKSTRUCT should be in milliseconds
- Screen saver parameters can't be retrieved with SystemParametersInfoW
- Probably others...

Plus a few less important ones:
- When sending a message with HWND_BROADCAST, the invisible SAS window doesn't get the message
- When calling (NtUser)SystemParametersInfo, WM_SETTINGSCHANGE message is not sent
- desk.cpl doesn't save (some) screensaver parameters to registry

svn path=/trunk/; revision=23540
This commit is contained in:
Hervé Poussineau 2006-08-10 18:37:03 +00:00
parent 3318c29301
commit e3d8854be7
6 changed files with 365 additions and 24 deletions

View file

@ -108,6 +108,10 @@ HandleLogon(
RemoveStatusMessage(Session);
*/
if (!InitializeScreenSaver(Session))
ERR("WL: Failed to initialize screen saver\n");
return TRUE;
}
@ -127,7 +131,7 @@ LogoffShutdownThread(LPVOID Parameter)
if (LSData->Session->UserToken && !ImpersonateLoggedOnUser(LSData->Session->UserToken))
{
ERR("ImpersonateLoggedOnUser failed with error %lu\n", GetLastError());
ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
return 0;
}
@ -240,6 +244,8 @@ UninitializeSAS(
DestroyWindow(Session->SASWindow);
Session->SASWindow = NULL;
}
if (Session->hEndOfScreenSaverThread)
SetEvent(Session->hEndOfScreenSaverThread);
UnregisterClassW(WINLOGON_SAS_CLASS, hAppInstance);
}
@ -378,7 +384,7 @@ DoGenericAction(
}
}
VOID
static VOID
DispatchSAS(
IN OUT PWLSESSION Session,
IN DWORD dwSasType)
@ -399,7 +405,7 @@ DispatchSAS(
Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context);
break;
}
case WLX_SAS_TYPE_CTRL_ALT_DEL: /* 0x01 */
default:
{
PSID LogonSid = NULL; /* FIXME */
@ -417,11 +423,27 @@ DispatchSAS(
(PVOID*)&Session->Profile);
break;
}
default:
WARN("Unknown SAS type 0x%lx\n", dwSasType);
}
}
if (dwSasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
{
BOOL bSecure = TRUE;
if (!Session->Gina.Functions.WlxScreenSaverNotify(Session->Gina.Context, &bSecure))
{
/* Skip start of screen saver */
SetEvent(Session->hUserActivity);
}
else
{
if (bSecure)
DoGenericAction(Session, WLX_SAS_ACTION_LOCK_WKSTA);
StartScreenSaver(Session);
}
}
else if (dwSasType == WLX_SAS_TYPE_SCRNSVR_ACTIVITY)
SetEvent(Session->hUserActivity);
DoGenericAction(Session, wlxAction);
}
@ -535,7 +557,7 @@ SASWindowProc(
TRACE("SAS: CONTROL+ALT+DELETE\n");
if (!Session->Gina.UseCtrlAltDelete)
break;
DispatchSAS(Session, WLX_SAS_TYPE_CTRL_ALT_DEL);
PostMessageW(Session->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0);
return TRUE;
}
case MAKELONG(MOD_CONTROL | MOD_SHIFT, VK_ESCAPE):
@ -562,6 +584,21 @@ SASWindowProc(
UnregisterHotKeys(Session, hwndDlg);
return TRUE;
}
case WM_SETTINGCHANGE:
{
UINT uiAction = (UINT)wParam;
if (uiAction == SPI_SETSCREENSAVETIMEOUT
|| uiAction == SPI_SETSCREENSAVEACTIVE)
{
SetEvent(Session->hScreenSaverParametersChanged);
}
return TRUE;
}
case WLX_WM_SAS:
{
DispatchSAS(Session, (DWORD)wParam);
return TRUE;
}
case PM_WINLOGON_EXITWINDOWS:
{
UINT Flags = (UINT)lParam;
@ -601,6 +638,7 @@ InitializeSAS(
IN OUT PWLSESSION Session)
{
WNDCLASSEXW swc;
BOOL ret = FALSE;
/* register SAS window class.
* WARNING! MAKE SURE WE ARE IN THE WINLOGON DESKTOP! */
@ -619,7 +657,7 @@ InitializeSAS(
if (RegisterClassExW(&swc) == 0)
{
ERR("WL: Failed to register SAS window class\n");
return FALSE;
goto cleanup;
}
/* create invisible SAS window */
@ -633,17 +671,20 @@ InitializeSAS(
if (!Session->SASWindow)
{
ERR("WL: Failed to create SAS window\n");
UninitializeSAS(Session);
return FALSE;
goto cleanup;
}
/* Register SAS window to receive SAS notifications */
if (!SetLogonNotifyWindow(Session->SASWindow, Session->InteractiveWindowStation))
{
UninitializeSAS(Session);
ERR("WL: Failed to register SAS window\n");
return FALSE;
goto cleanup;
}
return TRUE;
ret = TRUE;
cleanup:
if (!ret)
UninitializeSAS(Session);
return ret;
}

View file

@ -0,0 +1,269 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: services/winlogon/screensaver.c
* PURPOSE: Screen saver management
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
*/
#include "winlogon.h"
#define YDEBUG
#include <wine/debug.h>
static LRESULT CALLBACK
KeyboardActivityProc(
IN INT nCode,
IN WPARAM wParam,
IN LPARAM lParam)
{
InterlockedExchange(&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(&WLSession->LastActivity, ((PMSLLHOOKSTRUCT)lParam)->time);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
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];
DWORD LastActivity, 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;
}
HandleArray[0] = Session->hEndOfScreenSaverThread;
HandleArray[1] = Session->hScreenSaverParametersChanged;
HandleArray[2] = Session->hUserActivity;
LoadScreenSaverParameters(&Timeout);
InterlockedExchange((LONG*)&Session->LastActivity, GetTickCount());
for (;;)
{
/* See the time of last activity and calculate a timeout */
LastActivity = InterlockedCompareExchange((LONG*)&Session->LastActivity, 0, 0);
TimeToWait = Timeout - (GetTickCount() - LastActivity);
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 */
LastActivity = InterlockedCompareExchange(&Session->LastActivity, 0, 0);
if (LastActivity + Timeout > GetTickCount())
continue;
/* 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:
RevertToSelf();
if (Session->hUserActivity)
CloseHandle(Session->hUserActivity);
if (Session->KeyboardHook)
UnhookWindowsHookEx(Session->KeyboardHook);
if (Session->MouseHook)
UnhookWindowsHookEx(Session->MouseHook);
CloseHandle(Session->hEndOfScreenSaverThread);
CloseHandle(Session->hScreenSaverParametersChanged);
return 0;
}
BOOL
InitializeScreenSaver(
IN OUT PWLSESSION Session)
{
HANDLE ScreenSaverThread;
FIXME("Disabling screen saver due to numerous bugs in ReactOS (see r23540)!\n");
return TRUE;
/* 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;
}
if (!(Session->hScreenSaverParametersChanged = CreateEventW(NULL, FALSE, FALSE, NULL)))
{
WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
}
else if (!(Session->hEndOfScreenSaverThread = CreateEventW(NULL, FALSE, FALSE, NULL)))
{
WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
CloseHandle(Session->hScreenSaverParametersChanged);
}
else
{
ScreenSaverThread = CreateThread(
NULL,
0,
ScreenSaverThreadMain,
Session,
0,
NULL);
if (ScreenSaverThread)
CloseHandle(ScreenSaverThread);
else
WARN("WL: Unable to start screen saver thread\n");
}
return TRUE;
}
VOID
StartScreenSaver(
IN PWLSESSION Session)
{
HKEY hKey = NULL;
WCHAR szApplicationName[MAX_PATH];
WCHAR szCommandLine[MAX_PATH + 3];
DWORD bufferSize = sizeof(szApplicationName)- 1;
DWORD dwType;
STARTUPINFOW StartupInfo;
PROCESS_INFORMATION ProcessInformation;
LONG rc;
BOOL ret = FALSE;
if (!ImpersonateLoggedOnUser(Session->UserToken))
{
ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
goto cleanup;
}
rc = RegOpenKeyExW(
HKEY_CURRENT_USER,
L"Control Panel\\Desktop",
0,
KEY_QUERY_VALUE,
&hKey);
if (rc != ERROR_SUCCESS)
goto cleanup;
szApplicationName[bufferSize] = 0; /* Terminate the string */
rc = RegQueryValueExW(
hKey,
L"SCRNSAVE.EXE",
0,
&dwType,
(LPBYTE)szApplicationName,
&bufferSize);
if (rc != ERROR_SUCCESS || dwType != REG_SZ)
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);
/* FIXME: run the screen saver on the screen saver desktop */
ret = CreateProcessW(
szApplicationName,
szCommandLine,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&StartupInfo,
&ProcessInformation);
if (!ret)
{
WARN("WL: Unable to start %S, error %lu\n", szApplicationName, GetLastError());
goto cleanup;
}
CloseHandle(ProcessInformation.hProcess);
CloseHandle(ProcessInformation.hThread);
cleanup:
RevertToSelf();
if (hKey)
RegCloseKey(hKey);
if (ret)
SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING, TRUE, NULL, 0);
else
{
PostMessageW(Session->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_SCRNSVR_ACTIVITY, 0);
InterlockedExchange((LONG*)&Session->LastActivity, GetTickCount());
}
}

View file

@ -66,7 +66,7 @@ StartServicesManager(VOID)
TRACE("WL: Attempting to open event \"SvcctrlStartEvent_A3725DX\"\n");
ServicesInitEvent = OpenEventW(
EVENT_ALL_ACCESS, //SYNCHRONIZE,
SYNCHRONIZE,
FALSE,
L"SvcctrlStartEvent_A3725DX");
if (ServicesInitEvent)
@ -481,13 +481,13 @@ WinMain(
/* Display logged out screen */
WLSession->LogonStatus = WKSTA_IS_LOGGED_OFF;
RemoveStatusMessage(WLSession);
DispatchSAS(WLSession, WLX_SAS_TYPE_TIMEOUT);
PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_TIMEOUT, 0);
/* Message loop for the SAS window */
while (GetMessage(&Msg, WLSession->SASWindow, 0, 0))
while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
DispatchMessageW(&Msg);
}
/* We never go there */

View file

@ -87,7 +87,7 @@ typedef struct _GINAFUNCTIONS
PFWLXSHUTDOWN WlxShutdown;
/* Functions available if WlxVersion >= WLX_VERSION_1_1 (MS Windows 3.5.1) */
PFWLXSCREENSAVERNOTIFY WlxScreenSaverNotify; /* optional, not called ATM */
PFWLXSCREENSAVERNOTIFY WlxScreenSaverNotify; /* optional */
PFWLXSTARTAPPLICATION WlxStartApplication; /* optional, not called ATM */
/* Functions available if WlxVersion >= WLX_VERSION_1_2 (MS Windows NT 4.0) */
@ -123,7 +123,6 @@ typedef struct _WLSESSION
{
GINAINSTANCE Gina;
DWORD SASAction;
DWORD LogonStatus;
BOOL SuppressStatus;
BOOL TaskManHotkey;
HWND SASWindow;
@ -134,9 +133,17 @@ typedef struct _WLSESSION
HDESK ScreenSaverDesktop;
LUID LogonId;
HANDLE UserToken;
DWORD LogonStatus;
DWORD DialogTimeout; /* Timeout for dialog boxes, in seconds */
/* Screen-saver informations */
HHOOK KeyboardHook;
HHOOK MouseHook;
HANDLE hEndOfScreenSaverThread;
HANDLE hScreenSaverParametersChanged;
HANDLE hUserActivity;
DWORD LastActivity;
/* Logon informations */
DWORD Options;
WLX_MPR_NOTIFY_INFO MprNotifyInfo;
@ -164,14 +171,19 @@ UpdatePerUserSystemParameters(DWORD dwUnknown,
DWORD dwReserved);
/* sas.c */
VOID
DispatchSAS(
IN OUT PWLSESSION Session,
IN DWORD dwSasType);
BOOL
InitializeSAS(
IN OUT PWLSESSION Session);
/* screensaver.c */
BOOL
InitializeScreenSaver(
IN OUT PWLSESSION Session);
VOID
StartScreenSaver(
IN PWLSESSION Session);
/* winlogon.c */
BOOL
DisplayStatusMessage(

View file

@ -11,6 +11,7 @@
<library>userenv</library>
<library>secur32</library>
<file>sas.c</file>
<file>screensaver.c</file>
<file>setup.c</file>
<file>winlogon.c</file>
<file>wlx.c</file>

View file

@ -86,8 +86,12 @@ WlxSasNotify(
HANDLE hWlx,
DWORD dwSasType)
{
PWLSESSION Session = (PWLSESSION)hWlx;
TRACE("WlxSasNotify(0x%lx)\n", dwSasType);
DispatchSAS((PWLSESSION)hWlx, dwSasType);
if (dwSasType == WLX_SAS_TYPE_CTRL_ALT_DEL || dwSasType > WLX_SAS_TYPE_MAX_MSFT_VALUE)
PostMessageW(Session->SASWindow, WLX_WM_SAS, dwSasType, 0);
}
/*
@ -558,6 +562,16 @@ GetGinaPath(
return TRUE;
}
static BOOL WINAPI
DefaultWlxScreenSaverNotify(
IN PVOID pWlxContext,
IN OUT BOOL *pSecure)
{
if (*pSecure)
*pSecure = WLSession->Gina.Functions.WlxIsLogoffOk(pWlxContext);
return TRUE;
}
static BOOL
LoadGina(
IN OUT PGINAFUNCTIONS Functions,
@ -640,6 +654,10 @@ LoadGina(
if (!Functions->WlxRemoveStatusMessage) goto cleanup;
}
/* Provide some default functions */
if (!Functions->WlxScreenSaverNotify)
Functions->WlxScreenSaverNotify = DefaultWlxScreenSaverNotify;
ret = TRUE;
cleanup: