2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSRSS subsystem
4 * FILE: subsys/csrss/win32csr/exitros.c
5 * PURPOSE: Logout/shutdown
8 /* INCLUDES ******************************************************************/
15 static HANDLE LogonProcess
= NULL
;
17 CSR_API(CsrRegisterLogonProcess
)
19 if (Request
->Data
.RegisterLogonProcessRequest
.Register
)
21 if (0 != LogonProcess
)
23 return STATUS_LOGON_SESSION_EXISTS
;
25 LogonProcess
= Request
->Data
.RegisterLogonProcessRequest
.ProcessId
;
29 if (Request
->Header
.ClientId
.UniqueProcess
!= LogonProcess
)
31 DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n",
32 LogonProcess
, Request
->Header
.ClientId
.UniqueProcess
);
33 return STATUS_NOT_LOGON_PROCESS
;
38 return STATUS_SUCCESS
;
41 CSR_API(CsrSetLogonNotifyWindow
)
43 return STATUS_SUCCESS
;
46 typedef struct tagSHUTDOWN_SETTINGS
50 DWORD WaitToKillAppTimeout
;
51 } SHUTDOWN_SETTINGS
, *PSHUTDOWN_SETTINGS
;
53 #define DEFAULT_AUTO_END_TASKS FALSE
54 #define DEFAULT_HUNG_APP_TIMEOUT 5000
55 #define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
57 typedef struct tagNOTIFY_CONTEXT
72 PSHUTDOWN_SETTINGS ShutdownSettings
;
73 LPTHREAD_START_ROUTINE SendMessageProc
;
74 } NOTIFY_CONTEXT
, *PNOTIFY_CONTEXT
;
76 #define QUERY_RESULT_ABORT 0
77 #define QUERY_RESULT_CONTINUE 1
78 #define QUERY_RESULT_TIMEOUT 2
79 #define QUERY_RESULT_ERROR 3
80 #define QUERY_RESULT_FORCE 4
83 UpdateProgressBar(HWND ProgressBar
, PNOTIFY_CONTEXT NotifyContext
)
87 Passed
= GetTickCount() - NotifyContext
->StartTime
;
88 Passed
-= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
89 if (NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
< Passed
)
91 Passed
= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
93 SendMessageW(ProgressBar
, PBM_SETPOS
, Passed
/ 2, 0);
96 static INT_PTR CALLBACK
97 EndNowDlgProc(HWND Dlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
100 PNOTIFY_CONTEXT NotifyContext
;
109 NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
110 NotifyContext
->EndNowResult
= QUERY_RESULT_ABORT
;
111 SetWindowLongPtrW(Dlg
, DWLP_USER
, (LONG_PTR
) lParam
);
112 TitleLength
= SendMessageW(NotifyContext
->WndClient
, WM_GETTEXTLENGTH
,
114 GetWindowTextLengthW(Dlg
);
115 Title
= HeapAlloc(Win32CsrApiHeap
, 0, (TitleLength
+ 1) * sizeof(WCHAR
));
118 Len
= GetWindowTextW(Dlg
, Title
, TitleLength
+ 1);
119 SendMessageW(NotifyContext
->WndClient
, WM_GETTEXT
,
120 TitleLength
+ 1 - Len
, (LPARAM
) (Title
+ Len
));
121 SetWindowTextW(Dlg
, Title
);
122 HeapFree(Win32CsrApiHeap
, 0, Title
);
124 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
125 SendMessageW(ProgressBar
, PBM_SETRANGE32
, 0,
126 NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
/ 2);
127 UpdateProgressBar(ProgressBar
, NotifyContext
);
128 SetTimer(Dlg
, 0, 200, NULL
);
133 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
134 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
135 UpdateProgressBar(ProgressBar
, NotifyContext
);
140 if (BN_CLICKED
== HIWORD(wParam
) && IDC_END_NOW
== LOWORD(wParam
))
142 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
143 NotifyContext
->EndNowResult
= QUERY_RESULT_FORCE
;
144 SendMessageW(Dlg
, WM_CLOSE
, 0, 0);
159 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
160 NotifyContext
->Dlg
= NULL
;
162 PostQuitMessage(NotifyContext
->EndNowResult
);
174 typedef void (WINAPI
*INITCOMMONCONTROLS_PROC
)(void);
177 CallInitCommonControls()
179 static BOOL Initialized
= FALSE
;
181 INITCOMMONCONTROLS_PROC InitProc
;
188 Lib
= LoadLibraryW(L
"COMCTL32.DLL");
193 InitProc
= (INITCOMMONCONTROLS_PROC
) GetProcAddress(Lib
, "InitCommonControls");
194 if (NULL
== InitProc
)
205 EndNowThreadProc(LPVOID Parameter
)
207 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) Parameter
;
210 SetThreadDesktop(NotifyContext
->Desktop
);
211 SwitchDesktop(NotifyContext
->Desktop
);
212 CallInitCommonControls();
213 NotifyContext
->Dlg
= CreateDialogParam(GetModuleHandleW(L
"win32csr"),
214 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
215 EndNowDlgProc
, (LPARAM
) NotifyContext
);
216 if (NULL
== NotifyContext
->Dlg
)
220 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
222 while (GetMessageW(&Msg
, NULL
, 0, 0))
224 if (! IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
226 TranslateMessage(&Msg
);
227 DispatchMessageW(&Msg
);
234 typedef struct tagMESSAGE_CONTEXT
241 } MESSAGE_CONTEXT
, *PMESSAGE_CONTEXT
;
244 SendQueryEndSession(LPVOID Parameter
)
246 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
249 if (SendMessageTimeoutW(Context
->Wnd
, WM_QUERYENDSESSION
, Context
->wParam
,
250 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
253 return Result
? QUERY_RESULT_CONTINUE
: QUERY_RESULT_ABORT
;
256 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
260 SendEndSession(LPVOID Parameter
)
262 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
267 if (SendMessageTimeoutW(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
268 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
271 return QUERY_RESULT_CONTINUE
;
273 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
277 SendMessage(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
279 return QUERY_RESULT_CONTINUE
;
284 NotifyTopLevelEnum(HWND Wnd
, LPARAM lParam
)
286 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
287 MESSAGE_CONTEXT MessageContext
;
289 DWORD Timeout
, WaitStatus
;
291 HANDLE MessageThread
;
294 if (0 == GetWindowThreadProcessId(Wnd
, &ProcessId
))
296 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
300 if (ProcessId
== NotifyContext
->ProcessId
)
302 Now
= GetTickCount();
303 if (0 == NotifyContext
->StartTime
)
305 NotifyContext
->StartTime
= Now
;
307 /* Note: Passed is computed correctly even when GetTickCount() wraps due
308 to unsigned arithmetic */
309 Passed
= Now
- NotifyContext
->StartTime
;
310 MessageContext
.Wnd
= Wnd
;
311 MessageContext
.Msg
= NotifyContext
->Msg
;
312 MessageContext
.wParam
= NotifyContext
->wParam
;
313 MessageContext
.lParam
= NotifyContext
->lParam
;
314 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
315 if (! NotifyContext
->ShutdownSettings
->AutoEndTasks
)
317 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
319 if (Passed
< MessageContext
.Timeout
)
321 MessageContext
.Timeout
-= Passed
;
322 MessageThread
= CreateThread(NULL
, 0, NotifyContext
->SendMessageProc
,
323 (LPVOID
) &MessageContext
, 0, NULL
);
324 if (NULL
== MessageThread
)
326 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
329 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
330 if (Passed
< Timeout
)
333 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
337 WaitStatus
= WAIT_TIMEOUT
;
339 if (WAIT_TIMEOUT
== WaitStatus
)
341 NotifyContext
->WndClient
= Wnd
;
342 if (NULL
== NotifyContext
->UIThread
&& NotifyContext
->ShowUI
)
344 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
346 (LPVOID
) NotifyContext
,
349 Threads
[0] = MessageThread
;
350 Threads
[1] = NotifyContext
->UIThread
;
351 WaitStatus
= WaitForMultipleObjectsEx(NULL
== NotifyContext
->UIThread
?
353 Threads
, FALSE
, INFINITE
,
355 if (WAIT_OBJECT_0
== WaitStatus
)
357 if (! GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
359 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
362 else if (WAIT_OBJECT_0
+ 1 == WaitStatus
)
364 if (! GetExitCodeThread(NotifyContext
->UIThread
,
365 &NotifyContext
->QueryResult
))
367 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
372 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
374 if (WAIT_OBJECT_0
!= WaitStatus
)
376 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
379 else if (WAIT_OBJECT_0
== WaitStatus
)
381 if (! GetExitCodeThread(MessageThread
,
382 &NotifyContext
->QueryResult
))
384 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
389 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
391 CloseHandle(MessageThread
);
395 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
399 return QUERY_RESULT_CONTINUE
== NotifyContext
->QueryResult
;
403 NotifyDesktopEnum(LPWSTR DesktopName
, LPARAM lParam
)
405 PNOTIFY_CONTEXT Context
= (PNOTIFY_CONTEXT
) lParam
;
407 Context
->Desktop
= OpenDesktopW(DesktopName
, 0, FALSE
,
408 DESKTOP_ENUMERATE
| DESKTOP_SWITCHDESKTOP
);
409 if (NULL
== Context
->Desktop
)
411 DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
412 Context
->QueryResult
= QUERY_RESULT_ERROR
;
416 Context
->OldDesktop
= GetThreadDesktop(GetCurrentThreadId());
417 SwitchDesktop(Context
->Desktop
);
419 EnumDesktopWindows(Context
->Desktop
, NotifyTopLevelEnum
, lParam
);
421 SwitchDesktop(Context
->OldDesktop
);
423 CloseDesktop(Context
->Desktop
);
425 return QUERY_RESULT_CONTINUE
== Context
->QueryResult
;
429 NotifyTopLevelWindows(PNOTIFY_CONTEXT Context
)
431 HWINSTA WindowStation
;
433 WindowStation
= GetProcessWindowStation();
434 if (NULL
== WindowStation
)
436 DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
440 EnumDesktopsW(WindowStation
, NotifyDesktopEnum
, (LPARAM
) Context
);
446 NotifyAndTerminateProcess(PCSR_PROCESS ProcessData
,
447 PSHUTDOWN_SETTINGS ShutdownSettings
,
450 NOTIFY_CONTEXT Context
;
452 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
454 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
456 if (0 == (Flags
& EWX_FORCE
))
458 if (NULL
!= ProcessData
->Console
)
460 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, ProcessData
,
461 ShutdownSettings
->WaitToKillAppTimeout
);
465 Context
.ProcessId
= (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
;
467 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
468 ENDSESSION_LOGOFF
: 0);
469 Context
.StartTime
= 0;
470 Context
.UIThread
= NULL
;
471 Context
.ShowUI
= DtbgIsDesktopVisible();
473 Context
.ShutdownSettings
= ShutdownSettings
;
474 Context
.SendMessageProc
= SendQueryEndSession
;
476 NotifyTopLevelWindows(&Context
);
478 Context
.wParam
= (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
479 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
480 ENDSESSION_LOGOFF
: 0);
481 Context
.SendMessageProc
= SendEndSession
;
482 Context
.ShowUI
= DtbgIsDesktopVisible() &&
483 (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
484 QueryResult
= Context
.QueryResult
;
485 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
487 NotifyTopLevelWindows(&Context
);
489 if (NULL
!= Context
.UIThread
)
491 if (NULL
!= Context
.Dlg
)
493 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
497 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
499 CloseHandle(Context
.UIThread
);
503 if (QUERY_RESULT_ABORT
== QueryResult
)
509 /* Terminate this process */
510 Process
= OpenProcess(PROCESS_TERMINATE
, FALSE
,
511 (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
);
514 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ClientId
.UniqueProcess
,
518 TerminateProcess(Process
, 0);
519 CloseHandle(Process
);
524 typedef struct tagPROCESS_ENUM_CONTEXT
527 PCSR_PROCESS
*ProcessData
;
528 TOKEN_ORIGIN TokenOrigin
;
531 } PROCESS_ENUM_CONTEXT
, *PPROCESS_ENUM_CONTEXT
;
533 static NTSTATUS WINAPI
534 ExitReactosProcessEnum(PCSR_PROCESS ProcessData
, PVOID Data
)
540 PPROCESS_ENUM_CONTEXT Context
= (PPROCESS_ENUM_CONTEXT
) Data
;
541 PCSR_PROCESS
*NewData
;
543 /* Do not kill winlogon or csrss */
544 if ((DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
== Context
->CsrssProcess
||
545 ProcessData
->ClientId
.UniqueProcess
== LogonProcess
)
547 return STATUS_SUCCESS
;
550 /* Get the login session of this process */
551 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
,
552 (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
);
555 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ClientId
.UniqueProcess
,
557 return STATUS_UNSUCCESSFUL
;
560 if (! OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
562 DPRINT1("Unable to open token for process %d, error %d\n",
563 ProcessData
->ClientId
.UniqueProcess
, GetLastError());
564 CloseHandle(Process
);
565 return STATUS_UNSUCCESSFUL
;
567 CloseHandle(Process
);
569 if (! GetTokenInformation(Token
, TokenOrigin
, &Origin
,
570 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
572 DPRINT1("GetTokenInformation failed for process %d with error %d\n",
573 ProcessData
->ClientId
.UniqueProcess
, GetLastError());
575 return STATUS_UNSUCCESSFUL
;
579 /* This process will be killed if it's in the correct logon session */
580 if (RtlEqualLuid(&(Context
->TokenOrigin
.OriginatingLogonSession
),
581 &(Origin
.OriginatingLogonSession
)))
583 /* Kill the shell process last */
584 if ((DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
== Context
->ShellProcess
)
586 ProcessData
->ShutdownLevel
= 0;
588 NewData
= HeapAlloc(Win32CsrApiHeap
, 0, (Context
->ProcessCount
+ 1)
589 * sizeof(PCSR_PROCESS
));
592 return STATUS_NO_MEMORY
;
594 if (0 != Context
->ProcessCount
)
596 memcpy(NewData
, Context
->ProcessData
,
597 Context
->ProcessCount
* sizeof(PCSR_PROCESS
));
598 HeapFree(Win32CsrApiHeap
, 0, Context
->ProcessData
);
600 Context
->ProcessData
= NewData
;
601 Context
->ProcessData
[Context
->ProcessCount
] = ProcessData
;
602 Context
->ProcessCount
++;
605 return STATUS_SUCCESS
;
609 ProcessDataCompare(const void *Elem1
, const void *Elem2
)
611 const PCSR_PROCESS
*ProcessData1
= (PCSR_PROCESS
*) Elem1
;
612 const PCSR_PROCESS
*ProcessData2
= (PCSR_PROCESS
*) Elem2
;
614 if ((*ProcessData1
)->ShutdownLevel
< (*ProcessData2
)->ShutdownLevel
)
618 else if ((*ProcessData2
)->ShutdownLevel
< (*ProcessData1
)->ShutdownLevel
)
622 else if ((*ProcessData1
)->ClientId
.UniqueProcess
< (*ProcessData2
)->ClientId
.UniqueProcess
)
626 else if ((*ProcessData2
)->ClientId
.UniqueProcess
< (*ProcessData1
)->ClientId
.UniqueProcess
)
634 static DWORD FASTCALL
635 GetShutdownSetting(HKEY DesktopKey
, LPCWSTR ValueName
, DWORD DefaultValue
)
637 BYTE ValueBuffer
[16];
641 UNICODE_STRING StringValue
;
644 ValueSize
= sizeof(ValueBuffer
);
645 ErrCode
= RegQueryValueExW(DesktopKey
, ValueName
, NULL
, &Type
, ValueBuffer
,
647 if (ERROR_SUCCESS
!= ErrCode
)
649 DPRINT("GetShutdownSetting for %S failed with error code %ld\n",
656 RtlInitUnicodeString(&StringValue
, (LPCWSTR
) ValueBuffer
);
657 if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue
, 10, &Value
)))
659 DPRINT1("Unable to convert value %S for setting %S\n",
660 StringValue
.Buffer
, ValueName
);
663 return (DWORD
) Value
;
665 else if (REG_DWORD
== Type
)
667 return *((DWORD
*) ValueBuffer
);
670 DPRINT1("Unexpected registry type %d for setting %S\n", Type
, ValueName
);
675 LoadShutdownSettings(PSID Sid
, PSHUTDOWN_SETTINGS ShutdownSettings
)
677 static WCHAR Subkey
[] = L
"\\Control Panel\\Desktop";
679 WCHAR InitialKeyName
[128];
684 ShutdownSettings
->AutoEndTasks
= DEFAULT_AUTO_END_TASKS
;
685 ShutdownSettings
->HungAppTimeout
= DEFAULT_HUNG_APP_TIMEOUT
;
686 ShutdownSettings
->WaitToKillAppTimeout
= DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
;
688 if (! ConvertSidToStringSidW(Sid
, &StringSid
))
690 DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
694 if (wcslen(StringSid
) + wcslen(Subkey
) + 1 <=
695 sizeof(InitialKeyName
) / sizeof(WCHAR
))
697 KeyName
= InitialKeyName
;
701 KeyName
= HeapAlloc(Win32CsrApiHeap
, 0,
702 (wcslen(StringSid
) + wcslen(Subkey
) + 1) *
706 DPRINT1("Failed to allocate memory, using default shutdown settings\n");
707 LocalFree(StringSid
);
711 wcscat(wcscpy(KeyName
, StringSid
), Subkey
);
712 LocalFree(StringSid
);
714 ErrCode
= RegOpenKeyExW(HKEY_USERS
, KeyName
, 0, KEY_QUERY_VALUE
, &DesktopKey
);
715 if (KeyName
!= InitialKeyName
)
717 HeapFree(Win32CsrApiHeap
, 0, KeyName
);
719 if (ERROR_SUCCESS
!= ErrCode
)
721 DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode
);
725 ShutdownSettings
->AutoEndTasks
= (BOOL
) GetShutdownSetting(DesktopKey
, L
"AutoEndTasks",
726 (DWORD
) DEFAULT_AUTO_END_TASKS
);
727 ShutdownSettings
->HungAppTimeout
= GetShutdownSetting(DesktopKey
,
729 DEFAULT_HUNG_APP_TIMEOUT
);
730 ShutdownSettings
->WaitToKillAppTimeout
= GetShutdownSetting(DesktopKey
,
731 L
"WaitToKillAppTimeout",
732 DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
);
734 RegCloseKey(DesktopKey
);
737 static NTSTATUS FASTCALL
738 InternalExitReactos(DWORD ProcessId
, DWORD ThreadId
, UINT Flags
)
743 PROCESS_ENUM_CONTEXT Context
;
747 char FixedUserInfo
[64];
748 TOKEN_USER
*UserInfo
;
749 SHUTDOWN_SETTINGS ShutdownSettings
;
751 if (ProcessId
!= (DWORD_PTR
) LogonProcess
)
753 DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
754 return STATUS_ACCESS_DENIED
;
757 DPRINT1("FIXME: Need to close all user processes!\n");
758 return STATUS_SUCCESS
;
760 CallerThread
= OpenThread(THREAD_QUERY_INFORMATION
, FALSE
, ThreadId
);
761 if (NULL
== CallerThread
)
763 DPRINT1("OpenThread failed with error %d\n", GetLastError());
764 return STATUS_UNSUCCESSFUL
;
766 if (! OpenThreadToken(CallerThread
, TOKEN_QUERY
, FALSE
, &CallerToken
))
768 DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
769 CloseHandle(CallerThread
);
770 return STATUS_UNSUCCESSFUL
;
772 CloseHandle(CallerThread
);
774 Context
.ProcessCount
= 0;
775 Context
.ProcessData
= NULL
;
776 if (! GetTokenInformation(CallerToken
, TokenOrigin
, &Context
.TokenOrigin
,
777 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
779 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
780 CloseHandle(CallerToken
);
781 return STATUS_UNSUCCESSFUL
;
783 if (! GetTokenInformation(CallerToken
, TokenUser
, FixedUserInfo
,
784 sizeof(FixedUserInfo
), &ReturnLength
))
786 if (sizeof(FixedUserInfo
) < ReturnLength
)
788 UserInfo
= HeapAlloc(Win32CsrApiHeap
, 0, ReturnLength
);
789 if (NULL
== UserInfo
)
791 DPRINT1("Unable to allocate %u bytes for user info\n",
792 (unsigned) ReturnLength
);
793 CloseHandle(CallerToken
);
794 return STATUS_NO_MEMORY
;
796 if (! GetTokenInformation(CallerToken
, TokenUser
, UserInfo
,
797 ReturnLength
, &ReturnLength
))
799 DPRINT1("GetTokenInformation failed with error %d\n",
801 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
802 CloseHandle(CallerToken
);
803 return STATUS_UNSUCCESSFUL
;
808 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
809 CloseHandle(CallerToken
);
810 return STATUS_UNSUCCESSFUL
;
815 UserInfo
= (TOKEN_USER
*) FixedUserInfo
;
817 CloseHandle(CallerToken
);
818 LoadShutdownSettings(UserInfo
->User
.Sid
, &ShutdownSettings
);
819 if (UserInfo
!= (TOKEN_USER
*) FixedUserInfo
)
821 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
823 Context
.CsrssProcess
= GetCurrentProcessId();
824 ShellWnd
= GetShellWindow();
825 if (NULL
== ShellWnd
)
827 DPRINT("No shell present\n");
828 Context
.ShellProcess
= 0;
830 else if (0 == GetWindowThreadProcessId(ShellWnd
, &Context
.ShellProcess
))
832 DPRINT1("Can't get process id of shell window\n");
833 Context
.ShellProcess
= 0;
836 Status
= Win32CsrEnumProcesses(ExitReactosProcessEnum
, &Context
);
837 if (! NT_SUCCESS(Status
))
839 DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
841 if (NULL
!= Context
.ProcessData
)
843 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
848 qsort(Context
.ProcessData
, Context
.ProcessCount
, sizeof(PCSR_PROCESS
),
851 /* Terminate processes, stop if we find one kicking and screaming it doesn't
853 Status
= STATUS_SUCCESS
;
854 for (ProcessIndex
= 0;
855 ProcessIndex
< Context
.ProcessCount
&& NT_SUCCESS(Status
);
858 if (! NotifyAndTerminateProcess(Context
.ProcessData
[ProcessIndex
],
859 &ShutdownSettings
, Flags
))
861 Status
= STATUS_REQUEST_ABORTED
;
866 if (NULL
!= Context
.ProcessData
)
868 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
874 static NTSTATUS FASTCALL
875 UserExitReactos(DWORD UserProcessId
, UINT Flags
)
879 /* FIXME Inside 2000 says we should impersonate the caller here */
880 Status
= NtUserCallTwoParam (UserProcessId
, Flags
, TWOPARAM_ROUTINE_EXITREACTOS
);
882 /* If the message isn't handled, the return value is 0, so 0 doesn't indicate
883 success. Success is indicated by a 1 return value, if anything besides 0
884 or 1 it's a NTSTATUS value */
887 Status
= STATUS_SUCCESS
;
889 else if (0 == Status
)
891 Status
= STATUS_NOT_IMPLEMENTED
;
897 CSR_API(CsrExitReactos
)
899 if (0 == (Request
->Data
.ExitReactosRequest
.Flags
& EWX_INTERNAL_FLAG
))
901 return UserExitReactos((DWORD_PTR
) Request
->Header
.ClientId
.UniqueProcess
,
902 Request
->Data
.ExitReactosRequest
.Flags
);
906 return InternalExitReactos((DWORD_PTR
) Request
->Header
.ClientId
.UniqueProcess
,
907 (DWORD_PTR
) Request
->Header
.ClientId
.UniqueThread
,
908 Request
->Data
.ExitReactosRequest
.Flags
);