Author: hbelusca Date: Sun Feb 15 22:57:40 2015 New Revision: 66306
URL: http://svn.reactos.org/svn/reactos?rev=66306&view=rev Log: [WINSRV] - Part 2/2 of SrvLogon (see r66303): load the per-user shutdown timeouts. - Retrieve those per-user shutdown timeouts from the registry when the user logs on, adapted from Alex' shutdown patch plus existing code. - Commit the main part of shutdown code (finally!), still unfinished yet: * Need to switch to the desktop where the hanging GUI app's window is present, * Need to deal with apps from other users * What about SYSTEM processes? * What about console processes? - Reuse the old timeout code. - Fix the sending of WM_QUERYENDSESSION and WM_ENDSESSION messages (this is done by win32k directly; for that winsrv needs just to send one WM_CLIENTSHUTDOWN message with the correct wParam parameter).
Part 13/X CORE-8322 #comment Big commit in revision 66306!
Modified: trunk/reactos/win32ss/user/winsrv/consrv/consrv.h trunk/reactos/win32ss/user/winsrv/init.c trunk/reactos/win32ss/user/winsrv/usersrv/init.c trunk/reactos/win32ss/user/winsrv/usersrv/shutdown.c trunk/reactos/win32ss/user/winsrv/winsrv.h
Modified: trunk/reactos/win32ss/user/winsrv/consrv/consrv.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/winsrv/consrv/... ============================================================================== --- trunk/reactos/win32ss/user/winsrv/consrv/consrv.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/winsrv/consrv/consrv.h [iso-8859-1] Sun Feb 15 22:57:40 2015 @@ -18,7 +18,6 @@ #define COM_NO_WINDOWS_H
#include <winnls.h> -#include <winreg.h> #include <wincon.h>
#define NTOS_MODE_USER
Modified: trunk/reactos/win32ss/user/winsrv/init.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/winsrv/init.c?... ============================================================================== --- trunk/reactos/win32ss/user/winsrv/init.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/winsrv/init.c [iso-8859-1] Sun Feb 15 22:57:40 2015 @@ -13,6 +13,157 @@
#define NDEBUG #include <debug.h> + +/* GLOBALS ********************************************************************/ + +#define DEFAULT_AUTO_END_TASKS FALSE +#define DEFAULT_HUNG_APP_TIMEOUT 5000 +#define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000 +#define DEFAULT_PROCESS_TERMINATE_TIMEOUT 90000 + +SHUTDOWN_SETTINGS ShutdownSettings = +{ + DEFAULT_AUTO_END_TASKS, + DEFAULT_HUNG_APP_TIMEOUT, + DEFAULT_WAIT_TO_KILL_APP_TIMEOUT, + DEFAULT_WAIT_TO_KILL_APP_TIMEOUT, + DEFAULT_PROCESS_TERMINATE_TIMEOUT +}; + +/* FUNCTIONS ******************************************************************/ + +static ULONG +GetRegIntFromID(IN HANDLE KeyHandle, + IN PWCHAR ValueName, + IN ULONG DefaultValue) +{ + UNICODE_STRING ValueString; + ULONG Length; + UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32 * sizeof(WCHAR)]; + PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer; + NTSTATUS Status; + ULONG Value; + + /* Open the key */ + RtlInitUnicodeString(&ValueString, ValueName); + Status = NtQueryValueKey(KeyHandle, + &ValueString, + KeyValuePartialInformation, + PartialInfo, + sizeof(Buffer), + &Length); + if (NT_SUCCESS(Status)) + { + if (PartialInfo->Type == REG_SZ) + { + /* Convert to integer */ + RtlInitUnicodeString(&ValueString, (PWCHAR)PartialInfo->Data); + Status = RtlUnicodeStringToInteger(&ValueString, 10, &Value); + } + else if (PartialInfo->Type == REG_DWORD) + { + /* Directly retrieve the data */ + Value = *(PULONG)PartialInfo->Data; + Status = STATUS_SUCCESS; + } + else + { + DPRINT1("Unexpected registry type %d for setting %S\n", PartialInfo->Type, ValueName); + Status = STATUS_UNSUCCESSFUL; + } + } + + if (!NT_SUCCESS(Status)) + { + /* Use default value instead */ + Value = DefaultValue; + } + + /* Return the value */ + return Value; +} + +VOID FASTCALL +GetTimeouts(IN PSHUTDOWN_SETTINGS ShutdownSettings) +{ + NTSTATUS Status; + UNICODE_STRING RegistryString; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE CurrentUserKeyHandle; + HANDLE KeyHandle; + + /* Initialize with defaults first */ + ShutdownSettings->AutoEndTasks = DEFAULT_AUTO_END_TASKS; + ShutdownSettings->HungAppTimeout = DEFAULT_HUNG_APP_TIMEOUT; + ShutdownSettings->WaitToKillAppTimeout = DEFAULT_WAIT_TO_KILL_APP_TIMEOUT; + ShutdownSettings->WaitToKillServiceTimeout = ShutdownSettings->WaitToKillAppTimeout; + ShutdownSettings->ProcessTerminateTimeout = DEFAULT_PROCESS_TERMINATE_TIMEOUT; + + /* Open the per-user desktop key */ + Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &CurrentUserKeyHandle); + if (NT_SUCCESS(Status)) + { + RtlInitUnicodeString(&RegistryString, + L"Control Panel\Desktop"); + InitializeObjectAttributes(&ObjectAttributes, + &RegistryString, + OBJ_CASE_INSENSITIVE, + CurrentUserKeyHandle, + NULL); + Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Read timeouts */ + ShutdownSettings->HungAppTimeout = GetRegIntFromID(KeyHandle, + L"HungAppTimeout", + DEFAULT_HUNG_APP_TIMEOUT); + ShutdownSettings->WaitToKillAppTimeout = GetRegIntFromID(KeyHandle, + L"WaitToKillAppTimeout", + DEFAULT_WAIT_TO_KILL_APP_TIMEOUT); + ShutdownSettings->AutoEndTasks = GetRegIntFromID(KeyHandle, + L"AutoEndTasks", + DEFAULT_AUTO_END_TASKS); + /* Done */ + NtClose(KeyHandle); + } + + /* Done */ + NtClose(CurrentUserKeyHandle); + } + + /* Now open the control key */ + RtlInitUnicodeString(&RegistryString, + L"\Registry\Machine\System\CurrentControlSet\Control"); + InitializeObjectAttributes(&ObjectAttributes, + &RegistryString, + OBJ_CASE_INSENSITIVE, + NULL, NULL); + Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Read the services timeout */ + ShutdownSettings->WaitToKillServiceTimeout = GetRegIntFromID(KeyHandle, + L"WaitToKillServiceTimeout", + ShutdownSettings->WaitToKillAppTimeout); + + /* + * Retrieve the process terminate timeout. + * See ftp://ftp.microsoft.com/MISC1/BUSSYS/WINNT/KB/Q234/6/06.TXT + * and https://web.archive.org/web/20050216235758/http://support.microsoft.com/kb/2... + * for more details. + * + * NOTE: Unused at the moment... + */ + ShutdownSettings->ProcessTerminateTimeout = GetRegIntFromID(KeyHandle, + L"ProcessTerminateTimeout", + DEFAULT_PROCESS_TERMINATE_TIMEOUT); + if (ShutdownSettings->ProcessTerminateTimeout < DEFAULT_HUNG_APP_TIMEOUT) + ShutdownSettings->ProcessTerminateTimeout = DEFAULT_HUNG_APP_TIMEOUT; + + /* Done */ + NtClose(KeyHandle); + } +}
/* ENTRY-POINT ****************************************************************/
Modified: trunk/reactos/win32ss/user/winsrv/usersrv/init.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/winsrv/usersrv... ============================================================================== --- trunk/reactos/win32ss/user/winsrv/usersrv/init.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/winsrv/usersrv/init.c [iso-8859-1] Sun Feb 15 22:57:40 2015 @@ -135,6 +135,23 @@ { DPRINT1("%s not yet implemented\n", __FUNCTION__); return STATUS_NOT_IMPLEMENTED; +} + +CSR_API(SrvLogon) +{ + PUSER_LOGON LogonRequest = &((PUSER_API_MESSAGE)ApiMessage)->Data.LogonRequest; + + DPRINT1("We are logged %s\n", LogonRequest->IsLogon ? "on" : "off"); + + /* Impersonate the caller in order to retrieve settings in its context */ + if (!CsrImpersonateClient(NULL)) + return STATUS_UNSUCCESSFUL; + + GetTimeouts(&ShutdownSettings); + + /* We are done */ + CsrRevertToSelf(); + return STATUS_SUCCESS; }
NTSTATUS
Modified: trunk/reactos/win32ss/user/winsrv/usersrv/shutdown.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/winsrv/usersrv... ============================================================================== --- trunk/reactos/win32ss/user/winsrv/usersrv/shutdown.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/winsrv/usersrv/shutdown.c [iso-8859-1] Sun Feb 15 22:57:40 2015 @@ -4,19 +4,14 @@ * 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 "resource.h"
@@ -25,27 +20,25 @@
/* GLOBALS ********************************************************************/
-typedef struct tagSHUTDOWN_SETTINGS -{ - BOOL AutoEndTasks; - DWORD HungAppTimeout; - DWORD WaitToKillAppTimeout; -} SHUTDOWN_SETTINGS, *PSHUTDOWN_SETTINGS; - -SHUTDOWN_SETTINGS ShutdownSettings = {0}; - -#define DEFAULT_AUTO_END_TASKS FALSE -#define DEFAULT_HUNG_APP_TIMEOUT 5000 -#define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000 +// 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 + +// 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; @@ -54,7 +47,6 @@ HANDLE UIThread; HWND WndClient; PSHUTDOWN_SETTINGS ShutdownSettings; - LPTHREAD_START_ROUTINE SendMessageProc; } NOTIFY_CONTEXT, *PNOTIFY_CONTEXT;
#define QUERY_RESULT_ABORT 0 @@ -74,17 +66,29 @@ 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 ******************************************************************/ + +static HMODULE hComCtl32Lib = NULL; + +static VOID +CallInitCommonControls(VOID) +{ + 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 UpdateProgressBar(HWND ProgressBar, PNOTIFY_CONTEXT NotifyContext) @@ -113,18 +117,18 @@ 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); } @@ -137,7 +141,7 @@ 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; @@ -146,8 +150,9 @@ 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; } @@ -158,12 +163,14 @@ 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); @@ -178,48 +185,26 @@ return Result; }
-HMODULE hComCtl32Lib = NULL; - -static VOID -CallInitCommonControls(VOID) -{ - 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 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); @@ -230,70 +215,73 @@ }
static DWORD WINAPI -SendQueryEndSession(LPVOID Parameter) -{ - PMESSAGE_CONTEXT Context = (PMESSAGE_CONTEXT) Parameter; +SendClientShutdown(LPVOID 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)) - { - return Result ? QUERY_RESULT_CONTINUE : QUERY_RESULT_ABORT; - } - - 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_ENDSESSION, Context->wParam, - Context->lParam, SMTO_NORMAL, Context->Timeout, - &Result)) - { - return QUERY_RESULT_CONTINUE; - } - return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR; - } - else - { - SendMessage(Context->Wnd, WM_ENDSESSION, Context->wParam, - Context->lParam); + /* If the shutdown is aborted, just notify the process, there is no need to wait */ + if ((Context->wParam & (MCS_QUERYENDSESSION | MCS_ENDSESSION)) == 0) + { + MY_DPRINT("Called WM_CLIENTSHUTDOWN with wParam == 0 ...\n"); + SendNotifyMessageW(Context->Wnd, WM_CLIENTSHUTDOWN, + Context->wParam, Context->lParam); return QUERY_RESULT_CONTINUE; } -} - -static BOOL CALLBACK -NotifyTopLevelEnum(HWND Wnd, LPARAM lParam) -{ - PNOTIFY_CONTEXT NotifyContext = (PNOTIFY_CONTEXT) lParam; + + if (SendMessageTimeoutW(Context->Wnd, WM_CLIENTSHUTDOWN, + Context->wParam, Context->lParam, + SMTO_NORMAL, Context->Timeout, &Result)) + { + DWORD Ret; + + if (Context->wParam & MCS_QUERYENDSESSION) + { + /* WM_QUERYENDSESSION case */ + switch (Result) + { + case MCSR_DONOTSHUTDOWN: + Ret = QUERY_RESULT_ABORT; + break; + + case MCSR_GOODFORSHUTDOWN: + case MCSR_SHUTDOWNFINISHED: + default: + Ret = QUERY_RESULT_CONTINUE; + } + } + else + { + /* WM_ENDSESSION case */ + Ret = QUERY_RESULT_CONTINUE; + } + + MY_DPRINT("SendClientShutdown -- Return == %s\n", + Ret == QUERY_RESULT_CONTINUE ? "Continue" : "Abort"); + return Ret; + } + + MY_DPRINT("SendClientShutdown -- Error == %s\n", + GetLastError() == 0 ? "Timeout" : "error"); + + return (GetLastError() == 0 ? QUERY_RESULT_TIMEOUT : QUERY_RESULT_ERROR); +} + +static BOOL +NotifyTopLevelWindow(HWND Wnd, PNOTIFY_CONTEXT NotifyContext) +{ MESSAGE_CONTEXT MessageContext; DWORD Now, Passed; DWORD Timeout, WaitStatus; - DWORD ProcessId; HANDLE MessageThread; HANDLE Threads[2];
- if (0 == GetWindowThreadProcessId(Wnd, &ProcessId)) - { - NotifyContext->QueryResult = QUERY_RESULT_ERROR; - return FALSE; - } - - if (ProcessId != NotifyContext->ProcessId) - goto Quit; + SetForegroundWindow(Wnd);
Now = GetTickCount(); - if (0 == NotifyContext->StartTime) - { + if (NotifyContext->StartTime == 0) NotifyContext->StartTime = Now; - } + /* * Note: Passed is computed correctly even when GetTickCount() * wraps due to unsigned arithmetic. @@ -304,16 +292,16 @@ MessageContext.wParam = NotifyContext->wParam; MessageContext.lParam = NotifyContext->lParam; MessageContext.Timeout = NotifyContext->ShutdownSettings->HungAppTimeout; - if (! NotifyContext->ShutdownSettings->AutoEndTasks) + if (!NotifyContext->ShutdownSettings->AutoEndTasks) { MessageContext.Timeout += NotifyContext->ShutdownSettings->WaitToKillAppTimeout; } if (Passed < MessageContext.Timeout) { MessageContext.Timeout -= Passed; - MessageThread = CreateThread(NULL, 0, NotifyContext->SendMessageProc, - (LPVOID) &MessageContext, 0, NULL); - if (NULL == MessageThread) + MessageThread = CreateThread(NULL, 0, SendClientShutdown, + (LPVOID)&MessageContext, 0, NULL); + if (MessageThread == NULL) { NotifyContext->QueryResult = QUERY_RESULT_ERROR; return FALSE; @@ -331,30 +319,30 @@ if (WAIT_TIMEOUT == WaitStatus) { NotifyContext->WndClient = Wnd; - if (NULL == NotifyContext->UIThread && NotifyContext->ShowUI) + if (NotifyContext->UIThread == NULL && NotifyContext->ShowUI) { NotifyContext->UIThread = CreateThread(NULL, 0, EndNowThreadProc, - (LPVOID) NotifyContext, + (LPVOID)NotifyContext, 0, NULL); } Threads[0] = MessageThread; Threads[1] = NotifyContext->UIThread; - WaitStatus = WaitForMultipleObjectsEx(NULL == NotifyContext->UIThread ? + WaitStatus = WaitForMultipleObjectsEx(NotifyContext->UIThread == NULL ? 1 : 2, Threads, FALSE, INFINITE, FALSE); - if (WAIT_OBJECT_0 == WaitStatus) - { - if (! GetExitCodeThread(MessageThread, &NotifyContext->QueryResult)) + if (WaitStatus == WAIT_OBJECT_0) + { + if (!GetExitCodeThread(MessageThread, &NotifyContext->QueryResult)) { NotifyContext->QueryResult = QUERY_RESULT_ERROR; } } - else if (WAIT_OBJECT_0 + 1 == WaitStatus) - { - if (! GetExitCodeThread(NotifyContext->UIThread, - &NotifyContext->QueryResult)) + else if (WaitStatus == WAIT_OBJECT_0 + 1) + { + if (!GetExitCodeThread(NotifyContext->UIThread, + &NotifyContext->QueryResult)) { NotifyContext->QueryResult = QUERY_RESULT_ERROR; } @@ -363,15 +351,15 @@ { NotifyContext->QueryResult = QUERY_RESULT_ERROR; } - if (WAIT_OBJECT_0 != WaitStatus) + if (WaitStatus != WAIT_OBJECT_0) { TerminateThread(MessageThread, QUERY_RESULT_TIMEOUT); } } - else if (WAIT_OBJECT_0 == WaitStatus) - { - if (! GetExitCodeThread(MessageThread, - &NotifyContext->QueryResult)) + else if (WaitStatus == WAIT_OBJECT_0) + { + if (!GetExitCodeThread(MessageThread, + &NotifyContext->QueryResult)) { NotifyContext->QueryResult = QUERY_RESULT_ERROR; } @@ -387,59 +375,16 @@ NotifyContext->QueryResult = QUERY_RESULT_TIMEOUT; }
-Quit: - DPRINT1("NotifyContext->QueryResult == %d\n", NotifyContext->QueryResult); + MY_DPRINT("NotifyContext->QueryResult == %d\n", NotifyContext->QueryResult); return (NotifyContext->QueryResult == QUERY_RESULT_CONTINUE); }
-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) - { - DPRINT1("OpenDesktop failed with error %d\n", GetLastError()); - Context->QueryResult = QUERY_RESULT_ERROR; - return FALSE; - } - - Context->OldDesktop = GetThreadDesktop(GetCurrentThreadId()); - SwitchDesktop(Context->Desktop); - - EnumDesktopWindows(Context->Desktop, NotifyTopLevelEnum, lParam); - - SwitchDesktop(Context->OldDesktop); - - CloseDesktop(Context->Desktop); - - return QUERY_RESULT_CONTINUE == Context->QueryResult; -} - -static BOOL FASTCALL -NotifyTopLevelWindows(PNOTIFY_CONTEXT Context) -{ - HWINSTA WindowStation; - - WindowStation = GetProcessWindowStation(); - if (NULL == WindowStation) - { - DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError()); - return TRUE; - } - - EnumDesktopsW(WindowStation, NotifyDesktopEnum, (LPARAM) Context); - - return TRUE; -} - -static BOOL -DtbgIsDesktopVisible(VOID) -{ - return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE)); -} +static BOOLEAN +IsConsoleMode(VOID) +{ + return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE); +} +
/* TODO: Find an other way to do it. */ #if 0 @@ -452,11 +397,10 @@
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; @@ -468,296 +412,221 @@ #endif /************************************************/
-BOOL FASTCALL -NotifyAndTerminateProcess(PCSR_PROCESS ProcessData, - PSHUTDOWN_SETTINGS ShutdownSettings, - UINT Flags) -{ - NOTIFY_CONTEXT Context; - HANDLE Process; + +static BOOL CALLBACK +FindTopLevelWnd(IN HWND hWnd, + IN LPARAM lParam) +{ + if (GetWindow(hWnd, GW_OWNER) == NULL) + { + *(HWND*)lParam = hWnd; + return FALSE; + } + return TRUE; +} + +static VOID +ThreadShutdownNotify(IN PCSR_THREAD CsrThread, + IN ULONG Flags, + IN ULONG Flags2, + IN PNOTIFY_CONTEXT Context) +{ + HWND TopWnd = NULL; + + EnumThreadWindows(HandleToUlong(CsrThread->ClientId.UniqueThread), + FindTopLevelWnd, (LPARAM)&TopWnd); + if (TopWnd) + { + HWND hWndOwner; + + /*** FOR TESTING PURPOSES ONLY!! ***/ + HWND tmpWnd; + tmpWnd = TopWnd; + /***********************************/ + + while ((hWndOwner = GetWindow(TopWnd, GW_OWNER)) != NULL) + { + 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; + + Context->wParam = Flags2; + Context->lParam = (0 != (Flags & EWX_CALLER_WINLOGON_LOGOFF) ? + ENDSESSION_LOGOFF : 0); + + Context->StartTime = 0; + Context->UIThread = NULL; + Context->ShowUI = !IsConsoleMode() && (Flags2 & (MCS_QUERYENDSESSION | MCS_ENDSESSION)); + Context->Dlg = NULL; + +#if 0 // Obviously, switching desktops like that from within WINSRV doesn't work... + { + 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()); + } +#endif + + NotifyTopLevelWindow(TopWnd, Context); + +/******************************************************************************/ +#if 1 + if (Context->UIThread) + { + MY_DPRINT("Context->UIThread != NULL\n"); + if (Context->Dlg) + { + MY_DPRINT("Sending WM_CLOSE because Dlg is != NULL\n"); + SendMessageW(Context->Dlg, WM_CLOSE, 0, 0); + } + else + { + MY_DPRINT("Terminating UIThread thread with QUERY_RESULT_ERROR\n"); + TerminateThread(Context->UIThread, QUERY_RESULT_ERROR); + } + CloseHandle(Context->UIThread); + /**/Context->UIThread = NULL;/**/ + /**/Context->Dlg = NULL;/**/ + } +#endif +/******************************************************************************/ + +#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 BOOL +NotifyProcessForShutdown(PCSR_PROCESS CsrProcess, + PSHUTDOWN_SETTINGS ShutdownSettings, + UINT Flags) +{ DWORD QueryResult = QUERY_RESULT_CONTINUE;
- Context.QueryResult = QUERY_RESULT_CONTINUE; - - if (0 == (Flags & EWX_FORCE)) - { - // TODO: Find an other way whether or not the process has a console. + /* 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 (NULL != ProcessData->Console) - { - ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT, ProcessData, - ShutdownSettings->WaitToKillAppTimeout); - } - else + if (CsrProcess->Console) + { + ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT, CsrProcess, + ShutdownSettings->WaitToKillAppTimeout); + } + else #endif - { - Context.ProcessId = (DWORD_PTR) ProcessData->ClientId.UniqueProcess; - Context.wParam = 0; - Context.lParam = (0 != (Flags & EWX_CALLER_WINLOGON_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_CALLER_WINLOGON_LOGOFF) ? - ENDSESSION_LOGOFF : 0); - Context.SendMessageProc = SendEndSession; - Context.ShowUI = DtbgIsDesktopVisible() && - (QUERY_RESULT_ABORT != Context.QueryResult); - QueryResult = Context.QueryResult; + { + PCSR_PROCESS Process; + PCSR_THREAD Thread; + PLIST_ENTRY NextEntry; + + NOTIFY_CONTEXT Context; + Context.ShutdownSettings = ShutdownSettings; + + /* Lock the process */ + CsrLockProcessByClientId(CsrProcess->ClientId.UniqueProcess, &Process); + + /* 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) + { + /* 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; - - NotifyTopLevelWindows(&Context); - - 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); - } - } - - if (QUERY_RESULT_ABORT == QueryResult) - { - return FALSE; - } - } - - /* 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; -} + 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;/**/ + } + + QueryResult = Context.QueryResult; + MY_DPRINT2("QueryResult = %s\n", + QueryResult == QUERY_RESULT_ABORT ? "Abort" : "Continue"); + + /* Now send the ENDSESSION messages to the threads */ + MY_DPRINT2("Now sending the ENDSESSION messages...\n"); + + NextEntry = CsrProcess->ThreadList.Flink; + while (NextEntry != &CsrProcess->ThreadList) + { + /* 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); + } + +Quit: + /* Unlock the process */ + CsrUnlockProcess(Process);
#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; - } - - if (! OpenProcessToken(Process, TOKEN_QUERY, &Token)) - { - DPRINT1("Unable to open token for process %d, error %d\n", - ProcessData->ClientId.UniqueProcess, GetLastError()); - CloseHandle(Process); - return STATUS_UNSUCCESSFUL; - } - CloseHandle(Process); - - 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); - - /* This process will be killed if it's in the correct logon session */ - if (RtlEqualLuid(&(Context->TokenOrigin.OriginatingLogonSession), - &(Origin.OriginatingLogonSession))) - { - /* Kill the shell process last */ - if ((DWORD_PTR) ProcessData->ClientId.UniqueProcess == Context->ShellProcess) - { - ProcessData->ShutdownLevel = 0; - } - NewData = HeapAlloc(UserServerHeap, 0, (Context->ProcessCount + 1) - * sizeof(PCSR_PROCESS)); - if (NULL == NewData) - { - return STATUS_NO_MEMORY; - } - if (0 != Context->ProcessCount) - { - memcpy(NewData, Context->ProcessData, - Context->ProcessCount * sizeof(PCSR_PROCESS)); - HeapFree(UserServerHeap, 0, Context->ProcessData); - } - Context->ProcessData = NewData; - Context->ProcessData[Context->ProcessCount] = ProcessData; - Context->ProcessCount++; - } - - return STATUS_SUCCESS; -} + if (Context.UIThread) + { + if (Context.Dlg) + { + SendMessageW(Context.Dlg, WM_CLOSE, 0, 0); + } + else + { + TerminateThread(Context.UIThread, QUERY_RESULT_ERROR); + } + CloseHandle(Context.UIThread); + } #endif - -#if 0 -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; - } - - if (REG_SZ == Type) - { - RtlInitUnicodeString(&StringValue, (LPCWSTR) ValueBuffer); - if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue, 10, &Value))) - { - DPRINT1("Unable to convert value %S for setting %S\n", - StringValue.Buffer, ValueName); - return DefaultValue; - } - return (DWORD) Value; - } - else if (REG_DWORD == Type) - { - return *((DWORD *) ValueBuffer); - } - - DPRINT1("Unexpected registry type %d for setting %S\n", Type, ValueName); - return DefaultValue; -} - -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) - { - DPRINT1("Failed to allocate memory, using default shutdown settings\n"); - LocalFree(StringSid); - return; - } - } - 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; - } - - 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); - - RegCloseKey(DesktopKey); -} - -NTSTATUS FASTCALL -InternalExitReactos(DWORD ProcessId, DWORD ThreadId, UINT Flags) -{ - // PROCESS_ENUM_CONTEXT Context; - HWND ShellWnd; - char FixedUserInfo[64]; - TOKEN_USER *UserInfo; - SHUTDOWN_SETTINGS ShutdownSettings; - - LoadShutdownSettings(UserInfo->User.Sid, &ShutdownSettings); - - // Context.CsrssProcess = GetCurrentProcessId(); - // ShellWnd = GetShellWindow(); - // if (NULL == ShellWnd) - // { - // DPRINT("No shell present\n"); - // Context.ShellProcess = 0; - // } - // else if (0 == GetWindowThreadProcessId(ShellWnd, &Context.ShellProcess)) - // { - // DPRINT1("Can't get process id of shell window\n"); - // Context.ShellProcess = 0; - // } - - return STATUS_SUCCESS; -} -#endif + } + + /* Kill the process unless we abort shutdown */ + return (QueryResult != QUERY_RESULT_ABORT); +}
static NTSTATUS FASTCALL UserExitReactos(PCSR_THREAD CsrThread, UINT Flags) @@ -893,7 +762,7 @@ * Check for process validity */
- /* Do not kill WinLogon or CSRSS */ + /* Do not kill Winlogon or CSRSS */ if (CsrProcess->ClientId.UniqueProcess == NtCurrentProcess() || CsrProcess->ClientId.UniqueProcess == UlongToHandle(LogonProcessId)) { @@ -909,14 +778,25 @@ else DPRINT1("Killing process with ShutdownFlags = %lu\n", CsrProcess->ShutdownFlags);
-#if 0 - if (!NotifyAndTerminateProcess(CsrProcess, &ShutdownSettings, Flags)) - { + if (CsrProcess->ShutdownFlags & SHUTDOWN_OTHERCONTEXT) + DPRINT1("This process has SHUTDOWN_OTHERCONTEXT\n"); + + if (CsrProcess->ShutdownFlags & SHUTDOWN_SYSTEMCONTEXT) + DPRINT1("This process has SHUTDOWN_SYSTEMCONTEXT\n"); + + /* Notify the process for shutdown if needed */ + if (!NotifyProcessForShutdown(CsrProcess, &ShutdownSettings, Flags)) + { + /* Abort shutdown */ return CsrShutdownCancelled; } -#endif - - return CsrShutdownNonCsrProcess; + + /* Terminate this process */ + NtTerminateProcess(CsrProcess->ProcessHandle, 0); + + /* We are done */ + CsrDereferenceProcess(CsrProcess); + return CsrShutdownCsrProcess; }
@@ -965,16 +845,10 @@ return STATUS_SUCCESS; }
-CSR_API(SrvLogon) +CSR_API(SrvRecordShutdownReason) { DPRINT1("%s not yet implemented\n", __FUNCTION__); return STATUS_NOT_IMPLEMENTED; }
-CSR_API(SrvRecordShutdownReason) -{ - DPRINT1("%s not yet implemented\n", __FUNCTION__); - return STATUS_NOT_IMPLEMENTED; -} - /* EOF */
Modified: trunk/reactos/win32ss/user/winsrv/winsrv.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/winsrv/winsrv.... ============================================================================== --- trunk/reactos/win32ss/user/winsrv/winsrv.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/winsrv/winsrv.h [iso-8859-1] Sun Feb 15 22:57:40 2015 @@ -20,6 +20,7 @@ #include <windef.h> #include <winbase.h> #include <wingdi.h> +#include <winreg.h> #include <winuser.h> #include <imm.h>
@@ -42,4 +43,18 @@ /* CSRSS Header */ #include <csr/csrsrv.h>
+typedef struct tagSHUTDOWN_SETTINGS +{ + BOOL AutoEndTasks; + ULONG HungAppTimeout; + ULONG WaitToKillAppTimeout; + ULONG WaitToKillServiceTimeout; + ULONG ProcessTerminateTimeout; +} SHUTDOWN_SETTINGS, *PSHUTDOWN_SETTINGS; + +extern SHUTDOWN_SETTINGS ShutdownSettings; + +VOID FASTCALL +GetTimeouts(IN PSHUTDOWN_SETTINGS ShutdownSettings); + #endif /* __WINSRV_H__ */