* FILE: win32ss/user/winsrv/usersrv/shutdown.c
* PURPOSE: Logout/shutdown
* PROGRAMMERS:
- *
- * NOTE: The shutdown code must be rewritten completely. (hbelusca)
*/
/* INCLUDES *******************************************************************/
#include "usersrv.h"
-#include <stdlib.h>
-#include <winreg.h>
-#include <winlogon.h>
#include <commctrl.h>
-#include <sddl.h>
+#include <psapi.h>
#include "resource.h"
/* GLOBALS ********************************************************************/
-typedef struct tagSHUTDOWN_SETTINGS
-{
- BOOL AutoEndTasks;
- DWORD HungAppTimeout;
- DWORD WaitToKillAppTimeout;
-} SHUTDOWN_SETTINGS, *PSHUTDOWN_SETTINGS;
+// Those flags (that are used for CsrProcess->ShutdownFlags) are named
+// in accordance to the only public one: SHUTDOWN_NORETRY used for the
+// SetProcessShutdownParameters API.
+#if !defined(SHUTDOWN_SYSTEMCONTEXT) && !defined(SHUTDOWN_OTHERCONTEXT)
+#define SHUTDOWN_SYSTEMCONTEXT CsrShutdownSystem
+#define SHUTDOWN_OTHERCONTEXT CsrShutdownOther
+#endif
-#define DEFAULT_AUTO_END_TASKS FALSE
-#define DEFAULT_HUNG_APP_TIMEOUT 5000
-#define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
+// The DPRINTs that need to really be removed as soon as everything works.
+#define MY_DPRINT DPRINT1
+#define MY_DPRINT2 DPRINT
typedef struct tagNOTIFY_CONTEXT
{
- DWORD ProcessId;
UINT Msg;
WPARAM wParam;
LPARAM lParam;
- HDESK Desktop;
- HDESK OldDesktop;
+ // HDESK Desktop;
+ // HDESK OldDesktop;
DWORD StartTime;
DWORD QueryResult;
HWND Dlg;
HANDLE UIThread;
HWND WndClient;
PSHUTDOWN_SETTINGS ShutdownSettings;
- LPTHREAD_START_ROUTINE SendMessageProc;
} NOTIFY_CONTEXT, *PNOTIFY_CONTEXT;
#define QUERY_RESULT_ABORT 0
DWORD Timeout;
} MESSAGE_CONTEXT, *PMESSAGE_CONTEXT;
-typedef struct tagPROCESS_ENUM_CONTEXT
-{
- UINT ProcessCount;
- PCSR_PROCESS *ProcessData;
- TOKEN_ORIGIN TokenOrigin;
- DWORD ShellProcess;
- DWORD CsrssProcess;
-} PROCESS_ENUM_CONTEXT, *PPROCESS_ENUM_CONTEXT;
-
/* FUNCTIONS ******************************************************************/
-/*
-NTSTATUS FASTCALL
-Win32CsrEnumProcesses(CSRSS_ENUM_PROCESS_PROC EnumProc,
- PVOID Context)
+static HMODULE hComCtl32Lib = NULL;
+
+static VOID
+CallInitCommonControls(VOID)
{
- return CsrEnumProcesses(EnumProc, Context);
+ static BOOL Initialized = FALSE;
+ INITCOMMONCONTROLS_PROC InitProc;
+
+ if (Initialized) return;
+
+ hComCtl32Lib = LoadLibraryW(L"COMCTL32.DLL");
+ if (hComCtl32Lib == NULL) return;
+
+ InitProc = (INITCOMMONCONTROLS_PROC)GetProcAddress(hComCtl32Lib, "InitCommonControls");
+ if (InitProc == NULL) return;
+
+ (*InitProc)();
+
+ Initialized = TRUE;
}
-*/
-static void FASTCALL
+static VOID FASTCALL
UpdateProgressBar(HWND ProgressBar, PNOTIFY_CONTEXT NotifyContext)
{
DWORD Passed;
switch(Msg)
{
case WM_INITDIALOG:
- NotifyContext = (PNOTIFY_CONTEXT) lParam;
+ NotifyContext = (PNOTIFY_CONTEXT)lParam;
NotifyContext->EndNowResult = QUERY_RESULT_ABORT;
- SetWindowLongPtrW(Dlg, DWLP_USER, (LONG_PTR) lParam);
+ SetWindowLongPtrW(Dlg, DWLP_USER, (LONG_PTR)lParam);
TitleLength = SendMessageW(NotifyContext->WndClient, WM_GETTEXTLENGTH,
0, 0) +
GetWindowTextLengthW(Dlg);
Title = HeapAlloc(UserServerHeap, 0, (TitleLength + 1) * sizeof(WCHAR));
- if (NULL != Title)
+ if (Title)
{
Len = GetWindowTextW(Dlg, Title, TitleLength + 1);
SendMessageW(NotifyContext->WndClient, WM_GETTEXT,
- TitleLength + 1 - Len, (LPARAM) (Title + Len));
+ TitleLength + 1 - Len, (LPARAM)(Title + Len));
SetWindowTextW(Dlg, Title);
HeapFree(UserServerHeap, 0, Title);
}
break;
case WM_TIMER:
- NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
+ NotifyContext = (PNOTIFY_CONTEXT)GetWindowLongPtrW(Dlg, DWLP_USER);
ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS);
UpdateProgressBar(ProgressBar, NotifyContext);
Result = TRUE;
case WM_COMMAND:
if (BN_CLICKED == HIWORD(wParam) && IDC_END_NOW == LOWORD(wParam))
{
- NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
+ NotifyContext = (PNOTIFY_CONTEXT)GetWindowLongPtrW(Dlg, DWLP_USER);
NotifyContext->EndNowResult = QUERY_RESULT_FORCE;
+ MY_DPRINT("Closing progress dlg by hand\n");
SendMessageW(Dlg, WM_CLOSE, 0, 0);
Result = TRUE;
}
break;
case WM_CLOSE:
+ MY_DPRINT("WM_CLOSE\n");
DestroyWindow(Dlg);
Result = TRUE;
break;
case WM_DESTROY:
- NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
+ MY_DPRINT("WM_DESTROY\n");
+ NotifyContext = (PNOTIFY_CONTEXT)GetWindowLongPtrW(Dlg, DWLP_USER);
NotifyContext->Dlg = NULL;
KillTimer(Dlg, 0);
PostQuitMessage(NotifyContext->EndNowResult);
return Result;
}
-static void
-CallInitCommonControls()
-{
- static BOOL Initialized = FALSE;
- HMODULE Lib;
- INITCOMMONCONTROLS_PROC InitProc;
-
- if (Initialized) return;
-
- Lib = LoadLibraryW(L"COMCTL32.DLL");
- if (NULL == Lib) return;
-
- InitProc = (INITCOMMONCONTROLS_PROC) GetProcAddress(Lib, "InitCommonControls");
- if (NULL == InitProc) return;
-
- (*InitProc)();
-
- Initialized = TRUE;
-}
-
static DWORD WINAPI
EndNowThreadProc(LPVOID Parameter)
{
- PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) Parameter;
+ PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT)Parameter;
MSG Msg;
- SetThreadDesktop(NotifyContext->Desktop);
- SwitchDesktop(NotifyContext->Desktop);
+ // SetThreadDesktop(NotifyContext->Desktop);
+ // SwitchDesktop(NotifyContext->Desktop);
CallInitCommonControls();
NotifyContext->Dlg = CreateDialogParam(UserServerDllInstance,
MAKEINTRESOURCE(IDD_END_NOW), NULL,
- EndNowDlgProc, (LPARAM) NotifyContext);
- if (NULL == NotifyContext->Dlg)
- {
+ EndNowDlgProc, (LPARAM)NotifyContext);
+ if (NotifyContext->Dlg == NULL)
return 0;
- }
+
ShowWindow(NotifyContext->Dlg, SW_SHOWNORMAL);
while (GetMessageW(&Msg, NULL, 0, 0))
{
- if (! IsDialogMessage(NotifyContext->Dlg, &Msg))
+ if (!IsDialogMessage(NotifyContext->Dlg, &Msg))
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
static DWORD WINAPI
-SendQueryEndSession(LPVOID Parameter)
+SendClientShutdown(LPVOID Parameter)
{
- PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter;
+ PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT)Parameter;
DWORD_PTR Result;
- if (SendMessageTimeoutW(Context->Wnd, WM_QUERYENDSESSION, Context->wParam,
- Context->lParam, SMTO_NORMAL, Context->Timeout,
- &Result))
+ /* If the shutdown is aborted, just notify the process, there is no need to wait */
+ if ((Context->wParam & (MCS_QUERYENDSESSION | MCS_ENDSESSION)) == 0)
{
- return Result ? QUERY_RESULT_CONTINUE : QUERY_RESULT_ABORT;
+ DPRINT("Called WM_CLIENTSHUTDOWN with wParam == 0 ...\n");
+ SendNotifyMessageW(Context->Wnd, WM_CLIENTSHUTDOWN,
+ Context->wParam, Context->lParam);
+ return QUERY_RESULT_CONTINUE;
}
- return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR;
-}
-
-static DWORD WINAPI
-SendEndSession(LPVOID Parameter)
-{
- PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter;
- DWORD_PTR Result;
-
- if (Context->wParam)
+ if (SendMessageTimeoutW(Context->Wnd, WM_CLIENTSHUTDOWN,
+ Context->wParam, Context->lParam,
+ SMTO_NORMAL, Context->Timeout, &Result))
{
- if (SendMessageTimeoutW(Context->Wnd, WM_ENDSESSION, Context->wParam,
- Context->lParam, SMTO_NORMAL, Context->Timeout,
- &Result))
+ DWORD Ret;
+
+ if (Context->wParam & MCS_QUERYENDSESSION)
{
- return QUERY_RESULT_CONTINUE;
+ /* WM_QUERYENDSESSION case */
+ switch (Result)
+ {
+ case MCSR_DONOTSHUTDOWN:
+ Ret = QUERY_RESULT_ABORT;
+ break;
+
+ case MCSR_GOODFORSHUTDOWN:
+ case MCSR_SHUTDOWNFINISHED:
+ default:
+ Ret = QUERY_RESULT_CONTINUE;
+ }
}
- return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR;
- }
- else
- {
- SendMessage(Context->Wnd, WM_ENDSESSION, Context->wParam,
- Context->lParam);
- return QUERY_RESULT_CONTINUE;
+ else
+ {
+ /* WM_ENDSESSION case */
+ Ret = QUERY_RESULT_CONTINUE;
+ }
+
+ DPRINT("SendClientShutdown -- Return == %s\n",
+ Ret == QUERY_RESULT_CONTINUE ? "Continue" : "Abort");
+ return Ret;
}
+
+ DPRINT1("SendClientShutdown -- Error == %s\n",
+ GetLastError() == 0 ? "Timeout" : "error");
+
+ return (GetLastError() == 0 ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR);
}
-static BOOL CALLBACK
-NotifyTopLevelEnum(HWND Wnd, LPARAM lParam)
+static BOOL
+NotifyTopLevelWindow(HWND Wnd, PNOTIFY_CONTEXT NotifyContext)
{
- PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) lParam;
MESSAGE_CONTEXT MessageContext;
DWORD Now, Passed;
DWORD Timeout, WaitStatus;
- DWORD ProcessId;
HANDLE MessageThread;
HANDLE Threads[2];
- if (0 == GetWindowThreadProcessId(Wnd, &ProcessId))
+ SetForegroundWindow(Wnd);
+
+ Now = GetTickCount();
+ if (NotifyContext->StartTime == 0)
+ NotifyContext->StartTime = Now;
+
+ /*
+ * Note: Passed is computed correctly even when GetTickCount()
+ * wraps due to unsigned arithmetic.
+ */
+ Passed = Now - NotifyContext->StartTime;
+ MessageContext.Wnd = Wnd;
+ MessageContext.Msg = NotifyContext->Msg;
+ MessageContext.wParam = NotifyContext->wParam;
+ MessageContext.lParam = NotifyContext->lParam;
+ MessageContext.Timeout = NotifyContext->ShutdownSettings->HungAppTimeout;
+ if (!NotifyContext->ShutdownSettings->AutoEndTasks)
{
- NotifyContext->QueryResult = QUERY_RESULT_ERROR;
- return FALSE;
+ MessageContext.Timeout += NotifyContext->ShutdownSettings->WaitToKillAppTimeout;
}
-
- if (ProcessId == NotifyContext->ProcessId)
+ if (Passed < MessageContext.Timeout)
{
- Now = GetTickCount();
- if (0 == NotifyContext->StartTime)
+ MessageContext.Timeout -= Passed;
+ MessageThread = CreateThread(NULL, 0, SendClientShutdown,
+ (LPVOID)&MessageContext, 0, NULL);
+ if (MessageThread == NULL)
{
- NotifyContext->StartTime = Now;
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ return FALSE;
}
- /* Note: Passed is computed correctly even when GetTickCount() wraps due
- to unsigned arithmetic */
- Passed = Now - NotifyContext->StartTime;
- MessageContext.Wnd = Wnd;
- MessageContext.Msg = NotifyContext->Msg;
- MessageContext.wParam = NotifyContext->wParam;
- MessageContext.lParam = NotifyContext->lParam;
- MessageContext.Timeout = NotifyContext->ShutdownSettings->HungAppTimeout;
- if (! NotifyContext->ShutdownSettings->AutoEndTasks)
+ Timeout = NotifyContext->ShutdownSettings->HungAppTimeout;
+ if (Passed < Timeout)
{
- MessageContext.Timeout += NotifyContext->ShutdownSettings->WaitToKillAppTimeout;
+ Timeout -= Passed;
+ WaitStatus = WaitForSingleObjectEx(MessageThread, Timeout, FALSE);
}
- if (Passed < MessageContext.Timeout)
+ else
{
- MessageContext.Timeout -= Passed;
- MessageThread = CreateThread(NULL, 0, NotifyContext->SendMessageProc,
- (LPVOID) &MessageContext, 0, NULL);
- if (NULL == MessageThread)
- {
- NotifyContext->QueryResult = QUERY_RESULT_ERROR;
- return FALSE;
- }
- Timeout = NotifyContext->ShutdownSettings->HungAppTimeout;
- if (Passed < Timeout)
- {
- Timeout -= Passed;
- WaitStatus = WaitForSingleObjectEx(MessageThread, Timeout, FALSE);
- }
- else
+ WaitStatus = WAIT_TIMEOUT;
+ }
+ if (WAIT_TIMEOUT == WaitStatus)
+ {
+ NotifyContext->WndClient = Wnd;
+ if (NotifyContext->UIThread == NULL && NotifyContext->ShowUI)
{
- WaitStatus = WAIT_TIMEOUT;
+ NotifyContext->UIThread = CreateThread(NULL, 0,
+ EndNowThreadProc,
+ (LPVOID)NotifyContext,
+ 0, NULL);
}
- if (WAIT_TIMEOUT == WaitStatus)
+ Threads[0] = MessageThread;
+ Threads[1] = NotifyContext->UIThread;
+ WaitStatus = WaitForMultipleObjectsEx(NotifyContext->UIThread == NULL ?
+ 1 : 2,
+ Threads, FALSE, INFINITE,
+ FALSE);
+ if (WaitStatus == WAIT_OBJECT_0)
{
- NotifyContext->WndClient = Wnd;
- if (NULL == NotifyContext->UIThread && NotifyContext->ShowUI)
- {
- NotifyContext->UIThread = CreateThread(NULL, 0,
- EndNowThreadProc,
- (LPVOID) NotifyContext,
- 0, NULL);
- }
- Threads[0] = MessageThread;
- Threads[1] = NotifyContext->UIThread;
- WaitStatus = WaitForMultipleObjectsEx(NULL == NotifyContext->UIThread ?
- 1 : 2,
- Threads, FALSE, INFINITE,
- FALSE);
- if (WAIT_OBJECT_0 == WaitStatus)
- {
- if (! GetExitCodeThread(MessageThread, &NotifyContext->QueryResult))
- {
- NotifyContext->QueryResult = QUERY_RESULT_ERROR;
- }
- }
- else if (WAIT_OBJECT_0 + 1 == WaitStatus)
- {
- if (! GetExitCodeThread(NotifyContext->UIThread,
- &NotifyContext->QueryResult))
- {
- NotifyContext->QueryResult = QUERY_RESULT_ERROR;
- }
- }
- else
+ if (!GetExitCodeThread(MessageThread, &NotifyContext->QueryResult))
{
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
}
- if (WAIT_OBJECT_0 != WaitStatus)
- {
- TerminateThread(MessageThread, QUERY_RESULT_TIMEOUT);
- }
}
- else if (WAIT_OBJECT_0 == WaitStatus)
+ else if (WaitStatus == WAIT_OBJECT_0 + 1)
{
- if (! GetExitCodeThread(MessageThread,
- &NotifyContext->QueryResult))
+ if (!GetExitCodeThread(NotifyContext->UIThread,
+ &NotifyContext->QueryResult))
{
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
}
{
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
}
- CloseHandle(MessageThread);
+ if (WaitStatus != WAIT_OBJECT_0)
+ {
+ TerminateThread(MessageThread, QUERY_RESULT_TIMEOUT);
+ }
+ }
+ else if (WaitStatus == WAIT_OBJECT_0)
+ {
+ if (!GetExitCodeThread(MessageThread,
+ &NotifyContext->QueryResult))
+ {
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
+ }
}
else
{
- NotifyContext->QueryResult = QUERY_RESULT_TIMEOUT;
+ NotifyContext->QueryResult = QUERY_RESULT_ERROR;
}
+ CloseHandle(MessageThread);
}
-
- return QUERY_RESULT_CONTINUE == NotifyContext->QueryResult;
-}
-
-static BOOL CALLBACK
-NotifyDesktopEnum(LPWSTR DesktopName, LPARAM lParam)
-{
- PNOTIFY_CONTEXT Context = (PNOTIFY_CONTEXT) lParam;
-
- Context->Desktop = OpenDesktopW(DesktopName, 0, FALSE,
- DESKTOP_ENUMERATE | DESKTOP_SWITCHDESKTOP);
- if (NULL == Context->Desktop)
+ else
{
- DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
- Context->QueryResult = QUERY_RESULT_ERROR;
- return FALSE;
+ NotifyContext->QueryResult = QUERY_RESULT_TIMEOUT;
}
- Context->OldDesktop = GetThreadDesktop(GetCurrentThreadId());
- SwitchDesktop(Context->Desktop);
-
- EnumDesktopWindows(Context->Desktop, NotifyTopLevelEnum, lParam);
-
- SwitchDesktop(Context->OldDesktop);
-
- CloseDesktop(Context->Desktop);
-
- return QUERY_RESULT_CONTINUE == Context->QueryResult;
+ DPRINT("NotifyContext->QueryResult == %d\n", NotifyContext->QueryResult);
+ return (NotifyContext->QueryResult == QUERY_RESULT_CONTINUE);
}
-static BOOL FASTCALL
-NotifyTopLevelWindows(PNOTIFY_CONTEXT Context)
+static BOOLEAN
+IsConsoleMode(VOID)
{
- HWINSTA WindowStation;
-
- WindowStation = GetProcessWindowStation();
- if (NULL == WindowStation)
- {
- DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
- return TRUE;
- }
-
- EnumDesktopsW(WindowStation, NotifyDesktopEnum, (LPARAM) Context);
-
- return TRUE;
+ return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE);
}
-static BOOL
-DtbgIsDesktopVisible(VOID)
-{
- return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
-}
/* TODO: Find an other way to do it. */
#if 0
if (ProcessData->CtrlDispatcher)
{
-
Thread = CreateRemoteThread(ProcessData->ProcessHandle, NULL, 0,
(LPTHREAD_START_ROUTINE) ProcessData->CtrlDispatcher,
UlongToPtr(Event), 0, NULL);
- if (NULL == Thread)
+ if (Thread == NULL)
{
DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
return;
#endif
/************************************************/
-static BOOL FASTCALL
-NotifyAndTerminateProcess(PCSR_PROCESS ProcessData,
- PSHUTDOWN_SETTINGS ShutdownSettings,
- UINT Flags)
-{
- NOTIFY_CONTEXT Context;
- HANDLE Process;
- DWORD QueryResult = QUERY_RESULT_CONTINUE;
- Context.QueryResult = QUERY_RESULT_CONTINUE;
+static VOID
+ThreadShutdownNotify(IN PCSR_THREAD CsrThread,
+ IN ULONG Flags,
+ IN ULONG Flags2,
+ IN PNOTIFY_CONTEXT Context)
+{
+ HWND TopWnd = NULL;
- if (0 == (Flags & EWX_FORCE))
+ EnumThreadWindows(HandleToUlong(CsrThread->ClientId.UniqueThread),
+ FindTopLevelWnd, (LPARAM)&TopWnd);
+ if (TopWnd)
{
- // TODO: Find an other way whether or not the process has a console.
-#if 0
- if (NULL != ProcessData->Console)
- {
- ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT, ProcessData,
- ShutdownSettings->WaitToKillAppTimeout);
- }
- else
-#endif
- {
- Context.ProcessId = (DWORD_PTR) ProcessData->ClientId.UniqueProcess;
- Context.wParam = 0;
- Context.lParam = (0 != (Flags & EWX_INTERNAL_FLAG_LOGOFF) ?
- ENDSESSION_LOGOFF : 0);
- Context.StartTime = 0;
- Context.UIThread = NULL;
- Context.ShowUI = DtbgIsDesktopVisible();
- Context.Dlg = NULL;
- Context.ShutdownSettings = ShutdownSettings;
- Context.SendMessageProc = SendQueryEndSession;
-
- NotifyTopLevelWindows(&Context);
-
- Context.wParam = (QUERY_RESULT_ABORT != Context.QueryResult);
- Context.lParam = (0 != (Flags & EWX_INTERNAL_FLAG_LOGOFF) ?
- ENDSESSION_LOGOFF : 0);
- Context.SendMessageProc = SendEndSession;
- Context.ShowUI = DtbgIsDesktopVisible() &&
- (QUERY_RESULT_ABORT != Context.QueryResult);
- QueryResult = Context.QueryResult;
- Context.QueryResult = QUERY_RESULT_CONTINUE;
-
- NotifyTopLevelWindows(&Context);
+ HWND hWndOwner;
- if (NULL != Context.UIThread)
- {
- if (NULL != Context.Dlg)
- {
- SendMessageW(Context.Dlg, WM_CLOSE, 0, 0);
- }
- else
- {
- TerminateThread(Context.UIThread, QUERY_RESULT_ERROR);
- }
- CloseHandle(Context.UIThread);
- }
- }
+ /*** FOR TESTING PURPOSES ONLY!! ***/
+ HWND tmpWnd;
+ tmpWnd = TopWnd;
+ /***********************************/
- if (QUERY_RESULT_ABORT == QueryResult)
+ while ((hWndOwner = GetWindow(TopWnd, GW_OWNER)) != NULL)
{
- return FALSE;
+ MY_DPRINT("GetWindow(TopWnd, GW_OWNER) not returned NULL...\n");
+ TopWnd = hWndOwner;
}
+ if (TopWnd != tmpWnd) MY_DPRINT("(TopWnd = %x) != (tmpWnd = %x)\n", TopWnd, tmpWnd);
}
+ if (TopWnd == NULL)
+ return;
- /* Terminate this process */
- Process = OpenProcess(PROCESS_TERMINATE, FALSE,
- (DWORD_PTR) ProcessData->ClientId.UniqueProcess);
- if (NULL == Process)
- {
- DPRINT1("Unable to open process %d, error %d\n", ProcessData->ClientId.UniqueProcess,
- GetLastError());
- return TRUE;
- }
- TerminateProcess(Process, 0);
- CloseHandle(Process);
-
- return TRUE;
-}
+ Context->wParam = Flags2;
+ Context->lParam = (0 != (Flags & EWX_CALLER_WINLOGON_LOGOFF) ?
+ ENDSESSION_LOGOFF : 0);
-#if 0
-static NTSTATUS WINAPI
-ExitReactosProcessEnum(PCSR_PROCESS ProcessData, PVOID Data)
-{
- HANDLE Process;
- HANDLE Token;
- TOKEN_ORIGIN Origin;
- DWORD ReturnLength;
- PPROCESS_ENUM_CONTEXT Context = (PPROCESS_ENUM_CONTEXT) Data;
- PCSR_PROCESS *NewData;
-
- /* Do not kill winlogon or csrss */
- if ((DWORD_PTR) ProcessData->ClientId.UniqueProcess == Context->CsrssProcess ||
- ProcessData->ClientId.UniqueProcess == LogonProcessId)
- {
- return STATUS_SUCCESS;
- }
-
- /* Get the login session of this process */
- Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
- (DWORD_PTR) ProcessData->ClientId.UniqueProcess);
- if (NULL == Process)
- {
- DPRINT1("Unable to open process %d, error %d\n", ProcessData->ClientId.UniqueProcess,
- GetLastError());
- return STATUS_UNSUCCESSFUL;
- }
+ Context->StartTime = 0;
+ Context->UIThread = NULL;
+ Context->ShowUI = !IsConsoleMode() && (Flags2 & (MCS_QUERYENDSESSION | MCS_ENDSESSION));
+ Context->Dlg = NULL;
- if (! OpenProcessToken(Process, TOKEN_QUERY, &Token))
+#if 0 // Obviously, switching desktops like that from within WINSRV doesn't work...
{
- DPRINT1("Unable to open token for process %d, error %d\n",
- ProcessData->ClientId.UniqueProcess, GetLastError());
- CloseHandle(Process);
- return STATUS_UNSUCCESSFUL;
+ BOOL Success;
+ Context->OldDesktop = GetThreadDesktop(GetCurrentThreadId());
+ // Context->Desktop = GetThreadDesktop(HandleToUlong(CsrThread->ClientId.UniqueThread));
+ Context->Desktop = GetThreadDesktop(GetWindowThreadProcessId(TopWnd, NULL));
+ MY_DPRINT("Last error = %d\n", GetLastError());
+ MY_DPRINT("Before switching to desktop 0x%x\n", Context->Desktop);
+ Success = SwitchDesktop(Context->Desktop);
+ MY_DPRINT("After switching to desktop (Success = %s ; last error = %d); going to notify top-level...\n",
+ Success ? "TRUE" : "FALSE", GetLastError());
}
- CloseHandle(Process);
+#endif
- if (! GetTokenInformation(Token, TokenOrigin, &Origin,
- sizeof(TOKEN_ORIGIN), &ReturnLength))
- {
- DPRINT1("GetTokenInformation failed for process %d with error %d\n",
- ProcessData->ClientId.UniqueProcess, GetLastError());
- CloseHandle(Token);
- return STATUS_UNSUCCESSFUL;
- }
- CloseHandle(Token);
+ NotifyTopLevelWindow(TopWnd, Context);
- /* This process will be killed if it's in the correct logon session */
- if (RtlEqualLuid(&(Context->TokenOrigin.OriginatingLogonSession),
- &(Origin.OriginatingLogonSession)))
+/******************************************************************************/
+#if 1
+ if (Context->UIThread)
{
- /* Kill the shell process last */
- if ((DWORD_PTR) ProcessData->ClientId.UniqueProcess == Context->ShellProcess)
+ MY_DPRINT("Context->UIThread != NULL\n");
+ if (Context->Dlg)
{
- ProcessData->ShutdownLevel = 0;
+ MY_DPRINT("Sending WM_CLOSE because Dlg is != NULL\n");
+ SendMessageW(Context->Dlg, WM_CLOSE, 0, 0);
}
- NewData = HeapAlloc(UserServerHeap, 0, (Context->ProcessCount + 1)
- * sizeof(PCSR_PROCESS));
- if (NULL == NewData)
- {
- return STATUS_NO_MEMORY;
- }
- if (0 != Context->ProcessCount)
+ else
{
- memcpy(NewData, Context->ProcessData,
- Context->ProcessCount * sizeof(PCSR_PROCESS));
- HeapFree(UserServerHeap, 0, Context->ProcessData);
+ MY_DPRINT("Terminating UIThread thread with QUERY_RESULT_ERROR\n");
+ TerminateThread(Context->UIThread, QUERY_RESULT_ERROR);
}
- Context->ProcessData = NewData;
- Context->ProcessData[Context->ProcessCount] = ProcessData;
- Context->ProcessCount++;
+ CloseHandle(Context->UIThread);
+ /**/Context->UIThread = NULL;/**/
+ /**/Context->Dlg = NULL;/**/
}
+#endif
+/******************************************************************************/
- return STATUS_SUCCESS;
-}
+#if 0
+ MY_DPRINT("Switch back to old desktop 0x%x\n", Context->OldDesktop);
+ SwitchDesktop(Context->OldDesktop);
+ MY_DPRINT("Switched back ok\n");
#endif
+}
-static int
-ProcessDataCompare(const void *Elem1, const void *Elem2)
+static BOOL
+NotifyProcessForShutdown(PCSR_PROCESS CsrProcess,
+ PSHUTDOWN_SETTINGS ShutdownSettings,
+ UINT Flags)
{
- const PCSR_PROCESS *ProcessData1 = (PCSR_PROCESS *) Elem1;
- const PCSR_PROCESS *ProcessData2 = (PCSR_PROCESS *) Elem2;
+ DWORD QueryResult = QUERY_RESULT_CONTINUE;
- if ((*ProcessData1)->ShutdownLevel < (*ProcessData2)->ShutdownLevel)
- {
- return +1;
- }
- else if ((*ProcessData2)->ShutdownLevel < (*ProcessData1)->ShutdownLevel)
- {
- return -1;
- }
- else if ((*ProcessData1)->ClientId.UniqueProcess < (*ProcessData2)->ClientId.UniqueProcess)
+ /* In case we make a forced shutdown, just kill the process */
+ if (Flags & EWX_FORCE)
+ return TRUE;
+
+ // TODO: Find an other way whether or not the process has a console.
+#if 0
+ if (CsrProcess->Console)
{
- return +1;
+ ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT, CsrProcess,
+ ShutdownSettings->WaitToKillAppTimeout);
}
- else if ((*ProcessData2)->ClientId.UniqueProcess < (*ProcessData1)->ClientId.UniqueProcess)
+ else
+#endif
{
- return -1;
- }
+ PCSR_PROCESS Process;
+ PCSR_THREAD Thread;
+ PLIST_ENTRY NextEntry;
- return 0;
-}
+ NOTIFY_CONTEXT Context;
+ Context.ShutdownSettings = ShutdownSettings;
+ Context.QueryResult = QUERY_RESULT_CONTINUE; // We continue shutdown by default.
-static DWORD FASTCALL
-GetShutdownSettings(HKEY DesktopKey, LPCWSTR ValueName, DWORD DefaultValue)
-{
- BYTE ValueBuffer[16];
- LONG ErrCode;
- DWORD Type;
- DWORD ValueSize;
- UNICODE_STRING StringValue;
- ULONG Value;
-
- ValueSize = sizeof(ValueBuffer);
- ErrCode = RegQueryValueExW(DesktopKey, ValueName, NULL, &Type, ValueBuffer,
- &ValueSize);
- if (ERROR_SUCCESS != ErrCode)
- {
- DPRINT("GetShutdownSettings for %S failed with error code %ld\n",
- ValueName, ErrCode);
- return DefaultValue;
- }
+ /* Lock the process */
+ CsrLockProcessByClientId(CsrProcess->ClientId.UniqueProcess, &Process);
- if (REG_SZ == Type)
- {
- RtlInitUnicodeString(&StringValue, (LPCWSTR) ValueBuffer);
- if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue, 10, &Value)))
+ /* Send first the QUERYENDSESSION messages to all the threads of the process */
+ MY_DPRINT2("Sending the QUERYENDSESSION messages...\n");
+
+ NextEntry = CsrProcess->ThreadList.Flink;
+ while (NextEntry != &CsrProcess->ThreadList)
{
- DPRINT1("Unable to convert value %S for setting %S\n",
- StringValue.Buffer, ValueName);
- return DefaultValue;
+ /* Get the current thread entry */
+ Thread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
+
+ /* Move to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* If the thread is being terminated, just skip it */
+ if (Thread->Flags & CsrThreadTerminated) continue;
+
+ /* Reference the thread and temporarily unlock the process */
+ CsrReferenceThread(Thread);
+ CsrUnlockProcess(Process);
+
+ Context.QueryResult = QUERY_RESULT_CONTINUE;
+ ThreadShutdownNotify(Thread, Flags,
+ MCS_QUERYENDSESSION,
+ &Context);
+
+ /* Lock the process again and dereference the thread */
+ CsrLockProcessByClientId(CsrProcess->ClientId.UniqueProcess, &Process);
+ CsrDereferenceThread(Thread);
+
+ // FIXME: Analyze Context.QueryResult !!
+ /**/if (Context.QueryResult == QUERY_RESULT_ABORT) goto Quit;/**/
}
- return (DWORD) Value;
- }
- else if (REG_DWORD == Type)
- {
- return *((DWORD *) ValueBuffer);
- }
- DPRINT1("Unexpected registry type %d for setting %S\n", Type, ValueName);
- return DefaultValue;
-}
+ QueryResult = Context.QueryResult;
+ MY_DPRINT2("QueryResult = %s\n",
+ QueryResult == QUERY_RESULT_ABORT ? "Abort" : "Continue");
-static void FASTCALL
-LoadShutdownSettings(PSID Sid, PSHUTDOWN_SETTINGS ShutdownSettings)
-{
- static WCHAR Subkey[] = L"\\Control Panel\\Desktop";
- LPWSTR StringSid;
- WCHAR InitialKeyName[128];
- LPWSTR KeyName;
- HKEY DesktopKey;
- LONG ErrCode;
-
- ShutdownSettings->AutoEndTasks = DEFAULT_AUTO_END_TASKS;
- ShutdownSettings->HungAppTimeout = DEFAULT_HUNG_APP_TIMEOUT;
- ShutdownSettings->WaitToKillAppTimeout = DEFAULT_WAIT_TO_KILL_APP_TIMEOUT;
-
- if (! ConvertSidToStringSidW(Sid, &StringSid))
- {
- DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
- GetLastError());
- return;
- }
- if (wcslen(StringSid) + wcslen(Subkey) + 1 <=
- sizeof(InitialKeyName) / sizeof(WCHAR))
- {
- KeyName = InitialKeyName;
- }
- else
- {
- KeyName = HeapAlloc(UserServerHeap, 0,
- (wcslen(StringSid) + wcslen(Subkey) + 1) *
- sizeof(WCHAR));
- if (NULL == KeyName)
+ /* Now send the ENDSESSION messages to the threads */
+ MY_DPRINT2("Now sending the ENDSESSION messages...\n");
+
+ NextEntry = CsrProcess->ThreadList.Flink;
+ while (NextEntry != &CsrProcess->ThreadList)
{
- DPRINT1("Failed to allocate memory, using default shutdown settings\n");
- LocalFree(StringSid);
- return;
+ /* Get the current thread entry */
+ Thread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
+
+ /* Move to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* If the thread is being terminated, just skip it */
+ if (Thread->Flags & CsrThreadTerminated) continue;
+
+ /* Reference the thread and temporarily unlock the process */
+ CsrReferenceThread(Thread);
+ CsrUnlockProcess(Process);
+
+ Context.QueryResult = QUERY_RESULT_CONTINUE;
+ ThreadShutdownNotify(Thread, Flags,
+ (QUERY_RESULT_ABORT != QueryResult) ? MCS_ENDSESSION : 0,
+ &Context);
+
+ /* Lock the process again and dereference the thread */
+ CsrLockProcessByClientId(CsrProcess->ClientId.UniqueProcess, &Process);
+ CsrDereferenceThread(Thread);
}
- }
- wcscat(wcscpy(KeyName, StringSid), Subkey);
- LocalFree(StringSid);
- ErrCode = RegOpenKeyExW(HKEY_USERS, KeyName, 0, KEY_QUERY_VALUE, &DesktopKey);
- if (KeyName != InitialKeyName)
- {
- HeapFree(UserServerHeap, 0, KeyName);
- }
- if (ERROR_SUCCESS != ErrCode)
- {
- DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode);
- return;
- }
+Quit:
+ /* Unlock the process */
+ CsrUnlockProcess(Process);
- ShutdownSettings->AutoEndTasks = (BOOL) GetShutdownSettings(DesktopKey, L"AutoEndTasks",
- (DWORD) DEFAULT_AUTO_END_TASKS);
- ShutdownSettings->HungAppTimeout = GetShutdownSettings(DesktopKey,
- L"HungAppTimeout",
- DEFAULT_HUNG_APP_TIMEOUT);
- ShutdownSettings->WaitToKillAppTimeout = GetShutdownSettings(DesktopKey,
- L"WaitToKillAppTimeout",
- DEFAULT_WAIT_TO_KILL_APP_TIMEOUT);
+#if 0
+ if (Context.UIThread)
+ {
+ if (Context.Dlg)
+ {
+ SendMessageW(Context.Dlg, WM_CLOSE, 0, 0);
+ }
+ else
+ {
+ TerminateThread(Context.UIThread, QUERY_RESULT_ERROR);
+ }
+ CloseHandle(Context.UIThread);
+ }
+#endif
+ }
- RegCloseKey(DesktopKey);
+ /* Kill the process unless we abort shutdown */
+ return (QueryResult != QUERY_RESULT_ABORT);
}
static NTSTATUS FASTCALL
-InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags)
+UserExitReactOS(PCSR_THREAD CsrThread, UINT Flags)
{
- HANDLE CallerThread;
- HANDLE CallerToken;
NTSTATUS Status;
- PROCESS_ENUM_CONTEXT Context;
- DWORD ReturnLength;
- HWND ShellWnd;
- UINT ProcessIndex;
- char FixedUserInfo[64];
- TOKEN_USER *UserInfo;
- SHUTDOWN_SETTINGS ShutdownSettings;
-
- if (ProcessId != (DWORD_PTR) LogonProcessId)
- {
- DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
- return STATUS_ACCESS_DENIED;
- }
+ LUID CallerLuid;
- DPRINT1("FIXME: Need to close all user processes!\n");
- return STATUS_SUCCESS;
+ DWORD ProcessId = HandleToUlong(CsrThread->ClientId.UniqueProcess);
+ DWORD ThreadId = HandleToUlong(CsrThread->ClientId.UniqueThread);
- CallerThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, ThreadId);
- if (NULL == CallerThread)
- {
- DPRINT1("OpenThread failed with error %d\n", GetLastError());
- return STATUS_UNSUCCESSFUL;
- }
- if (! OpenThreadToken(CallerThread, TOKEN_QUERY, FALSE, &CallerToken))
+ DPRINT1("SrvExitWindowsEx(ClientId: %lx.%lx, Flags: 0x%x)\n",
+ ProcessId, ThreadId, Flags);
+
+ /*
+ * Check for flags validity
+ */
+
+ if (Flags & EWX_CALLER_WINLOGON)
{
- DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
- CloseHandle(CallerThread);
- return STATUS_UNSUCCESSFUL;
+ /* Only Winlogon can call this */
+ if (ProcessId != LogonProcessId)
+ {
+ DPRINT1("SrvExitWindowsEx call not from Winlogon\n");
+ return STATUS_ACCESS_DENIED;
+ }
}
- CloseHandle(CallerThread);
- Context.ProcessCount = 0;
- Context.ProcessData = NULL;
- if (! GetTokenInformation(CallerToken, TokenOrigin, &Context.TokenOrigin,
- sizeof(TOKEN_ORIGIN), &ReturnLength))
+ /* 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;
+
+ Status = CsrGetProcessLuid(NULL, &CallerLuid);
+ if (!NT_SUCCESS(Status))
{
- DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
- CloseHandle(CallerToken);
- return STATUS_UNSUCCESSFUL;
+ DPRINT1("Unable to get caller LUID, Status = 0x%08x\n", Status);
+ goto Quit;
}
- if (! GetTokenInformation(CallerToken, TokenUser, FixedUserInfo,
- sizeof(FixedUserInfo), &ReturnLength))
+
+ DPRINT("Caller LUID is: %lx.%lx\n", CallerLuid.HighPart, CallerLuid.LowPart);
+
+ /* Shutdown loop */
+ while (TRUE)
{
- if (sizeof(FixedUserInfo) < ReturnLength)
+ /* Notify Win32k and potentially Winlogon of the shutdown */
+ Status = NtUserSetInformationThread(CsrThread->ThreadHandle,
+ UserThreadInitiateShutdown,
+ &Flags, sizeof(Flags));
+ DPRINT("Win32k says: %lx\n", Status);
+ switch (Status)
{
- UserInfo = HeapAlloc(UserServerHeap, 0, ReturnLength);
- if (NULL == UserInfo)
+ /* We cannot wait here, the caller should start a new thread */
+ case STATUS_CANT_WAIT:
+ DPRINT1("NtUserSetInformationThread returned STATUS_CANT_WAIT\n");
+ goto Quit;
+
+ /* Shutdown is in progress */
+ case STATUS_PENDING:
+ DPRINT1("NtUserSetInformationThread returned STATUS_PENDING\n");
+ goto Quit;
+
+ /* Abort */
+ case STATUS_RETRY:
{
- DPRINT1("Unable to allocate %u bytes for user info\n",
- (unsigned) ReturnLength);
- CloseHandle(CallerToken);
- return STATUS_NO_MEMORY;
+ DPRINT1("NtUserSetInformationThread returned STATUS_RETRY\n");
+ UNIMPLEMENTED;
+ continue;
}
- if (! GetTokenInformation(CallerToken, TokenUser, UserInfo,
- ReturnLength, &ReturnLength))
+
+ default:
{
- DPRINT1("GetTokenInformation failed with error %d\n",
- GetLastError());
- HeapFree(UserServerHeap, 0, UserInfo);
- CloseHandle(CallerToken);
- return STATUS_UNSUCCESSFUL;
+ 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;
+ }
}
}
- else
- {
- DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
- CloseHandle(CallerToken);
- return STATUS_UNSUCCESSFUL;
- }
+
+ /* All good */
+ break;
}
- else
+
+ /*
+ * 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))
{
- UserInfo = (TOKEN_USER *) FixedUserInfo;
+ DPRINT1("Failed to shutdown processes, Status = 0x%08x\n", Status);
}
- CloseHandle(CallerToken);
- LoadShutdownSettings(UserInfo->User.Sid, &ShutdownSettings);
- if (UserInfo != (TOKEN_USER *) FixedUserInfo)
+
+ // FIXME: If Status == STATUS_CANCELLED, call RecordShutdownReason
+
+ /* Tell Win32k and potentially Winlogon that we're done */
+ NtUserSetInformationThread(CsrThread->ThreadHandle,
+ UserThreadEndShutdown,
+ &Status, sizeof(Status));
+
+ DPRINT("SrvExitWindowsEx returned 0x%08x\n", Status);
+
+Quit:
+ /* We are done */
+ CsrRevertToSelf();
+ return Status;
+}
+
+
+ULONG
+NTAPI
+UserClientShutdown(IN PCSR_PROCESS CsrProcess,
+ IN ULONG Flags,
+ IN BOOLEAN FirstPhase)
+{
+ DPRINT("UserClientShutdown(0x%p, 0x%x, %s) - [0x%x, 0x%x], ShutdownFlags: %lu\n",
+ CsrProcess, Flags, FirstPhase ? "FirstPhase" : "LastPhase",
+ CsrProcess->ClientId.UniqueProcess, CsrProcess->ClientId.UniqueThread,
+ CsrProcess->ShutdownFlags);
+
+ /*
+ * Check for process validity
+ */
+
+ /* Do not kill system processes when a user is logging off */
+ if ((Flags & EWX_SHUTDOWN) == EWX_LOGOFF &&
+ (CsrProcess->ShutdownFlags & (SHUTDOWN_OTHERCONTEXT | SHUTDOWN_SYSTEMCONTEXT)))
{
- HeapFree(UserServerHeap, 0, UserInfo);
+ DPRINT("Do not kill a system process in a logoff request!\n");
+ return CsrShutdownNonCsrProcess;
}
- Context.CsrssProcess = GetCurrentProcessId();
- ShellWnd = GetShellWindow();
- if (NULL == ShellWnd)
+
+ /* Do not kill Winlogon or CSRSS */
+ if (CsrProcess->ClientId.UniqueProcess == NtCurrentProcess() ||
+ CsrProcess->ClientId.UniqueProcess == UlongToHandle(LogonProcessId))
{
- DPRINT("No shell present\n");
- Context.ShellProcess = 0;
+ DPRINT("Not killing %s; CsrProcess->ShutdownFlags = %lu\n",
+ CsrProcess->ClientId.UniqueProcess == NtCurrentProcess() ? "CSRSS" : "Winlogon",
+ CsrProcess->ShutdownFlags);
+
+ return CsrShutdownNonCsrProcess;
}
- else if (0 == GetWindowThreadProcessId(ShellWnd, &Context.ShellProcess))
+
+ /* Notify the process for shutdown if needed */
+ if (!NotifyProcessForShutdown(CsrProcess, &ShutdownSettings, Flags))
{
- DPRINT1("Can't get process id of shell window\n");
- Context.ShellProcess = 0;
+ DPRINT1("Process 0x%x aborted shutdown\n", CsrProcess->ClientId.UniqueProcess);
+ /* Abort shutdown */
+ return CsrShutdownCancelled;
}
- // Status = Win32CsrEnumProcesses(ExitReactosProcessEnum, &Context);
- if (! NT_SUCCESS(Status))
+ /* Terminate this process */
+#if DBG
{
- DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
- Status);
- if (NULL != Context.ProcessData)
+ WCHAR buffer[MAX_PATH];
+ if (!GetProcessImageFileNameW(CsrProcess->ProcessHandle, buffer, MAX_PATH))
{
- HeapFree(UserServerHeap, 0, Context.ProcessData);
+ DPRINT1("Terminating process %x\n", CsrProcess->ClientId.UniqueProcess);
}
- return Status;
- }
-
- qsort(Context.ProcessData, Context.ProcessCount, sizeof(PCSR_PROCESS),
- ProcessDataCompare);
-
- /* Terminate processes, stop if we find one kicking and screaming it doesn't
- want to die */
- Status = STATUS_SUCCESS;
- for (ProcessIndex = 0;
- ProcessIndex < Context.ProcessCount && NT_SUCCESS(Status);
- ProcessIndex++)
- {
- if (! NotifyAndTerminateProcess(Context.ProcessData[ProcessIndex],
- &ShutdownSettings, Flags))
+ else
{
- Status = STATUS_REQUEST_ABORTED;
+ DPRINT1("Terminating process %x (%S)\n", CsrProcess->ClientId.UniqueProcess, buffer);
}
}
+#endif
+ NtTerminateProcess(CsrProcess->ProcessHandle, 0);
- /* Cleanup */
- if (NULL != Context.ProcessData)
- {
- HeapFree(UserServerHeap, 0, Context.ProcessData);
- }
-
- return Status;
+ /* We are done */
+ CsrDereferenceProcess(CsrProcess);
+ return CsrShutdownCsrProcess;
}
-static NTSTATUS FASTCALL
-UserExitReactos(DWORD UserProcessId, UINT Flags)
+
+/* PUBLIC SERVER APIS *********************************************************/
+
+CSR_API(SrvExitWindowsEx)
{
NTSTATUS Status;
+ PUSER_EXIT_REACTOS ExitReactOSRequest = &((PUSER_API_MESSAGE)ApiMessage)->Data.ExitReactOSRequest;
- /* FIXME Inside 2000 says we should impersonate the caller here */
- Status = NtUserCallTwoParam(UserProcessId, Flags, TWOPARAM_ROUTINE_EXITREACTOS);
-
- /* 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;
- }
+ Status = UserExitReactOS(CsrGetClientThread(), ExitReactOSRequest->Flags);
+ ExitReactOSRequest->Success = NT_SUCCESS(Status);
+ ExitReactOSRequest->LastError = GetLastError();
return Status;
}
+CSR_API(SrvEndTask)
+{
+ PUSER_END_TASK EndTaskRequest = &((PUSER_API_MESSAGE)ApiMessage)->Data.EndTaskRequest;
-/* PUBLIC SERVER APIS *********************************************************/
+ // FIXME: This is HACK-plemented!!
+ DPRINT1("SrvEndTask is HACKPLEMENTED!!\n");
-CSR_API(SrvExitWindowsEx)
-{
- PUSER_EXIT_REACTOS ExitReactosRequest = &((PUSER_API_MESSAGE)ApiMessage)->Data.ExitReactosRequest;
+ SendMessageW(EndTaskRequest->WndHandle, WM_CLOSE, 0, 0);
+ // PostMessageW(EndTaskRequest->WndHandle, WM_CLOSE, 0, 0);
- if (0 == (ExitReactosRequest->Flags & EWX_INTERNAL_FLAG))
+ if (IsWindow(EndTaskRequest->WndHandle))
{
- return UserExitReactos((DWORD_PTR) ApiMessage->Header.ClientId.UniqueProcess,
- ExitReactosRequest->Flags);
+ if (EndTaskRequest->Force)
+ {
+ EndTaskRequest->Success = DestroyWindow(EndTaskRequest->WndHandle);
+ EndTaskRequest->LastError = GetLastError();
+ }
+ else
+ {
+ EndTaskRequest->Success = FALSE;
+ }
}
else
{
- return InternalExitReactos((DWORD_PTR) ApiMessage->Header.ClientId.UniqueProcess,
- (DWORD_PTR) ApiMessage->Header.ClientId.UniqueThread,
- ExitReactosRequest->Flags);
+ EndTaskRequest->Success = TRUE;
+ EndTaskRequest->LastError = ERROR_SUCCESS;
}
-}
-
-CSR_API(SrvEndTask)
-{
- DPRINT1("%s not yet implemented\n", __FUNCTION__);
- return STATUS_NOT_IMPLEMENTED;
-}
-CSR_API(SrvLogon)
-{
- DPRINT1("%s not yet implemented\n", __FUNCTION__);
- return STATUS_NOT_IMPLEMENTED;
+ return STATUS_SUCCESS;
}
CSR_API(SrvRecordShutdownReason)