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/scree…
==============================================================================
--- 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(a)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/winlo…
==============================================================================
--- 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/winlo…
==============================================================================
--- 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/winlo…
==============================================================================
--- 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: