2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS User API Server DLL
4 * FILE: win32ss/user/winsrv/usersrv/shutdown.c
5 * PURPOSE: Logout/shutdown
9 /* INCLUDES *******************************************************************/
20 /* GLOBALS ********************************************************************/
22 // Those flags (that are used for CsrProcess->ShutdownFlags) are named
23 // in accordance to the only public one: SHUTDOWN_NORETRY used for the
24 // SetProcessShutdownParameters API.
25 #if !defined(SHUTDOWN_SYSTEMCONTEXT) && !defined(SHUTDOWN_OTHERCONTEXT)
26 #define SHUTDOWN_SYSTEMCONTEXT CsrShutdownSystem
27 #define SHUTDOWN_OTHERCONTEXT CsrShutdownOther
30 // The DPRINTs that need to really be removed as soon as everything works.
31 #define MY_DPRINT DPRINT1
32 #define MY_DPRINT2 DPRINT
34 typedef struct tagNOTIFY_CONTEXT
48 PSHUTDOWN_SETTINGS ShutdownSettings
;
49 } NOTIFY_CONTEXT
, *PNOTIFY_CONTEXT
;
51 #define QUERY_RESULT_ABORT 0
52 #define QUERY_RESULT_CONTINUE 1
53 #define QUERY_RESULT_TIMEOUT 2
54 #define QUERY_RESULT_ERROR 3
55 #define QUERY_RESULT_FORCE 4
57 typedef void (WINAPI
*INITCOMMONCONTROLS_PROC
)(void);
59 typedef struct tagMESSAGE_CONTEXT
66 } MESSAGE_CONTEXT
, *PMESSAGE_CONTEXT
;
69 /* FUNCTIONS ******************************************************************/
71 static HMODULE hComCtl32Lib
= NULL
;
74 CallInitCommonControls(VOID
)
76 static BOOL Initialized
= FALSE
;
77 INITCOMMONCONTROLS_PROC InitProc
;
79 if (Initialized
) return;
81 hComCtl32Lib
= LoadLibraryW(L
"COMCTL32.DLL");
82 if (hComCtl32Lib
== NULL
) return;
84 InitProc
= (INITCOMMONCONTROLS_PROC
)GetProcAddress(hComCtl32Lib
, "InitCommonControls");
85 if (InitProc
== NULL
) return;
93 UpdateProgressBar(HWND ProgressBar
, PNOTIFY_CONTEXT NotifyContext
)
97 Passed
= GetTickCount() - NotifyContext
->StartTime
;
98 Passed
-= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
99 if (NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
< Passed
)
101 Passed
= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
103 SendMessageW(ProgressBar
, PBM_SETPOS
, Passed
/ 2, 0);
106 static INT_PTR CALLBACK
107 EndNowDlgProc(HWND Dlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
110 PNOTIFY_CONTEXT NotifyContext
;
119 NotifyContext
= (PNOTIFY_CONTEXT
)lParam
;
120 NotifyContext
->EndNowResult
= QUERY_RESULT_ABORT
;
121 SetWindowLongPtrW(Dlg
, DWLP_USER
, (LONG_PTR
)lParam
);
122 TitleLength
= SendMessageW(NotifyContext
->WndClient
, WM_GETTEXTLENGTH
,
124 GetWindowTextLengthW(Dlg
);
125 Title
= HeapAlloc(UserServerHeap
, 0, (TitleLength
+ 1) * sizeof(WCHAR
));
128 Len
= GetWindowTextW(Dlg
, Title
, TitleLength
+ 1);
129 SendMessageW(NotifyContext
->WndClient
, WM_GETTEXT
,
130 TitleLength
+ 1 - Len
, (LPARAM
)(Title
+ Len
));
131 SetWindowTextW(Dlg
, Title
);
132 HeapFree(UserServerHeap
, 0, Title
);
134 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
135 SendMessageW(ProgressBar
, PBM_SETRANGE32
, 0,
136 NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
/ 2);
137 UpdateProgressBar(ProgressBar
, NotifyContext
);
138 SetTimer(Dlg
, 0, 200, NULL
);
143 NotifyContext
= (PNOTIFY_CONTEXT
)GetWindowLongPtrW(Dlg
, DWLP_USER
);
144 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
145 UpdateProgressBar(ProgressBar
, NotifyContext
);
150 if (BN_CLICKED
== HIWORD(wParam
) && IDC_END_NOW
== LOWORD(wParam
))
152 NotifyContext
= (PNOTIFY_CONTEXT
)GetWindowLongPtrW(Dlg
, DWLP_USER
);
153 NotifyContext
->EndNowResult
= QUERY_RESULT_FORCE
;
154 MY_DPRINT("Closing progress dlg by hand\n");
155 SendMessageW(Dlg
, WM_CLOSE
, 0, 0);
165 MY_DPRINT("WM_CLOSE\n");
171 MY_DPRINT("WM_DESTROY\n");
172 NotifyContext
= (PNOTIFY_CONTEXT
)GetWindowLongPtrW(Dlg
, DWLP_USER
);
173 NotifyContext
->Dlg
= NULL
;
175 PostQuitMessage(NotifyContext
->EndNowResult
);
188 EndNowThreadProc(LPVOID Parameter
)
190 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
)Parameter
;
193 // SetThreadDesktop(NotifyContext->Desktop);
194 // SwitchDesktop(NotifyContext->Desktop);
195 CallInitCommonControls();
196 NotifyContext
->Dlg
= CreateDialogParam(UserServerDllInstance
,
197 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
198 EndNowDlgProc
, (LPARAM
)NotifyContext
);
199 if (NotifyContext
->Dlg
== NULL
)
202 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
204 while (GetMessageW(&Msg
, NULL
, 0, 0))
206 if (!IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
208 TranslateMessage(&Msg
);
209 DispatchMessageW(&Msg
);
217 SendClientShutdown(LPVOID Parameter
)
219 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
)Parameter
;
222 /* If the shutdown is aborted, just notify the process, there is no need to wait */
223 if ((Context
->wParam
& (MCS_QUERYENDSESSION
| MCS_ENDSESSION
)) == 0)
225 MY_DPRINT("Called WM_CLIENTSHUTDOWN with wParam == 0 ...\n");
226 SendNotifyMessageW(Context
->Wnd
, WM_CLIENTSHUTDOWN
,
227 Context
->wParam
, Context
->lParam
);
228 return QUERY_RESULT_CONTINUE
;
231 if (SendMessageTimeoutW(Context
->Wnd
, WM_CLIENTSHUTDOWN
,
232 Context
->wParam
, Context
->lParam
,
233 SMTO_NORMAL
, Context
->Timeout
, &Result
))
237 if (Context
->wParam
& MCS_QUERYENDSESSION
)
239 /* WM_QUERYENDSESSION case */
242 case MCSR_DONOTSHUTDOWN
:
243 Ret
= QUERY_RESULT_ABORT
;
246 case MCSR_GOODFORSHUTDOWN
:
247 case MCSR_SHUTDOWNFINISHED
:
249 Ret
= QUERY_RESULT_CONTINUE
;
254 /* WM_ENDSESSION case */
255 Ret
= QUERY_RESULT_CONTINUE
;
258 MY_DPRINT("SendClientShutdown -- Return == %s\n",
259 Ret
== QUERY_RESULT_CONTINUE
? "Continue" : "Abort");
263 MY_DPRINT("SendClientShutdown -- Error == %s\n",
264 GetLastError() == 0 ? "Timeout" : "error");
266 return (GetLastError() == 0 ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
);
270 NotifyTopLevelWindow(HWND Wnd
, PNOTIFY_CONTEXT NotifyContext
)
272 MESSAGE_CONTEXT MessageContext
;
274 DWORD Timeout
, WaitStatus
;
275 HANDLE MessageThread
;
278 SetForegroundWindow(Wnd
);
280 Now
= GetTickCount();
281 if (NotifyContext
->StartTime
== 0)
282 NotifyContext
->StartTime
= Now
;
285 * Note: Passed is computed correctly even when GetTickCount()
286 * wraps due to unsigned arithmetic.
288 Passed
= Now
- NotifyContext
->StartTime
;
289 MessageContext
.Wnd
= Wnd
;
290 MessageContext
.Msg
= NotifyContext
->Msg
;
291 MessageContext
.wParam
= NotifyContext
->wParam
;
292 MessageContext
.lParam
= NotifyContext
->lParam
;
293 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
294 if (!NotifyContext
->ShutdownSettings
->AutoEndTasks
)
296 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
298 if (Passed
< MessageContext
.Timeout
)
300 MessageContext
.Timeout
-= Passed
;
301 MessageThread
= CreateThread(NULL
, 0, SendClientShutdown
,
302 (LPVOID
)&MessageContext
, 0, NULL
);
303 if (MessageThread
== NULL
)
305 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
308 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
309 if (Passed
< Timeout
)
312 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
316 WaitStatus
= WAIT_TIMEOUT
;
318 if (WAIT_TIMEOUT
== WaitStatus
)
320 NotifyContext
->WndClient
= Wnd
;
321 if (NotifyContext
->UIThread
== NULL
&& NotifyContext
->ShowUI
)
323 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
325 (LPVOID
)NotifyContext
,
328 Threads
[0] = MessageThread
;
329 Threads
[1] = NotifyContext
->UIThread
;
330 WaitStatus
= WaitForMultipleObjectsEx(NotifyContext
->UIThread
== NULL
?
332 Threads
, FALSE
, INFINITE
,
334 if (WaitStatus
== WAIT_OBJECT_0
)
336 if (!GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
338 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
341 else if (WaitStatus
== WAIT_OBJECT_0
+ 1)
343 if (!GetExitCodeThread(NotifyContext
->UIThread
,
344 &NotifyContext
->QueryResult
))
346 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
351 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
353 if (WaitStatus
!= WAIT_OBJECT_0
)
355 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
358 else if (WaitStatus
== WAIT_OBJECT_0
)
360 if (!GetExitCodeThread(MessageThread
,
361 &NotifyContext
->QueryResult
))
363 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
368 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
370 CloseHandle(MessageThread
);
374 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
377 MY_DPRINT("NotifyContext->QueryResult == %d\n", NotifyContext
->QueryResult
);
378 return (NotifyContext
->QueryResult
== QUERY_RESULT_CONTINUE
);
384 return (BOOLEAN
)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE
);
388 /* TODO: Find an other way to do it. */
391 ConioConsoleCtrlEventTimeout(DWORD Event
, PCSR_PROCESS ProcessData
, DWORD Timeout
)
395 DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData
->ClientId
.UniqueProcess
);
397 if (ProcessData
->CtrlDispatcher
)
399 Thread
= CreateRemoteThread(ProcessData
->ProcessHandle
, NULL
, 0,
400 (LPTHREAD_START_ROUTINE
) ProcessData
->CtrlDispatcher
,
401 UlongToPtr(Event
), 0, NULL
);
404 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
407 WaitForSingleObject(Thread
, Timeout
);
412 /************************************************/
416 FindTopLevelWnd(IN HWND hWnd
,
419 if (GetWindow(hWnd
, GW_OWNER
) == NULL
)
421 *(HWND
*)lParam
= hWnd
;
428 ThreadShutdownNotify(IN PCSR_THREAD CsrThread
,
431 IN PNOTIFY_CONTEXT Context
)
435 EnumThreadWindows(HandleToUlong(CsrThread
->ClientId
.UniqueThread
),
436 FindTopLevelWnd
, (LPARAM
)&TopWnd
);
441 /*** FOR TESTING PURPOSES ONLY!! ***/
444 /***********************************/
446 while ((hWndOwner
= GetWindow(TopWnd
, GW_OWNER
)) != NULL
)
448 MY_DPRINT("GetWindow(TopWnd, GW_OWNER) not returned NULL...\n");
451 if (TopWnd
!= tmpWnd
) MY_DPRINT("(TopWnd = %x) != (tmpWnd = %x)\n", TopWnd
, tmpWnd
);
456 Context
->wParam
= Flags2
;
457 Context
->lParam
= (0 != (Flags
& EWX_CALLER_WINLOGON_LOGOFF
) ?
458 ENDSESSION_LOGOFF
: 0);
460 Context
->StartTime
= 0;
461 Context
->UIThread
= NULL
;
462 Context
->ShowUI
= !IsConsoleMode() && (Flags2
& (MCS_QUERYENDSESSION
| MCS_ENDSESSION
));
465 #if 0 // Obviously, switching desktops like that from within WINSRV doesn't work...
468 Context
->OldDesktop
= GetThreadDesktop(GetCurrentThreadId());
469 // Context->Desktop = GetThreadDesktop(HandleToUlong(CsrThread->ClientId.UniqueThread));
470 Context
->Desktop
= GetThreadDesktop(GetWindowThreadProcessId(TopWnd
, NULL
));
471 MY_DPRINT("Last error = %d\n", GetLastError());
472 MY_DPRINT("Before switching to desktop 0x%x\n", Context
->Desktop
);
473 Success
= SwitchDesktop(Context
->Desktop
);
474 MY_DPRINT("After switching to desktop (Success = %s ; last error = %d); going to notify top-level...\n",
475 Success
? "TRUE" : "FALSE", GetLastError());
479 NotifyTopLevelWindow(TopWnd
, Context
);
481 /******************************************************************************/
483 if (Context
->UIThread
)
485 MY_DPRINT("Context->UIThread != NULL\n");
488 MY_DPRINT("Sending WM_CLOSE because Dlg is != NULL\n");
489 SendMessageW(Context
->Dlg
, WM_CLOSE
, 0, 0);
493 MY_DPRINT("Terminating UIThread thread with QUERY_RESULT_ERROR\n");
494 TerminateThread(Context
->UIThread
, QUERY_RESULT_ERROR
);
496 CloseHandle(Context
->UIThread
);
497 /**/Context
->UIThread
= NULL
;/**/
498 /**/Context
->Dlg
= NULL
;/**/
501 /******************************************************************************/
504 MY_DPRINT("Switch back to old desktop 0x%x\n", Context
->OldDesktop
);
505 SwitchDesktop(Context
->OldDesktop
);
506 MY_DPRINT("Switched back ok\n");
511 NotifyProcessForShutdown(PCSR_PROCESS CsrProcess
,
512 PSHUTDOWN_SETTINGS ShutdownSettings
,
515 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
517 /* In case we make a forced shutdown, just kill the process */
518 if (Flags
& EWX_FORCE
)
521 // TODO: Find an other way whether or not the process has a console.
523 if (CsrProcess
->Console
)
525 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, CsrProcess
,
526 ShutdownSettings
->WaitToKillAppTimeout
);
531 PCSR_PROCESS Process
;
533 PLIST_ENTRY NextEntry
;
535 NOTIFY_CONTEXT Context
;
536 Context
.ShutdownSettings
= ShutdownSettings
;
537 Context
.QueryResult
= QUERY_RESULT_CONTINUE
; // We continue shutdown by default.
539 /* Lock the process */
540 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
542 /* Send first the QUERYENDSESSION messages to all the threads of the process */
543 MY_DPRINT2("Sending the QUERYENDSESSION messages...\n");
545 NextEntry
= CsrProcess
->ThreadList
.Flink
;
546 while (NextEntry
!= &CsrProcess
->ThreadList
)
548 /* Get the current thread entry */
549 Thread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
551 /* Move to the next entry */
552 NextEntry
= NextEntry
->Flink
;
554 /* If the thread is being terminated, just skip it */
555 if (Thread
->Flags
& CsrThreadTerminated
) continue;
557 /* Reference the thread and temporarily unlock the process */
558 CsrReferenceThread(Thread
);
559 CsrUnlockProcess(Process
);
561 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
562 ThreadShutdownNotify(Thread
, Flags
,
566 /* Lock the process again and dereference the thread */
567 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
568 CsrDereferenceThread(Thread
);
570 // FIXME: Analyze Context.QueryResult !!
571 /**/if (Context
.QueryResult
== QUERY_RESULT_ABORT
) goto Quit
;/**/
574 QueryResult
= Context
.QueryResult
;
575 MY_DPRINT2("QueryResult = %s\n",
576 QueryResult
== QUERY_RESULT_ABORT
? "Abort" : "Continue");
578 /* Now send the ENDSESSION messages to the threads */
579 MY_DPRINT2("Now sending the ENDSESSION messages...\n");
581 NextEntry
= CsrProcess
->ThreadList
.Flink
;
582 while (NextEntry
!= &CsrProcess
->ThreadList
)
584 /* Get the current thread entry */
585 Thread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
587 /* Move to the next entry */
588 NextEntry
= NextEntry
->Flink
;
590 /* If the thread is being terminated, just skip it */
591 if (Thread
->Flags
& CsrThreadTerminated
) continue;
593 /* Reference the thread and temporarily unlock the process */
594 CsrReferenceThread(Thread
);
595 CsrUnlockProcess(Process
);
597 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
598 ThreadShutdownNotify(Thread
, Flags
,
599 (QUERY_RESULT_ABORT
!= QueryResult
) ? MCS_ENDSESSION
: 0,
602 /* Lock the process again and dereference the thread */
603 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
604 CsrDereferenceThread(Thread
);
608 /* Unlock the process */
609 CsrUnlockProcess(Process
);
612 if (Context
.UIThread
)
616 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
620 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
622 CloseHandle(Context
.UIThread
);
627 /* Kill the process unless we abort shutdown */
628 return (QueryResult
!= QUERY_RESULT_ABORT
);
631 static NTSTATUS FASTCALL
632 UserExitReactOS(PCSR_THREAD CsrThread
, UINT Flags
)
637 DWORD ProcessId
= HandleToUlong(CsrThread
->ClientId
.UniqueProcess
);
638 DWORD ThreadId
= HandleToUlong(CsrThread
->ClientId
.UniqueThread
);
640 DPRINT1("SrvExitWindowsEx(ClientId: %lx.%lx, Flags: 0x%x)\n",
641 ProcessId
, ThreadId
, Flags
);
644 * Check for flags validity
647 if (Flags
& EWX_CALLER_WINLOGON
)
649 /* Only Winlogon can call this */
650 if (ProcessId
!= LogonProcessId
)
652 DPRINT1("SrvExitWindowsEx call not from Winlogon\n");
653 return STATUS_ACCESS_DENIED
;
657 /* Implicitely add the shutdown flag when we poweroff or reboot */
658 if (Flags
& (EWX_POWEROFF
| EWX_REBOOT
))
659 Flags
|= EWX_SHUTDOWN
;
662 * Impersonate and retrieve the caller's LUID so that
663 * we can only shutdown processes in its context.
665 if (!CsrImpersonateClient(NULL
))
666 return STATUS_BAD_IMPERSONATION_LEVEL
;
668 Status
= CsrGetProcessLuid(NULL
, &CallerLuid
);
669 if (!NT_SUCCESS(Status
))
671 DPRINT1("Unable to get caller LUID, Status = 0x%08x\n", Status
);
675 DPRINT1("Caller LUID is: %lx.%lx\n", CallerLuid
.HighPart
, CallerLuid
.LowPart
);
680 /* Notify Win32k and potentially Winlogon of the shutdown */
681 Status
= NtUserSetInformationThread(CsrThread
->ThreadHandle
,
682 UserThreadInitiateShutdown
,
683 &Flags
, sizeof(Flags
));
684 DPRINT1("Win32k says: %lx\n", Status
);
687 /* We cannot wait here, the caller should start a new thread */
688 case STATUS_CANT_WAIT
:
689 DPRINT1("STATUS_CANT_WAIT\n");
692 /* Shutdown is in progress */
694 DPRINT1("STATUS_PENDING\n");
700 DPRINT1("STATUS_RETRY\n");
707 if (!NT_SUCCESS(Status
))
709 // FIXME: Use some UserSetLastNTError or SetLastNtError
710 // that we have defined for user32 or win32k usage only...
711 SetLastError(RtlNtStatusToDosError(Status
));
722 * OK we can continue. Now magic happens:
724 * Terminate all Win32 processes, stop if we find one kicking
725 * and screaming it doesn't want to die.
727 * This function calls the ShutdownProcessCallback callback of
728 * each CSR server for each Win32 process.
730 Status
= CsrShutdownProcesses(&CallerLuid
, Flags
);
731 if (!NT_SUCCESS(Status
))
733 DPRINT1("Failed to shutdown processes, Status = 0x%08x\n", Status
);
736 // FIXME: If Status == STATUS_CANCELLED, call RecordShutdownReason
738 /* Tell Win32k and potentially Winlogon that we're done */
739 NtUserSetInformationThread(CsrThread
->ThreadHandle
,
740 UserThreadEndShutdown
,
741 &Status
, sizeof(Status
));
743 DPRINT1("SrvExitWindowsEx returned 0x%08x\n", Status
);
754 UserClientShutdown(IN PCSR_PROCESS CsrProcess
,
756 IN BOOLEAN FirstPhase
)
758 DPRINT1("UserClientShutdown(0x%p, 0x%x, %s) - [0x%x, 0x%x]\n",
759 CsrProcess
, Flags
, FirstPhase
? "FirstPhase" : "LastPhase",
760 CsrProcess
->ClientId
.UniqueProcess
, CsrProcess
->ClientId
.UniqueThread
);
763 * Check for process validity
766 /* Do not kill Winlogon or CSRSS */
767 if (CsrProcess
->ClientId
.UniqueProcess
== NtCurrentProcess() ||
768 CsrProcess
->ClientId
.UniqueProcess
== UlongToHandle(LogonProcessId
))
770 DPRINT1("Not killing %s; CsrProcess->ShutdownFlags = %lu\n",
771 CsrProcess
->ClientId
.UniqueProcess
== NtCurrentProcess() ? "CSRSS" : "Winlogon",
772 CsrProcess
->ShutdownFlags
);
774 return CsrShutdownNonCsrProcess
;
777 if (Flags
& EWX_CALLER_SYSTEM
)
778 DPRINT1("Killed by a SYSTEM process -- ShutdownFlags = %lu\n", CsrProcess
->ShutdownFlags
);
780 DPRINT1("Killing process with ShutdownFlags = %lu\n", CsrProcess
->ShutdownFlags
);
782 if (CsrProcess
->ShutdownFlags
& SHUTDOWN_OTHERCONTEXT
)
783 DPRINT1("This process has SHUTDOWN_OTHERCONTEXT\n");
785 if (CsrProcess
->ShutdownFlags
& SHUTDOWN_SYSTEMCONTEXT
)
786 DPRINT1("This process has SHUTDOWN_SYSTEMCONTEXT\n");
788 /* Notify the process for shutdown if needed */
789 if (!NotifyProcessForShutdown(CsrProcess
, &ShutdownSettings
, Flags
))
792 return CsrShutdownCancelled
;
795 /* Terminate this process */
796 NtTerminateProcess(CsrProcess
->ProcessHandle
, 0);
799 CsrDereferenceProcess(CsrProcess
);
800 return CsrShutdownCsrProcess
;
804 /* PUBLIC SERVER APIS *********************************************************/
806 CSR_API(SrvExitWindowsEx
)
809 PUSER_EXIT_REACTOS ExitReactOSRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.ExitReactOSRequest
;
811 Status
= UserExitReactOS(CsrGetClientThread(), ExitReactOSRequest
->Flags
);
812 ExitReactOSRequest
->Success
= NT_SUCCESS(Status
);
813 ExitReactOSRequest
->LastError
= GetLastError();
820 PUSER_END_TASK EndTaskRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.EndTaskRequest
;
822 // FIXME: This is HACK-plemented!!
823 DPRINT1("SrvEndTask is HACKPLEMENTED!!\n");
825 SendMessageW(EndTaskRequest
->WndHandle
, WM_CLOSE
, 0, 0);
826 // PostMessageW(EndTaskRequest->WndHandle, WM_CLOSE, 0, 0);
828 if (IsWindow(EndTaskRequest
->WndHandle
))
830 if (EndTaskRequest
->Force
)
832 EndTaskRequest
->Success
= DestroyWindow(EndTaskRequest
->WndHandle
);
833 EndTaskRequest
->LastError
= GetLastError();
837 EndTaskRequest
->Success
= FALSE
;
842 EndTaskRequest
->Success
= TRUE
;
843 EndTaskRequest
->LastError
= ERROR_SUCCESS
;
846 return STATUS_SUCCESS
;
849 CSR_API(SrvRecordShutdownReason
)
851 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
852 return STATUS_NOT_IMPLEMENTED
;