⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exitros.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $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 + -