ReactOS  0.4.14-dev-583-g2a1ba2c
exit.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS user32.dll
4  * FILE: win32ss/user/user32/misc/exit.c
5  * PURPOSE: Shutdown related functions
6  * PROGRAMMER: Eric Kohl
7  */
8 
9 #include <user32.h>
10 
11 /*
12  * Sequence of events:
13  *
14  * - App (usually explorer) calls ExitWindowsEx()
15  * - ExitWindowsEx() sends a message to CSRSS
16  * - CSRSS impersonates the caller and sends a message to a hidden Winlogon window
17  * - Winlogon checks if the caller has the required privileges
18  * - Winlogon enters pending log-out state
19  * - Winlogon impersonates the interactive user and calls ExitWindowsEx() again,
20  * passing some special internal flags
21  * - CSRSS loops over all processes of the interactive user (sorted by their
22  * SetProcessShutdownParameters() level), sending WM_QUERYENDSESSION and
23  * WM_ENDSESSION messages to its top-level windows. If the messages aren't
24  * processed within the timeout period (registry key HKCU\Control Panel\Desktop\HungAppTimeout)
25  * CSRSS will put up a dialog box asking if the process should be terminated.
26  * Using the registry key HKCU\Control Panel\Desktop\AutoEndTask you can
27  * specify that the dialog box shouldn't be shown and CSRSS should just
28  * terminate the thread. If the the WM_ENDSESSION message is processed
29  * but the thread doesn't terminate within the timeout specified by
30  * HKCU\Control Panel\Desktop\WaitToKillAppTimeout CSRSS will terminate
31  * the thread. When all the top-level windows have been destroyed CSRSS
32  * will terminate the process.
33  * If the process is a console process, CSRSS will send a CTRL_LOGOFF_EVENT
34  * to the console control handler on logoff. No event is sent on shutdown.
35  * If the handler doesn't respond in time the same activities as for GUI
36  * apps (i.e. display dialog box etc) take place. This also happens if
37  * the handler returns TRUE.
38  * - This ends the processing for the first ExitWindowsEx() call from Winlogon.
39  * Execution continues in Winlogon, which calls ExitWindowsEx() again to
40  * terminate COM processes in the interactive user's session.
41  * - Winlogon stops impersonating the interactive user (whose processes are
42  * all dead by now). and enters log-out state
43  * - If the ExitWindowsEx() request was for a logoff, Winlogon sends a SAS
44  * event (to display the "press ctrl+alt+del") to the GINA. Winlogon then
45  * waits for the GINA to send a SAS event to login.
46  * - If the ExitWindowsEx() request was for shutdown/restart, Winlogon calls
47  * ExitWindowsEx() again in the system process context.
48  * - CSRSS goes through the motions of sending WM_QUERYENDSESSION/WM_ENDSESSION
49  * to GUI processes running in the system process context but won't display
50  * dialog boxes or kill threads/processes. Same for console processes,
51  * using the CTRL_SHUTDOWN_EVENT. The Service Control Manager is one of
52  * these console processes and has a special timeout value WaitToKillServiceTimeout.
53  * - After CSRSS has finished its pass notifying processes that system is shutting down,
54  * Winlogon finishes the shutdown process by calling the executive subsystem
55  * function NtShutdownSystem.
56  */
57 
58 typedef struct
59 {
63 
64 static BOOL
67  BOOL bCalledFromThread);
68 
69 static DWORD
70 WINAPI
72 {
73  DWORD dwExitCode;
74  PEXIT_REACTOS_DATA ExitData = (PEXIT_REACTOS_DATA)Param;
75 
76  /* Do the exit asynchronously */
77  if (ExitWindowsWorker(ExitData->uFlags, ExitData->dwReserved, TRUE))
78  dwExitCode = ERROR_SUCCESS;
79  else
80  dwExitCode = GetLastError();
81 
82  ExitThread(dwExitCode);
83  return ERROR_SUCCESS;
84 }
85 
86 static BOOL
89  BOOL bCalledFromThread)
90 {
91  EXIT_REACTOS_DATA ExitData;
92  HANDLE hExitThread;
93  DWORD ExitCode;
94  MSG msg;
95 
96  USER_API_MESSAGE ApiMessage;
97  PUSER_EXIT_REACTOS ExitReactOSRequest = &ApiMessage.Data.ExitReactOSRequest;
98 
99  /*
100  * 1- FIXME: Call NtUserCallOneParam(uFlags, ONEPARAM_ROUTINE_PREPAREFORLOGOFF);
101  * If success we can continue, otherwise we must fail.
102  */
103 
104  /*
105  * 2- Send the Exit request to CSRSS (and to Win32k indirectly).
106  * We can shutdown synchronously or asynchronously.
107  */
108 
109  // ExitReactOSRequest->LastError = ERROR_SUCCESS;
110  ExitReactOSRequest->Flags = uFlags;
111 
113  NULL,
115  sizeof(*ExitReactOSRequest));
116 
117  /* Set the last error accordingly */
118  if (NT_SUCCESS(ApiMessage.Status) || ApiMessage.Status == STATUS_CANT_WAIT)
119  {
120  if (ExitReactOSRequest->LastError != ERROR_SUCCESS)
121  UserSetLastError(ExitReactOSRequest->LastError);
122  }
123  else
124  {
125  UserSetLastNTError(ApiMessage.Status);
126  ExitReactOSRequest->Success = FALSE;
127  }
128 
129  /*
130  * In case CSR call succeeded and we did a synchronous exit
131  * (STATUS_CANT_WAIT is considered as a non-success status),
132  * return the real state of the operation now.
133  */
134  if (NT_SUCCESS(ApiMessage.Status))
135  return ExitReactOSRequest->Success;
136 
137  /*
138  * In case something failed: we have a non-success status and:
139  * - either we were doing a synchronous exit (Status != STATUS_CANT_WAIT), or
140  * - we were doing an asynchronous exit because we were called recursively via
141  * another thread but we failed to exit,
142  * then bail out immediately, otherwise we would enter an infinite loop of exit requests.
143  *
144  * On the contrary if we need to do an asynchronous exit (Status == STATUS_CANT_WAIT
145  * and not called recursively via another thread), then continue and do the exit.
146  */
147  if (ApiMessage.Status != STATUS_CANT_WAIT || bCalledFromThread)
148  {
149  UserSetLastNTError(ApiMessage.Status);
150  return FALSE;
151  }
152 
153  /*
154  * 3- Win32k wants us to perform an asynchronous exit. Run the request in a thread.
155  * (ApiMessage.Status == STATUS_CANT_WAIT and not already called from a thread)
156  */
157  ExitData.uFlags = uFlags;
158  ExitData.dwReserved = dwReserved;
159  hExitThread = CreateThread(NULL, 0, ExitWindowsThread, &ExitData, 0, NULL);
160  if (hExitThread == NULL)
161  return FALSE;
162 
163  /* Pump and discard any input events sent to the app(s) */
164  while (MsgWaitForMultipleObjectsEx(1, &hExitThread, INFINITE, QS_ALLINPUT, 0))
165  {
166  while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
168  }
169 
170  /* Finally, return to caller */
171  if (!GetExitCodeThread(hExitThread, &ExitCode))
172  ExitCode = GetLastError();
173 
174  CloseHandle(hExitThread);
175 
176  if (ExitCode != ERROR_SUCCESS)
177  UserSetLastError(ExitCode);
178 
179  return (ExitCode == ERROR_SUCCESS);
180 }
181 
182 /*
183  * @implemented
184  */
185 BOOL WINAPI
188 {
189  /*
190  * FIXME:
191  * 1- Calling the Exit worker must be done under certain conditions.
192  * We may also need to warn the user if there are other people logged
193  * on this computer (see http://pve.proxmox.com/wiki/Windows_2003_guest_best_practices )
194  * 2- Call SrvRecordShutdownReason.
195  */
196 
198 
199  /* FIXME: Call SrvRecordShutdownReason if we failed */
200 }
201 
202 /*
203  * @implemented
204  */
205 BOOL
206 WINAPI
208  BOOL fShutDown,
209  BOOL fForce)
210 {
211  USER_API_MESSAGE ApiMessage;
212  PUSER_END_TASK EndTaskRequest = &ApiMessage.Data.EndTaskRequest;
213 
214  UNREFERENCED_PARAMETER(fShutDown);
215 
216  // EndTaskRequest->LastError = ERROR_SUCCESS;
217  EndTaskRequest->WndHandle = hWnd;
218  EndTaskRequest->Force = fForce;
219 
221  NULL,
223  sizeof(*EndTaskRequest));
224  if (!NT_SUCCESS(ApiMessage.Status))
225  {
226  UserSetLastNTError(ApiMessage.Status);
227  return FALSE;
228  }
229 
230  if (EndTaskRequest->LastError != ERROR_SUCCESS)
231  UserSetLastError(EndTaskRequest->LastError);
232 
233  return EndTaskRequest->Success;
234 }
235 
236 /* EOF */
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:406
BOOL Force
Definition: winmsg.h:59
#define ERROR_SUCCESS
Definition: deptool.c:10
#define USERSRV_SERVERDLL_INDEX
Definition: winmsg.h:15
static DWORD WINAPI ExitWindowsThread(LPVOID Param)
Definition: exit.c:71
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
DWORD LastError
Definition: winmsg.h:50
NTSTATUS NTAPI CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage, IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer OPTIONAL, IN CSR_API_NUMBER ApiNumber, IN ULONG DataLength)
Definition: connect.c:365
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
static BOOL ExitWindowsWorker(UINT uFlags, DWORD dwReserved, BOOL bCalledFromThread)
Definition: exit.c:87
HWND hWnd
Definition: settings.c:17
USER_EXIT_REACTOS ExitReactOSRequest
Definition: winmsg.h:100
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
BOOL Success
Definition: winmsg.h:60
HWND WndHandle
Definition: winmsg.h:58
UINT uFlags
Definition: api.c:59
VOID WINAPI UserSetLastError(IN DWORD dwErrCode)
Definition: misc.c:13
struct EXIT_REACTOS_DATA * PEXIT_REACTOS_DATA
UINT uFlags
Definition: exit.c:60
BOOL WINAPI GetExitCodeThread(IN HANDLE hThread, OUT LPDWORD lpExitCode)
Definition: thread.c:540
DWORD WINAPI MsgWaitForMultipleObjectsEx(_In_ DWORD nCount, _In_reads_opt_(nCount) CONST HANDLE *pHandles, _In_ DWORD dwMilliseconds, _In_ DWORD dwWakeMask, _In_ DWORD dwFlags)
NTSTATUS Status
Definition: csrmsg.h:112
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
_In_ HANDLE _In_ DWORD _In_ DWORD _Inout_opt_ LPOVERLAPPED _In_opt_ LPTRANSMIT_FILE_BUFFERS _In_ DWORD dwReserved
Definition: mswsock.h:90
unsigned int BOOL
Definition: ntddk_ex.h:94
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:136
smooth NULL
Definition: ftsmooth.c:416
VOID WINAPI ExitThread(IN DWORD uExitCode)
Definition: thread.c:364
DWORD dwReserved
Definition: exit.c:61
#define CSR_CREATE_API_NUMBER(ServerId, ApiId)
Definition: csrmsg.h:37
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
USER_END_TASK EndTaskRequest
Definition: winmsg.h:101
#define WINAPI
Definition: msvc.h:6
unsigned long DWORD
Definition: ntddk_ex.h:95
union _USER_API_MESSAGE::@3414 Data
VOID WINAPI UserSetLastNTError(IN NTSTATUS Status)
Definition: misc.c:25
BOOL WINAPI EndTask(HWND hWnd, BOOL fShutDown, BOOL fForce)
Definition: exit.c:207
#define QS_ALLINPUT
Definition: winuser.h:874
unsigned int UINT
Definition: ndis.h:50
#define msg(x)
Definition: auth_time.c:54
DWORD LastError
Definition: winmsg.h:57
BOOL WINAPI PeekMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define PM_REMOVE
Definition: winuser.h:1182
#define INFINITE
Definition: serial.h:102
BOOL WINAPI ExitWindowsEx(UINT uFlags, DWORD dwReserved)
Definition: exit.c:186
#define STATUS_CANT_WAIT
Definition: ntstatus.h:438