Author: hpoussin Date: Thu Aug 10 22:37:03 2006 New Revision: 23540
URL: http://svn.reactos.org/svn/reactos?rev=23540&view=rev Log: 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
Added: trunk/reactos/base/system/winlogon/screensaver.c Modified: trunk/reactos/base/system/winlogon/sas.c trunk/reactos/base/system/winlogon/winlogon.c trunk/reactos/base/system/winlogon/winlogon.h trunk/reactos/base/system/winlogon/winlogon.rbuild trunk/reactos/base/system/winlogon/wlx.c
Modified: trunk/reactos/base/system/winlogon/sas.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/winlogon/sas.c?... ============================================================================== --- trunk/reactos/base/system/winlogon/sas.c (original) +++ trunk/reactos/base/system/winlogon/sas.c Thu Aug 10 22:37:03 2006 @@ -108,6 +108,10 @@
RemoveStatusMessage(Session); */ + + if (!InitializeScreenSaver(Session)) + ERR("WL: Failed to initialize screen saver\n"); + return TRUE; }
@@ -127,7 +131,7 @@
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 @@ DestroyWindow(Session->SASWindow); Session->SASWindow = NULL; } + if (Session->hEndOfScreenSaverThread) + SetEvent(Session->hEndOfScreenSaverThread); UnregisterClassW(WINLOGON_SAS_CLASS, hAppInstance); }
@@ -378,7 +384,7 @@ } }
-VOID +static VOID DispatchSAS( IN OUT PWLSESSION Session, IN DWORD dwSasType) @@ -399,7 +405,7 @@ Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); break; } - case WLX_SAS_TYPE_CTRL_ALT_DEL: /* 0x01 */ + default: { PSID LogonSid = NULL; /* FIXME */
@@ -417,10 +423,26 @@ (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 @@ 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): @@ -560,6 +582,21 @@ case WM_DESTROY: { 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: @@ -601,6 +638,7 @@ 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 @@ 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 @@ 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)) { + ERR("WL: Failed to register SAS window\n"); + goto cleanup; + } + + ret = TRUE; + +cleanup: + if (!ret) UninitializeSAS(Session); - ERR("WL: Failed to register SAS window\n"); - return FALSE; - } - - return TRUE; -} + return ret; +}
Added: trunk/reactos/base/system/winlogon/screensaver.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/winlogon/screen... ============================================================================== --- trunk/reactos/base/system/winlogon/screensaver.c (added) +++ trunk/reactos/base/system/winlogon/screensaver.c Thu Aug 10 22:37:03 2006 @@ -1,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()); + } +}
Modified: trunk/reactos/base/system/winlogon/winlogon.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/winlogon/winlog... ============================================================================== --- trunk/reactos/base/system/winlogon/winlogon.c (original) +++ trunk/reactos/base/system/winlogon/winlogon.c Thu Aug 10 22:37:03 2006 @@ -66,7 +66,7 @@
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 @@ /* 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 */
Modified: trunk/reactos/base/system/winlogon/winlogon.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/winlogon/winlog... ============================================================================== --- trunk/reactos/base/system/winlogon/winlogon.h (original) +++ trunk/reactos/base/system/winlogon/winlogon.h Thu Aug 10 22:37:03 2006 @@ -87,7 +87,7 @@ 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 @@ { GINAINSTANCE Gina; DWORD SASAction; - DWORD LogonStatus; BOOL SuppressStatus; BOOL TaskManHotkey; HWND SASWindow; @@ -134,8 +133,16 @@ 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; @@ -164,13 +171,18 @@ DWORD dwReserved);
/* sas.c */ +BOOL +InitializeSAS( + IN OUT PWLSESSION Session); + +/* screensaver.c */ +BOOL +InitializeScreenSaver( + IN OUT PWLSESSION Session); + VOID -DispatchSAS( - IN OUT PWLSESSION Session, - IN DWORD dwSasType); -BOOL -InitializeSAS( - IN OUT PWLSESSION Session); +StartScreenSaver( + IN PWLSESSION Session);
/* winlogon.c */ BOOL
Modified: trunk/reactos/base/system/winlogon/winlogon.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/winlogon/winlog... ============================================================================== --- trunk/reactos/base/system/winlogon/winlogon.rbuild (original) +++ trunk/reactos/base/system/winlogon/winlogon.rbuild Thu Aug 10 22:37:03 2006 @@ -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>
Modified: trunk/reactos/base/system/winlogon/wlx.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/winlogon/wlx.c?... ============================================================================== --- trunk/reactos/base/system/winlogon/wlx.c (original) +++ trunk/reactos/base/system/winlogon/wlx.c Thu Aug 10 22:37:03 2006 @@ -86,8 +86,12 @@ 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 @@ 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 @@ if (!Functions->WlxRemoveStatusMessage) goto cleanup; }
+ /* Provide some default functions */ + if (!Functions->WlxScreenSaverNotify) + Functions->WlxScreenSaverNotify = DefaultWlxScreenSaverNotify; + ret = TRUE;
cleanup: