2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS User API Server DLL
4 * FILE: win32ss/user/winsrv/shutdown.c
5 * PURPOSE: Logout/shutdown
8 * NOTE: The shutdown code must be rewritten completely. (hbelusca)
11 /* INCLUDES *******************************************************************/
19 /* GLOBALS ********************************************************************/
21 typedef struct tagSHUTDOWN_SETTINGS
25 DWORD WaitToKillAppTimeout
;
26 } SHUTDOWN_SETTINGS
, *PSHUTDOWN_SETTINGS
;
28 #define DEFAULT_AUTO_END_TASKS FALSE
29 #define DEFAULT_HUNG_APP_TIMEOUT 5000
30 #define DEFAULT_WAIT_TO_KILL_APP_TIMEOUT 20000
32 typedef struct tagNOTIFY_CONTEXT
47 PSHUTDOWN_SETTINGS ShutdownSettings
;
48 LPTHREAD_START_ROUTINE SendMessageProc
;
49 } NOTIFY_CONTEXT
, *PNOTIFY_CONTEXT
;
51 #define QUERY_RESULT_ABORT 0
52 #define QUERY_RESULT_CONTINUE 1
53 #define QUERY_RESULT_TIMEOUT 2
54 #define QUERY_RESULT_ERROR 3
55 #define QUERY_RESULT_FORCE 4
57 typedef void (WINAPI
*INITCOMMONCONTROLS_PROC
)(void);
59 typedef struct tagMESSAGE_CONTEXT
66 } MESSAGE_CONTEXT
, *PMESSAGE_CONTEXT
;
68 typedef struct tagPROCESS_ENUM_CONTEXT
71 PCSR_PROCESS
*ProcessData
;
72 TOKEN_ORIGIN TokenOrigin
;
75 } PROCESS_ENUM_CONTEXT
, *PPROCESS_ENUM_CONTEXT
;
78 /* FUNCTIONS ******************************************************************/
82 Win32CsrEnumProcesses(CSRSS_ENUM_PROCESS_PROC EnumProc,
85 return CsrEnumProcesses(EnumProc, Context);
90 UpdateProgressBar(HWND ProgressBar
, PNOTIFY_CONTEXT NotifyContext
)
94 Passed
= GetTickCount() - NotifyContext
->StartTime
;
95 Passed
-= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
96 if (NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
< Passed
)
98 Passed
= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
100 SendMessageW(ProgressBar
, PBM_SETPOS
, Passed
/ 2, 0);
103 static INT_PTR CALLBACK
104 EndNowDlgProc(HWND Dlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
107 PNOTIFY_CONTEXT NotifyContext
;
116 NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
117 NotifyContext
->EndNowResult
= QUERY_RESULT_ABORT
;
118 SetWindowLongPtrW(Dlg
, DWLP_USER
, (LONG_PTR
) lParam
);
119 TitleLength
= SendMessageW(NotifyContext
->WndClient
, WM_GETTEXTLENGTH
,
121 GetWindowTextLengthW(Dlg
);
122 Title
= HeapAlloc(UserServerHeap
, 0, (TitleLength
+ 1) * sizeof(WCHAR
));
125 Len
= GetWindowTextW(Dlg
, Title
, TitleLength
+ 1);
126 SendMessageW(NotifyContext
->WndClient
, WM_GETTEXT
,
127 TitleLength
+ 1 - Len
, (LPARAM
) (Title
+ Len
));
128 SetWindowTextW(Dlg
, Title
);
129 HeapFree(UserServerHeap
, 0, Title
);
131 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
132 SendMessageW(ProgressBar
, PBM_SETRANGE32
, 0,
133 NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
/ 2);
134 UpdateProgressBar(ProgressBar
, NotifyContext
);
135 SetTimer(Dlg
, 0, 200, NULL
);
140 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
141 ProgressBar
= GetDlgItem(Dlg
, IDC_PROGRESS
);
142 UpdateProgressBar(ProgressBar
, NotifyContext
);
147 if (BN_CLICKED
== HIWORD(wParam
) && IDC_END_NOW
== LOWORD(wParam
))
149 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
150 NotifyContext
->EndNowResult
= QUERY_RESULT_FORCE
;
151 SendMessageW(Dlg
, WM_CLOSE
, 0, 0);
166 NotifyContext
= (PNOTIFY_CONTEXT
) GetWindowLongPtrW(Dlg
, DWLP_USER
);
167 NotifyContext
->Dlg
= NULL
;
169 PostQuitMessage(NotifyContext
->EndNowResult
);
182 CallInitCommonControls()
184 static BOOL Initialized
= FALSE
;
186 INITCOMMONCONTROLS_PROC InitProc
;
188 if (Initialized
) return;
190 Lib
= LoadLibraryW(L
"COMCTL32.DLL");
191 if (NULL
== Lib
) return;
193 InitProc
= (INITCOMMONCONTROLS_PROC
) GetProcAddress(Lib
, "InitCommonControls");
194 if (NULL
== InitProc
) return;
202 EndNowThreadProc(LPVOID Parameter
)
204 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) Parameter
;
207 SetThreadDesktop(NotifyContext
->Desktop
);
208 SwitchDesktop(NotifyContext
->Desktop
);
209 CallInitCommonControls();
210 NotifyContext
->Dlg
= CreateDialogParam(UserServerDllInstance
,
211 MAKEINTRESOURCE(IDD_END_NOW
), NULL
,
212 EndNowDlgProc
, (LPARAM
) NotifyContext
);
213 if (NULL
== NotifyContext
->Dlg
)
217 ShowWindow(NotifyContext
->Dlg
, SW_SHOWNORMAL
);
219 while (GetMessageW(&Msg
, NULL
, 0, 0))
221 if (! IsDialogMessage(NotifyContext
->Dlg
, &Msg
))
223 TranslateMessage(&Msg
);
224 DispatchMessageW(&Msg
);
232 SendQueryEndSession(LPVOID Parameter
)
234 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
237 if (SendMessageTimeoutW(Context
->Wnd
, WM_QUERYENDSESSION
, Context
->wParam
,
238 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
241 return Result
? QUERY_RESULT_CONTINUE
: QUERY_RESULT_ABORT
;
244 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
248 SendEndSession(LPVOID Parameter
)
250 PMESSAGE_CONTEXT Context
= (PMESSAGE_CONTEXT
) Parameter
;
255 if (SendMessageTimeoutW(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
256 Context
->lParam
, SMTO_NORMAL
, Context
->Timeout
,
259 return QUERY_RESULT_CONTINUE
;
261 return 0 == GetLastError() ? QUERY_RESULT_TIMEOUT
: QUERY_RESULT_ERROR
;
265 SendMessage(Context
->Wnd
, WM_ENDSESSION
, Context
->wParam
,
267 return QUERY_RESULT_CONTINUE
;
272 NotifyTopLevelEnum(HWND Wnd
, LPARAM lParam
)
274 PNOTIFY_CONTEXT NotifyContext
= (PNOTIFY_CONTEXT
) lParam
;
275 MESSAGE_CONTEXT MessageContext
;
277 DWORD Timeout
, WaitStatus
;
279 HANDLE MessageThread
;
282 if (0 == GetWindowThreadProcessId(Wnd
, &ProcessId
))
284 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
288 if (ProcessId
== NotifyContext
->ProcessId
)
290 Now
= GetTickCount();
291 if (0 == NotifyContext
->StartTime
)
293 NotifyContext
->StartTime
= Now
;
295 /* Note: Passed is computed correctly even when GetTickCount() wraps due
296 to unsigned arithmetic */
297 Passed
= Now
- NotifyContext
->StartTime
;
298 MessageContext
.Wnd
= Wnd
;
299 MessageContext
.Msg
= NotifyContext
->Msg
;
300 MessageContext
.wParam
= NotifyContext
->wParam
;
301 MessageContext
.lParam
= NotifyContext
->lParam
;
302 MessageContext
.Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
303 if (! NotifyContext
->ShutdownSettings
->AutoEndTasks
)
305 MessageContext
.Timeout
+= NotifyContext
->ShutdownSettings
->WaitToKillAppTimeout
;
307 if (Passed
< MessageContext
.Timeout
)
309 MessageContext
.Timeout
-= Passed
;
310 MessageThread
= CreateThread(NULL
, 0, NotifyContext
->SendMessageProc
,
311 (LPVOID
) &MessageContext
, 0, NULL
);
312 if (NULL
== MessageThread
)
314 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
317 Timeout
= NotifyContext
->ShutdownSettings
->HungAppTimeout
;
318 if (Passed
< Timeout
)
321 WaitStatus
= WaitForSingleObjectEx(MessageThread
, Timeout
, FALSE
);
325 WaitStatus
= WAIT_TIMEOUT
;
327 if (WAIT_TIMEOUT
== WaitStatus
)
329 NotifyContext
->WndClient
= Wnd
;
330 if (NULL
== NotifyContext
->UIThread
&& NotifyContext
->ShowUI
)
332 NotifyContext
->UIThread
= CreateThread(NULL
, 0,
334 (LPVOID
) NotifyContext
,
337 Threads
[0] = MessageThread
;
338 Threads
[1] = NotifyContext
->UIThread
;
339 WaitStatus
= WaitForMultipleObjectsEx(NULL
== NotifyContext
->UIThread
?
341 Threads
, FALSE
, INFINITE
,
343 if (WAIT_OBJECT_0
== WaitStatus
)
345 if (! GetExitCodeThread(MessageThread
, &NotifyContext
->QueryResult
))
347 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
350 else if (WAIT_OBJECT_0
+ 1 == WaitStatus
)
352 if (! GetExitCodeThread(NotifyContext
->UIThread
,
353 &NotifyContext
->QueryResult
))
355 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
360 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
362 if (WAIT_OBJECT_0
!= WaitStatus
)
364 TerminateThread(MessageThread
, QUERY_RESULT_TIMEOUT
);
367 else if (WAIT_OBJECT_0
== WaitStatus
)
369 if (! GetExitCodeThread(MessageThread
,
370 &NotifyContext
->QueryResult
))
372 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
377 NotifyContext
->QueryResult
= QUERY_RESULT_ERROR
;
379 CloseHandle(MessageThread
);
383 NotifyContext
->QueryResult
= QUERY_RESULT_TIMEOUT
;
387 return QUERY_RESULT_CONTINUE
== NotifyContext
->QueryResult
;
391 NotifyDesktopEnum(LPWSTR DesktopName
, LPARAM lParam
)
393 PNOTIFY_CONTEXT Context
= (PNOTIFY_CONTEXT
) lParam
;
395 Context
->Desktop
= OpenDesktopW(DesktopName
, 0, FALSE
,
396 DESKTOP_ENUMERATE
| DESKTOP_SWITCHDESKTOP
);
397 if (NULL
== Context
->Desktop
)
399 DPRINT1("OpenDesktop failed with error %d\n", GetLastError());
400 Context
->QueryResult
= QUERY_RESULT_ERROR
;
404 Context
->OldDesktop
= GetThreadDesktop(GetCurrentThreadId());
405 SwitchDesktop(Context
->Desktop
);
407 EnumDesktopWindows(Context
->Desktop
, NotifyTopLevelEnum
, lParam
);
409 SwitchDesktop(Context
->OldDesktop
);
411 CloseDesktop(Context
->Desktop
);
413 return QUERY_RESULT_CONTINUE
== Context
->QueryResult
;
417 NotifyTopLevelWindows(PNOTIFY_CONTEXT Context
)
419 HWINSTA WindowStation
;
421 WindowStation
= GetProcessWindowStation();
422 if (NULL
== WindowStation
)
424 DPRINT1("GetProcessWindowStation failed with error %d\n", GetLastError());
428 EnumDesktopsW(WindowStation
, NotifyDesktopEnum
, (LPARAM
) Context
);
433 /*** Taken from win32ss/user/consrv/console.c ***/
435 DtbgIsDesktopVisible(VOID
)
437 return !((BOOL
)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE
));
440 /* TODO: Find an other way to do it. */
443 ConioConsoleCtrlEventTimeout(DWORD Event
, PCSR_PROCESS ProcessData
, DWORD Timeout
)
447 DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData
->ClientId
.UniqueProcess
);
449 if (ProcessData
->CtrlDispatcher
)
452 Thread
= CreateRemoteThread(ProcessData
->ProcessHandle
, NULL
, 0,
453 (LPTHREAD_START_ROUTINE
) ProcessData
->CtrlDispatcher
,
454 UlongToPtr(Event
), 0, NULL
);
457 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
460 WaitForSingleObject(Thread
, Timeout
);
465 /************************************************/
468 NotifyAndTerminateProcess(PCSR_PROCESS ProcessData
,
469 PSHUTDOWN_SETTINGS ShutdownSettings
,
472 NOTIFY_CONTEXT Context
;
474 DWORD QueryResult
= QUERY_RESULT_CONTINUE
;
476 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
478 if (0 == (Flags
& EWX_FORCE
))
480 // TODO: Find an other way whether or not the process has a console.
482 if (NULL
!= ProcessData
->Console
)
484 ConioConsoleCtrlEventTimeout(CTRL_LOGOFF_EVENT
, ProcessData
,
485 ShutdownSettings
->WaitToKillAppTimeout
);
490 Context
.ProcessId
= (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
;
492 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
493 ENDSESSION_LOGOFF
: 0);
494 Context
.StartTime
= 0;
495 Context
.UIThread
= NULL
;
496 Context
.ShowUI
= DtbgIsDesktopVisible();
498 Context
.ShutdownSettings
= ShutdownSettings
;
499 Context
.SendMessageProc
= SendQueryEndSession
;
501 NotifyTopLevelWindows(&Context
);
503 Context
.wParam
= (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
504 Context
.lParam
= (0 != (Flags
& EWX_INTERNAL_FLAG_LOGOFF
) ?
505 ENDSESSION_LOGOFF
: 0);
506 Context
.SendMessageProc
= SendEndSession
;
507 Context
.ShowUI
= DtbgIsDesktopVisible() &&
508 (QUERY_RESULT_ABORT
!= Context
.QueryResult
);
509 QueryResult
= Context
.QueryResult
;
510 Context
.QueryResult
= QUERY_RESULT_CONTINUE
;
512 NotifyTopLevelWindows(&Context
);
514 if (NULL
!= Context
.UIThread
)
516 if (NULL
!= Context
.Dlg
)
518 SendMessageW(Context
.Dlg
, WM_CLOSE
, 0, 0);
522 TerminateThread(Context
.UIThread
, QUERY_RESULT_ERROR
);
524 CloseHandle(Context
.UIThread
);
528 if (QUERY_RESULT_ABORT
== QueryResult
)
534 /* Terminate this process */
535 Process
= OpenProcess(PROCESS_TERMINATE
, FALSE
,
536 (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
);
539 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ClientId
.UniqueProcess
,
543 TerminateProcess(Process
, 0);
544 CloseHandle(Process
);
550 static NTSTATUS WINAPI
551 ExitReactosProcessEnum(PCSR_PROCESS ProcessData
, PVOID Data
)
557 PPROCESS_ENUM_CONTEXT Context
= (PPROCESS_ENUM_CONTEXT
) Data
;
558 PCSR_PROCESS
*NewData
;
560 /* Do not kill winlogon or csrss */
561 if ((DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
== Context
->CsrssProcess
||
562 ProcessData
->ClientId
.UniqueProcess
== LogonProcessId
)
564 return STATUS_SUCCESS
;
567 /* Get the login session of this process */
568 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
,
569 (DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
);
572 DPRINT1("Unable to open process %d, error %d\n", ProcessData
->ClientId
.UniqueProcess
,
574 return STATUS_UNSUCCESSFUL
;
577 if (! OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
579 DPRINT1("Unable to open token for process %d, error %d\n",
580 ProcessData
->ClientId
.UniqueProcess
, GetLastError());
581 CloseHandle(Process
);
582 return STATUS_UNSUCCESSFUL
;
584 CloseHandle(Process
);
586 if (! GetTokenInformation(Token
, TokenOrigin
, &Origin
,
587 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
589 DPRINT1("GetTokenInformation failed for process %d with error %d\n",
590 ProcessData
->ClientId
.UniqueProcess
, GetLastError());
592 return STATUS_UNSUCCESSFUL
;
596 /* This process will be killed if it's in the correct logon session */
597 if (RtlEqualLuid(&(Context
->TokenOrigin
.OriginatingLogonSession
),
598 &(Origin
.OriginatingLogonSession
)))
600 /* Kill the shell process last */
601 if ((DWORD_PTR
) ProcessData
->ClientId
.UniqueProcess
== Context
->ShellProcess
)
603 ProcessData
->ShutdownLevel
= 0;
605 NewData
= HeapAlloc(UserServerHeap
, 0, (Context
->ProcessCount
+ 1)
606 * sizeof(PCSR_PROCESS
));
609 return STATUS_NO_MEMORY
;
611 if (0 != Context
->ProcessCount
)
613 memcpy(NewData
, Context
->ProcessData
,
614 Context
->ProcessCount
* sizeof(PCSR_PROCESS
));
615 HeapFree(UserServerHeap
, 0, Context
->ProcessData
);
617 Context
->ProcessData
= NewData
;
618 Context
->ProcessData
[Context
->ProcessCount
] = ProcessData
;
619 Context
->ProcessCount
++;
622 return STATUS_SUCCESS
;
627 ProcessDataCompare(const void *Elem1
, const void *Elem2
)
629 const PCSR_PROCESS
*ProcessData1
= (PCSR_PROCESS
*) Elem1
;
630 const PCSR_PROCESS
*ProcessData2
= (PCSR_PROCESS
*) Elem2
;
632 if ((*ProcessData1
)->ShutdownLevel
< (*ProcessData2
)->ShutdownLevel
)
636 else if ((*ProcessData2
)->ShutdownLevel
< (*ProcessData1
)->ShutdownLevel
)
640 else if ((*ProcessData1
)->ClientId
.UniqueProcess
< (*ProcessData2
)->ClientId
.UniqueProcess
)
644 else if ((*ProcessData2
)->ClientId
.UniqueProcess
< (*ProcessData1
)->ClientId
.UniqueProcess
)
652 static DWORD FASTCALL
653 GetShutdownSettings(HKEY DesktopKey
, LPCWSTR ValueName
, DWORD DefaultValue
)
655 BYTE ValueBuffer
[16];
659 UNICODE_STRING StringValue
;
662 ValueSize
= sizeof(ValueBuffer
);
663 ErrCode
= RegQueryValueExW(DesktopKey
, ValueName
, NULL
, &Type
, ValueBuffer
,
665 if (ERROR_SUCCESS
!= ErrCode
)
667 DPRINT("GetShutdownSettings for %S failed with error code %ld\n",
674 RtlInitUnicodeString(&StringValue
, (LPCWSTR
) ValueBuffer
);
675 if (! NT_SUCCESS(RtlUnicodeStringToInteger(&StringValue
, 10, &Value
)))
677 DPRINT1("Unable to convert value %S for setting %S\n",
678 StringValue
.Buffer
, ValueName
);
681 return (DWORD
) Value
;
683 else if (REG_DWORD
== Type
)
685 return *((DWORD
*) ValueBuffer
);
688 DPRINT1("Unexpected registry type %d for setting %S\n", Type
, ValueName
);
693 LoadShutdownSettings(PSID Sid
, PSHUTDOWN_SETTINGS ShutdownSettings
)
695 static WCHAR Subkey
[] = L
"\\Control Panel\\Desktop";
697 WCHAR InitialKeyName
[128];
702 ShutdownSettings
->AutoEndTasks
= DEFAULT_AUTO_END_TASKS
;
703 ShutdownSettings
->HungAppTimeout
= DEFAULT_HUNG_APP_TIMEOUT
;
704 ShutdownSettings
->WaitToKillAppTimeout
= DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
;
706 if (! ConvertSidToStringSidW(Sid
, &StringSid
))
708 DPRINT1("ConvertSidToStringSid failed with error %d, using default shutdown settings\n",
712 if (wcslen(StringSid
) + wcslen(Subkey
) + 1 <=
713 sizeof(InitialKeyName
) / sizeof(WCHAR
))
715 KeyName
= InitialKeyName
;
719 KeyName
= HeapAlloc(UserServerHeap
, 0,
720 (wcslen(StringSid
) + wcslen(Subkey
) + 1) *
724 DPRINT1("Failed to allocate memory, using default shutdown settings\n");
725 LocalFree(StringSid
);
729 wcscat(wcscpy(KeyName
, StringSid
), Subkey
);
730 LocalFree(StringSid
);
732 ErrCode
= RegOpenKeyExW(HKEY_USERS
, KeyName
, 0, KEY_QUERY_VALUE
, &DesktopKey
);
733 if (KeyName
!= InitialKeyName
)
735 HeapFree(UserServerHeap
, 0, KeyName
);
737 if (ERROR_SUCCESS
!= ErrCode
)
739 DPRINT1("RegOpenKeyEx failed with error %ld, using default shutdown settings\n", ErrCode
);
743 ShutdownSettings
->AutoEndTasks
= (BOOL
) GetShutdownSettings(DesktopKey
, L
"AutoEndTasks",
744 (DWORD
) DEFAULT_AUTO_END_TASKS
);
745 ShutdownSettings
->HungAppTimeout
= GetShutdownSettings(DesktopKey
,
747 DEFAULT_HUNG_APP_TIMEOUT
);
748 ShutdownSettings
->WaitToKillAppTimeout
= GetShutdownSettings(DesktopKey
,
749 L
"WaitToKillAppTimeout",
750 DEFAULT_WAIT_TO_KILL_APP_TIMEOUT
);
752 RegCloseKey(DesktopKey
);
755 static NTSTATUS FASTCALL
756 InternalExitReactos(DWORD ProcessId
, DWORD ThreadId
, UINT Flags
)
761 PROCESS_ENUM_CONTEXT Context
;
765 char FixedUserInfo
[64];
766 TOKEN_USER
*UserInfo
;
767 SHUTDOWN_SETTINGS ShutdownSettings
;
769 if (ProcessId
!= (DWORD_PTR
) LogonProcessId
)
771 DPRINT1("Internal ExitWindowsEx call not from winlogon\n");
772 return STATUS_ACCESS_DENIED
;
775 DPRINT1("FIXME: Need to close all user processes!\n");
776 return STATUS_SUCCESS
;
778 CallerThread
= OpenThread(THREAD_QUERY_INFORMATION
, FALSE
, ThreadId
);
779 if (NULL
== CallerThread
)
781 DPRINT1("OpenThread failed with error %d\n", GetLastError());
782 return STATUS_UNSUCCESSFUL
;
784 if (! OpenThreadToken(CallerThread
, TOKEN_QUERY
, FALSE
, &CallerToken
))
786 DPRINT1("OpenThreadToken failed with error %d\n", GetLastError());
787 CloseHandle(CallerThread
);
788 return STATUS_UNSUCCESSFUL
;
790 CloseHandle(CallerThread
);
792 Context
.ProcessCount
= 0;
793 Context
.ProcessData
= NULL
;
794 if (! GetTokenInformation(CallerToken
, TokenOrigin
, &Context
.TokenOrigin
,
795 sizeof(TOKEN_ORIGIN
), &ReturnLength
))
797 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
798 CloseHandle(CallerToken
);
799 return STATUS_UNSUCCESSFUL
;
801 if (! GetTokenInformation(CallerToken
, TokenUser
, FixedUserInfo
,
802 sizeof(FixedUserInfo
), &ReturnLength
))
804 if (sizeof(FixedUserInfo
) < ReturnLength
)
806 UserInfo
= HeapAlloc(UserServerHeap
, 0, ReturnLength
);
807 if (NULL
== UserInfo
)
809 DPRINT1("Unable to allocate %u bytes for user info\n",
810 (unsigned) ReturnLength
);
811 CloseHandle(CallerToken
);
812 return STATUS_NO_MEMORY
;
814 if (! GetTokenInformation(CallerToken
, TokenUser
, UserInfo
,
815 ReturnLength
, &ReturnLength
))
817 DPRINT1("GetTokenInformation failed with error %d\n",
819 HeapFree(UserServerHeap
, 0, UserInfo
);
820 CloseHandle(CallerToken
);
821 return STATUS_UNSUCCESSFUL
;
826 DPRINT1("GetTokenInformation failed with error %d\n", GetLastError());
827 CloseHandle(CallerToken
);
828 return STATUS_UNSUCCESSFUL
;
833 UserInfo
= (TOKEN_USER
*) FixedUserInfo
;
835 CloseHandle(CallerToken
);
836 LoadShutdownSettings(UserInfo
->User
.Sid
, &ShutdownSettings
);
837 if (UserInfo
!= (TOKEN_USER
*) FixedUserInfo
)
839 HeapFree(UserServerHeap
, 0, UserInfo
);
841 Context
.CsrssProcess
= GetCurrentProcessId();
842 ShellWnd
= GetShellWindow();
843 if (NULL
== ShellWnd
)
845 DPRINT("No shell present\n");
846 Context
.ShellProcess
= 0;
848 else if (0 == GetWindowThreadProcessId(ShellWnd
, &Context
.ShellProcess
))
850 DPRINT1("Can't get process id of shell window\n");
851 Context
.ShellProcess
= 0;
854 // Status = Win32CsrEnumProcesses(ExitReactosProcessEnum, &Context);
855 if (! NT_SUCCESS(Status
))
857 DPRINT1("Failed to enumerate registered processes, status 0x%x\n",
859 if (NULL
!= Context
.ProcessData
)
861 HeapFree(UserServerHeap
, 0, Context
.ProcessData
);
866 qsort(Context
.ProcessData
, Context
.ProcessCount
, sizeof(PCSR_PROCESS
),
869 /* Terminate processes, stop if we find one kicking and screaming it doesn't
871 Status
= STATUS_SUCCESS
;
872 for (ProcessIndex
= 0;
873 ProcessIndex
< Context
.ProcessCount
&& NT_SUCCESS(Status
);
876 if (! NotifyAndTerminateProcess(Context
.ProcessData
[ProcessIndex
],
877 &ShutdownSettings
, Flags
))
879 Status
= STATUS_REQUEST_ABORTED
;
884 if (NULL
!= Context
.ProcessData
)
886 HeapFree(UserServerHeap
, 0, Context
.ProcessData
);
892 static NTSTATUS FASTCALL
893 UserExitReactos(DWORD UserProcessId
, UINT Flags
)
897 /* FIXME Inside 2000 says we should impersonate the caller here */
898 Status
= NtUserCallTwoParam(UserProcessId
, Flags
, TWOPARAM_ROUTINE_EXITREACTOS
);
900 /* If the message isn't handled, the return value is 0, so 0 doesn't indicate
901 success. Success is indicated by a 1 return value, if anything besides 0
902 or 1 it's a NTSTATUS value */
905 Status
= STATUS_SUCCESS
;
907 else if (0 == Status
)
909 Status
= STATUS_NOT_IMPLEMENTED
;
916 /* PUBLIC SERVER APIS *********************************************************/
918 CSR_API(SrvExitWindowsEx
)
920 PUSER_EXIT_REACTOS ExitReactosRequest
= &((PUSER_API_MESSAGE
)ApiMessage
)->Data
.ExitReactosRequest
;
922 if (0 == (ExitReactosRequest
->Flags
& EWX_INTERNAL_FLAG
))
924 return UserExitReactos((DWORD_PTR
) ApiMessage
->Header
.ClientId
.UniqueProcess
,
925 ExitReactosRequest
->Flags
);
929 return InternalExitReactos((DWORD_PTR
) ApiMessage
->Header
.ClientId
.UniqueProcess
,
930 (DWORD_PTR
) ApiMessage
->Header
.ClientId
.UniqueThread
,
931 ExitReactosRequest
->Flags
);