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 *******************************************************************/
21 /* GLOBALS ********************************************************************/
23 // Those flags (that are used for CsrProcess->ShutdownFlags) are named
24 // in accordance to the only public one: SHUTDOWN_NORETRY used for the
25 // SetProcessShutdownParameters API.
26 #if !defined(SHUTDOWN_SYSTEMCONTEXT) && !defined(SHUTDOWN_OTHERCONTEXT)
27 #define SHUTDOWN_SYSTEMCONTEXT CsrShutdownSystem
28 #define SHUTDOWN_OTHERCONTEXT CsrShutdownOther
31 // The DPRINTs that need to really be removed as soon as everything works.
32 #define MY_DPRINT DPRINT1
33 #define MY_DPRINT2 DPRINT
35 typedef struct tagNOTIFY_CONTEXT
49 PSHUTDOWN_SETTINGS ShutdownSettings
;
50 } NOTIFY_CONTEXT
, *PNOTIFY_CONTEXT
;
52 #define QUERY_RESULT_ABORT 0
53 #define QUERY_RESULT_CONTINUE 1
54 #define QUERY_RESULT_TIMEOUT 2
55 #define QUERY_RESULT_ERROR 3
56 #define QUERY_RESULT_FORCE 4
58 typedef void (WINAPI
*INITCOMMONCONTROLS_PROC
)(void);
60 typedef struct tagMESSAGE_CONTEXT
67 } MESSAGE_CONTEXT
, *PMESSAGE_CONTEXT
;
70 /* FUNCTIONS ******************************************************************/
72 static HMODULE hComCtl32Lib
= NULL
;
75 CallInitCommonControls(VOID
)
77 static BOOL Initialized
= FALSE
;
78 INITCOMMONCONTROLS_PROC InitProc
;
80 if (Initialized
) return;
82 hComCtl32Lib
= LoadLibraryW(L
"COMCTL32.DLL");
83 if (hComCtl32Lib
== NULL
) return;
85 InitProc
= (INITCOMMONCONTROLS_PROC
)GetProcAddress(hComCtl32Lib
, "InitCommonControls");
86 if (InitProc
== NULL
) return;
94 UpdateProgressBar(HWND ProgressBar
, PNOTIFY_CONTEXT NotifyContext
)
98 Passed
= GetTickCount() - NotifyContext
->StartTime
;
99 Passed
-= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
100 if (NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
< Passed
)
102 Passed
= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
104 SendMessageW(ProgressBar
, PBM_SETPOS
, Passed
/ 2, 0);
107 static INT_PTR CALLBACK
108 EndNowDlgProc(HWND Dlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
111 PNOTIFY_CONTEXT NotifyContext
;
120 NotifyContext
= (PNOTIFY_CONTEXT
)lParam
;
121 NotifyContext
->EndNowResult
= QUERY_RESULT_ABORT
;
122 SetWindowLongPtrW(Dlg
, DWLP_USER
, (LONG_PTR
)lParam
);
123 TitleLength
= SendMessageW(NotifyContext
->WndClient
, WM_GETTEXTLENGTH
,
125 GetWindowTextLengthW(Dlg
);
126 Title
= HeapAlloc(UserServerHeap
, 0, (TitleLength
+ 1) * sizeof(WCHAR
));
129 Len
= GetWindowTextW(Dlg
, Title
, TitleLength
+ 1);
130 SendMessageW(NotifyContext
->WndClient
, WM_GETTEXT
,
131 TitleLength
+ 1 - Len
, (LPARAM
)(Title
+ Len
));
132 SetWindowTextW(Dlg
, Title
);
133 HeapFree(UserServerHeap
, 0, Title
);
135 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
136 SendMessageW(ProgressBar
, PBM_SETRANGE32
, 0,
137 NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
/ 2);
138 UpdateProgressBar(ProgressBar
, NotifyContext
);
139 SetTimer(Dlg
, 0, 200, NULL
);
144 NotifyContext
= (PNOTIFY_CONTEXT
)GetWindowLongPtrW(Dlg
, DWLP_USER
);
145 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
146 UpdateProgressBar(ProgressBar
, NotifyContext
);
151 if (BN_CLICKED
== HIWORD(wParam
) && IDC_END_NOW
== LOWORD(wParam
))
153 NotifyContext
= (PNOTIFY_CONTEXT
)GetWindowLongPtrW(Dlg
, DWLP_USER
);
154 NotifyContext
->EndNowResult
= QUERY_RESULT_FORCE
;
155 MY_DPRINT("Closing progress dlg by hand\n");
156 SendMessageW(Dlg
, WM_CLOSE
, 0, 0);
166 MY_DPRINT("WM_CLOSE\n");
172 MY_DPRINT("WM_DESTROY\n");
173 NotifyContext
= (PNOTIFY_CONTEXT
)GetWindowLongPtrW(Dlg
, DWLP_USER
);
174 NotifyContext
->Dlg
= NULL
;
176 PostQuitMessage(NotifyContext
->EndNowResult
);
189 EndNowThreadProc(LPVOID Parameter
)
191 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
)Parameter
;
194 // SetThreadDesktop(NotifyContext->Desktop);
195 // SwitchDesktop(NotifyContext->Desktop);
196 CallInitCommonControls();
197 NotifyContext
->Dlg
= CreateDialogParam(UserServerDllInstance
,
198 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
199 EndNowDlgProc
, (LPARAM
)NotifyContext
);
200 if (NotifyContext
->Dlg
== NULL
)
203 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
205 while (GetMessageW(&Msg
, NULL
, 0, 0))
207 if (!IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
209 TranslateMessage(&Msg
);
210 DispatchMessageW(&Msg
);
218 SendClientShutdown(LPVOID Parameter
)
220 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
)Parameter
;
223 /* If the shutdown is aborted, just notify the process, there is no need to wait */
224 if ((Context
->wParam
& (MCS_QUERYENDSESSION
| MCS_ENDSESSION
)) == 0)
226 DPRINT("Called WM_CLIENTSHUTDOWN with wParam == 0 ...\n");
227 SendNotifyMessageW(Context
->Wnd
, WM_CLIENTSHUTDOWN
,
228 Context
->wParam
, Context
->lParam
);
229 return QUERY_RESULT_CONTINUE
;
232 if (SendMessageTimeoutW(Context
->Wnd
, WM_CLIENTSHUTDOWN
,
233 Context
->wParam
, Context
->lParam
,
234 SMTO_NORMAL
, Context
->Timeout
, &Result
))
238 if (Context
->wParam
& MCS_QUERYENDSESSION
)
240 /* WM_QUERYENDSESSION case */
243 case MCSR_DONOTSHUTDOWN
:
244 Ret
= QUERY_RESULT_ABORT
;
247 case MCSR_GOODFORSHUTDOWN
:
248 case MCSR_SHUTDOWNFINISHED
:
250 Ret
= QUERY_RESULT_CONTINUE
;
255 /* WM_ENDSESSION case */
256 Ret
= QUERY_RESULT_CONTINUE
;
259 DPRINT("SendClientShutdown -- Return == %s\n",
260 Ret
== QUERY_RESULT_CONTINUE
? "Continue" : "Abort");
264 DPRINT1("SendClientShutdown -- Error == %s\n",
265 GetLastError() == 0 ? "Timeout" : "error");
267 return (GetLastError() == 0 ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
);
271 NotifyTopLevelWindow(HWND Wnd
, PNOTIFY_CONTEXT NotifyContext
)
273 MESSAGE_CONTEXT MessageContext
;
275 DWORD Timeout
, WaitStatus
;
276 HANDLE MessageThread
;
279 SetForegroundWindow(Wnd
);
281 Now
= GetTickCount();
282 if (NotifyContext
->StartTime
== 0)
283 NotifyContext
->StartTime
= Now
;
286 * Note: Passed is computed correctly even when GetTickCount()
287 * wraps due to unsigned arithmetic.
289 Passed
= Now
- NotifyContext
->StartTime
;
290 MessageContext
.Wnd
= Wnd
;
291 MessageContext
.Msg
= NotifyContext
->Msg
;
292 MessageContext
.wParam
= NotifyContext
->wParam
;
293 MessageContext
.lParam
= NotifyContext
->lParam
;
294 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
295 if (!NotifyContext
->ShutdownSettings
->AutoEndTasks
)
297 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
299 if (Passed
< MessageContext
.Timeout
)
301 MessageContext
.Timeout
-= Passed
;
302 MessageThread
= CreateThread(NULL
, 0, SendClientShutdown
,
303 (LPVOID
)&MessageContext
, 0, NULL
);
304 if (MessageThread
== NULL
)
306 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
309 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
310 if (Passed
< Timeout
)
313 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
317 WaitStatus
= WAIT_TIMEOUT
;
319 if (WAIT_TIMEOUT
== WaitStatus
)
321 NotifyContext
->WndClient
= Wnd
;
322 if (NotifyContext
->UIThread
== NULL
&& NotifyContext
->ShowUI
)
324 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
326 (LPVOID
)NotifyContext
,
329 Threads
[0] = MessageThread
;
330 Threads
[1] = NotifyContext
->UIThread
;
331 WaitStatus
= WaitForMultipleObjectsEx(NotifyContext
->UIThread
== NULL
?
333 Threads
, FALSE
, INFINITE
,
335 if (WaitStatus
== WAIT_OBJECT_0
)
337 if (!GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
339 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
342 else if (WaitStatus
== WAIT_OBJECT_0
+ 1)
344 if (!GetExitCodeThread(NotifyContext
->UIThread
,
345 &NotifyContext
->QueryResult
))
347 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
352 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
354 if (WaitStatus
!= WAIT_OBJECT_0
)
356 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
359 else if (WaitStatus
== WAIT_OBJECT_0
)
361 if (!GetExitCodeThread(MessageThread
,
362 &NotifyContext
->QueryResult
))
364 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
369 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
371 CloseHandle(MessageThread
);
375 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
378 DPRINT("NotifyContext->QueryResult == %d\n", NotifyContext
->QueryResult
);
379 return (NotifyContext
->QueryResult
== QUERY_RESULT_CONTINUE
);
385 return (BOOLEAN
)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE
);
389 /* TODO: Find an other way to do it. */
392 ConioConsoleCtrlEventTimeout(DWORD Event
, PCSR_PROCESS ProcessData
, DWORD Timeout
)
396 DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData
->ClientId
.UniqueProcess
);
398 if (ProcessData
->CtrlDispatcher
)
400 Thread
= CreateRemoteThread(ProcessData
->ProcessHandle
, NULL
, 0,
401 (LPTHREAD_START_ROUTINE
) ProcessData
->CtrlDispatcher
,
402 UlongToPtr(Event
), 0, NULL
);
405 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
408 WaitForSingleObject(Thread
, Timeout
);
413 /************************************************/
417 FindTopLevelWnd(IN HWND hWnd
,
420 if (GetWindow(hWnd
, GW_OWNER
) == NULL
)
422 *(HWND
*)lParam
= hWnd
;
429 ThreadShutdownNotify(IN PCSR_THREAD CsrThread
,
432 IN PNOTIFY_CONTEXT Context
)
436 EnumThreadWindows(HandleToUlong(CsrThread
->ClientId
.UniqueThread
),
437 FindTopLevelWnd
, (LPARAM
)&TopWnd
);
442 /*** FOR TESTING PURPOSES ONLY!! ***/
445 /***********************************/
447 while ((hWndOwner
= GetWindow(TopWnd
, GW_OWNER
)) != NULL
)
449 MY_DPRINT("GetWindow(TopWnd, GW_OWNER) not returned NULL...\n");
452 if (TopWnd
!= tmpWnd
) MY_DPRINT("(TopWnd = %x) != (tmpWnd = %x)\n", TopWnd
, tmpWnd
);
457 Context
->wParam
= Flags2
;
458 Context
->lParam
= (0 != (Flags
& EWX_CALLER_WINLOGON_LOGOFF
) ?
459 ENDSESSION_LOGOFF
: 0);
461 Context
->StartTime
= 0;
462 Context
->UIThread
= NULL
;
463 Context
->ShowUI
= !IsConsoleMode() && (Flags2
& (MCS_QUERYENDSESSION
| MCS_ENDSESSION
));
466 #if 0 // Obviously, switching desktops like that from within WINSRV doesn't work...
469 Context
->OldDesktop
= GetThreadDesktop(GetCurrentThreadId());
470 // Context->Desktop = GetThreadDesktop(HandleToUlong(CsrThread->ClientId.UniqueThread));
471 Context
->Desktop
= GetThreadDesktop(GetWindowThreadProcessId(TopWnd
, NULL
));
472 MY_DPRINT("Last error = %d\n", GetLastError());
473 MY_DPRINT("Before switching to desktop 0x%x\n", Context
->Desktop
);
474 Success
= SwitchDesktop(Context
->Desktop
);
475 MY_DPRINT("After switching to desktop (Success = %s ; last error = %d); going to notify top-level...\n",
476 Success
? "TRUE" : "FALSE", GetLastError());
480 NotifyTopLevelWindow(TopWnd
, Context
);
482 /******************************************************************************/
484 if (Context
->UIThread
)
486 MY_DPRINT("Context->UIThread != NULL\n");
489 MY_DPRINT("Sending WM_CLOSE because Dlg is != NULL\n");
490 SendMessageW(Context
->Dlg
, WM_CLOSE
, 0, 0);
494 MY_DPRINT("Terminating UIThread thread with QUERY_RESULT_ERROR\n");
495 TerminateThread(Context
->UIThread
, QUERY_RESULT_ERROR
);
497 CloseHandle(Context
->UIThread
);
498 /**/Context
->UIThread
= NULL
;/**/
499 /**/Context
->Dlg
= NULL
;/**/
502 /******************************************************************************/
505 MY_DPRINT("Switch back to old desktop 0x%x\n", Context
->OldDesktop
);
506 SwitchDesktop(Context
->OldDesktop
);
507 MY_DPRINT("Switched back ok\n");
512 NotifyProcessForShutdown(PCSR_PROCESS CsrProcess
,
513 PSHUTDOWN_SETTINGS ShutdownSettings
,
516 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
518 /* In case we make a forced shutdown, just kill the process */
519 if (Flags
& EWX_FORCE
)
522 // TODO: Find an other way whether or not the process has a console.
524 if (CsrProcess
->Console
)
526 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, CsrProcess
,
527 ShutdownSettings
->WaitToKillAppTimeout
);
532 PCSR_PROCESS Process
;
534 PLIST_ENTRY NextEntry
;
536 NOTIFY_CONTEXT Context
;
537 Context
.ShutdownSettings
= ShutdownSettings
;
538 Context
.QueryResult
= QUERY_RESULT_CONTINUE
; // We continue shutdown by default.
540 /* Lock the process */
541 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
543 /* Send first the QUERYENDSESSION messages to all the threads of the process */
544 MY_DPRINT2("Sending the QUERYENDSESSION messages...\n");
546 NextEntry
= CsrProcess
->ThreadList
.Flink
;
547 while (NextEntry
!= &CsrProcess
->ThreadList
)
549 /* Get the current thread entry */
550 Thread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
552 /* Move to the next entry */
553 NextEntry
= NextEntry
->Flink
;
555 /* If the thread is being terminated, just skip it */
556 if (Thread
->Flags
& CsrThreadTerminated
) continue;
558 /* Reference the thread and temporarily unlock the process */
559 CsrReferenceThread(Thread
);
560 CsrUnlockProcess(Process
);
562 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
563 ThreadShutdownNotify(Thread
, Flags
,
567 /* Lock the process again and dereference the thread */
568 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
569 CsrDereferenceThread(Thread
);
571 // FIXME: Analyze Context.QueryResult !!
572 /**/if (Context
.QueryResult
== QUERY_RESULT_ABORT
) goto Quit
;/**/
575 QueryResult
= Context
.QueryResult
;
576 MY_DPRINT2("QueryResult = %s\n",
577 QueryResult
== QUERY_RESULT_ABORT
? "Abort" : "Continue");
579 /* Now send the ENDSESSION messages to the threads */
580 MY_DPRINT2("Now sending the ENDSESSION messages...\n");
582 NextEntry
= CsrProcess
->ThreadList
.Flink
;
583 while (NextEntry
!= &CsrProcess
->ThreadList
)
585 /* Get the current thread entry */
586 Thread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
588 /* Move to the next entry */
589 NextEntry
= NextEntry
->Flink
;
591 /* If the thread is being terminated, just skip it */
592 if (Thread
->Flags
& CsrThreadTerminated
) continue;
594 /* Reference the thread and temporarily unlock the process */
595 CsrReferenceThread(Thread
);
596 CsrUnlockProcess(Process
);
598 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
599 ThreadShutdownNotify(Thread
, Flags
,
600 (QUERY_RESULT_ABORT
!= QueryResult
) ? MCS_ENDSESSION
: 0,
603 /* Lock the process again and dereference the thread */
604 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
605 CsrDereferenceThread(Thread
);
609 /* Unlock the process */
610 CsrUnlockProcess(Process
);
613 if (Context
.UIThread
)
617 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
621 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
623 CloseHandle(Context
.UIThread
);
628 /* Kill the process unless we abort shutdown */
629 return (QueryResult
!= QUERY_RESULT_ABORT
);
632 static NTSTATUS FASTCALL
633 UserExitReactOS(PCSR_THREAD CsrThread
, UINT Flags
)
638 DWORD ProcessId
= HandleToUlong(CsrThread
->ClientId
.UniqueProcess
);
639 DWORD ThreadId
= HandleToUlong(CsrThread
->ClientId
.UniqueThread
);
641 DPRINT1("SrvExitWindowsEx(ClientId: %lx.%lx, Flags: 0x%x)\n",
642 ProcessId
, ThreadId
, Flags
);
645 * Check for flags validity
648 if (Flags
& EWX_CALLER_WINLOGON
)
650 /* Only Winlogon can call this */
651 if (ProcessId
!= LogonProcessId
)
653 DPRINT1("SrvExitWindowsEx call not from Winlogon\n");
654 return STATUS_ACCESS_DENIED
;
658 /* Implicitely add the shutdown flag when we poweroff or reboot */
659 if (Flags
& (EWX_POWEROFF
| EWX_REBOOT
))
660 Flags
|= EWX_SHUTDOWN
;
663 * Impersonate and retrieve the caller's LUID so that
664 * we can only shutdown processes in its context.
666 if (!CsrImpersonateClient(NULL
))
667 return STATUS_BAD_IMPERSONATION_LEVEL
;
669 Status
= CsrGetProcessLuid(NULL
, &CallerLuid
);
670 if (!NT_SUCCESS(Status
))
672 DPRINT1("Unable to get caller LUID, Status = 0x%08x\n", Status
);
676 DPRINT("Caller LUID is: %lx.%lx\n", CallerLuid
.HighPart
, CallerLuid
.LowPart
);
681 /* Notify Win32k and potentially Winlogon of the shutdown */
682 Status
= NtUserSetInformationThread(CsrThread
->ThreadHandle
,
683 UserThreadInitiateShutdown
,
684 &Flags
, sizeof(Flags
));
685 DPRINT("Win32k says: %lx\n", Status
);
688 /* We cannot wait here, the caller should start a new thread */
689 case STATUS_CANT_WAIT
:
690 DPRINT1("NtUserSetInformationThread returned STATUS_CANT_WAIT\n");
693 /* Shutdown is in progress */
695 DPRINT1("NtUserSetInformationThread returned STATUS_PENDING\n");
701 DPRINT1("NtUserSetInformationThread returned STATUS_RETRY\n");
708 if (!NT_SUCCESS(Status
))
710 // FIXME: Use some UserSetLastNTError or SetLastNtError
711 // that we have defined for user32 or win32k usage only...
712 SetLastError(RtlNtStatusToDosError(Status
));
723 * OK we can continue. Now magic happens:
725 * Terminate all Win32 processes, stop if we find one kicking
726 * and screaming it doesn't want to die.
728 * This function calls the ShutdownProcessCallback callback of
729 * each CSR server for each Win32 process.
731 Status
= CsrShutdownProcesses(&CallerLuid
, Flags
);
732 if (!NT_SUCCESS(Status
))
734 DPRINT1("Failed to shutdown processes, Status = 0x%08x\n", Status
);
737 // FIXME: If Status == STATUS_CANCELLED, call RecordShutdownReason
739 /* Tell Win32k and potentially Winlogon that we're done */
740 NtUserSetInformationThread(CsrThread
->ThreadHandle
,
741 UserThreadEndShutdown
,
742 &Status
, sizeof(Status
));
744 DPRINT("SrvExitWindowsEx returned 0x%08x\n", Status
);
755 UserClientShutdown(IN PCSR_PROCESS CsrProcess
,
757 IN BOOLEAN FirstPhase
)
759 DPRINT("UserClientShutdown(0x%p, 0x%x, %s) - [0x%x, 0x%x], ShutdownFlags: %lu\n",
760 CsrProcess
, Flags
, FirstPhase
? "FirstPhase" : "LastPhase",
761 CsrProcess
->ClientId
.UniqueProcess
, CsrProcess
->ClientId
.UniqueThread
,
762 CsrProcess
->ShutdownFlags
);
765 * Check for process validity
768 /* Do not kill system processes when a user is logging off */
769 if ((Flags
& EWX_SHUTDOWN
) == EWX_LOGOFF
&&
770 (CsrProcess
->ShutdownFlags
& (SHUTDOWN_OTHERCONTEXT
| SHUTDOWN_SYSTEMCONTEXT
)))
772 DPRINT("Do not kill a system process in a logoff request!\n");
773 return CsrShutdownNonCsrProcess
;
776 /* Do not kill Winlogon or CSRSS */
777 if (CsrProcess
->ClientId
.UniqueProcess
== NtCurrentProcess() ||
778 CsrProcess
->ClientId
.UniqueProcess
== UlongToHandle(LogonProcessId
))
780 DPRINT("Not killing %s; CsrProcess->ShutdownFlags = %lu\n",
781 CsrProcess
->ClientId
.UniqueProcess
== NtCurrentProcess() ? "CSRSS" : "Winlogon",
782 CsrProcess
->ShutdownFlags
);
784 return CsrShutdownNonCsrProcess
;
787 /* Notify the process for shutdown if needed */
788 if (!NotifyProcessForShutdown(CsrProcess
, &ShutdownSettings
, Flags
))
790 DPRINT1("Process 0x%x aborted shutdown\n", CsrProcess
->ClientId
.UniqueProcess
);
792 return CsrShutdownCancelled
;
795 /* Terminate this process */
798 WCHAR buffer
[MAX_PATH
];
799 if (!GetProcessImageFileNameW(CsrProcess
->ProcessHandle
, buffer
, MAX_PATH
))
801 DPRINT1("Terminating process %x\n", CsrProcess
->ClientId
.UniqueProcess
);
805 DPRINT1("Terminating process %x (%S)\n", CsrProcess
->ClientId
.UniqueProcess
, buffer
);
809 NtTerminateProcess(CsrProcess
->ProcessHandle
, 0);
812 CsrDereferenceProcess(CsrProcess
);
813 return CsrShutdownCsrProcess
;
817 /* PUBLIC SERVER APIS *********************************************************/
819 CSR_API(SrvExitWindowsEx
)
822 PUSER_EXIT_REACTOS ExitReactOSRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.ExitReactOSRequest
;
824 Status
= UserExitReactOS(CsrGetClientThread(), ExitReactOSRequest
->Flags
);
825 ExitReactOSRequest
->Success
= NT_SUCCESS(Status
);
826 ExitReactOSRequest
->LastError
= GetLastError();
833 PUSER_END_TASK EndTaskRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.EndTaskRequest
;
835 // FIXME: This is HACK-plemented!!
836 DPRINT1("SrvEndTask is HACKPLEMENTED!!\n");
838 SendMessageW(EndTaskRequest
->WndHandle
, WM_CLOSE
, 0, 0);
839 // PostMessageW(EndTaskRequest->WndHandle, WM_CLOSE, 0, 0);
841 if (IsWindow(EndTaskRequest
->WndHandle
))
843 if (EndTaskRequest
->Force
)
845 EndTaskRequest
->Success
= DestroyWindow(EndTaskRequest
->WndHandle
);
846 EndTaskRequest
->LastError
= GetLastError();
850 EndTaskRequest
->Success
= FALSE
;
855 EndTaskRequest
->Success
= TRUE
;
856 EndTaskRequest
->LastError
= ERROR_SUCCESS
;
859 return STATUS_SUCCESS
;
862 CSR_API(SrvRecordShutdownReason
)
864 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
865 return STATUS_NOT_IMPLEMENTED
;