📄 exitros.c
字号:
/* $Id: exitros.c 23445 2006-08-04 15:39:44Z hpoussin $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS CSRSS subsystem
* FILE: subsys/csrss/win32csr/exitros.c
* PURPOSE: Logout/shutdown
*/
/* INCLUDES ******************************************************************/
#include "w32csr.h"
#include <sddl.h>
#include "resource.h"
#define NDEBUG
#include <debug.h>
static HWND LogonNotifyWindow = NULL;
static HANDLE LogonProcess = NULL;
CSR_API(CsrRegisterLogonProcess)
{
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (Request->Data.RegisterLogonProcessRequest.Register)
{
if (0 != LogonProcess)
{
Request->Status = STATUS_LOGON_SESSION_EXISTS;
return Request->Status;
}
LogonProcess = Request->Data.RegisterLogonProcessRequest.ProcessId;
}
else
{
if (Request->Header.ClientId.UniqueProcess != LogonProcess)
{
DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n",
LogonProcess, Request->Header.ClientId.UniqueProcess);
Request->Status = STATUS_NOT_LOGON_PROCESS;
return Request->Status;
}
LogonProcess = 0;
}
Request->Status = STATUS_SUCCESS;
return Request->Status;
}
CSR_API(CsrSetLogonNotifyWindow)
{
DWORD WindowCreator;
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) -
sizeof(PORT_MESSAGE);
if (0 == GetWindowThreadProcessId(Request->Data.SetLogonNotifyWindowRequest.LogonNotifyWindow,
&WindowCreator))
{
DPRINT1("Can't get window creator\n");
Request->Status = STATUS_INVALID_HANDLE;
return Request->Status;
}
if (WindowCreator != (DWORD)LogonProcess)
{
DPRINT1("Trying to register window not created by winlogon as notify window\n");
Request->Status = STATUS_ACCESS_DENIED;
return Request->Status;
}
LogonNotifyWindow = Request->Data.SetLogonNotifyWindowRequest.LogonNotifyWindow;
Request->Status = STATUS_SUCCESS;
return Request->Status;
}
typedef struct tagSHUTDOWN_SETTINGS
{
BOOL AutoEndTasks;
DWORD HungAppTimeout;
DWORD WaitToKillAppTimeout;
} SHUTDOWN_SETTINGS, *PSHUTDOWN_SETTINGS;
#define DEFAULT_AUTO_END_TASKS FALSE
#define DEFAULT_HUNG_APP_TIMEOUT 5000
#define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
typedef struct tagNOTIFY_CONTEXT
{
DWORD ProcessId;
UINT Msg;
WPARAM wParam;
LPARAM lParam;
HDESK Desktop;
DWORD StartTime;
DWORD QueryResult;
HWND Dlg;
DWORD EndNowResult;
BOOL ShowUI;
HANDLE UIThread;
HWND WndClient;
PSHUTDOWN_SETTINGS ShutdownSettings;
LPTHREAD_START_ROUTINE SendMessageProc;
} NOTIFY_CONTEXT, *PNOTIFY_CONTEXT;
#define QUERY_RESULT_ABORT 0
#define QUERY_RESULT_CONTINUE 1
#define QUERY_RESULT_TIMEOUT 2
#define QUERY_RESULT_ERROR 3
#define QUERY_RESULT_FORCE 4
static void FASTCALL
UpdateProgressBar(HWND ProgressBar, PNOTIFY_CONTEXT NotifyContext)
{
DWORD Passed;
Passed = GetTickCount() - NotifyContext->StartTime;
Passed -= NotifyContext->ShutdownSettings->HungAppTimeout;
if (NotifyContext->ShutdownSettings->WaitToKillAppTimeout < Passed)
{
Passed = NotifyContext->ShutdownSettings->WaitToKillAppTimeout;
}
SendMessageW(ProgressBar, PBM_SETPOS, Passed / 2, 0);
}
static INT_PTR CALLBACK
EndNowDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
INT_PTR Result;
PNOTIFY_CONTEXT NotifyContext;
HWND ProgressBar;
DWORD TitleLength;
int Len;
LPWSTR Title;
switch(Msg)
{
case WM_INITDIALOG:
NotifyContext = (PNOTIFY_CONTEXT) lParam;
NotifyContext->EndNowResult = QUERY_RESULT_ABORT;
SetWindowLongPtrW(Dlg, DWLP_USER, (LONG_PTR) lParam);
TitleLength = SendMessageW(NotifyContext->WndClient, WM_GETTEXTLENGTH,
0, 0) +
GetWindowTextLengthW(Dlg);
Title = HeapAlloc(Win32CsrApiHeap, 0, (TitleLength + 1) * sizeof(WCHAR));
if (NULL != Title)
{
Len = GetWindowTextW(Dlg, Title, TitleLength + 1);
SendMessageW(NotifyContext->WndClient, WM_GETTEXT,
TitleLength + 1 - Len, (LPARAM) (Title + Len));
SetWindowTextW(Dlg, Title);
HeapFree(Win32CsrApiHeap, 0, Title);
}
ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS);
SendMessageW(ProgressBar, PBM_SETRANGE32, 0,
NotifyContext->ShutdownSettings->WaitToKillAppTimeout / 2);
UpdateProgressBar(ProgressBar, NotifyContext);
SetTimer(Dlg, 0, 200, NULL);
Result = FALSE;
break;
case WM_TIMER:
NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
ProgressBar = GetDlgItem(Dlg, IDC_PROGRESS);
UpdateProgressBar(ProgressBar, NotifyContext);
Result = TRUE;
break;
case WM_COMMAND:
if (BN_CLICKED == HIWORD(wParam) && IDC_END_NOW == LOWORD(wParam))
{
NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
NotifyContext->EndNowResult = QUERY_RESULT_FORCE;
SendMessageW(Dlg, WM_CLOSE, 0, 0);
Result = TRUE;
}
else
{
Result = FALSE;
}
break;
case WM_CLOSE:
DestroyWindow(Dlg);
Result = TRUE;
break;
case WM_DESTROY:
NotifyContext = (PNOTIFY_CONTEXT) GetWindowLongPtrW(Dlg, DWLP_USER);
NotifyContext->Dlg = NULL;
KillTimer(Dlg, 0);
PostQuitMessage(NotifyContext->EndNowResult);
Result = TRUE;
break;
default:
Result = FALSE;
break;
}
return Result;
}
typedef void (STDCALL *INITCOMMONCONTROLS_PROC)(void);
static void FASTCALL
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;
MSG Msg;
SetThreadDesktop(NotifyContext->Desktop);
SwitchDesktop(NotifyContext->Desktop);
CallInitCommonControls();
NotifyContext->Dlg = CreateDialogParam(Win32CsrDllHandle,
MAKEINTRESOURCE(IDD_END_NOW), NULL,
EndNowDlgProc, (LPARAM) NotifyContext);
if (NULL == NotifyContext->Dlg)
{
return 0;
}
ShowWindow(NotifyContext->Dlg, SW_SHOWNORMAL);
while (GetMessageW(&Msg, NULL, 0, 0))
{
if (! IsDialogMessage(NotifyContext->Dlg, &Msg))
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
}
return Msg.wParam;
}
typedef struct tagMESSAGE_CONTEXT
{
HWND Wnd;
UINT Msg;
WPARAM wParam;
LPARAM lParam;
DWORD Timeout;
} MESSAGE_CONTEXT, *PMESSAGE_CONTEXT;
static DWORD WINAPI
SendQueryEndSession(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);
return QUERY_RESULT_CONTINUE;
}
}
static BOOL CALLBACK
NotifyTopLevelEnum(HWND Wnd, LPARAM lParam)
{
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))
{
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
return FALSE;
}
if (ProcessId == NotifyContext->ProcessId)
{
Now = GetTickCount();
if (0 == NotifyContext->StartTime)
{
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)
{
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)
{
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 (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
{
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
}
if (WAIT_OBJECT_0 != WaitStatus)
{
TerminateThread(MessageThread, QUERY_RESULT_TIMEOUT);
}
}
else if (WAIT_OBJECT_0 == WaitStatus)
{
if (! GetExitCodeThread(MessageThread,
&NotifyContext->QueryResult))
{
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
}
}
else
{
NotifyContext->QueryResult = QUERY_RESULT_ERROR;
}
CloseHandle(MessageThread);
}
else
{
NotifyContext->QueryResult = QUERY_RESULT_TIMEOUT;
}
}
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)
{
DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
Context->QueryResult = QUERY_RESULT_ERROR;
return FALSE;
}
EnumDesktopWindows(Context->Desktop, NotifyTopLevelEnum, lParam);
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 FASTCALL
NotifyAndTerminateProcess(PCSRSS_PROCESS_DATA ProcessData,
PSHUTDOWN_SETTINGS ShutdownSettings,
UINT Flags)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -