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
;
195 SetThreadDesktop(NotifyContext
->Desktop
);
196 SwitchDesktop(NotifyContext
->Desktop
);
198 /* For now show the end task dialog in the active desktop */
199 NtUserSetInformationThread(NtCurrentThread(),
200 UserThreadUseActiveDesktop
,
205 CallInitCommonControls();
206 NotifyContext
->Dlg
= CreateDialogParam(UserServerDllInstance
,
207 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
208 EndNowDlgProc
, (LPARAM
)NotifyContext
);
209 if (NotifyContext
->Dlg
== NULL
)
212 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
214 while (GetMessageW(&Msg
, NULL
, 0, 0))
216 if (!IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
218 TranslateMessage(&Msg
);
219 DispatchMessageW(&Msg
);
227 SendClientShutdown(LPVOID Parameter
)
229 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
)Parameter
;
232 /* If the shutdown is aborted, just notify the process, there is no need to wait */
233 if ((Context
->wParam
& (MCS_QUERYENDSESSION
| MCS_ENDSESSION
)) == 0)
235 DPRINT("Called WM_CLIENTSHUTDOWN with wParam == 0 ...\n");
236 SendNotifyMessageW(Context
->Wnd
, WM_CLIENTSHUTDOWN
,
237 Context
->wParam
, Context
->lParam
);
238 return QUERY_RESULT_CONTINUE
;
241 if (SendMessageTimeoutW(Context
->Wnd
, WM_CLIENTSHUTDOWN
,
242 Context
->wParam
, Context
->lParam
,
243 SMTO_NORMAL
, Context
->Timeout
, &Result
))
247 if (Context
->wParam
& MCS_QUERYENDSESSION
)
249 /* WM_QUERYENDSESSION case */
252 case MCSR_DONOTSHUTDOWN
:
253 Ret
= QUERY_RESULT_ABORT
;
256 case MCSR_GOODFORSHUTDOWN
:
257 case MCSR_SHUTDOWNFINISHED
:
259 Ret
= QUERY_RESULT_CONTINUE
;
264 /* WM_ENDSESSION case */
265 Ret
= QUERY_RESULT_CONTINUE
;
268 DPRINT("SendClientShutdown -- Return == %s\n",
269 Ret
== QUERY_RESULT_CONTINUE
? "Continue" : "Abort");
273 DPRINT1("SendClientShutdown -- Error == %s\n",
274 GetLastError() == 0 ? "Timeout" : "error");
276 return (GetLastError() == 0 ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
);
280 NotifyTopLevelWindow(HWND Wnd
, PNOTIFY_CONTEXT NotifyContext
)
282 MESSAGE_CONTEXT MessageContext
;
284 DWORD Timeout
, WaitStatus
;
285 HANDLE MessageThread
;
288 SetForegroundWindow(Wnd
);
290 Now
= GetTickCount();
291 if (NotifyContext
->StartTime
== 0)
292 NotifyContext
->StartTime
= Now
;
295 * Note: Passed is computed correctly even when GetTickCount()
296 * wraps due to unsigned arithmetic.
298 Passed
= Now
- NotifyContext
->StartTime
;
299 MessageContext
.Wnd
= Wnd
;
300 MessageContext
.Msg
= NotifyContext
->Msg
;
301 MessageContext
.wParam
= NotifyContext
->wParam
;
302 MessageContext
.lParam
= NotifyContext
->lParam
;
303 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
304 if (!NotifyContext
->ShutdownSettings
->AutoEndTasks
)
306 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
308 if (Passed
< MessageContext
.Timeout
)
310 MessageContext
.Timeout
-= Passed
;
311 MessageThread
= CreateThread(NULL
, 0, SendClientShutdown
,
312 (LPVOID
)&MessageContext
, 0, NULL
);
313 if (MessageThread
== NULL
)
315 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
318 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
319 if (Passed
< Timeout
)
322 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
326 WaitStatus
= WAIT_TIMEOUT
;
328 if (WAIT_TIMEOUT
== WaitStatus
)
330 NotifyContext
->WndClient
= Wnd
;
331 if (NotifyContext
->UIThread
== NULL
&& NotifyContext
->ShowUI
)
333 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
335 (LPVOID
)NotifyContext
,
338 Threads
[0] = MessageThread
;
339 Threads
[1] = NotifyContext
->UIThread
;
340 WaitStatus
= WaitForMultipleObjectsEx(NotifyContext
->UIThread
== NULL
?
342 Threads
, FALSE
, INFINITE
,
344 if (WaitStatus
== WAIT_OBJECT_0
)
346 if (!GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
348 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
351 else if (WaitStatus
== WAIT_OBJECT_0
+ 1)
353 if (!GetExitCodeThread(NotifyContext
->UIThread
,
354 &NotifyContext
->QueryResult
))
356 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
361 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
363 if (WaitStatus
!= WAIT_OBJECT_0
)
365 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
368 else if (WaitStatus
== WAIT_OBJECT_0
)
370 if (!GetExitCodeThread(MessageThread
,
371 &NotifyContext
->QueryResult
))
373 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
378 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
380 CloseHandle(MessageThread
);
384 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
387 DPRINT("NotifyContext->QueryResult == %d\n", NotifyContext
->QueryResult
);
388 return (NotifyContext
->QueryResult
== QUERY_RESULT_CONTINUE
);
394 return (BOOLEAN
)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE
);
397 /************************************************/
401 ThreadShutdownNotify(IN PCSR_THREAD CsrThread
,
404 IN PNOTIFY_CONTEXT Context
)
408 EnumThreadWindows(HandleToUlong(CsrThread
->ClientId
.UniqueThread
),
409 FindTopLevelWnd
, (LPARAM
)&TopWnd
);
414 /*** FOR TESTING PURPOSES ONLY!! ***/
417 /***********************************/
419 while ((hWndOwner
= GetWindow(TopWnd
, GW_OWNER
)) != NULL
)
421 MY_DPRINT("GetWindow(TopWnd, GW_OWNER) not returned NULL...\n");
424 if (TopWnd
!= tmpWnd
) MY_DPRINT("(TopWnd = %x) != (tmpWnd = %x)\n", TopWnd
, tmpWnd
);
431 Context
->wParam
= Flags2
;
432 Context
->lParam
= (0 != (Flags
& EWX_CALLER_WINLOGON_LOGOFF
) ?
433 ENDSESSION_LOGOFF
: 0);
435 Context
->StartTime
= 0;
436 Context
->UIThread
= NULL
;
437 Context
->ShowUI
= !IsConsoleMode() && (Flags2
& (MCS_QUERYENDSESSION
| MCS_ENDSESSION
));
440 #if 0 // Obviously, switching desktops like that from within WINSRV doesn't work...
443 Context
->OldDesktop
= GetThreadDesktop(GetCurrentThreadId());
444 // Context->Desktop = GetThreadDesktop(HandleToUlong(CsrThread->ClientId.UniqueThread));
445 Context
->Desktop
= GetThreadDesktop(GetWindowThreadProcessId(TopWnd
, NULL
));
446 MY_DPRINT("Last error = %d\n", GetLastError());
447 MY_DPRINT("Before switching to desktop 0x%x\n", Context
->Desktop
);
448 Success
= SwitchDesktop(Context
->Desktop
);
449 MY_DPRINT("After switching to desktop (Success = %s ; last error = %d); going to notify top-level...\n",
450 Success
? "TRUE" : "FALSE", GetLastError());
454 NotifyTopLevelWindow(TopWnd
, Context
);
456 /******************************************************************************/
458 if (Context
->UIThread
)
460 MY_DPRINT("Context->UIThread != NULL\n");
463 MY_DPRINT("Sending WM_CLOSE because Dlg is != NULL\n");
464 SendMessageW(Context
->Dlg
, WM_CLOSE
, 0, 0);
468 MY_DPRINT("Terminating UIThread thread with QUERY_RESULT_ERROR\n");
469 TerminateThread(Context
->UIThread
, QUERY_RESULT_ERROR
);
471 CloseHandle(Context
->UIThread
);
472 /**/Context
->UIThread
= NULL
;/**/
473 /**/Context
->Dlg
= NULL
;/**/
476 /******************************************************************************/
479 MY_DPRINT("Switch back to old desktop 0x%x\n", Context
->OldDesktop
);
480 SwitchDesktop(Context
->OldDesktop
);
481 MY_DPRINT("Switched back ok\n");
488 NotifyUserProcessForShutdown(PCSR_PROCESS CsrProcess
,
489 PSHUTDOWN_SETTINGS ShutdownSettings
,
492 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
493 PCSR_PROCESS Process
;
495 PLIST_ENTRY NextEntry
;
496 NOTIFY_CONTEXT Context
;
497 BOOL FoundWindows
= FALSE
;
499 /* In case we make a forced shutdown, just kill the process */
500 if (Flags
& EWX_FORCE
)
501 return CsrShutdownCsrProcess
;
503 Context
.ShutdownSettings
= ShutdownSettings
;
504 Context
.QueryResult
= QUERY_RESULT_CONTINUE
; // We continue shutdown by default.
506 /* Lock the process */
507 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
509 /* Send first the QUERYENDSESSION messages to all the threads of the process */
510 MY_DPRINT2("Sending the QUERYENDSESSION messages...\n");
512 NextEntry
= CsrProcess
->ThreadList
.Flink
;
513 while (NextEntry
!= &CsrProcess
->ThreadList
)
515 /* Get the current thread entry */
516 Thread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
518 /* Move to the next entry */
519 NextEntry
= NextEntry
->Flink
;
521 /* If the thread is being terminated, just skip it */
522 if (Thread
->Flags
& CsrThreadTerminated
) continue;
524 /* Reference the thread and temporarily unlock the process */
525 CsrReferenceThread(Thread
);
526 CsrUnlockProcess(Process
);
528 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
529 if (ThreadShutdownNotify(Thread
, Flags
, MCS_QUERYENDSESSION
, &Context
))
534 /* Lock the process again and dereference the thread */
535 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
536 CsrDereferenceThread(Thread
);
538 // FIXME: Analyze Context.QueryResult !!
539 /**/if (Context
.QueryResult
== QUERY_RESULT_ABORT
) goto Quit
;/**/
544 /* We looped all threads but no top level window was found so we didn't send any message */
545 /* Let the console server run the generic process shutdown handler */
546 CsrUnlockProcess(Process
);
547 return CsrShutdownNonCsrProcess
;
550 QueryResult
= Context
.QueryResult
;
551 MY_DPRINT2("QueryResult = %s\n",
552 QueryResult
== QUERY_RESULT_ABORT
? "Abort" : "Continue");
554 /* Now send the ENDSESSION messages to the threads */
555 MY_DPRINT2("Now sending the ENDSESSION messages...\n");
557 NextEntry
= CsrProcess
->ThreadList
.Flink
;
558 while (NextEntry
!= &CsrProcess
->ThreadList
)
560 /* Get the current thread entry */
561 Thread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
563 /* Move to the next entry */
564 NextEntry
= NextEntry
->Flink
;
566 /* If the thread is being terminated, just skip it */
567 if (Thread
->Flags
& CsrThreadTerminated
) continue;
569 /* Reference the thread and temporarily unlock the process */
570 CsrReferenceThread(Thread
);
571 CsrUnlockProcess(Process
);
573 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
574 ThreadShutdownNotify(Thread
, Flags
,
575 (QUERY_RESULT_ABORT
!= QueryResult
) ? MCS_ENDSESSION
: 0,
578 /* Lock the process again and dereference the thread */
579 CsrLockProcessByClientId(CsrProcess
->ClientId
.UniqueProcess
, &Process
);
580 CsrDereferenceThread(Thread
);
584 /* Unlock the process */
585 CsrUnlockProcess(Process
);
588 if (Context
.UIThread
)
592 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
596 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
598 CloseHandle(Context
.UIThread
);
602 /* Kill the process unless we abort shutdown */
603 if (QueryResult
== QUERY_RESULT_ABORT
)
604 return CsrShutdownCancelled
;
606 return CsrShutdownCsrProcess
;
609 static NTSTATUS FASTCALL
610 UserExitReactOS(PCSR_THREAD CsrThread
, UINT Flags
)
615 DWORD ProcessId
= HandleToUlong(CsrThread
->ClientId
.UniqueProcess
);
616 DWORD ThreadId
= HandleToUlong(CsrThread
->ClientId
.UniqueThread
);
618 DPRINT1("SrvExitWindowsEx(ClientId: %lx.%lx, Flags: 0x%x)\n",
619 ProcessId
, ThreadId
, Flags
);
622 * Check for flags validity
625 if (Flags
& EWX_CALLER_WINLOGON
)
627 /* Only Winlogon can call this */
628 if (ProcessId
!= LogonProcessId
)
630 DPRINT1("SrvExitWindowsEx call not from Winlogon\n");
631 return STATUS_ACCESS_DENIED
;
635 /* Implicitely add the shutdown flag when we poweroff or reboot */
636 if (Flags
& (EWX_POWEROFF
| EWX_REBOOT
))
637 Flags
|= EWX_SHUTDOWN
;
640 * Impersonate and retrieve the caller's LUID so that
641 * we can only shutdown processes in its context.
643 if (!CsrImpersonateClient(NULL
))
644 return STATUS_BAD_IMPERSONATION_LEVEL
;
646 Status
= CsrGetProcessLuid(NULL
, &CallerLuid
);
647 if (!NT_SUCCESS(Status
))
649 DPRINT1("Unable to get caller LUID, Status = 0x%08x\n", Status
);
653 DPRINT("Caller LUID is: %lx.%lx\n", CallerLuid
.HighPart
, CallerLuid
.LowPart
);
658 /* Notify Win32k and potentially Winlogon of the shutdown */
659 Status
= NtUserSetInformationThread(CsrThread
->ThreadHandle
,
660 UserThreadInitiateShutdown
,
661 &Flags
, sizeof(Flags
));
662 DPRINT("Win32k says: %lx\n", Status
);
665 /* We cannot wait here, the caller should start a new thread */
666 case STATUS_CANT_WAIT
:
667 DPRINT1("NtUserSetInformationThread returned STATUS_CANT_WAIT\n");
670 /* Shutdown is in progress */
672 DPRINT1("NtUserSetInformationThread returned STATUS_PENDING\n");
678 DPRINT1("NtUserSetInformationThread returned STATUS_RETRY\n");
685 if (!NT_SUCCESS(Status
))
687 // FIXME: Use some UserSetLastNTError or SetLastNtError
688 // that we have defined for user32 or win32k usage only...
689 SetLastError(RtlNtStatusToDosError(Status
));
700 * OK we can continue. Now magic happens:
702 * Terminate all Win32 processes, stop if we find one kicking
703 * and screaming it doesn't want to die.
705 * This function calls the ShutdownProcessCallback callback of
706 * each CSR server for each Win32 process.
708 Status
= CsrShutdownProcesses(&CallerLuid
, Flags
);
709 if (!NT_SUCCESS(Status
))
711 DPRINT1("Failed to shutdown processes, Status = 0x%08x\n", Status
);
714 // FIXME: If Status == STATUS_CANCELLED, call RecordShutdownReason
716 /* Tell Win32k and potentially Winlogon that we're done */
717 NtUserSetInformationThread(CsrThread
->ThreadHandle
,
718 UserThreadEndShutdown
,
719 &Status
, sizeof(Status
));
721 DPRINT("SrvExitWindowsEx returned 0x%08x\n", Status
);
732 UserClientShutdown(IN PCSR_PROCESS CsrProcess
,
734 IN BOOLEAN FirstPhase
)
738 DPRINT("UserClientShutdown(0x%p, 0x%x, %s) - [0x%x, 0x%x], ShutdownFlags: %lu\n",
739 CsrProcess
, Flags
, FirstPhase
? "FirstPhase" : "LastPhase",
740 CsrProcess
->ClientId
.UniqueProcess
, CsrProcess
->ClientId
.UniqueThread
,
741 CsrProcess
->ShutdownFlags
);
744 * Check for process validity
747 /* Do not kill system processes when a user is logging off */
748 if ((Flags
& EWX_SHUTDOWN
) == EWX_LOGOFF
&&
749 (CsrProcess
->ShutdownFlags
& (SHUTDOWN_OTHERCONTEXT
| SHUTDOWN_SYSTEMCONTEXT
)))
751 DPRINT("Do not kill a system process in a logoff request!\n");
752 return CsrShutdownNonCsrProcess
;
755 /* Do not kill Winlogon */
756 if (CsrProcess
->ClientId
.UniqueProcess
== UlongToHandle(LogonProcessId
))
758 DPRINT("Not killing Winlogon; CsrProcess->ShutdownFlags = %lu\n",
759 CsrProcess
->ShutdownFlags
);
761 /* Returning CsrShutdownCsrProcess means that we handled this process by doing nothing */
762 /* This will mark winlogon as processed so consrv won't be notified again for it */
763 CsrDereferenceProcess(CsrProcess
);
764 return CsrShutdownCsrProcess
;
767 /* Notify the process for shutdown if needed */
768 result
= NotifyUserProcessForShutdown(CsrProcess
, &ShutdownSettings
, Flags
);
769 if (result
== CsrShutdownCancelled
|| result
== CsrShutdownNonCsrProcess
)
771 if (result
== CsrShutdownCancelled
)
772 DPRINT1("Process 0x%x aborted shutdown\n", CsrProcess
->ClientId
.UniqueProcess
);
776 /* Terminate this process */
779 WCHAR buffer
[MAX_PATH
];
780 if (!GetProcessImageFileNameW(CsrProcess
->ProcessHandle
, buffer
, MAX_PATH
))
782 DPRINT1("Terminating process %x\n", CsrProcess
->ClientId
.UniqueProcess
);
786 DPRINT1("Terminating process %x (%S)\n", CsrProcess
->ClientId
.UniqueProcess
, buffer
);
790 NtTerminateProcess(CsrProcess
->ProcessHandle
, 0);
792 WaitForSingleObject(CsrProcess
->ProcessHandle
, ShutdownSettings
.ProcessTerminateTimeout
);
795 CsrDereferenceProcess(CsrProcess
);
796 return CsrShutdownCsrProcess
;
800 /* PUBLIC SERVER APIS *********************************************************/
802 /* API_NUMBER: UserpExitWindowsEx */
803 CSR_API(SrvExitWindowsEx
)
806 PUSER_EXIT_REACTOS ExitReactOSRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.ExitReactOSRequest
;
808 Status
= NtUserSetInformationThread(NtCurrentThread(),
809 UserThreadUseActiveDesktop
,
812 if (!NT_SUCCESS(Status
))
814 DPRINT1("Failed to set thread desktop!\n");
818 Status
= UserExitReactOS(CsrGetClientThread(), ExitReactOSRequest
->Flags
);
819 ExitReactOSRequest
->Success
= NT_SUCCESS(Status
);
820 ExitReactOSRequest
->LastError
= GetLastError();
822 NtUserSetInformationThread(NtCurrentThread(), UserThreadRestoreDesktop
, NULL
, 0);
827 /* API_NUMBER: UserpEndTask */
830 PUSER_END_TASK EndTaskRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.EndTaskRequest
;
833 // FIXME: This is HACK-plemented!!
834 DPRINT1("SrvEndTask is HACKPLEMENTED!!\n");
836 Status
= NtUserSetInformationThread(NtCurrentThread(),
837 UserThreadUseActiveDesktop
,
840 if (!NT_SUCCESS(Status
))
842 DPRINT1("Failed to set thread desktop!\n");
846 SendMessageW(EndTaskRequest
->WndHandle
, WM_CLOSE
, 0, 0);
847 // PostMessageW(EndTaskRequest->WndHandle, WM_CLOSE, 0, 0);
849 if (IsWindow(EndTaskRequest
->WndHandle
))
851 if (EndTaskRequest
->Force
)
853 EndTaskRequest
->Success
= DestroyWindow(EndTaskRequest
->WndHandle
);
854 EndTaskRequest
->LastError
= GetLastError();
858 EndTaskRequest
->Success
= FALSE
;
863 EndTaskRequest
->Success
= TRUE
;
864 EndTaskRequest
->LastError
= ERROR_SUCCESS
;
867 NtUserSetInformationThread(NtCurrentThread(), UserThreadRestoreDesktop
, NULL
, 0);
869 return STATUS_SUCCESS
;
872 /* API_NUMBER: UserpRecordShutdownReason */
873 CSR_API(SrvRecordShutdownReason
)
875 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
876 return STATUS_NOT_IMPLEMENTED
;