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 ******************************************************************/
18 static HWND LogonNotifyWindow
= NULL
;
19 static HANDLE LogonProcess
= NULL
;
21 CSR_API(CsrRegisterLogonProcess
)
23 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
24 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) - sizeof(PORT_MESSAGE
);
26 if (Request
->Data
.RegisterLogonProcessRequest
.Register
)
28 if (0 != LogonProcess
)
30 Request
->Status
= STATUS_LOGON_SESSION_EXISTS
;
31 return Request
->Status
;
33 LogonProcess
= Request
->Data
.RegisterLogonProcessRequest
.ProcessId
;
37 if (Request
->Header
.ClientId
.UniqueProcess
!= LogonProcess
)
39 DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n",
40 LogonProcess
, Request
->Header
.ClientId
.UniqueProcess
);
41 Request
->Status
= STATUS_NOT_LOGON_PROCESS
;
42 return Request
->Status
;
47 Request
->Status
= STATUS_SUCCESS
;
49 return Request
->Status
;
52 CSR_API(CsrSetLogonNotifyWindow
)
56 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
57 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) -
60 if (0 == GetWindowThreadProcessId(Request
->Data
.SetLogonNotifyWindowRequest
.LogonNotifyWindow
,
63 DPRINT1("Can't get window creator\n");
64 Request
->Status
= STATUS_INVALID_HANDLE
;
65 return Request
->Status
;
67 if (WindowCreator
!= (DWORD
)LogonProcess
)
69 DPRINT1("Trying to register window not created by winlogon as notify window\n");
70 Request
->Status
= STATUS_ACCESS_DENIED
;
71 return Request
->Status
;
74 LogonNotifyWindow
= Request
->Data
.SetLogonNotifyWindowRequest
.LogonNotifyWindow
;
76 Request
->Status
= STATUS_SUCCESS
;
78 return Request
->Status
;
81 typedef struct tagSHUTDOWN_SETTINGS
85 DWORD WaitToKillAppTimeout
;
86 } SHUTDOWN_SETTINGS
, *PSHUTDOWN_SETTINGS
;
88 #define DEFAULT_AUTO_END_TASKS FALSE
89 #define DEFAULT_HUNG_APP_TIMEOUT 5000
90 #define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
92 typedef struct tagNOTIFY_CONTEXT
106 PSHUTDOWN_SETTINGS ShutdownSettings
;
107 LPTHREAD_START_ROUTINE SendMessageProc
;
108 } NOTIFY_CONTEXT
, *PNOTIFY_CONTEXT
;
110 #define QUERY_RESULT_ABORT 0
111 #define QUERY_RESULT_CONTINUE 1
112 #define QUERY_RESULT_TIMEOUT 2
113 #define QUERY_RESULT_ERROR 3
114 #define QUERY_RESULT_FORCE 4
117 UpdateProgressBar(HWND ProgressBar
, PNOTIFY_CONTEXT NotifyContext
)
121 Passed
= GetTickCount() - NotifyContext
->StartTime
;
122 Passed
-= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
123 if (NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
< Passed
)
125 Passed
= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
127 SendMessageW(ProgressBar
, PBM_SETPOS
, Passed
/ 2, 0);
130 static INT_PTR CALLBACK
131 EndNowDlgProc(HWND Dlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
134 PNOTIFY_CONTEXT NotifyContext
;
143 NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
144 NotifyContext
->EndNowResult
= QUERY_RESULT_ABORT
;
145 SetWindowLongPtrW(Dlg
, DWLP_USER
, (LONG_PTR
) lParam
);
146 TitleLength
= SendMessageW(NotifyContext
->WndClient
, WM_GETTEXTLENGTH
,
148 GetWindowTextLengthW(Dlg
);
149 Title
= HeapAlloc(Win32CsrApiHeap
, 0, (TitleLength
+ 1) * sizeof(WCHAR
));
152 Len
= GetWindowTextW(Dlg
, Title
, TitleLength
+ 1);
153 SendMessageW(NotifyContext
->WndClient
, WM_GETTEXT
,
154 TitleLength
+ 1 - Len
, (LPARAM
) (Title
+ Len
));
155 SetWindowTextW(Dlg
, Title
);
156 HeapFree(Win32CsrApiHeap
, 0, Title
);
158 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
159 SendMessageW(ProgressBar
, PBM_SETRANGE32
, 0,
160 NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
/ 2);
161 UpdateProgressBar(ProgressBar
, NotifyContext
);
162 SetTimer(Dlg
, 0, 200, NULL
);
167 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
168 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
169 UpdateProgressBar(ProgressBar
, NotifyContext
);
174 if (BN_CLICKED
== HIWORD(wParam
) && IDC_END_NOW
== LOWORD(wParam
))
176 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
177 NotifyContext
->EndNowResult
= QUERY_RESULT_FORCE
;
178 SendMessageW(Dlg
, WM_CLOSE
, 0, 0);
193 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
194 NotifyContext
->Dlg
= NULL
;
196 PostQuitMessage(NotifyContext
->EndNowResult
);
208 typedef void (STDCALL
*INITCOMMONCONTROLS_PROC
)(void);
211 CallInitCommonControls()
213 static BOOL Initialized
= FALSE
;
215 INITCOMMONCONTROLS_PROC InitProc
;
222 Lib
= LoadLibraryW(L
"COMCTL32.DLL");
227 InitProc
= (INITCOMMONCONTROLS_PROC
) GetProcAddress(Lib
, "InitCommonControls");
228 if (NULL
== InitProc
)
239 EndNowThreadProc(LPVOID Parameter
)
241 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) Parameter
;
244 SetThreadDesktop(NotifyContext
->Desktop
);
245 SwitchDesktop(NotifyContext
->Desktop
);
246 CallInitCommonControls();
247 NotifyContext
->Dlg
= CreateDialogParam(Win32CsrDllHandle
,
248 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
249 EndNowDlgProc
, (LPARAM
) NotifyContext
);
250 if (NULL
== NotifyContext
->Dlg
)
254 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
256 while (GetMessageW(&Msg
, NULL
, 0, 0))
258 if (! IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
260 TranslateMessage(&Msg
);
261 DispatchMessageW(&Msg
);
268 typedef struct tagMESSAGE_CONTEXT
275 } MESSAGE_CONTEXT
, *PMESSAGE_CONTEXT
;
278 SendQueryEndSession(LPVOID Parameter
)
280 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
283 if (SendMessageTimeoutW(Context
->Wnd
, WM_QUERYENDSESSION
, Context
->wParam
,
284 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
287 return Result
? QUERY_RESULT_CONTINUE
: QUERY_RESULT_ABORT
;
290 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
294 SendEndSession(LPVOID Parameter
)
296 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
301 if (SendMessageTimeoutW(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
302 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
305 return QUERY_RESULT_CONTINUE
;
307 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
311 SendMessage(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
313 return QUERY_RESULT_CONTINUE
;
318 NotifyTopLevelEnum(HWND Wnd
, LPARAM lParam
)
320 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
321 MESSAGE_CONTEXT MessageContext
;
323 DWORD Timeout
, WaitStatus
;
325 HANDLE MessageThread
;
328 if (0 == GetWindowThreadProcessId(Wnd
, &ProcessId
))
330 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
334 if (ProcessId
== NotifyContext
->ProcessId
)
336 Now
= GetTickCount();
337 if (0 == NotifyContext
->StartTime
)
339 NotifyContext
->StartTime
= Now
;
341 /* Note: Passed is computed correctly even when GetTickCount() wraps due
342 to unsigned arithmetic */
343 Passed
= Now
- NotifyContext
->StartTime
;
344 MessageContext
.Wnd
= Wnd
;
345 MessageContext
.Msg
= NotifyContext
->Msg
;
346 MessageContext
.wParam
= NotifyContext
->wParam
;
347 MessageContext
.lParam
= NotifyContext
->lParam
;
348 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
349 if (! NotifyContext
->ShutdownSettings
->AutoEndTasks
)
351 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
353 if (Passed
< MessageContext
.Timeout
)
355 MessageContext
.Timeout
-= Passed
;
356 MessageThread
= CreateThread(NULL
, 0, NotifyContext
->SendMessageProc
,
357 (LPVOID
) &MessageContext
, 0, NULL
);
358 if (NULL
== MessageThread
)
360 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
363 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
364 if (Passed
< Timeout
)
367 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
371 WaitStatus
= WAIT_TIMEOUT
;
373 if (WAIT_TIMEOUT
== WaitStatus
)
375 NotifyContext
->WndClient
= Wnd
;
376 if (NULL
== NotifyContext
->UIThread
&& NotifyContext
->ShowUI
)
378 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
380 (LPVOID
) NotifyContext
,
383 Threads
[0] = MessageThread
;
384 Threads
[1] = NotifyContext
->UIThread
;
385 WaitStatus
= WaitForMultipleObjectsEx(NULL
== NotifyContext
->UIThread
?
387 Threads
, FALSE
, INFINITE
,
389 if (WAIT_OBJECT_0
== WaitStatus
)
391 if (! GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
393 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
396 else if (WAIT_OBJECT_0
+ 1 == WaitStatus
)
398 if (! GetExitCodeThread(NotifyContext
->UIThread
,
399 &NotifyContext
->QueryResult
))
401 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
406 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
408 if (WAIT_OBJECT_0
!= WaitStatus
)
410 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
413 else if (WAIT_OBJECT_0
== WaitStatus
)
415 if (! GetExitCodeThread(MessageThread
,
416 &NotifyContext
->QueryResult
))
418 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
423 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
425 CloseHandle(MessageThread
);
429 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
433 return QUERY_RESULT_CONTINUE
== NotifyContext
->QueryResult
;
437 NotifyDesktopEnum(LPWSTR DesktopName
, LPARAM lParam
)
439 PNOTIFY_CONTEXT Context
= (PNOTIFY_CONTEXT
) lParam
;
441 Context
->Desktop
= OpenDesktopW(DesktopName
, 0, FALSE
,
442 DESKTOP_ENUMERATE
| DESKTOP_SWITCHDESKTOP
);
443 if (NULL
== Context
->Desktop
)
445 DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
446 Context
->QueryResult
= QUERY_RESULT_ERROR
;
450 EnumDesktopWindows(Context
->Desktop
, NotifyTopLevelEnum
, lParam
);
452 CloseDesktop(Context
->Desktop
);
454 return QUERY_RESULT_CONTINUE
== Context
->QueryResult
;
458 NotifyTopLevelWindows(PNOTIFY_CONTEXT Context
)
460 HWINSTA WindowStation
;
462 WindowStation
= GetProcessWindowStation();
463 if (NULL
== WindowStation
)
465 DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
469 EnumDesktopsW(WindowStation
, NotifyDesktopEnum
, (LPARAM
) Context
);
475 NotifyAndTerminateProcess(PCSRSS_PROCESS_DATA ProcessData
,
476 PSHUTDOWN_SETTINGS ShutdownSettings
,
479 NOTIFY_CONTEXT Context
;
481 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
483 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
485 if (0 == (Flags
& EWX_FORCE
))
487 if (NULL
!= ProcessData
->Console
)
489 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, ProcessData
,
490 ShutdownSettings
->WaitToKillAppTimeout
);
494 Context
.ProcessId
= (DWORD
) ProcessData
->ProcessId
;
496 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
497 ENDSESSION_LOGOFF
: 0);
498 Context
.StartTime
= 0;
499 Context
.UIThread
= NULL
;
500 Context
.ShowUI
= DtbgIsDesktopVisible();
502 Context
.ShutdownSettings
= ShutdownSettings
;
503 Context
.SendMessageProc
= SendQueryEndSession
;
505 NotifyTopLevelWindows(&Context
);
507 Context
.wParam
= (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
508 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
509 ENDSESSION_LOGOFF
: 0);
510 Context
.SendMessageProc
= SendEndSession
;
511 Context
.ShowUI
= DtbgIsDesktopVisible() &&
512 (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
513 QueryResult
= Context
.QueryResult
;
514 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
516 NotifyTopLevelWindows(&Context
);
518 if (NULL
!= Context
.UIThread
)
520 if (NULL
!= Context
.Dlg
)
522 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
526 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
528 CloseHandle(Context
.UIThread
);
532 if (QUERY_RESULT_ABORT
== QueryResult
)
538 /* Terminate this process */
539 Process
= OpenProcess(PROCESS_TERMINATE
, FALSE
,
540 (DWORD
) ProcessData
->ProcessId
);
543 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ProcessId
,
547 TerminateProcess(Process
, 0);
548 CloseHandle(Process
);
553 typedef struct tagPROCESS_ENUM_CONTEXT
556 PCSRSS_PROCESS_DATA
*ProcessData
;
557 TOKEN_ORIGIN TokenOrigin
;
560 } PROCESS_ENUM_CONTEXT
, *PPROCESS_ENUM_CONTEXT
;
562 static NTSTATUS STDCALL
563 ExitReactosProcessEnum(PCSRSS_PROCESS_DATA ProcessData
, PVOID Data
)
569 PPROCESS_ENUM_CONTEXT Context
= (PPROCESS_ENUM_CONTEXT
) Data
;
570 PCSRSS_PROCESS_DATA
*NewData
;
572 /* Do not kill winlogon or csrss */
573 if ((DWORD
) ProcessData
->ProcessId
== Context
->CsrssProcess
||
574 ProcessData
->ProcessId
== LogonProcess
)
576 return STATUS_SUCCESS
;
579 /* Get the login session of this process */
580 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
,
581 (DWORD
) ProcessData
->ProcessId
);
584 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ProcessId
,
586 return STATUS_UNSUCCESSFUL
;
589 if (! OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
591 DPRINT1("Unable to open token for process %d, error %d\n",
592 ProcessData
->ProcessId
, GetLastError());
593 CloseHandle(Process
);
594 return STATUS_UNSUCCESSFUL
;
596 CloseHandle(Process
);
598 if (! GetTokenInformation(Token
, TokenOrigin
, &Origin
,
599 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
601 DPRINT1("GetTokenInformation failed for process %d with error %d\n",
602 ProcessData
->ProcessId
, GetLastError());
604 return STATUS_UNSUCCESSFUL
;
608 /* This process will be killed if it's in the correct logon session */
609 if (RtlEqualLuid(&(Context
->TokenOrigin
.OriginatingLogonSession
),
610 &(Origin
.OriginatingLogonSession
)))
612 /* Kill the shell process last */
613 if ((DWORD
) ProcessData
->ProcessId
== Context
->ShellProcess
)
615 ProcessData
->ShutdownLevel
= 0;
617 NewData
= HeapAlloc(Win32CsrApiHeap
, 0, (Context
->ProcessCount
+ 1)
618 * sizeof(PCSRSS_PROCESS_DATA
));
621 return STATUS_NO_MEMORY
;
623 if (0 != Context
->ProcessCount
)
625 memcpy(NewData
, Context
->ProcessData
,
626 Context
->ProcessCount
* sizeof(PCSRSS_PROCESS_DATA
));
627 HeapFree(Win32CsrApiHeap
, 0, Context
->ProcessData
);
629 Context
->ProcessData
= NewData
;
630 Context
->ProcessData
[Context
->ProcessCount
] = ProcessData
;
631 Context
->ProcessCount
++;
634 return STATUS_SUCCESS
;
638 ProcessDataCompare(const void *Elem1
, const void *Elem2
)
640 const PCSRSS_PROCESS_DATA
*ProcessData1
= (PCSRSS_PROCESS_DATA
*) Elem1
;
641 const PCSRSS_PROCESS_DATA
*ProcessData2
= (PCSRSS_PROCESS_DATA
*) Elem2
;
643 if ((*ProcessData1
)->ShutdownLevel
< (*ProcessData2
)->ShutdownLevel
)
647 else if ((*ProcessData2
)->ShutdownLevel
< (*ProcessData1
)->ShutdownLevel
)
651 else if ((*ProcessData1
)->ProcessId
< (*ProcessData2
)->ProcessId
)
655 else if ((*ProcessData2
)->ProcessId
< (*ProcessData1
)->ProcessId
)
663 static DWORD FASTCALL
664 GetShutdownSetting(HKEY DesktopKey
, LPCWSTR ValueName
, DWORD DefaultValue
)
666 BYTE ValueBuffer
[16];
670 UNICODE_STRING StringValue
;
673 ValueSize
= sizeof(ValueBuffer
);
674 ErrCode
= RegQueryValueExW(DesktopKey
, ValueName
, NULL
, &Type
, ValueBuffer
,
676 if (ERROR_SUCCESS
!= ErrCode
)
678 DPRINT("GetShutdownSetting for %S failed with error code %ld\n",
685 RtlInitUnicodeString(&StringValue
, (LPCWSTR
) ValueBuffer
);
686 if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue
, 10, &Value
)))
688 DPRINT1("Unable to convert value %S for setting %S\n",
689 StringValue
.Buffer
, ValueName
);
692 return (DWORD
) Value
;
694 else if (REG_DWORD
== Type
)
696 return *((DWORD
*) ValueBuffer
);
699 DPRINT1("Unexpected registry type %d for setting %S\n", Type
, ValueName
);
704 LoadShutdownSettings(PSID Sid
, PSHUTDOWN_SETTINGS ShutdownSettings
)
706 static WCHAR Subkey
[] = L
"\\Control Panel\\Desktop";
708 WCHAR InitialKeyName
[128];
713 ShutdownSettings
->AutoEndTasks
= DEFAULT_AUTO_END_TASKS
;
714 ShutdownSettings
->HungAppTimeout
= DEFAULT_HUNG_APP_TIMEOUT
;
715 ShutdownSettings
->WaitToKillAppTimeout
= DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
;
717 if (! ConvertSidToStringSidW(Sid
, &StringSid
))
719 DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
723 if (wcslen(StringSid
) + wcslen(Subkey
) + 1 <=
724 sizeof(InitialKeyName
) / sizeof(WCHAR
))
726 KeyName
= InitialKeyName
;
730 KeyName
= HeapAlloc(Win32CsrApiHeap
, 0,
731 (wcslen(StringSid
) + wcslen(Subkey
) + 1) *
735 DPRINT1("Failed to allocate memory, using default shutdown settings\n");
736 LocalFree(StringSid
);
740 wcscat(wcscpy(KeyName
, StringSid
), Subkey
);
741 LocalFree(StringSid
);
743 ErrCode
= RegOpenKeyExW(HKEY_USERS
, KeyName
, 0, KEY_QUERY_VALUE
, &DesktopKey
);
744 if (KeyName
!= InitialKeyName
)
746 HeapFree(Win32CsrApiHeap
, 0, KeyName
);
748 if (ERROR_SUCCESS
!= ErrCode
)
750 DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode
);
754 ShutdownSettings
->AutoEndTasks
= (BOOL
) GetShutdownSetting(DesktopKey
, L
"AutoEndTasks",
755 (DWORD
) DEFAULT_AUTO_END_TASKS
);
756 ShutdownSettings
->HungAppTimeout
= GetShutdownSetting(DesktopKey
,
758 DEFAULT_HUNG_APP_TIMEOUT
);
759 ShutdownSettings
->WaitToKillAppTimeout
= GetShutdownSetting(DesktopKey
,
760 L
"WaitToKillAppTimeout",
761 DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
);
763 RegCloseKey(DesktopKey
);
766 static NTSTATUS FASTCALL
767 InternalExitReactos(DWORD ProcessId
, DWORD ThreadId
, UINT Flags
)
772 PROCESS_ENUM_CONTEXT Context
;
776 char FixedUserInfo
[64];
777 TOKEN_USER
*UserInfo
;
778 SHUTDOWN_SETTINGS ShutdownSettings
;
780 if (ProcessId
!= (DWORD
) LogonProcess
)
782 DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
783 return STATUS_ACCESS_DENIED
;
786 DPRINT1("FIXME: Need to close all user processes!\n");
787 return STATUS_SUCCESS
;
789 CallerThread
= OpenThread(THREAD_QUERY_INFORMATION
, FALSE
, ThreadId
);
790 if (NULL
== CallerThread
)
792 DPRINT1("OpenThread failed with error %d\n", GetLastError());
793 return STATUS_UNSUCCESSFUL
;
795 if (! OpenThreadToken(CallerThread
, TOKEN_QUERY
, FALSE
, &CallerToken
))
797 DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
798 CloseHandle(CallerThread
);
799 return STATUS_UNSUCCESSFUL
;
801 CloseHandle(CallerThread
);
803 Context
.ProcessCount
= 0;
804 Context
.ProcessData
= NULL
;
805 if (! GetTokenInformation(CallerToken
, TokenOrigin
, &Context
.TokenOrigin
,
806 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
808 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
809 CloseHandle(CallerToken
);
810 return STATUS_UNSUCCESSFUL
;
812 if (! GetTokenInformation(CallerToken
, TokenUser
, FixedUserInfo
,
813 sizeof(FixedUserInfo
), &ReturnLength
))
815 if (sizeof(FixedUserInfo
) < ReturnLength
)
817 UserInfo
= HeapAlloc(Win32CsrApiHeap
, 0, ReturnLength
);
818 if (NULL
== UserInfo
)
820 DPRINT1("Unable to allocate %u bytes for user info\n",
821 (unsigned) ReturnLength
);
822 CloseHandle(CallerToken
);
823 return STATUS_NO_MEMORY
;
825 if (! GetTokenInformation(CallerToken
, TokenUser
, UserInfo
,
826 ReturnLength
, &ReturnLength
))
828 DPRINT1("GetTokenInformation failed with error %d\n",
830 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
831 CloseHandle(CallerToken
);
832 return STATUS_UNSUCCESSFUL
;
837 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
838 CloseHandle(CallerToken
);
839 return STATUS_UNSUCCESSFUL
;
844 UserInfo
= (TOKEN_USER
*) FixedUserInfo
;
846 CloseHandle(CallerToken
);
847 LoadShutdownSettings(UserInfo
->User
.Sid
, &ShutdownSettings
);
848 if (UserInfo
!= (TOKEN_USER
*) FixedUserInfo
)
850 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
852 Context
.CsrssProcess
= GetCurrentProcessId();
853 ShellWnd
= GetShellWindow();
854 if (NULL
== ShellWnd
)
856 DPRINT("No shell present\n");
857 Context
.ShellProcess
= 0;
859 else if (0 == GetWindowThreadProcessId(ShellWnd
, &Context
.ShellProcess
))
861 DPRINT1("Can't get process id of shell window\n");
862 Context
.ShellProcess
= 0;
865 Status
= Win32CsrEnumProcesses(ExitReactosProcessEnum
, &Context
);
866 if (! NT_SUCCESS(Status
))
868 DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
870 if (NULL
!= Context
.ProcessData
)
872 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
877 qsort(Context
.ProcessData
, Context
.ProcessCount
, sizeof(PCSRSS_PROCESS_DATA
),
880 /* Terminate processes, stop if we find one kicking and screaming it doesn't
882 Status
= STATUS_SUCCESS
;
883 for (ProcessIndex
= 0;
884 ProcessIndex
< Context
.ProcessCount
&& NT_SUCCESS(Status
);
887 if (! NotifyAndTerminateProcess(Context
.ProcessData
[ProcessIndex
],
888 &ShutdownSettings
, Flags
))
890 Status
= STATUS_REQUEST_ABORTED
;
895 if (NULL
!= Context
.ProcessData
)
897 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
903 static NTSTATUS FASTCALL
904 UserExitReactos(DWORD UserProcessId
, UINT Flags
)
908 if (NULL
== LogonNotifyWindow
)
910 DPRINT1("No LogonNotifyWindow registered\n");
911 return STATUS_NOT_FOUND
;
914 /* FIXME Inside 2000 says we should impersonate the caller here */
915 Status
= SendMessageW(LogonNotifyWindow
, PM_WINLOGON_EXITWINDOWS
,
916 (WPARAM
) UserProcessId
,
918 /* If the message isn't handled, the return value is 0, so 0 doesn't indicate
919 success. Success is indicated by a 1 return value, if anything besides 0
920 or 1 it's a NTSTATUS value */
923 Status
= STATUS_SUCCESS
;
925 else if (0 == Status
)
927 Status
= STATUS_NOT_IMPLEMENTED
;
933 CSR_API(CsrExitReactos
)
935 Request
->Header
.u1
.s1
.TotalLength
= sizeof(CSR_API_MESSAGE
);
936 Request
->Header
.u1
.s1
.DataLength
= sizeof(CSR_API_MESSAGE
) -
937 sizeof(PORT_MESSAGE
);
939 if (0 == (Request
->Data
.ExitReactosRequest
.Flags
& EWX_INTERNAL_FLAG
))
941 Request
->Status
= UserExitReactos((DWORD
) Request
->Header
.ClientId
.UniqueProcess
,
942 Request
->Data
.ExitReactosRequest
.Flags
);
946 Request
->Status
= InternalExitReactos((DWORD
) Request
->Header
.ClientId
.UniqueProcess
,
947 (DWORD
) Request
->Header
.ClientId
.UniqueThread
,
948 Request
->Data
.ExitReactosRequest
.Flags
);
951 return Request
->Status
;