3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS CSRSS subsystem
5 * FILE: subsys/csrss/win32csr/exitros.c
6 * PURPOSE: Logout/shutdown
9 /* INCLUDES ******************************************************************/
16 static HWND LogonNotifyWindow
= NULL
;
17 static HANDLE LogonProcess
= NULL
;
19 CSR_API(CsrRegisterLogonProcess
)
21 if (Request
->Data
.RegisterLogonProcessRequest
.Register
)
23 if (0 != LogonProcess
)
25 return STATUS_LOGON_SESSION_EXISTS
;
27 LogonProcess
= Request
->Data
.RegisterLogonProcessRequest
.ProcessId
;
31 if (Request
->Header
.ClientId
.UniqueProcess
!= LogonProcess
)
33 DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n",
34 LogonProcess
, Request
->Header
.ClientId
.UniqueProcess
);
35 return STATUS_NOT_LOGON_PROCESS
;
40 return STATUS_SUCCESS
;
43 CSR_API(CsrSetLogonNotifyWindow
)
47 if (0 == GetWindowThreadProcessId(Request
->Data
.SetLogonNotifyWindowRequest
.LogonNotifyWindow
,
50 DPRINT1("Can't get window creator\n");
51 return STATUS_INVALID_HANDLE
;
53 if (WindowCreator
!= (DWORD_PTR
)LogonProcess
)
55 DPRINT1("Trying to register window not created by winlogon as notify window\n");
56 return STATUS_ACCESS_DENIED
;
59 LogonNotifyWindow
= Request
->Data
.SetLogonNotifyWindowRequest
.LogonNotifyWindow
;
61 return STATUS_SUCCESS
;
64 typedef struct tagSHUTDOWN_SETTINGS
68 DWORD WaitToKillAppTimeout
;
69 } SHUTDOWN_SETTINGS
, *PSHUTDOWN_SETTINGS
;
71 #define DEFAULT_AUTO_END_TASKS FALSE
72 #define DEFAULT_HUNG_APP_TIMEOUT 5000
73 #define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
75 typedef struct tagNOTIFY_CONTEXT
89 PSHUTDOWN_SETTINGS ShutdownSettings
;
90 LPTHREAD_START_ROUTINE SendMessageProc
;
91 } NOTIFY_CONTEXT
, *PNOTIFY_CONTEXT
;
93 #define QUERY_RESULT_ABORT 0
94 #define QUERY_RESULT_CONTINUE 1
95 #define QUERY_RESULT_TIMEOUT 2
96 #define QUERY_RESULT_ERROR 3
97 #define QUERY_RESULT_FORCE 4
100 UpdateProgressBar(HWND ProgressBar
, PNOTIFY_CONTEXT NotifyContext
)
104 Passed
= GetTickCount() - NotifyContext
->StartTime
;
105 Passed
-= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
106 if (NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
< Passed
)
108 Passed
= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
110 SendMessageW(ProgressBar
, PBM_SETPOS
, Passed
/ 2, 0);
113 static INT_PTR CALLBACK
114 EndNowDlgProc(HWND Dlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
117 PNOTIFY_CONTEXT NotifyContext
;
126 NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
127 NotifyContext
->EndNowResult
= QUERY_RESULT_ABORT
;
128 SetWindowLongPtrW(Dlg
, DWLP_USER
, (LONG_PTR
) lParam
);
129 TitleLength
= SendMessageW(NotifyContext
->WndClient
, WM_GETTEXTLENGTH
,
131 GetWindowTextLengthW(Dlg
);
132 Title
= HeapAlloc(Win32CsrApiHeap
, 0, (TitleLength
+ 1) * sizeof(WCHAR
));
135 Len
= GetWindowTextW(Dlg
, Title
, TitleLength
+ 1);
136 SendMessageW(NotifyContext
->WndClient
, WM_GETTEXT
,
137 TitleLength
+ 1 - Len
, (LPARAM
) (Title
+ Len
));
138 SetWindowTextW(Dlg
, Title
);
139 HeapFree(Win32CsrApiHeap
, 0, Title
);
141 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
142 SendMessageW(ProgressBar
, PBM_SETRANGE32
, 0,
143 NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
/ 2);
144 UpdateProgressBar(ProgressBar
, NotifyContext
);
145 SetTimer(Dlg
, 0, 200, NULL
);
150 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
151 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
152 UpdateProgressBar(ProgressBar
, NotifyContext
);
157 if (BN_CLICKED
== HIWORD(wParam
) && IDC_END_NOW
== LOWORD(wParam
))
159 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
160 NotifyContext
->EndNowResult
= QUERY_RESULT_FORCE
;
161 SendMessageW(Dlg
, WM_CLOSE
, 0, 0);
176 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
177 NotifyContext
->Dlg
= NULL
;
179 PostQuitMessage(NotifyContext
->EndNowResult
);
191 typedef void (WINAPI
*INITCOMMONCONTROLS_PROC
)(void);
194 CallInitCommonControls()
196 static BOOL Initialized
= FALSE
;
198 INITCOMMONCONTROLS_PROC InitProc
;
205 Lib
= LoadLibraryW(L
"COMCTL32.DLL");
210 InitProc
= (INITCOMMONCONTROLS_PROC
) GetProcAddress(Lib
, "InitCommonControls");
211 if (NULL
== InitProc
)
222 EndNowThreadProc(LPVOID Parameter
)
224 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) Parameter
;
227 SetThreadDesktop(NotifyContext
->Desktop
);
228 SwitchDesktop(NotifyContext
->Desktop
);
229 CallInitCommonControls();
230 NotifyContext
->Dlg
= CreateDialogParam(GetModuleHandleW(L
"win32csr"),
231 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
232 EndNowDlgProc
, (LPARAM
) NotifyContext
);
233 if (NULL
== NotifyContext
->Dlg
)
237 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
239 while (GetMessageW(&Msg
, NULL
, 0, 0))
241 if (! IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
243 TranslateMessage(&Msg
);
244 DispatchMessageW(&Msg
);
251 typedef struct tagMESSAGE_CONTEXT
258 } MESSAGE_CONTEXT
, *PMESSAGE_CONTEXT
;
261 SendQueryEndSession(LPVOID Parameter
)
263 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
266 if (SendMessageTimeoutW(Context
->Wnd
, WM_QUERYENDSESSION
, Context
->wParam
,
267 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
270 return Result
? QUERY_RESULT_CONTINUE
: QUERY_RESULT_ABORT
;
273 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
277 SendEndSession(LPVOID Parameter
)
279 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
284 if (SendMessageTimeoutW(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
285 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
288 return QUERY_RESULT_CONTINUE
;
290 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
294 SendMessage(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
296 return QUERY_RESULT_CONTINUE
;
301 NotifyTopLevelEnum(HWND Wnd
, LPARAM lParam
)
303 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
304 MESSAGE_CONTEXT MessageContext
;
306 DWORD Timeout
, WaitStatus
;
308 HANDLE MessageThread
;
311 if (0 == GetWindowThreadProcessId(Wnd
, &ProcessId
))
313 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
317 if (ProcessId
== NotifyContext
->ProcessId
)
319 Now
= GetTickCount();
320 if (0 == NotifyContext
->StartTime
)
322 NotifyContext
->StartTime
= Now
;
324 /* Note: Passed is computed correctly even when GetTickCount() wraps due
325 to unsigned arithmetic */
326 Passed
= Now
- NotifyContext
->StartTime
;
327 MessageContext
.Wnd
= Wnd
;
328 MessageContext
.Msg
= NotifyContext
->Msg
;
329 MessageContext
.wParam
= NotifyContext
->wParam
;
330 MessageContext
.lParam
= NotifyContext
->lParam
;
331 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
332 if (! NotifyContext
->ShutdownSettings
->AutoEndTasks
)
334 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
336 if (Passed
< MessageContext
.Timeout
)
338 MessageContext
.Timeout
-= Passed
;
339 MessageThread
= CreateThread(NULL
, 0, NotifyContext
->SendMessageProc
,
340 (LPVOID
) &MessageContext
, 0, NULL
);
341 if (NULL
== MessageThread
)
343 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
346 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
347 if (Passed
< Timeout
)
350 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
354 WaitStatus
= WAIT_TIMEOUT
;
356 if (WAIT_TIMEOUT
== WaitStatus
)
358 NotifyContext
->WndClient
= Wnd
;
359 if (NULL
== NotifyContext
->UIThread
&& NotifyContext
->ShowUI
)
361 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
363 (LPVOID
) NotifyContext
,
366 Threads
[0] = MessageThread
;
367 Threads
[1] = NotifyContext
->UIThread
;
368 WaitStatus
= WaitForMultipleObjectsEx(NULL
== NotifyContext
->UIThread
?
370 Threads
, FALSE
, INFINITE
,
372 if (WAIT_OBJECT_0
== WaitStatus
)
374 if (! GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
376 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
379 else if (WAIT_OBJECT_0
+ 1 == WaitStatus
)
381 if (! GetExitCodeThread(NotifyContext
->UIThread
,
382 &NotifyContext
->QueryResult
))
384 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
389 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
391 if (WAIT_OBJECT_0
!= WaitStatus
)
393 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
396 else if (WAIT_OBJECT_0
== WaitStatus
)
398 if (! GetExitCodeThread(MessageThread
,
399 &NotifyContext
->QueryResult
))
401 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
406 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
408 CloseHandle(MessageThread
);
412 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
416 return QUERY_RESULT_CONTINUE
== NotifyContext
->QueryResult
;
420 NotifyDesktopEnum(LPWSTR DesktopName
, LPARAM lParam
)
422 PNOTIFY_CONTEXT Context
= (PNOTIFY_CONTEXT
) lParam
;
424 Context
->Desktop
= OpenDesktopW(DesktopName
, 0, FALSE
,
425 DESKTOP_ENUMERATE
| DESKTOP_SWITCHDESKTOP
);
426 if (NULL
== Context
->Desktop
)
428 DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
429 Context
->QueryResult
= QUERY_RESULT_ERROR
;
433 EnumDesktopWindows(Context
->Desktop
, NotifyTopLevelEnum
, lParam
);
435 CloseDesktop(Context
->Desktop
);
437 return QUERY_RESULT_CONTINUE
== Context
->QueryResult
;
441 NotifyTopLevelWindows(PNOTIFY_CONTEXT Context
)
443 HWINSTA WindowStation
;
445 WindowStation
= GetProcessWindowStation();
446 if (NULL
== WindowStation
)
448 DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
452 EnumDesktopsW(WindowStation
, NotifyDesktopEnum
, (LPARAM
) Context
);
458 NotifyAndTerminateProcess(PCSR_PROCESS ProcessData
,
459 PSHUTDOWN_SETTINGS ShutdownSettings
,
462 NOTIFY_CONTEXT Context
;
464 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
466 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
468 if (0 == (Flags
& EWX_FORCE
))
470 if (NULL
!= ProcessData
->Console
)
472 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, ProcessData
,
473 ShutdownSettings
->WaitToKillAppTimeout
);
477 Context
.ProcessId
= (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
;
479 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
480 ENDSESSION_LOGOFF
: 0);
481 Context
.StartTime
= 0;
482 Context
.UIThread
= NULL
;
483 Context
.ShowUI
= DtbgIsDesktopVisible();
485 Context
.ShutdownSettings
= ShutdownSettings
;
486 Context
.SendMessageProc
= SendQueryEndSession
;
488 NotifyTopLevelWindows(&Context
);
490 Context
.wParam
= (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
491 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
492 ENDSESSION_LOGOFF
: 0);
493 Context
.SendMessageProc
= SendEndSession
;
494 Context
.ShowUI
= DtbgIsDesktopVisible() &&
495 (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
496 QueryResult
= Context
.QueryResult
;
497 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
499 NotifyTopLevelWindows(&Context
);
501 if (NULL
!= Context
.UIThread
)
503 if (NULL
!= Context
.Dlg
)
505 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
509 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
511 CloseHandle(Context
.UIThread
);
515 if (QUERY_RESULT_ABORT
== QueryResult
)
521 /* Terminate this process */
522 Process
= OpenProcess(PROCESS_TERMINATE
, FALSE
,
523 (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
);
526 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ClientId
.UniqueProcess
,
530 TerminateProcess(Process
, 0);
531 CloseHandle(Process
);
536 typedef struct tagPROCESS_ENUM_CONTEXT
539 PCSR_PROCESS
*ProcessData
;
540 TOKEN_ORIGIN TokenOrigin
;
543 } PROCESS_ENUM_CONTEXT
, *PPROCESS_ENUM_CONTEXT
;
545 static NTSTATUS WINAPI
546 ExitReactosProcessEnum(PCSR_PROCESS ProcessData
, PVOID Data
)
552 PPROCESS_ENUM_CONTEXT Context
= (PPROCESS_ENUM_CONTEXT
) Data
;
553 PCSR_PROCESS
*NewData
;
555 /* Do not kill winlogon or csrss */
556 if ((DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
== Context
->CsrssProcess
||
557 ProcessData
->ClientId
.UniqueProcess
== LogonProcess
)
559 return STATUS_SUCCESS
;
562 /* Get the login session of this process */
563 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
,
564 (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
);
567 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ClientId
.UniqueProcess
,
569 return STATUS_UNSUCCESSFUL
;
572 if (! OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
574 DPRINT1("Unable to open token for process %d, error %d\n",
575 ProcessData
->ClientId
.UniqueProcess
, GetLastError());
576 CloseHandle(Process
);
577 return STATUS_UNSUCCESSFUL
;
579 CloseHandle(Process
);
581 if (! GetTokenInformation(Token
, TokenOrigin
, &Origin
,
582 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
584 DPRINT1("GetTokenInformation failed for process %d with error %d\n",
585 ProcessData
->ClientId
.UniqueProcess
, GetLastError());
587 return STATUS_UNSUCCESSFUL
;
591 /* This process will be killed if it's in the correct logon session */
592 if (RtlEqualLuid(&(Context
->TokenOrigin
.OriginatingLogonSession
),
593 &(Origin
.OriginatingLogonSession
)))
595 /* Kill the shell process last */
596 if ((DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
== Context
->ShellProcess
)
598 ProcessData
->ShutdownLevel
= 0;
600 NewData
= HeapAlloc(Win32CsrApiHeap
, 0, (Context
->ProcessCount
+ 1)
601 * sizeof(PCSR_PROCESS
));
604 return STATUS_NO_MEMORY
;
606 if (0 != Context
->ProcessCount
)
608 memcpy(NewData
, Context
->ProcessData
,
609 Context
->ProcessCount
* sizeof(PCSR_PROCESS
));
610 HeapFree(Win32CsrApiHeap
, 0, Context
->ProcessData
);
612 Context
->ProcessData
= NewData
;
613 Context
->ProcessData
[Context
->ProcessCount
] = ProcessData
;
614 Context
->ProcessCount
++;
617 return STATUS_SUCCESS
;
621 ProcessDataCompare(const void *Elem1
, const void *Elem2
)
623 const PCSR_PROCESS
*ProcessData1
= (PCSR_PROCESS
*) Elem1
;
624 const PCSR_PROCESS
*ProcessData2
= (PCSR_PROCESS
*) Elem2
;
626 if ((*ProcessData1
)->ShutdownLevel
< (*ProcessData2
)->ShutdownLevel
)
630 else if ((*ProcessData2
)->ShutdownLevel
< (*ProcessData1
)->ShutdownLevel
)
634 else if ((*ProcessData1
)->ClientId
.UniqueProcess
< (*ProcessData2
)->ClientId
.UniqueProcess
)
638 else if ((*ProcessData2
)->ClientId
.UniqueProcess
< (*ProcessData1
)->ClientId
.UniqueProcess
)
646 static DWORD FASTCALL
647 GetShutdownSetting(HKEY DesktopKey
, LPCWSTR ValueName
, DWORD DefaultValue
)
649 BYTE ValueBuffer
[16];
653 UNICODE_STRING StringValue
;
656 ValueSize
= sizeof(ValueBuffer
);
657 ErrCode
= RegQueryValueExW(DesktopKey
, ValueName
, NULL
, &Type
, ValueBuffer
,
659 if (ERROR_SUCCESS
!= ErrCode
)
661 DPRINT("GetShutdownSetting for %S failed with error code %ld\n",
668 RtlInitUnicodeString(&StringValue
, (LPCWSTR
) ValueBuffer
);
669 if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue
, 10, &Value
)))
671 DPRINT1("Unable to convert value %S for setting %S\n",
672 StringValue
.Buffer
, ValueName
);
675 return (DWORD
) Value
;
677 else if (REG_DWORD
== Type
)
679 return *((DWORD
*) ValueBuffer
);
682 DPRINT1("Unexpected registry type %d for setting %S\n", Type
, ValueName
);
687 LoadShutdownSettings(PSID Sid
, PSHUTDOWN_SETTINGS ShutdownSettings
)
689 static WCHAR Subkey
[] = L
"\\Control Panel\\Desktop";
691 WCHAR InitialKeyName
[128];
696 ShutdownSettings
->AutoEndTasks
= DEFAULT_AUTO_END_TASKS
;
697 ShutdownSettings
->HungAppTimeout
= DEFAULT_HUNG_APP_TIMEOUT
;
698 ShutdownSettings
->WaitToKillAppTimeout
= DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
;
700 if (! ConvertSidToStringSidW(Sid
, &StringSid
))
702 DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
706 if (wcslen(StringSid
) + wcslen(Subkey
) + 1 <=
707 sizeof(InitialKeyName
) / sizeof(WCHAR
))
709 KeyName
= InitialKeyName
;
713 KeyName
= HeapAlloc(Win32CsrApiHeap
, 0,
714 (wcslen(StringSid
) + wcslen(Subkey
) + 1) *
718 DPRINT1("Failed to allocate memory, using default shutdown settings\n");
719 LocalFree(StringSid
);
723 wcscat(wcscpy(KeyName
, StringSid
), Subkey
);
724 LocalFree(StringSid
);
726 ErrCode
= RegOpenKeyExW(HKEY_USERS
, KeyName
, 0, KEY_QUERY_VALUE
, &DesktopKey
);
727 if (KeyName
!= InitialKeyName
)
729 HeapFree(Win32CsrApiHeap
, 0, KeyName
);
731 if (ERROR_SUCCESS
!= ErrCode
)
733 DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode
);
737 ShutdownSettings
->AutoEndTasks
= (BOOL
) GetShutdownSetting(DesktopKey
, L
"AutoEndTasks",
738 (DWORD
) DEFAULT_AUTO_END_TASKS
);
739 ShutdownSettings
->HungAppTimeout
= GetShutdownSetting(DesktopKey
,
741 DEFAULT_HUNG_APP_TIMEOUT
);
742 ShutdownSettings
->WaitToKillAppTimeout
= GetShutdownSetting(DesktopKey
,
743 L
"WaitToKillAppTimeout",
744 DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
);
746 RegCloseKey(DesktopKey
);
749 static NTSTATUS FASTCALL
750 InternalExitReactos(DWORD ProcessId
, DWORD ThreadId
, UINT Flags
)
755 PROCESS_ENUM_CONTEXT Context
;
759 char FixedUserInfo
[64];
760 TOKEN_USER
*UserInfo
;
761 SHUTDOWN_SETTINGS ShutdownSettings
;
763 if (ProcessId
!= (DWORD_PTR
) LogonProcess
)
765 DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
766 return STATUS_ACCESS_DENIED
;
769 DPRINT1("FIXME: Need to close all user processes!\n");
770 return STATUS_SUCCESS
;
772 CallerThread
= OpenThread(THREAD_QUERY_INFORMATION
, FALSE
, ThreadId
);
773 if (NULL
== CallerThread
)
775 DPRINT1("OpenThread failed with error %d\n", GetLastError());
776 return STATUS_UNSUCCESSFUL
;
778 if (! OpenThreadToken(CallerThread
, TOKEN_QUERY
, FALSE
, &CallerToken
))
780 DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
781 CloseHandle(CallerThread
);
782 return STATUS_UNSUCCESSFUL
;
784 CloseHandle(CallerThread
);
786 Context
.ProcessCount
= 0;
787 Context
.ProcessData
= NULL
;
788 if (! GetTokenInformation(CallerToken
, TokenOrigin
, &Context
.TokenOrigin
,
789 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
791 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
792 CloseHandle(CallerToken
);
793 return STATUS_UNSUCCESSFUL
;
795 if (! GetTokenInformation(CallerToken
, TokenUser
, FixedUserInfo
,
796 sizeof(FixedUserInfo
), &ReturnLength
))
798 if (sizeof(FixedUserInfo
) < ReturnLength
)
800 UserInfo
= HeapAlloc(Win32CsrApiHeap
, 0, ReturnLength
);
801 if (NULL
== UserInfo
)
803 DPRINT1("Unable to allocate %u bytes for user info\n",
804 (unsigned) ReturnLength
);
805 CloseHandle(CallerToken
);
806 return STATUS_NO_MEMORY
;
808 if (! GetTokenInformation(CallerToken
, TokenUser
, UserInfo
,
809 ReturnLength
, &ReturnLength
))
811 DPRINT1("GetTokenInformation failed with error %d\n",
813 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
814 CloseHandle(CallerToken
);
815 return STATUS_UNSUCCESSFUL
;
820 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
821 CloseHandle(CallerToken
);
822 return STATUS_UNSUCCESSFUL
;
827 UserInfo
= (TOKEN_USER
*) FixedUserInfo
;
829 CloseHandle(CallerToken
);
830 LoadShutdownSettings(UserInfo
->User
.Sid
, &ShutdownSettings
);
831 if (UserInfo
!= (TOKEN_USER
*) FixedUserInfo
)
833 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
835 Context
.CsrssProcess
= GetCurrentProcessId();
836 ShellWnd
= GetShellWindow();
837 if (NULL
== ShellWnd
)
839 DPRINT("No shell present\n");
840 Context
.ShellProcess
= 0;
842 else if (0 == GetWindowThreadProcessId(ShellWnd
, &Context
.ShellProcess
))
844 DPRINT1("Can't get process id of shell window\n");
845 Context
.ShellProcess
= 0;
848 Status
= Win32CsrEnumProcesses(ExitReactosProcessEnum
, &Context
);
849 if (! NT_SUCCESS(Status
))
851 DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
853 if (NULL
!= Context
.ProcessData
)
855 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
860 qsort(Context
.ProcessData
, Context
.ProcessCount
, sizeof(PCSR_PROCESS
),
863 /* Terminate processes, stop if we find one kicking and screaming it doesn't
865 Status
= STATUS_SUCCESS
;
866 for (ProcessIndex
= 0;
867 ProcessIndex
< Context
.ProcessCount
&& NT_SUCCESS(Status
);
870 if (! NotifyAndTerminateProcess(Context
.ProcessData
[ProcessIndex
],
871 &ShutdownSettings
, Flags
))
873 Status
= STATUS_REQUEST_ABORTED
;
878 if (NULL
!= Context
.ProcessData
)
880 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
886 static NTSTATUS FASTCALL
887 UserExitReactos(DWORD UserProcessId
, UINT Flags
)
891 if (NULL
== LogonNotifyWindow
)
893 DPRINT1("No LogonNotifyWindow registered\n");
894 return STATUS_NOT_FOUND
;
897 /* FIXME Inside 2000 says we should impersonate the caller here */
898 Status
= SendMessageW(LogonNotifyWindow
, PM_WINLOGON_EXITWINDOWS
,
899 (WPARAM
) UserProcessId
,
901 /* If the message isn't handled, the return value is 0, so 0 doesn't indicate
902 success. Success is indicated by a 1 return value, if anything besides 0
903 or 1 it's a NTSTATUS value */
906 Status
= STATUS_SUCCESS
;
908 else if (0 == Status
)
910 Status
= STATUS_NOT_IMPLEMENTED
;
916 CSR_API(CsrExitReactos
)
918 if (0 == (Request
->Data
.ExitReactosRequest
.Flags
& EWX_INTERNAL_FLAG
))
920 return UserExitReactos((DWORD_PTR
) Request
->Header
.ClientId
.UniqueProcess
,
921 Request
->Data
.ExitReactosRequest
.Flags
);
925 return InternalExitReactos((DWORD_PTR
) Request
->Header
.ClientId
.UniqueProcess
,
926 (DWORD_PTR
) Request
->Header
.ClientId
.UniqueThread
,
927 Request
->Data
.ExitReactosRequest
.Flags
);