diff --git a/reactos/base/system/winlogon/sas.c b/reactos/base/system/winlogon/sas.c index 98db8b67733..c65092cbe55 100644 --- a/reactos/base/system/winlogon/sas.c +++ b/reactos/base/system/winlogon/sas.c @@ -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; } diff --git a/reactos/base/system/winlogon/screensaver.c b/reactos/base/system/winlogon/screensaver.c new file mode 100644 index 00000000000..991e65f5bdd --- /dev/null +++ b/reactos/base/system/winlogon/screensaver.c @@ -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 + +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()); + } +} diff --git a/reactos/base/system/winlogon/winlogon.c b/reactos/base/system/winlogon/winlogon.c index 6e3458494de..c0896e980cc 100644 --- a/reactos/base/system/winlogon/winlogon.c +++ b/reactos/base/system/winlogon/winlogon.c @@ -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 */ diff --git a/reactos/base/system/winlogon/winlogon.h b/reactos/base/system/winlogon/winlogon.h index 15a1d2d714b..4bcaa421c8a 100644 --- a/reactos/base/system/winlogon/winlogon.h +++ b/reactos/base/system/winlogon/winlogon.h @@ -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( diff --git a/reactos/base/system/winlogon/winlogon.rbuild b/reactos/base/system/winlogon/winlogon.rbuild index 08e27da01ee..e596514e5bd 100644 --- a/reactos/base/system/winlogon/winlogon.rbuild +++ b/reactos/base/system/winlogon/winlogon.rbuild @@ -11,6 +11,7 @@ userenv secur32 sas.c + screensaver.c setup.c winlogon.c wlx.c diff --git a/reactos/base/system/winlogon/wlx.c b/reactos/base/system/winlogon/wlx.c index 4169d65db2d..5dd0399d192 100644 --- a/reactos/base/system/winlogon/wlx.c +++ b/reactos/base/system/winlogon/wlx.c @@ -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: