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 ThreadShutdownNotify(IN PCSR_THREAD CsrThread
,
420 IN PNOTIFY_CONTEXT Context
)
424 EnumThreadWindows(HandleToUlong(CsrThread
->ClientId
.UniqueThread
),
425 FindTopLevelWnd
, (LPARAM
)&TopWnd
);
430 /*** FOR TESTING PURPOSES ONLY!! ***/
433 /***********************************/
435 while ((hWndOwner
= GetWindow(TopWnd
, GW_OWNER
)) != NULL
)
437 MY_DPRINT("GetWindow(TopWnd, GW_OWNER) not returned NULL...\n");
440 if (TopWnd
!= tmpWnd
) MY_DPRINT("(TopWnd = %x) != (tmpWnd = %x)\n", TopWnd
, tmpWnd
);
445 Context
->wParam
= Flags2
;
446 Context
->lParam
= (0 != (Flags
& EWX_CALLER_WINLOGON_LOGOFF
) ?
447 ENDSESSION_LOGOFF
: 0);
449 Context
->StartTime
= 0;
450 Context
->UIThread
= NULL
;
451 Context
->ShowUI
= !IsConsoleMode() && (Flags2
& (MCS_QUERYENDSESSION
| MCS_ENDSESSION
));
454 #if 0 // Obviously, switching desktops like that from within WINSRV doesn't work...
457 Context
->OldDesktop
= GetThreadDesktop(GetCurrentThreadId());
458 // Context->Desktop = GetThreadDesktop(HandleToUlong(CsrThread->ClientId.UniqueThread));
459 Context
->Desktop
= GetThreadDesktop(GetWindowThreadProcessId(TopWnd
, NULL
));
460 MY_DPRINT("Last error = %d\n", GetLastError());
461 MY_DPRINT("Before switching to desktop 0x%x\n", Context
->Desktop
);
462 Success
= SwitchDesktop(Context
->Desktop
);
463 MY_DPRINT("After switching to desktop (Success = %s ; last error = %d); going to notify top-level...\n",
464 Success
? "TRUE" : "FALSE", GetLastError());
468 NotifyTopLevelWindow(TopWnd
, Context
);
470 /******************************************************************************/
472 if (Context
->UIThread
)
474 MY_DPRINT("Context->UIThread != NULL\n");
477 MY_DPRINT("Sending WM_CLOSE because Dlg is != NULL\n");
478 SendMessageW(Context
->Dlg
, WM_CLOSE
, 0, 0);
482 MY_DPRINT("Terminating UIThread thread with QUERY_RESULT_ERROR\n");
483 TerminateThread(Context
->UIThread
, QUERY_RESULT_ERROR
);
485 CloseHandle(Context
->UIThread
);
486 /**/Context
->UIThread
= NULL
;/**/
487 /**/Context
->Dlg
= NULL
;/**/
490 /******************************************************************************/
493 MY_DPRINT("Switch back to old desktop 0x%x\n", Context
->OldDesktop
);
494 SwitchDesktop(Context
->OldDesktop
);
495 MY_DPRINT("Switched back ok\n");
500 NotifyProcessForShutdown(PCSR_PROCESS CsrProcess
,
501 PSHUTDOWN_SETTINGS ShutdownSettings
,
504 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
506 /* In case we make a forced shutdown, just kill the process */
507 if (Flags
& EWX_FORCE
)
510 // TODO: Find an other way whether or not the process has a console.
512 if (CsrProcess
->Console
)
514 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, CsrProcess
,
515 ShutdownSettings
->WaitToKillAppTimeout
);
520 PCSR_PROCESS Process
;
522 PLIST_ENTRY NextEntry
;
524 NOTIFY_CONTEXT Context
;
525 Context
.ShutdownSettings
= ShutdownSettings
;
526 Context
.QueryResult
= QUERY_RESULT_CONTINUE
; // We continue shutdown by default.
528 /* Lock the process */
529 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
531 /* Send first the QUERYENDSESSION messages to all the threads of the process */
532 MY_DPRINT2("Sending the QUERYENDSESSION messages...\n");
534 NextEntry
= CsrProcess
->ThreadList
.Flink
;
535 while (NextEntry
!= &CsrProcess
->ThreadList
)
537 /* Get the current thread entry */
538 Thread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
540 /* Move to the next entry */
541 NextEntry
= NextEntry
->Flink
;
543 /* If the thread is being terminated, just skip it */
544 if (Thread
->Flags
& CsrThreadTerminated
) continue;
546 /* Reference the thread and temporarily unlock the process */
547 CsrReferenceThread(Thread
);
548 CsrUnlockProcess(Process
);
550 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
551 ThreadShutdownNotify(Thread
, Flags
,
555 /* Lock the process again and dereference the thread */
556 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
557 CsrDereferenceThread(Thread
);
559 // FIXME: Analyze Context.QueryResult !!
560 /**/if (Context
.QueryResult
== QUERY_RESULT_ABORT
) goto Quit
;/**/
563 QueryResult
= Context
.QueryResult
;
564 MY_DPRINT2("QueryResult = %s\n",
565 QueryResult
== QUERY_RESULT_ABORT
? "Abort" : "Continue");
567 /* Now send the ENDSESSION messages to the threads */
568 MY_DPRINT2("Now sending the ENDSESSION messages...\n");
570 NextEntry
= CsrProcess
->ThreadList
.Flink
;
571 while (NextEntry
!= &CsrProcess
->ThreadList
)
573 /* Get the current thread entry */
574 Thread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
576 /* Move to the next entry */
577 NextEntry
= NextEntry
->Flink
;
579 /* If the thread is being terminated, just skip it */
580 if (Thread
->Flags
& CsrThreadTerminated
) continue;
582 /* Reference the thread and temporarily unlock the process */
583 CsrReferenceThread(Thread
);
584 CsrUnlockProcess(Process
);
586 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
587 ThreadShutdownNotify(Thread
, Flags
,
588 (QUERY_RESULT_ABORT
!= QueryResult
) ? MCS_ENDSESSION
: 0,
591 /* Lock the process again and dereference the thread */
592 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
593 CsrDereferenceThread(Thread
);
597 /* Unlock the process */
598 CsrUnlockProcess(Process
);
601 if (Context
.UIThread
)
605 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
609 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
611 CloseHandle(Context
.UIThread
);
616 /* Kill the process unless we abort shutdown */
617 return (QueryResult
!= QUERY_RESULT_ABORT
);
620 static NTSTATUS FASTCALL
621 UserExitReactOS(PCSR_THREAD CsrThread
, UINT Flags
)
626 DWORD ProcessId
= HandleToUlong(CsrThread
->ClientId
.UniqueProcess
);
627 DWORD ThreadId
= HandleToUlong(CsrThread
->ClientId
.UniqueThread
);
629 DPRINT1("SrvExitWindowsEx(ClientId: %lx.%lx, Flags: 0x%x)\n",
630 ProcessId
, ThreadId
, Flags
);
633 * Check for flags validity
636 if (Flags
& EWX_CALLER_WINLOGON
)
638 /* Only Winlogon can call this */
639 if (ProcessId
!= LogonProcessId
)
641 DPRINT1("SrvExitWindowsEx call not from Winlogon\n");
642 return STATUS_ACCESS_DENIED
;
646 /* Implicitely add the shutdown flag when we poweroff or reboot */
647 if (Flags
& (EWX_POWEROFF
| EWX_REBOOT
))
648 Flags
|= EWX_SHUTDOWN
;
651 * Impersonate and retrieve the caller's LUID so that
652 * we can only shutdown processes in its context.
654 if (!CsrImpersonateClient(NULL
))
655 return STATUS_BAD_IMPERSONATION_LEVEL
;
657 Status
= CsrGetProcessLuid(NULL
, &CallerLuid
);
658 if (!NT_SUCCESS(Status
))
660 DPRINT1("Unable to get caller LUID, Status = 0x%08x\n", Status
);
664 DPRINT("Caller LUID is: %lx.%lx\n", CallerLuid
.HighPart
, CallerLuid
.LowPart
);
669 /* Notify Win32k and potentially Winlogon of the shutdown */
670 Status
= NtUserSetInformationThread(CsrThread
->ThreadHandle
,
671 UserThreadInitiateShutdown
,
672 &Flags
, sizeof(Flags
));
673 DPRINT("Win32k says: %lx\n", Status
);
676 /* We cannot wait here, the caller should start a new thread */
677 case STATUS_CANT_WAIT
:
678 DPRINT1("NtUserSetInformationThread returned STATUS_CANT_WAIT\n");
681 /* Shutdown is in progress */
683 DPRINT1("NtUserSetInformationThread returned STATUS_PENDING\n");
689 DPRINT1("NtUserSetInformationThread returned STATUS_RETRY\n");
696 if (!NT_SUCCESS(Status
))
698 // FIXME: Use some UserSetLastNTError or SetLastNtError
699 // that we have defined for user32 or win32k usage only...
700 SetLastError(RtlNtStatusToDosError(Status
));
711 * OK we can continue. Now magic happens:
713 * Terminate all Win32 processes, stop if we find one kicking
714 * and screaming it doesn't want to die.
716 * This function calls the ShutdownProcessCallback callback of
717 * each CSR server for each Win32 process.
719 Status
= CsrShutdownProcesses(&CallerLuid
, Flags
);
720 if (!NT_SUCCESS(Status
))
722 DPRINT1("Failed to shutdown processes, Status = 0x%08x\n", Status
);
725 // FIXME: If Status == STATUS_CANCELLED, call RecordShutdownReason
727 /* Tell Win32k and potentially Winlogon that we're done */
728 NtUserSetInformationThread(CsrThread
->ThreadHandle
,
729 UserThreadEndShutdown
,
730 &Status
, sizeof(Status
));
732 DPRINT("SrvExitWindowsEx returned 0x%08x\n", Status
);
743 UserClientShutdown(IN PCSR_PROCESS CsrProcess
,
745 IN BOOLEAN FirstPhase
)
747 DPRINT("UserClientShutdown(0x%p, 0x%x, %s) - [0x%x, 0x%x], ShutdownFlags: %lu\n",
748 CsrProcess
, Flags
, FirstPhase
? "FirstPhase" : "LastPhase",
749 CsrProcess
->ClientId
.UniqueProcess
, CsrProcess
->ClientId
.UniqueThread
,
750 CsrProcess
->ShutdownFlags
);
753 * Check for process validity
756 /* Do not kill system processes when a user is logging off */
757 if ((Flags
& EWX_SHUTDOWN
) == EWX_LOGOFF
&&
758 (CsrProcess
->ShutdownFlags
& (SHUTDOWN_OTHERCONTEXT
| SHUTDOWN_SYSTEMCONTEXT
)))
760 DPRINT("Do not kill a system process in a logoff request!\n");
761 return CsrShutdownNonCsrProcess
;
764 /* Do not kill Winlogon or CSRSS */
765 if (CsrProcess
->ClientId
.UniqueProcess
== NtCurrentProcess() ||
766 CsrProcess
->ClientId
.UniqueProcess
== UlongToHandle(LogonProcessId
))
768 DPRINT("Not killing %s; CsrProcess->ShutdownFlags = %lu\n",
769 CsrProcess
->ClientId
.UniqueProcess
== NtCurrentProcess() ? "CSRSS" : "Winlogon",
770 CsrProcess
->ShutdownFlags
);
772 return CsrShutdownNonCsrProcess
;
775 /* Notify the process for shutdown if needed */
776 if (!NotifyProcessForShutdown(CsrProcess
, &ShutdownSettings
, Flags
))
778 DPRINT1("Process 0x%x aborted shutdown\n", CsrProcess
->ClientId
.UniqueProcess
);
780 return CsrShutdownCancelled
;
783 /* Terminate this process */
786 WCHAR buffer
[MAX_PATH
];
787 if (!GetProcessImageFileNameW(CsrProcess
->ProcessHandle
, buffer
, MAX_PATH
))
789 DPRINT1("Terminating process %x\n", CsrProcess
->ClientId
.UniqueProcess
);
793 DPRINT1("Terminating process %x (%S)\n", CsrProcess
->ClientId
.UniqueProcess
, buffer
);
797 NtTerminateProcess(CsrProcess
->ProcessHandle
, 0);
800 CsrDereferenceProcess(CsrProcess
);
801 return CsrShutdownCsrProcess
;
805 /* PUBLIC SERVER APIS *********************************************************/
807 CSR_API(SrvExitWindowsEx
)
810 PUSER_EXIT_REACTOS ExitReactOSRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.ExitReactOSRequest
;
812 Status
= UserExitReactOS(CsrGetClientThread(), ExitReactOSRequest
->Flags
);
813 ExitReactOSRequest
->Success
= NT_SUCCESS(Status
);
814 ExitReactOSRequest
->LastError
= GetLastError();
821 PUSER_END_TASK EndTaskRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.EndTaskRequest
;
823 // FIXME: This is HACK-plemented!!
824 DPRINT1("SrvEndTask is HACKPLEMENTED!!\n");
826 SendMessageW(EndTaskRequest
->WndHandle
, WM_CLOSE
, 0, 0);
827 // PostMessageW(EndTaskRequest->WndHandle, WM_CLOSE, 0, 0);
829 if (IsWindow(EndTaskRequest
->WndHandle
))
831 if (EndTaskRequest
->Force
)
833 EndTaskRequest
->Success
= DestroyWindow(EndTaskRequest
->WndHandle
);
834 EndTaskRequest
->LastError
= GetLastError();
838 EndTaskRequest
->Success
= FALSE
;
843 EndTaskRequest
->Success
= TRUE
;
844 EndTaskRequest
->LastError
= ERROR_SUCCESS
;
847 return STATUS_SUCCESS
;
850 CSR_API(SrvRecordShutdownReason
)
852 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
853 return STATUS_NOT_IMPLEMENTED
;