2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSRSS subsystem
4 * FILE: win32ss/user/winsrv/exitros.c
5 * PURPOSE: Logout/shutdown
8 /* INCLUDES ******************************************************************/
18 static HWND LogonNotifyWindow
= NULL
;
19 static HANDLE LogonProcess
= NULL
;
22 /* FUNCTIONS *****************************************************************/
25 Win32CsrEnumProcesses(CSRSS_ENUM_PROCESS_PROC EnumProc
,
28 return CsrEnumProcesses(EnumProc
, Context
);
31 CSR_API(CsrRegisterLogonProcess
)
33 if (ApiMessage
->Data
.RegisterLogonProcessRequest
.Register
)
35 if (0 != LogonProcess
)
37 return STATUS_LOGON_SESSION_EXISTS
;
39 LogonProcess
= ApiMessage
->Data
.RegisterLogonProcessRequest
.ProcessId
;
43 if (ApiMessage
->Header
.ClientId
.UniqueProcess
!= LogonProcess
)
45 DPRINT1("Current logon process 0x%x, can't deregister from process 0x%x\n",
46 LogonProcess
, ApiMessage
->Header
.ClientId
.UniqueProcess
);
47 return STATUS_NOT_LOGON_PROCESS
;
52 return STATUS_SUCCESS
;
55 CSR_API(CsrSetLogonNotifyWindow
)
59 if (0 == GetWindowThreadProcessId(ApiMessage
->Data
.SetLogonNotifyWindowRequest
.LogonNotifyWindow
,
62 DPRINT1("Can't get window creator\n");
63 return STATUS_INVALID_HANDLE
;
65 if (WindowCreator
!= (DWORD_PTR
)LogonProcess
)
67 DPRINT1("Trying to register window not created by winlogon as notify window\n");
68 return STATUS_ACCESS_DENIED
;
71 LogonNotifyWindow
= ApiMessage
->Data
.SetLogonNotifyWindowRequest
.LogonNotifyWindow
;
73 return STATUS_SUCCESS
;
76 typedef struct tagSHUTDOWN_SETTINGS
80 DWORD WaitToKillAppTimeout
;
81 } SHUTDOWN_SETTINGS
, *PSHUTDOWN_SETTINGS
;
83 #define DEFAULT_AUTO_END_TASKS FALSE
84 #define DEFAULT_HUNG_APP_TIMEOUT 5000
85 #define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
87 typedef struct tagNOTIFY_CONTEXT
101 PSHUTDOWN_SETTINGS ShutdownSettings
;
102 LPTHREAD_START_ROUTINE SendMessageProc
;
103 } NOTIFY_CONTEXT
, *PNOTIFY_CONTEXT
;
105 #define QUERY_RESULT_ABORT 0
106 #define QUERY_RESULT_CONTINUE 1
107 #define QUERY_RESULT_TIMEOUT 2
108 #define QUERY_RESULT_ERROR 3
109 #define QUERY_RESULT_FORCE 4
112 UpdateProgressBar(HWND ProgressBar
, PNOTIFY_CONTEXT NotifyContext
)
116 Passed
= GetTickCount() - NotifyContext
->StartTime
;
117 Passed
-= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
118 if (NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
< Passed
)
120 Passed
= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
122 SendMessageW(ProgressBar
, PBM_SETPOS
, Passed
/ 2, 0);
125 static INT_PTR CALLBACK
126 EndNowDlgProc(HWND Dlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
129 PNOTIFY_CONTEXT NotifyContext
;
138 NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
139 NotifyContext
->EndNowResult
= QUERY_RESULT_ABORT
;
140 SetWindowLongPtrW(Dlg
, DWLP_USER
, (LONG_PTR
) lParam
);
141 TitleLength
= SendMessageW(NotifyContext
->WndClient
, WM_GETTEXTLENGTH
,
143 GetWindowTextLengthW(Dlg
);
144 Title
= HeapAlloc(Win32CsrApiHeap
, 0, (TitleLength
+ 1) * sizeof(WCHAR
));
147 Len
= GetWindowTextW(Dlg
, Title
, TitleLength
+ 1);
148 SendMessageW(NotifyContext
->WndClient
, WM_GETTEXT
,
149 TitleLength
+ 1 - Len
, (LPARAM
) (Title
+ Len
));
150 SetWindowTextW(Dlg
, Title
);
151 HeapFree(Win32CsrApiHeap
, 0, Title
);
153 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
154 SendMessageW(ProgressBar
, PBM_SETRANGE32
, 0,
155 NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
/ 2);
156 UpdateProgressBar(ProgressBar
, NotifyContext
);
157 SetTimer(Dlg
, 0, 200, NULL
);
162 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
163 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
164 UpdateProgressBar(ProgressBar
, NotifyContext
);
169 if (BN_CLICKED
== HIWORD(wParam
) && IDC_END_NOW
== LOWORD(wParam
))
171 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
172 NotifyContext
->EndNowResult
= QUERY_RESULT_FORCE
;
173 SendMessageW(Dlg
, WM_CLOSE
, 0, 0);
188 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
189 NotifyContext
->Dlg
= NULL
;
191 PostQuitMessage(NotifyContext
->EndNowResult
);
203 typedef void (WINAPI
*INITCOMMONCONTROLS_PROC
)(void);
206 CallInitCommonControls()
208 static BOOL Initialized
= FALSE
;
210 INITCOMMONCONTROLS_PROC InitProc
;
217 Lib
= LoadLibraryW(L
"COMCTL32.DLL");
222 InitProc
= (INITCOMMONCONTROLS_PROC
) GetProcAddress(Lib
, "InitCommonControls");
223 if (NULL
== InitProc
)
234 EndNowThreadProc(LPVOID Parameter
)
236 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) Parameter
;
239 SetThreadDesktop(NotifyContext
->Desktop
);
240 SwitchDesktop(NotifyContext
->Desktop
);
241 CallInitCommonControls();
242 NotifyContext
->Dlg
= CreateDialogParam(GetModuleHandleW(L
"win32csr"),
243 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
244 EndNowDlgProc
, (LPARAM
) NotifyContext
);
245 if (NULL
== NotifyContext
->Dlg
)
249 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
251 while (GetMessageW(&Msg
, NULL
, 0, 0))
253 if (! IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
255 TranslateMessage(&Msg
);
256 DispatchMessageW(&Msg
);
263 typedef struct tagMESSAGE_CONTEXT
270 } MESSAGE_CONTEXT
, *PMESSAGE_CONTEXT
;
273 SendQueryEndSession(LPVOID Parameter
)
275 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
278 if (SendMessageTimeoutW(Context
->Wnd
, WM_QUERYENDSESSION
, Context
->wParam
,
279 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
282 return Result
? QUERY_RESULT_CONTINUE
: QUERY_RESULT_ABORT
;
285 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
289 SendEndSession(LPVOID Parameter
)
291 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
296 if (SendMessageTimeoutW(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
297 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
300 return QUERY_RESULT_CONTINUE
;
302 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
306 SendMessage(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
308 return QUERY_RESULT_CONTINUE
;
313 NotifyTopLevelEnum(HWND Wnd
, LPARAM lParam
)
315 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
316 MESSAGE_CONTEXT MessageContext
;
318 DWORD Timeout
, WaitStatus
;
320 HANDLE MessageThread
;
323 if (0 == GetWindowThreadProcessId(Wnd
, &ProcessId
))
325 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
329 if (ProcessId
== NotifyContext
->ProcessId
)
331 Now
= GetTickCount();
332 if (0 == NotifyContext
->StartTime
)
334 NotifyContext
->StartTime
= Now
;
336 /* Note: Passed is computed correctly even when GetTickCount() wraps due
337 to unsigned arithmetic */
338 Passed
= Now
- NotifyContext
->StartTime
;
339 MessageContext
.Wnd
= Wnd
;
340 MessageContext
.Msg
= NotifyContext
->Msg
;
341 MessageContext
.wParam
= NotifyContext
->wParam
;
342 MessageContext
.lParam
= NotifyContext
->lParam
;
343 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
344 if (! NotifyContext
->ShutdownSettings
->AutoEndTasks
)
346 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
348 if (Passed
< MessageContext
.Timeout
)
350 MessageContext
.Timeout
-= Passed
;
351 MessageThread
= CreateThread(NULL
, 0, NotifyContext
->SendMessageProc
,
352 (LPVOID
) &MessageContext
, 0, NULL
);
353 if (NULL
== MessageThread
)
355 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
358 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
359 if (Passed
< Timeout
)
362 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
366 WaitStatus
= WAIT_TIMEOUT
;
368 if (WAIT_TIMEOUT
== WaitStatus
)
370 NotifyContext
->WndClient
= Wnd
;
371 if (NULL
== NotifyContext
->UIThread
&& NotifyContext
->ShowUI
)
373 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
375 (LPVOID
) NotifyContext
,
378 Threads
[0] = MessageThread
;
379 Threads
[1] = NotifyContext
->UIThread
;
380 WaitStatus
= WaitForMultipleObjectsEx(NULL
== NotifyContext
->UIThread
?
382 Threads
, FALSE
, INFINITE
,
384 if (WAIT_OBJECT_0
== WaitStatus
)
386 if (! GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
388 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
391 else if (WAIT_OBJECT_0
+ 1 == WaitStatus
)
393 if (! GetExitCodeThread(NotifyContext
->UIThread
,
394 &NotifyContext
->QueryResult
))
396 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
401 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
403 if (WAIT_OBJECT_0
!= WaitStatus
)
405 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
408 else if (WAIT_OBJECT_0
== WaitStatus
)
410 if (! GetExitCodeThread(MessageThread
,
411 &NotifyContext
->QueryResult
))
413 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
418 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
420 CloseHandle(MessageThread
);
424 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
428 return QUERY_RESULT_CONTINUE
== NotifyContext
->QueryResult
;
432 NotifyDesktopEnum(LPWSTR DesktopName
, LPARAM lParam
)
434 PNOTIFY_CONTEXT Context
= (PNOTIFY_CONTEXT
) lParam
;
436 Context
->Desktop
= OpenDesktopW(DesktopName
, 0, FALSE
,
437 DESKTOP_ENUMERATE
| DESKTOP_SWITCHDESKTOP
);
438 if (NULL
== Context
->Desktop
)
440 DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
441 Context
->QueryResult
= QUERY_RESULT_ERROR
;
445 EnumDesktopWindows(Context
->Desktop
, NotifyTopLevelEnum
, lParam
);
447 CloseDesktop(Context
->Desktop
);
449 return QUERY_RESULT_CONTINUE
== Context
->QueryResult
;
453 NotifyTopLevelWindows(PNOTIFY_CONTEXT Context
)
455 HWINSTA WindowStation
;
457 WindowStation
= GetProcessWindowStation();
458 if (NULL
== WindowStation
)
460 DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
464 EnumDesktopsW(WindowStation
, NotifyDesktopEnum
, (LPARAM
) Context
);
470 NotifyAndTerminateProcess(PCSR_PROCESS ProcessData
,
471 PSHUTDOWN_SETTINGS ShutdownSettings
,
474 NOTIFY_CONTEXT Context
;
476 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
478 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
480 if (0 == (Flags
& EWX_FORCE
))
482 if (NULL
!= ProcessData
->Console
)
484 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, ProcessData
,
485 ShutdownSettings
->WaitToKillAppTimeout
);
489 Context
.ProcessId
= (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
;
491 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
492 ENDSESSION_LOGOFF
: 0);
493 Context
.StartTime
= 0;
494 Context
.UIThread
= NULL
;
495 Context
.ShowUI
= DtbgIsDesktopVisible();
497 Context
.ShutdownSettings
= ShutdownSettings
;
498 Context
.SendMessageProc
= SendQueryEndSession
;
500 NotifyTopLevelWindows(&Context
);
502 Context
.wParam
= (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
503 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
504 ENDSESSION_LOGOFF
: 0);
505 Context
.SendMessageProc
= SendEndSession
;
506 Context
.ShowUI
= DtbgIsDesktopVisible() &&
507 (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
508 QueryResult
= Context
.QueryResult
;
509 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
511 NotifyTopLevelWindows(&Context
);
513 if (NULL
!= Context
.UIThread
)
515 if (NULL
!= Context
.Dlg
)
517 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
521 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
523 CloseHandle(Context
.UIThread
);
527 if (QUERY_RESULT_ABORT
== QueryResult
)
533 /* Terminate this process */
534 Process
= OpenProcess(PROCESS_TERMINATE
, FALSE
,
535 (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
);
538 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ClientId
.UniqueProcess
,
542 TerminateProcess(Process
, 0);
543 CloseHandle(Process
);
548 typedef struct tagPROCESS_ENUM_CONTEXT
551 PCSR_PROCESS
*ProcessData
;
552 TOKEN_ORIGIN TokenOrigin
;
555 } PROCESS_ENUM_CONTEXT
, *PPROCESS_ENUM_CONTEXT
;
557 static NTSTATUS WINAPI
558 ExitReactosProcessEnum(PCSR_PROCESS ProcessData
, PVOID Data
)
564 PPROCESS_ENUM_CONTEXT Context
= (PPROCESS_ENUM_CONTEXT
) Data
;
565 PCSR_PROCESS
*NewData
;
567 /* Do not kill winlogon or csrss */
568 if ((DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
== Context
->CsrssProcess
||
569 ProcessData
->ClientId
.UniqueProcess
== LogonProcess
)
571 return STATUS_SUCCESS
;
574 /* Get the login session of this process */
575 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
,
576 (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
);
579 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ClientId
.UniqueProcess
,
581 return STATUS_UNSUCCESSFUL
;
584 if (! OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
586 DPRINT1("Unable to open token for process %d, error %d\n",
587 ProcessData
->ClientId
.UniqueProcess
, GetLastError());
588 CloseHandle(Process
);
589 return STATUS_UNSUCCESSFUL
;
591 CloseHandle(Process
);
593 if (! GetTokenInformation(Token
, TokenOrigin
, &Origin
,
594 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
596 DPRINT1("GetTokenInformation failed for process %d with error %d\n",
597 ProcessData
->ClientId
.UniqueProcess
, GetLastError());
599 return STATUS_UNSUCCESSFUL
;
603 /* This process will be killed if it's in the correct logon session */
604 if (RtlEqualLuid(&(Context
->TokenOrigin
.OriginatingLogonSession
),
605 &(Origin
.OriginatingLogonSession
)))
607 /* Kill the shell process last */
608 if ((DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
== Context
->ShellProcess
)
610 ProcessData
->ShutdownLevel
= 0;
612 NewData
= HeapAlloc(Win32CsrApiHeap
, 0, (Context
->ProcessCount
+ 1)
613 * sizeof(PCSR_PROCESS
));
616 return STATUS_NO_MEMORY
;
618 if (0 != Context
->ProcessCount
)
620 memcpy(NewData
, Context
->ProcessData
,
621 Context
->ProcessCount
* sizeof(PCSR_PROCESS
));
622 HeapFree(Win32CsrApiHeap
, 0, Context
->ProcessData
);
624 Context
->ProcessData
= NewData
;
625 Context
->ProcessData
[Context
->ProcessCount
] = ProcessData
;
626 Context
->ProcessCount
++;
629 return STATUS_SUCCESS
;
633 ProcessDataCompare(const void *Elem1
, const void *Elem2
)
635 const PCSR_PROCESS
*ProcessData1
= (PCSR_PROCESS
*) Elem1
;
636 const PCSR_PROCESS
*ProcessData2
= (PCSR_PROCESS
*) Elem2
;
638 if ((*ProcessData1
)->ShutdownLevel
< (*ProcessData2
)->ShutdownLevel
)
642 else if ((*ProcessData2
)->ShutdownLevel
< (*ProcessData1
)->ShutdownLevel
)
646 else if ((*ProcessData1
)->ClientId
.UniqueProcess
< (*ProcessData2
)->ClientId
.UniqueProcess
)
650 else if ((*ProcessData2
)->ClientId
.UniqueProcess
< (*ProcessData1
)->ClientId
.UniqueProcess
)
658 static DWORD FASTCALL
659 GetShutdownSetting(HKEY DesktopKey
, LPCWSTR ValueName
, DWORD DefaultValue
)
661 BYTE ValueBuffer
[16];
665 UNICODE_STRING StringValue
;
668 ValueSize
= sizeof(ValueBuffer
);
669 ErrCode
= RegQueryValueExW(DesktopKey
, ValueName
, NULL
, &Type
, ValueBuffer
,
671 if (ERROR_SUCCESS
!= ErrCode
)
673 DPRINT("GetShutdownSetting for %S failed with error code %ld\n",
680 RtlInitUnicodeString(&StringValue
, (LPCWSTR
) ValueBuffer
);
681 if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue
, 10, &Value
)))
683 DPRINT1("Unable to convert value %S for setting %S\n",
684 StringValue
.Buffer
, ValueName
);
687 return (DWORD
) Value
;
689 else if (REG_DWORD
== Type
)
691 return *((DWORD
*) ValueBuffer
);
694 DPRINT1("Unexpected registry type %d for setting %S\n", Type
, ValueName
);
699 LoadShutdownSettings(PSID Sid
, PSHUTDOWN_SETTINGS ShutdownSettings
)
701 static WCHAR Subkey
[] = L
"\\Control Panel\\Desktop";
703 WCHAR InitialKeyName
[128];
708 ShutdownSettings
->AutoEndTasks
= DEFAULT_AUTO_END_TASKS
;
709 ShutdownSettings
->HungAppTimeout
= DEFAULT_HUNG_APP_TIMEOUT
;
710 ShutdownSettings
->WaitToKillAppTimeout
= DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
;
712 if (! ConvertSidToStringSidW(Sid
, &StringSid
))
714 DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
718 if (wcslen(StringSid
) + wcslen(Subkey
) + 1 <=
719 sizeof(InitialKeyName
) / sizeof(WCHAR
))
721 KeyName
= InitialKeyName
;
725 KeyName
= HeapAlloc(Win32CsrApiHeap
, 0,
726 (wcslen(StringSid
) + wcslen(Subkey
) + 1) *
730 DPRINT1("Failed to allocate memory, using default shutdown settings\n");
731 LocalFree(StringSid
);
735 wcscat(wcscpy(KeyName
, StringSid
), Subkey
);
736 LocalFree(StringSid
);
738 ErrCode
= RegOpenKeyExW(HKEY_USERS
, KeyName
, 0, KEY_QUERY_VALUE
, &DesktopKey
);
739 if (KeyName
!= InitialKeyName
)
741 HeapFree(Win32CsrApiHeap
, 0, KeyName
);
743 if (ERROR_SUCCESS
!= ErrCode
)
745 DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode
);
749 ShutdownSettings
->AutoEndTasks
= (BOOL
) GetShutdownSetting(DesktopKey
, L
"AutoEndTasks",
750 (DWORD
) DEFAULT_AUTO_END_TASKS
);
751 ShutdownSettings
->HungAppTimeout
= GetShutdownSetting(DesktopKey
,
753 DEFAULT_HUNG_APP_TIMEOUT
);
754 ShutdownSettings
->WaitToKillAppTimeout
= GetShutdownSetting(DesktopKey
,
755 L
"WaitToKillAppTimeout",
756 DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
);
758 RegCloseKey(DesktopKey
);
761 static NTSTATUS FASTCALL
762 InternalExitReactos(DWORD ProcessId
, DWORD ThreadId
, UINT Flags
)
767 PROCESS_ENUM_CONTEXT Context
;
771 char FixedUserInfo
[64];
772 TOKEN_USER
*UserInfo
;
773 SHUTDOWN_SETTINGS ShutdownSettings
;
775 if (ProcessId
!= (DWORD_PTR
) LogonProcess
)
777 DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
778 return STATUS_ACCESS_DENIED
;
781 DPRINT1("FIXME: Need to close all user processes!\n");
782 return STATUS_SUCCESS
;
784 CallerThread
= OpenThread(THREAD_QUERY_INFORMATION
, FALSE
, ThreadId
);
785 if (NULL
== CallerThread
)
787 DPRINT1("OpenThread failed with error %d\n", GetLastError());
788 return STATUS_UNSUCCESSFUL
;
790 if (! OpenThreadToken(CallerThread
, TOKEN_QUERY
, FALSE
, &CallerToken
))
792 DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
793 CloseHandle(CallerThread
);
794 return STATUS_UNSUCCESSFUL
;
796 CloseHandle(CallerThread
);
798 Context
.ProcessCount
= 0;
799 Context
.ProcessData
= NULL
;
800 if (! GetTokenInformation(CallerToken
, TokenOrigin
, &Context
.TokenOrigin
,
801 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
803 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
804 CloseHandle(CallerToken
);
805 return STATUS_UNSUCCESSFUL
;
807 if (! GetTokenInformation(CallerToken
, TokenUser
, FixedUserInfo
,
808 sizeof(FixedUserInfo
), &ReturnLength
))
810 if (sizeof(FixedUserInfo
) < ReturnLength
)
812 UserInfo
= HeapAlloc(Win32CsrApiHeap
, 0, ReturnLength
);
813 if (NULL
== UserInfo
)
815 DPRINT1("Unable to allocate %u bytes for user info\n",
816 (unsigned) ReturnLength
);
817 CloseHandle(CallerToken
);
818 return STATUS_NO_MEMORY
;
820 if (! GetTokenInformation(CallerToken
, TokenUser
, UserInfo
,
821 ReturnLength
, &ReturnLength
))
823 DPRINT1("GetTokenInformation failed with error %d\n",
825 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
826 CloseHandle(CallerToken
);
827 return STATUS_UNSUCCESSFUL
;
832 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
833 CloseHandle(CallerToken
);
834 return STATUS_UNSUCCESSFUL
;
839 UserInfo
= (TOKEN_USER
*) FixedUserInfo
;
841 CloseHandle(CallerToken
);
842 LoadShutdownSettings(UserInfo
->User
.Sid
, &ShutdownSettings
);
843 if (UserInfo
!= (TOKEN_USER
*) FixedUserInfo
)
845 HeapFree(Win32CsrApiHeap
, 0, UserInfo
);
847 Context
.CsrssProcess
= GetCurrentProcessId();
848 ShellWnd
= GetShellWindow();
849 if (NULL
== ShellWnd
)
851 DPRINT("No shell present\n");
852 Context
.ShellProcess
= 0;
854 else if (0 == GetWindowThreadProcessId(ShellWnd
, &Context
.ShellProcess
))
856 DPRINT1("Can't get process id of shell window\n");
857 Context
.ShellProcess
= 0;
860 Status
= Win32CsrEnumProcesses(ExitReactosProcessEnum
, &Context
);
861 if (! NT_SUCCESS(Status
))
863 DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
865 if (NULL
!= Context
.ProcessData
)
867 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
872 qsort(Context
.ProcessData
, Context
.ProcessCount
, sizeof(PCSR_PROCESS
),
875 /* Terminate processes, stop if we find one kicking and screaming it doesn't
877 Status
= STATUS_SUCCESS
;
878 for (ProcessIndex
= 0;
879 ProcessIndex
< Context
.ProcessCount
&& NT_SUCCESS(Status
);
882 if (! NotifyAndTerminateProcess(Context
.ProcessData
[ProcessIndex
],
883 &ShutdownSettings
, Flags
))
885 Status
= STATUS_REQUEST_ABORTED
;
890 if (NULL
!= Context
.ProcessData
)
892 HeapFree(Win32CsrApiHeap
, 0, Context
.ProcessData
);
898 static NTSTATUS FASTCALL
899 UserExitReactos(DWORD UserProcessId
, UINT Flags
)
903 if (NULL
== LogonNotifyWindow
)
905 DPRINT1("No LogonNotifyWindow registered\n");
906 return STATUS_NOT_FOUND
;
909 /* FIXME Inside 2000 says we should impersonate the caller here */
910 Status
= SendMessageW(LogonNotifyWindow
, PM_WINLOGON_EXITWINDOWS
,
911 (WPARAM
) UserProcessId
,
913 /* If the message isn't handled, the return value is 0, so 0 doesn't indicate
914 success. Success is indicated by a 1 return value, if anything besides 0
915 or 1 it's a NTSTATUS value */
918 Status
= STATUS_SUCCESS
;
920 else if (0 == Status
)
922 Status
= STATUS_NOT_IMPLEMENTED
;
928 CSR_API(CsrExitReactos
)
930 if (0 == (ApiMessage
->Data
.ExitReactosRequest
.Flags
& EWX_INTERNAL_FLAG
))
932 return UserExitReactos((DWORD_PTR
) ApiMessage
->Header
.ClientId
.UniqueProcess
,
933 ApiMessage
->Data
.ExitReactosRequest
.Flags
);
937 return InternalExitReactos((DWORD_PTR
) ApiMessage
->Header
.ClientId
.UniqueProcess
,
938 (DWORD_PTR
) ApiMessage
->Header
.ClientId
.UniqueThread
,
939 ApiMessage
->Data
.ExitReactosRequest
.Flags
);