Author: hbelusca
Date: Sat Feb 7 20:46:27 2015
New Revision: 66197
URL: http://svn.reactos.org/svn/reactos?rev=66197&view=rev
Log:
[WINLOGON]
- Add DPRINTs to monitor how shutdown goes on (obviously they will go away when shutdown on ROS will be working).
- Add dumb handler for LN_LOGOFF_CANCELED message (unused for now...)
[WIN32K]: DPRINTs added for monitoring shutdown.
[WINSRV]: Start to plugin the whole thing (using pieces of Alex' shutdown patch):
- We need to use a "shutdown" loop (for UserThreadInitiateShutdown win32k call) for being able to cancel shuts down (not implemented yet).
- Add the "magic" call to CsrShutdownProcesses that calls the Shutdown callback of each CSR server for each Win32 process (these are those callbacks that do the real job of terminating the apps, displaying the "Kill the app" dialog, etc...). In few words, the old (disabled) code of InternalExitReactos need to go into those shutdown callbacks (but this is for other commits!).
Part 9/X
CORE-8322 #comment Continue plugging in the shutdown code (from Alex' patch) in WINSRV with adaptations into WINLOGON (+ adding DPRINTs for controlling the whole thing).
Modified:
trunk/reactos/base/system/winlogon/sas.c
trunk/reactos/win32ss/user/ntuser/shutdown.c
trunk/reactos/win32ss/user/winsrv/usersrv/shutdown.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 [iso-8859-1] (original)
+++ trunk/reactos/base/system/winlogon/sas.c [iso-8859-1] Sat Feb 7 20:46:27 2015
@@ -37,6 +37,8 @@
UINT Flags;
PWLSESSION Session;
} LOGOFF_SHUTDOWN_DATA, *PLOGOFF_SHUTDOWN_DATA;
+
+static BOOL ExitReactOSInProgress = FALSE;
/* FUNCTIONS ****************************************************************/
@@ -499,25 +501,33 @@
LPVOID Parameter)
{
PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA)Parameter;
-
- if (LSData->Session->UserToken != NULL && !ImpersonateLoggedOnUser(LSData->Session->UserToken))
+ UINT uFlags;
+
+ if (LSData->Session->UserToken != NULL &&
+ !ImpersonateLoggedOnUser(LSData->Session->UserToken))
{
ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
return 0;
}
+ uFlags = EWX_INTERNAL_KILL_USER_APPS | (LSData->Flags & EWX_FLAGS_MASK) |
+ ((LSData->Flags & EWX_ACTION_MASK) == EWX_LOGOFF ? EWX_INTERNAL_FLAG_LOGOFF : 0);
+
+ ERR("In LogoffShutdownThread with uFlags == 0x%x; exit_in_progress == %s\n",
+ uFlags, ExitReactOSInProgress ? "true" : "false");
+
+ ExitReactOSInProgress = TRUE;
+
/* Close processes of the interactive user */
- if (!ExitWindowsEx(
- EWX_INTERNAL_KILL_USER_APPS | (LSData->Flags & EWX_FLAGS_MASK) |
- (EWX_LOGOFF == (LSData->Flags & EWX_ACTION_MASK) ? EWX_INTERNAL_FLAG_LOGOFF : 0),
- 0))
+ if (!ExitWindowsEx(uFlags, 0))
{
ERR("Unable to kill user apps, error %lu\n", GetLastError());
RevertToSelf();
return 0;
}
- /* FIXME: Call ExitWindowsEx() to terminate COM processes */
+ /* FIXME: Call ExitWindowsEx() to terminate COM processes only at logoff! */
+ ERR("Should terminate COM processes only at logoff!\n");
if (LSData->Session->UserToken)
RevertToSelf();
@@ -687,7 +697,7 @@
/* Run logoff thread */
hThread = CreateThread(psa, 0, LogoffShutdownThread, (LPVOID)LSData, 0, NULL);
- /* we're done with the SECURITY_DESCRIPTOR */
+ /* We're done with the SECURITY_DESCRIPTOR */
DestroyLogoffSecurityAttributes(psa);
psa = NULL;
@@ -1317,8 +1327,36 @@
}
}
+ ERR("In LN_LOGOFF, exit_in_progress == %s\n",
+ ExitReactOSInProgress ? "true" : "false");
+
+ /*
+ * In case a parallel shutdown request is done (while we are
+ * being to shut down) and it was not done by Winlogon itself,
+ * then just stop here.
+ */
+#if 0
+// This code is commented at the moment (even if it's correct) because
+// our log-offs do not really work: the shell is restarted, no app is killed
+// etc... and as a result you just get explorer opening "My Documents". And
+// if you try now a shut down, it won't work because winlogon thinks it is
+// still in the middle of a shutdown.
+// Maybe we also need to reset ExitReactOSInProgress somewhere else??
+ if (ExitReactOSInProgress && (lParam & EWX_INTERNAL_FLAG) == 0)
+ {
+ break;
+ }
+#endif
/* Now do the shutdown action proper */
DoGenericAction(Session, wlxAction);
+ return 1;
+ }
+ case LN_LOGOFF_CANCELED:
+ {
+ ERR("Logoff canceled!!, before: exit_in_progress == %s, after will be false\n",
+ ExitReactOSInProgress ? "true" : "false");
+
+ ExitReactOSInProgress = FALSE;
return 1;
}
default:
Modified: trunk/reactos/win32ss/user/ntuser/shutdown.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/shutdo…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/shutdown.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/shutdown.c [iso-8859-1] Sat Feb 7 20:46:27 2015
@@ -228,11 +228,13 @@
if (PsGetThreadProcessId(Thread) != gpidLogon)
{
// FIXME: HACK!! Do more checks!!
+ ERR("UserInitiateShutdown -- Notify Winlogon for shutdown\n");
UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOGOFF, (LPARAM)Flags);
return STATUS_PENDING;
}
// If we reach this point, that means it's Winlogon that triggered the shutdown.
+ ERR("UserInitiateShutdown -- Winlogon shuts down\n");
/*
* FIXME:
Modified: trunk/reactos/win32ss/user/winsrv/usersrv/shutdown.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/winsrv/usersr…
==============================================================================
--- trunk/reactos/win32ss/user/winsrv/usersrv/shutdown.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/winsrv/usersrv/shutdown.c [iso-8859-1] Sat Feb 7 20:46:27 2015
@@ -758,7 +758,7 @@
RegCloseKey(DesktopKey);
}
-static NTSTATUS FASTCALL
+NTSTATUS FASTCALL
InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags)
{
HANDLE CallerThread;
@@ -772,7 +772,7 @@
TOKEN_USER *UserInfo;
SHUTDOWN_SETTINGS ShutdownSettings;
- if (ProcessId != (DWORD_PTR) LogonProcessId)
+ if (ProcessId != LogonProcessId)
{
DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
return STATUS_ACCESS_DENIED;
@@ -902,11 +902,17 @@
NTSTATUS Status;
LUID CallerLuid;
- // FIXME: HACK!!
-
/*
- * Retrieve the caller's LUID so that we can only shutdown
- * processes in the caller's LUID.
+ * Check for flags validity
+ */
+
+ /* Implicitely add the shutdown flag when we poweroff or reboot */
+ if (Flags & (EWX_POWEROFF | EWX_REBOOT))
+ Flags |= EWX_SHUTDOWN;
+
+ /*
+ * Impersonate and retrieve the caller's LUID so that
+ * we can only shutdown processes in its context.
*/
if (!CsrImpersonateClient(NULL))
return STATUS_BAD_IMPERSONATION_LEVEL;
@@ -920,27 +926,84 @@
DPRINT1("Caller LUID is: %lx.%lx\n", CallerLuid.HighPart, CallerLuid.LowPart);
- /* Notify Win32k and potentially Winlogon of the shutdown */
- Status = NtUserSetInformationThread(CsrThread->ThreadHandle,
- UserThreadInitiateShutdown,
- &Flags, sizeof(Flags));
- DPRINT1("Win32k says: %lx\n", Status);
-
- /* If the message isn't handled, the return value is 0, so 0 doesn't indicate
- success. Success is indicated by a 1 return value, if anything besides 0
- or 1 it's a NTSTATUS value */
- if (1 == Status)
- {
- Status = STATUS_SUCCESS;
- }
- else if (0 == Status)
- {
- Status = STATUS_NOT_IMPLEMENTED;
- }
+ /* Shutdown loop */
+ while (TRUE)
+ {
+ /* Notify Win32k and potentially Winlogon of the shutdown */
+ Status = NtUserSetInformationThread(CsrThread->ThreadHandle,
+ UserThreadInitiateShutdown,
+ &Flags, sizeof(Flags));
+ DPRINT1("Win32k says: %lx\n", Status);
+ switch (Status)
+ {
+ /* We cannot wait here, the caller should start a new thread */
+ case STATUS_CANT_WAIT:
+ DPRINT1("STATUS_CANT_WAIT\n");
+ goto Quit;
+
+ /* Shutdown is in progress */
+ case STATUS_PENDING:
+ DPRINT1("STATUS_PENDING\n");
+ goto Quit;
+
+ /* Abort */
+ case STATUS_RETRY:
+ {
+ DPRINT1("STATUS_RETRY\n");
+ UNIMPLEMENTED;
+ continue;
+ }
+
+ default:
+ {
+ if (!NT_SUCCESS(Status))
+ {
+ // FIXME: Use some UserSetLastNTError or SetLastNtError
+ // that we have defined for user32 or win32k usage only...
+ SetLastError(RtlNtStatusToDosError(Status));
+ goto Quit;
+ }
+ }
+ }
+
+ /* All good */
+ break;
+ }
+
+ /*
+ * OK we can continue. Now magic happens:
+ *
+ * Terminate all Win32 processes, stop if we find one kicking
+ * and screaming it doesn't want to die.
+ *
+ * This function calls the ShutdownProcessCallback callback of
+ * each CSR server for each Win32 process.
+ */
+ Status = CsrShutdownProcesses(&CallerLuid, Flags);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to shutdown processes, Status = 0x%08x\n", Status);
+ }
+ /*
+ * FIXME:
+ * At the moment the callbacks just do nothing so no process will be killed.
+ * It's not dramatic since:
+ * 1- We didn't do that before,
+ * 2- Related to point 1, the hackish InternalExitReactos call will end back
+ * into Winlogon that will directly call NtShutdownSystem.
+ */
+
+ // FIXME: If Status == STATUS_CANCELLED, call RecordShutdownReason
+
+ /* Tell Win32k and potentially Winlogon that we're done */
+ NtUserSetInformationThread(CsrThread->ThreadHandle,
+ UserThreadEndShutdown,
+ &Status, sizeof(Status));
DPRINT1("SrvExitWindowsEx returned 0x%08x\n", Status);
Quit:
+ /* We are done */
CsrRevertToSelf();
return Status;
}
@@ -970,33 +1033,35 @@
PCSR_THREAD CsrThread = CsrGetClientThread();
ULONG Flags = ExitReactosRequest->Flags;
- /*
- * Check for flags validity
- */
-
DWORD ProcessId = HandleToUlong(CsrThread->ClientId.UniqueProcess);
DWORD ThreadId = HandleToUlong(CsrThread->ClientId.UniqueThread);
DPRINT1("SrvExitWindowsEx(ClientId: %lx.%lx, Flags: 0x%x)\n",
ProcessId, ThreadId, Flags);
- /* Implicitely add the shutdown flag when we poweroff or reboot */
- if (Flags & (EWX_POWEROFF | EWX_REBOOT))
- Flags |= EWX_SHUTDOWN;
-
// FIXME: Everything else starting after this line is a HAAACK!!
- if (0 == (Flags & EWX_INTERNAL_FLAG))
- {
+ if (Flags & EWX_INTERNAL_FLAG)
+ {
+ /* Only Winlogon can call this */
+ if (ProcessId != LogonProcessId)
+ {
+ DPRINT1("SrvExitWindowsEx call not from Winlogon\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ // This function is a HACK!!
+ // EWX_INTERNAL_FLAG --> For Winlogon only!!
+ // Status = InternalExitReactos(ProcessId, ThreadId, Flags);
+
+ // This is this function that we need to call instead!
Status = UserExitReactos(CsrThread, Flags);
}
else
{
- // EWX_INTERNAL_FLAG --> For Winlogon only!!
- // FIXME: This is just a big HAAAACK!!
- Status = InternalExitReactos(ProcessId, ThreadId, Flags);
+ Status = UserExitReactos(CsrThread, Flags);
}
ExitReactosRequest->Success = NT_SUCCESS(Status);