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 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
22 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
24 if (Request
->Data
.RegisterLogonProcessRequest
.Register
)
26 if (0 != LogonProcess
)
28 return STATUS_LOGON_SESSION_EXISTS
;
30 LogonProcess
= Request
->Data
.RegisterLogonProcessRequest
.ProcessId
;
34 if (Request
->Header
.ClientId
.UniqueProcess
!= LogonProcess
)
36 DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n",
37 LogonProcess
, Request
->Header
.ClientId
.UniqueProcess
);
38 return STATUS_NOT_LOGON_PROCESS
;
43 return STATUS_SUCCESS
;
46 CSR_API(CsrSetLogonNotifyWindow
)
50 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
51 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) -
54 if (0 == GetWindowThreadProcessId(Request
->Data
.SetLogonNotifyWindowRequest
.LogonNotifyWindow
,
57 DPRINT1("Can't get window creator\n");
58 return STATUS_INVALID_HANDLE
;
60 if (WindowCreator
!= (DWORD_PTR
)LogonProcess
)
62 DPRINT1("Trying to register window not created by winlogon as notify window\n");
63 return STATUS_ACCESS_DENIED
;
66 LogonNotifyWindow
= Request
->Data
.SetLogonNotifyWindowRequest
.LogonNotifyWindow
;
68 return STATUS_SUCCESS
;
71 typedef struct tagSHUTDOWN_SETTINGS
75 DWORD WaitToKillAppTimeout
;
76 } SHUTDOWN_SETTINGS
, *PSHUTDOWN_SETTINGS
;
78 #define DEFAULT_AUTO_END_TASKS FALSE
79 #define DEFAULT_HUNG_APP_TIMEOUT 5000
80 #define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
82 typedef struct tagNOTIFY_CONTEXT
96 PSHUTDOWN_SETTINGS ShutdownSettings
;
97 LPTHREAD_START_ROUTINE SendMessageProc
;
98 } NOTIFY_CONTEXT
, *PNOTIFY_CONTEXT
;
100 #define QUERY_RESULT_ABORT 0
101 #define QUERY_RESULT_CONTINUE 1
102 #define QUERY_RESULT_TIMEOUT 2
103 #define QUERY_RESULT_ERROR 3
104 #define QUERY_RESULT_FORCE 4
107 UpdateProgressBar(HWND ProgressBar
, PNOTIFY_CONTEXT NotifyContext
)
111 Passed
= GetTickCount() - NotifyContext
->StartTime
;
112 Passed
-= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
113 if (NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
< Passed
)
115 Passed
= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
117 SendMessageW(ProgressBar
, PBM_SETPOS
, Passed
/ 2, 0);
120 static INT_PTR CALLBACK
121 EndNowDlgProc(HWND Dlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
124 PNOTIFY_CONTEXT NotifyContext
;
133 NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
134 NotifyContext
->EndNowResult
= QUERY_RESULT_ABORT
;
135 SetWindowLongPtrW(Dlg
, DWLP_USER
, (LONG_PTR
) lParam
);
136 TitleLength
= SendMessageW(NotifyContext
->WndClient
, WM_GETTEXTLENGTH
,
138 GetWindowTextLengthW(Dlg
);
139 Title
= HeapAlloc(Win32CsrApiHeap
, 0, (TitleLength
+ 1) * sizeof(WCHAR
));
142 Len
= GetWindowTextW(Dlg
, Title
, TitleLength
+ 1);
143 SendMessageW(NotifyContext
->WndClient
, WM_GETTEXT
,
144 TitleLength
+ 1 - Len
, (LPARAM
) (Title
+ Len
));
145 SetWindowTextW(Dlg
, Title
);
146 HeapFree(Win32CsrApiHeap
, 0, Title
);
148 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
149 SendMessageW(ProgressBar
, PBM_SETRANGE32
, 0,
150 NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
/ 2);
151 UpdateProgressBar(ProgressBar
, NotifyContext
);
152 SetTimer(Dlg
, 0, 200, NULL
);
157 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
158 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
159 UpdateProgressBar(ProgressBar
, NotifyContext
);
164 if (BN_CLICKED
== HIWORD(wParam
) && IDC_END_NOW
== LOWORD(wParam
))
166 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
167 NotifyContext
->EndNowResult
= QUERY_RESULT_FORCE
;
168 SendMessageW(Dlg
, WM_CLOSE
, 0, 0);
183 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
184 NotifyContext
->Dlg
= NULL
;
186 PostQuitMessage(NotifyContext
->EndNowResult
);
198 typedef void (WINAPI
*INITCOMMONCONTROLS_PROC
)(void);
201 CallInitCommonControls()
203 static BOOL Initialized
= FALSE
;
205 INITCOMMONCONTROLS_PROC InitProc
;
212 Lib
= LoadLibraryW(L
"COMCTL32.DLL");
217 InitProc
= (INITCOMMONCONTROLS_PROC
) GetProcAddress(Lib
, "InitCommonControls");
218 if (NULL
== InitProc
)
229 EndNowThreadProc(LPVOID Parameter
)
231 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) Parameter
;
234 SetThreadDesktop(NotifyContext
->Desktop
);
235 SwitchDesktop(NotifyContext
->Desktop
);
236 CallInitCommonControls();
237 NotifyContext
->Dlg
= CreateDialogParam(GetModuleHandleW(L
"win32csr"),
238 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
239 EndNowDlgProc
, (LPARAM
) NotifyContext
);
240 if (NULL
== NotifyContext
->Dlg
)
244 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
246 while (GetMessageW(&Msg
, NULL
, 0, 0))
248 if (! IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
250 TranslateMessage(&Msg
);
251 DispatchMessageW(&Msg
);
258 typedef struct tagMESSAGE_CONTEXT
265 } MESSAGE_CONTEXT
, *PMESSAGE_CONTEXT
;
268 SendQueryEndSession(LPVOID Parameter
)
270 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
273 if (SendMessageTimeoutW(Context
->Wnd
, WM_QUERYENDSESSION
, Context
->wParam
,
274 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
277 return Result
? QUERY_RESULT_CONTINUE
: QUERY_RESULT_ABORT
;
280 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
284 SendEndSession(LPVOID Parameter
)
286 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
291 if (SendMessageTimeoutW(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
292 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
295 return QUERY_RESULT_CONTINUE
;
297 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
301 SendMessage(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
303 return QUERY_RESULT_CONTINUE
;
308 NotifyTopLevelEnum(HWND Wnd
, LPARAM lParam
)
310 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
311 MESSAGE_CONTEXT MessageContext
;
313 DWORD Timeout
, WaitStatus
;
315 HANDLE MessageThread
;
318 if (0 == GetWindowThreadProcessId(Wnd
, &ProcessId
))
320 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
324 if (ProcessId
== NotifyContext
->ProcessId
)
326 Now
= GetTickCount();
327 if (0 == NotifyContext
->StartTime
)
329 NotifyContext
->StartTime
= Now
;
331 /* Note: Passed is computed correctly even when GetTickCount() wraps due
332 to unsigned arithmetic */
333 Passed
= Now
- NotifyContext
->StartTime
;
334 MessageContext
.Wnd
= Wnd
;
335 MessageContext
.Msg
= NotifyContext
->Msg
;
336 MessageContext
.wParam
= NotifyContext
->wParam
;
337 MessageContext
.lParam
= NotifyContext
->lParam
;
338 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
339 if (! NotifyContext
->ShutdownSettings
->AutoEndTasks
)
341 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
343 if (Passed
< MessageContext
.Timeout
)
345 MessageContext
.Timeout
-= Passed
;
346 MessageThread
= CreateThread(NULL
, 0, NotifyContext
->SendMessageProc
,
347 (LPVOID
) &MessageContext
, 0, NULL
);
348 if (NULL
== MessageThread
)
350 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
353 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
354 if (Passed
< Timeout
)
357 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
361 WaitStatus
= WAIT_TIMEOUT
;
363 if (WAIT_TIMEOUT
== WaitStatus
)
365 NotifyContext
->WndClient
= Wnd
;
366 if (NULL
== NotifyContext
->UIThread
&& NotifyContext
->ShowUI
)
368 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
370 (LPVOID
) NotifyContext
,
373 Threads
[0] = MessageThread
;
374 Threads
[1] = NotifyContext
->UIThread
;
375 WaitStatus
= WaitForMultipleObjectsEx(NULL
== NotifyContext
->UIThread
?
377 Threads
, FALSE
, INFINITE
,
379 if (WAIT_OBJECT_0
== WaitStatus
)
381 if (! GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
383 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
386 else if (WAIT_OBJECT_0
+ 1 == WaitStatus
)
388 if (! GetExitCodeThread(NotifyContext
->UIThread
,
389 &NotifyContext
->QueryResult
))
391 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
396 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
398 if (WAIT_OBJECT_0
!= WaitStatus
)
400 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
403 else if (WAIT_OBJECT_0
== WaitStatus
)
405 if (! GetExitCodeThread(MessageThread
,
406 &NotifyContext
->QueryResult
))
408 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
413 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
415 CloseHandle(MessageThread
);
419 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
423 return QUERY_RESULT_CONTINUE
== NotifyContext
->QueryResult
;
427 NotifyDesktopEnum(LPWSTR DesktopName
, LPARAM lParam
)
429 PNOTIFY_CONTEXT Context
= (PNOTIFY_CONTEXT
) lParam
;
431 Context
->Desktop
= OpenDesktopW(DesktopName
, 0, FALSE
,
432 DESKTOP_ENUMERATE
| DESKTOP_SWITCHDESKTOP
);
433 if (NULL
== Context
->Desktop
)
435 DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
436 Context
->QueryResult
= QUERY_RESULT_ERROR
;
440 EnumDesktopWindows(Context
->Desktop
, NotifyTopLevelEnum
, lParam
);
442 CloseDesktop(Context
->Desktop
);
444 return QUERY_RESULT_CONTINUE
== Context
->QueryResult
;
448 NotifyTopLevelWindows(PNOTIFY_CONTEXT Context
)
450 HWINSTA WindowStation
;
452 WindowStation
= GetProcessWindowStation();
453 if (NULL
== WindowStation
)
455 DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
459 EnumDesktopsW(WindowStation
, NotifyDesktopEnum
, (LPARAM
) Context
);
465 NotifyAndTerminateProcess(PCSRSS_PROCESS_DATA ProcessData
,
466 PSHUTDOWN_SETTINGS ShutdownSettings
,
469 NOTIFY_CONTEXT Context
;
471 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
473 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
475 if (0 == (Flags
& EWX_FORCE
))
477 if (NULL
!= ProcessData
->Console
)
479 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, ProcessData
,
480 ShutdownSettings
->WaitToKillAppTimeout
);
484 Context
.ProcessId
= (DWORD_PTR
) ProcessData
->ProcessId
;
486 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
487 ENDSESSION_LOGOFF
: 0);
488 Context
.StartTime
= 0;
489 Context
.UIThread
= NULL
;
490 Context
.ShowUI
= DtbgIsDesktopVisible();
492 Context
.ShutdownSettings
= ShutdownSettings
;
493 Context
.SendMessageProc
= SendQueryEndSession
;
495 NotifyTopLevelWindows(&Context
);
497 Context
.wParam
= (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
498 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
499 ENDSESSION_LOGOFF
: 0);
500 Context
.SendMessageProc
= SendEndSession
;
501 Context
.ShowUI
= DtbgIsDesktopVisible() &&
502 (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
503 QueryResult
= Context
.QueryResult
;
504 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
506 NotifyTopLevelWindows(&Context
);
508 if (NULL
!= Context
.UIThread
)
510 if (NULL
!= Context
.Dlg
)
512 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
516 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
518 CloseHandle(Context
.UIThread
);
522 if (QUERY_RESULT_ABORT
== QueryResult
)
528 /* Terminate this process */
529 Process
= OpenProcess(PROCESS_TERMINATE
, FALSE
,
530 (DWORD_PTR
) ProcessData
->ProcessId
);
533 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ProcessId
,
537 TerminateProcess(Process
, 0);
538 CloseHandle(Process
);
543 typedef struct tagPROCESS_ENUM_CONTEXT
546 PCSRSS_PROCESS_DATA
*ProcessData
;
547 TOKEN_ORIGIN TokenOrigin
;
550 } PROCESS_ENUM_CONTEXT
, *PPROCESS_ENUM_CONTEXT
;
552 static NTSTATUS WINAPI
553 ExitReactosProcessEnum(PCSRSS_PROCESS_DATA ProcessData
, PVOID Data
)
559 PPROCESS_ENUM_CONTEXT Context
= (PPROCESS_ENUM_CONTEXT
) Data
;
560 PCSRSS_PROCESS_DATA
*NewData
;
562 /* Do not kill winlogon or csrss */
563 if ((DWORD_PTR
) ProcessData
->ProcessId
== Context
->CsrssProcess
||
564 ProcessData
->ProcessId
== LogonProcess
)
566 return STATUS_SUCCESS
;
569 /* Get the login session of this process */
570 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
,
571 (DWORD_PTR
) ProcessData
->ProcessId
);
574 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ProcessId
,
576 return STATUS_UNSUCCESSFUL
;
579 if (! OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
581 DPRINT1("Unable to open token for process %d, error %d\n",
582 ProcessData
->ProcessId
, GetLastError());
583 CloseHandle(Process
);
584 return STATUS_UNSUCCESSFUL
;
586 CloseHandle(Process
);
588 if (! GetTokenInformation(Token
, TokenOrigin
, &Origin
,
589 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
591 DPRINT1("GetTokenInformation failed for process %d with error %d\n",
592 ProcessData
->ProcessId
, GetLastError());
594 return STATUS_UNSUCCESSFUL
;
598 /* This process will be killed if it's in the correct logon session */
599 if (RtlEqualLuid(&(Context
->TokenOrigin
.OriginatingLogonSession
),
600 &(Origin
.OriginatingLogonSession
)))
602 /* Kill the shell process last */
603 if ((DWORD_PTR
) ProcessData
->ProcessId
== Context
->ShellProcess
)
605 ProcessData
->ShutdownLevel
= 0;
607 NewData
= HeapAlloc(Win32CsrApiHeap
, 0, (Context
->ProcessCount
+ 1)
608 * sizeof(PCSRSS_PROCESS_DATA
));
611 return STATUS_NO_MEMORY
;
613 if (0 != Context
->ProcessCount
)
615 memcpy(NewData
, Context
->ProcessData
,
616 Context
->ProcessCount
* sizeof(PCSRSS_PROCESS_DATA
));
617 HeapFree(Win32CsrApiHeap
, 0, Context
->ProcessData
);
619 Context
->ProcessData
= NewData
;
620 Context
->ProcessData
[Context
->ProcessCount
] = ProcessData
;
621 Context
->ProcessCount
++;
624 return STATUS_SUCCESS
;
628 ProcessDataCompare(const void *Elem1
, const void *Elem2
)
630 const PCSRSS_PROCESS_DATA
*ProcessData1
= (PCSRSS_PROCESS_DATA
*) Elem1
;
631 const PCSRSS_PROCESS_DATA
*ProcessData2
= (PCSRSS_PROCESS_DATA
*) Elem2
;
633 if ((*ProcessData1
)->ShutdownLevel
< (*ProcessData2
)->ShutdownLevel
)
637 else if ((*ProcessData2
)->ShutdownLevel
< (*ProcessData1
)->ShutdownLevel
)
641 else if ((*ProcessData1
)->ProcessId
< (*ProcessData2
)->ProcessId
)
645 else if ((*ProcessData2
)->ProcessId
< (*ProcessData1
)->ProcessId
)
653 static DWORD FASTCALL
654 GetShutdownSetting(HKEY DesktopKey
, LPCWSTR ValueName
, DWORD DefaultValue
)
656 BYTE ValueBuffer
[16];
660 UNICODE_STRING StringValue
;
663 ValueSize
= sizeof(ValueBuffer
);
664 ErrCode
= RegQueryValueExW(DesktopKey
, ValueName
, NULL
, &Type
, ValueBuffer
,
666 if (ERROR_SUCCESS
!= ErrCode
)
668 DPRINT("GetShutdownSetting for %S failed with error code %ld\n",
675 RtlInitUnicodeString(&StringValue
, (LPCWSTR
) ValueBuffer
);
676 if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue
, 10, &Value
)))
678 DPRINT1("Unable to convert value %S for setting %S\n",
679 StringValue
.Buffer
, ValueName
);
682 return (DWORD
) Value
;
684 else if (REG_DWORD
== Type
)
686 return *((DWORD
*) ValueBuffer
);
689 DPRINT1("Unexpected registry type %d for setting %S\n", Type
, ValueName
);
694 LoadShutdownSettings(PSID Sid
, PSHUTDOWN_SETTINGS ShutdownSettings
)
696 static WCHAR Subkey
[] = L
"\\Control Panel\\Desktop";
698 WCHAR InitialKeyName
[128];
703 ShutdownSettings
->AutoEndTasks
= DEFAULT_AUTO_END_TASKS
;
704 ShutdownSettings
->HungAppTimeout
= DEFAULT_HUNG_APP_TIMEOUT
;
705 ShutdownSettings
->WaitToKillAppTimeout
= DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
;
707 if (! ConvertSidToStringSidW(Sid
, &StringSid
))
709 DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
713 if (wcslen(StringSid
) + wcslen(Subkey
) + 1 <=
714 sizeof(InitialKeyName
) / sizeof(WCHAR
))
716 KeyName
= InitialKeyName
;
720 KeyName
= HeapAlloc(Win32CsrApiHeap
, 0,
721 (wcslen(StringSid
) + wcslen(Subkey
) + 1) *
725 DPRINT1("Failed to allocate memory, using default shutdown settings\n");
726 LocalFree(StringSid
);
730 wcscat(wcscpy(KeyName
, StringSid
), Subkey
);
731 LocalFree(StringSid
);
733 ErrCode
= RegOpenKeyExW(HKEY_USERS
, KeyName
, 0, KEY_QUERY_VALUE
, &DesktopKey
);
734 if (KeyName
!= InitialKeyName
)
736 HeapFree(Win32CsrApiHeap
, 0, KeyName
);
738 if (ERROR_SUCCESS
!= ErrCode
)
740 DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode
);
744 ShutdownSettings
->AutoEndTasks
= (BOOL
) GetShutdownSetting(DesktopKey
, L
"AutoEndTasks",
745 (DWORD
) DEFAULT_AUTO_END_TASKS
);
746 ShutdownSettings
->HungAppTimeout
= GetShutdownSetting(DesktopKey
,
748 DEFAULT_HUNG_APP_TIMEOUT
);
749 ShutdownSettings
->WaitToKillAppTimeout
= GetShutdownSetting(DesktopKey
,
750 L
"WaitToKillAppTimeout",
751 DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
);
753 RegCloseKey(DesktopKey
);
756 static NTSTATUS FASTCALL
757 InternalExitReactos(DWORD ProcessId
, DWORD ThreadId
, UINT Flags
)
762 PROCESS_ENUM_CONTEXT Context
;
766 char FixedUserInfo
[64];
767 TOKEN_USER
*UserInfo
;
768 SHUTDOWN_SETTINGS ShutdownSettings
;
770 if (ProcessId
!= (DWORD_PTR
) LogonProcess
)
772 DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
773 return STATUS_ACCESS_DENIED
;
776 DPRINT1("FIXME: Need to close all user processes!\n");
777 return STATUS_SUCCESS
;
779 CallerThread
= OpenThread(THREAD_QUERY_INFORMATION
, FALSE
, ThreadId
);
780 if (NULL
== CallerThread
)
782 DPRINT1("OpenThread failed with error %d\n", GetLastError());
783 return STATUS_UNSUCCESSFUL
;
785 if (! OpenThreadToken(CallerThread
, TOKEN_QUERY
, FALSE
, &CallerToken
))
787 DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
788 CloseHandle(CallerThread
);
789 return STATUS_UNSUCCESSFUL
;
791 CloseHandle(CallerThread
);
793 Context
.ProcessCount
= 0;
794 Context
.ProcessData
= NULL
;
795 if (! GetTokenInformation(CallerToken
, TokenOrigin
, &Context
.TokenOrigin
,
796 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
798 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
799 CloseHandle(CallerToken
);
800 return STATUS_UNSUCCESSFUL
;
802 if (! GetTokenInformation(CallerToken
, TokenUser
, FixedUserInfo
,
803 sizeof(FixedUserInfo
), &ReturnLength
))
805 if (sizeof(FixedUserInfo
) < ReturnLength
)
807 UserInfo
= HeapAlloc(Win32CsrApiHeap
, 0, ReturnLength
);
808 if (NULL
== UserInfo
)
810 DPRINT1("Unable to allocate %u bytes for user info\n",
811 (unsigned) ReturnLength
);
812 CloseHandle(CallerToken
);
813 return STATUS_NO_MEMORY
;
815 if (! GetTokenInformation(CallerToken
, TokenUser
, UserInfo
,
816 ReturnLength
, &ReturnLength
))
818 DPRINT1("GetTokenInformation failed with error %d\n",
820 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
821 CloseHandle(CallerToken
);
822 return STATUS_UNSUCCESSFUL
;
827 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
828 CloseHandle(CallerToken
);
829 return STATUS_UNSUCCESSFUL
;
834 UserInfo
= (TOKEN_USER
*) FixedUserInfo
;
836 CloseHandle(CallerToken
);
837 LoadShutdownSettings(UserInfo
->User
.Sid
, &ShutdownSettings
);
838 if (UserInfo
!= (TOKEN_USER
*) FixedUserInfo
)
840 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
842 Context
.CsrssProcess
= GetCurrentProcessId();
843 ShellWnd
= GetShellWindow();
844 if (NULL
== ShellWnd
)
846 DPRINT("No shell present\n");
847 Context
.ShellProcess
= 0;
849 else if (0 == GetWindowThreadProcessId(ShellWnd
, &Context
.ShellProcess
))
851 DPRINT1("Can't get process id of shell window\n");
852 Context
.ShellProcess
= 0;
855 Status
= Win32CsrEnumProcesses(ExitReactosProcessEnum
, &Context
);
856 if (! NT_SUCCESS(Status
))
858 DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
860 if (NULL
!= Context
.ProcessData
)
862 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
867 qsort(Context
.ProcessData
, Context
.ProcessCount
, sizeof(PCSRSS_PROCESS_DATA
),
870 /* Terminate processes, stop if we find one kicking and screaming it doesn't
872 Status
= STATUS_SUCCESS
;
873 for (ProcessIndex
= 0;
874 ProcessIndex
< Context
.ProcessCount
&& NT_SUCCESS(Status
);
877 if (! NotifyAndTerminateProcess(Context
.ProcessData
[ProcessIndex
],
878 &ShutdownSettings
, Flags
))
880 Status
= STATUS_REQUEST_ABORTED
;
885 if (NULL
!= Context
.ProcessData
)
887 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
893 static NTSTATUS FASTCALL
894 UserExitReactos(DWORD UserProcessId
, UINT Flags
)
898 if (NULL
== LogonNotifyWindow
)
900 DPRINT1("No LogonNotifyWindow registered\n");
901 return STATUS_NOT_FOUND
;
904 /* FIXME Inside 2000 says we should impersonate the caller here */
905 Status
= SendMessageW(LogonNotifyWindow
, PM_WINLOGON_EXITWINDOWS
,
906 (WPARAM
) UserProcessId
,
908 /* If the message isn't handled, the return value is 0, so 0 doesn't indicate
909 success. Success is indicated by a 1 return value, if anything besides 0
910 or 1 it's a NTSTATUS value */
913 Status
= STATUS_SUCCESS
;
915 else if (0 == Status
)
917 Status
= STATUS_NOT_IMPLEMENTED
;
923 CSR_API(CsrExitReactos
)
925 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
926 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) -
927 sizeof(PORT_MESSAGE
);
929 if (0 == (Request
->Data
.ExitReactosRequest
.Flags
& EWX_INTERNAL_FLAG
))
931 return UserExitReactos((DWORD_PTR
) Request
->Header
.ClientId
.UniqueProcess
,
932 Request
->Data
.ExitReactosRequest
.Flags
);
936 return InternalExitReactos((DWORD_PTR
) Request
->Header
.ClientId
.UniqueProcess
,
937 (DWORD_PTR
) Request
->Header
.ClientId
.UniqueThread
,
938 Request
->Data
.ExitReactosRequest
.Flags
);