[ros-diffs] [hpoussin] 23540: 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

hpoussin at svn.reactos.org hpoussin at svn.reactos.org
Thu Aug 10 20:37:04 CEST 2006


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?rev=23540&r1=23539&r2=23540&view=diff
==============================================================================
--- 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/screensaver.c?rev=23540&view=auto
==============================================================================
--- 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 at 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/winlogon.c?rev=23540&r1=23539&r2=23540&view=diff
==============================================================================
--- 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/winlogon.h?rev=23540&r1=23539&r2=23540&view=diff
==============================================================================
--- 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/winlogon.rbuild?rev=23540&r1=23539&r2=23540&view=diff
==============================================================================
--- 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?rev=23540&r1=23539&r2=23540&view=diff
==============================================================================
--- 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:




More information about the Ros-diffs mailing list