Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

exitwin.c File Reference

#include "precomp.h"

Go to the source code of this file.

Defines

#define BEGIN_LPC_RECV(API)
#define END_LPC_RECV()
#define CCHMSGMAX   256
#define CCHBODYMAX   512
#define CSR_THREAD_SHUTDOWNSKIP   0x00000008
#define ESMH_CANCELEVENT   0
#define ESMH_THREAD   1
#define ESMH_HANDLECOUNT   2

Functions

BOOL WowExitTask (PCSR_THREAD pcsrt)
NTSTATUS UserClientShutdown (PCSR_PROCESS pcsrp, ULONG dwFlags, BOOLEAN fFirstPass)
NTSTATUS _ExitWindowsEx (PCSR_THREAD pcsrt, UINT dwFlags, DWORD dwReserved)
VOID CALLBACK WMCSCallback (HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult)
HWND GetInputWindow (PCSR_THREAD pcsrt, HWND hwnd)
void GetApplicationText (HWND hwnd, HANDLE hThread, WCHAR *pwcText, UINT uLen)
DWORD ThreadShutdownNotify (DWORD dwClientFlags, ULONG_PTR dwThread, LPARAM lParam)
void SetEndTaskDlgStatus (ENDDLGPARAMS *pedp, HWND hwndDlg, UINT uStrId, BOOL fInit)
INT_PTR APIENTRY EndTaskDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
BOOL _EndTask (HWND hwnd, BOOL fShutdown, BOOL fMeanKill)
DWORD InternalWaitCancel (HANDLE handle, DWORD dwMilliseconds)
HANDLE InternalCreateCallbackThread (HANDLE hProcess, ULONG_PTR lpfn, ULONG_PTR dwData)
ULONG SrvExitWindowsEx (IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus)
ULONG SrvEndTask (IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus)
BOOL IsPrivileged (PPRIVILEGE_SET ppSet)
ULONG SrvRegisterServicesProcess (IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus)


Define Documentation

#define BEGIN_LPC_RECV API   ) 
 

Value:

P##API##MSG a = (P##API##MSG)&m->u.ApiMessageData; \ PCSR_THREAD pcsrt; \ PTEB Teb = NtCurrentTeb(); \ NTSTATUS Status = STATUS_SUCCESS; \ UNREFERENCED_PARAMETER(ReplyStatus); \ \ Teb->LastErrorValue = 0; \ pcsrt = CSR_SERVER_QUERYCLIENTTHREAD();

Definition at line 16 of file server/exitwin.c.

Referenced by SrvExitWindowsEx(), and SrvRegisterServicesProcess().

#define CCHBODYMAX   512
 

Definition at line 31 of file server/exitwin.c.

Referenced by EndTaskDlgProc(), and ThreadShutdownNotify().

#define CCHMSGMAX   256
 

Definition at line 30 of file server/exitwin.c.

#define CSR_THREAD_SHUTDOWNSKIP   0x00000008
 

Definition at line 33 of file server/exitwin.c.

Referenced by UserClientShutdown().

 
#define END_LPC_RECV  ) 
 

Value:

a->dwLastError = Teb->LastErrorValue; \ return Status;

Definition at line 26 of file server/exitwin.c.

Referenced by SrvExitWindowsEx(), and SrvRegisterServicesProcess().

#define ESMH_CANCELEVENT   0
 

Referenced by ThreadShutdownNotify().

#define ESMH_HANDLECOUNT   2
 

Referenced by ThreadShutdownNotify().

#define ESMH_THREAD   1
 

Referenced by ThreadShutdownNotify().


Function Documentation

BOOL _EndTask HWND  hwnd,
BOOL  fShutdown,
BOOL  fMeanKill
 

Definition at line 1601 of file server/exitwin.c.

References BOOL, DebugPort, DWORD, FALSE, GetWindowLongPtr(), GetWindowThreadProcessId(), ghModuleWin, gIdLogon, ISTS, NT_SUCCESS, NtQueryInformationProcess(), NTSTATUS(), NtTerminateProcess(), NtUserSetInformationThread(), NULL, PostMessage(), ServerLoadString, Status, ThreadShutdownNotify(), TRUE, TSN_APPSAYSNOTOK, TSN_USERSAYSCANCEL, WMCS_ENDTASK, and WowExitTask().

Referenced by SrvEndTask().

01605 { 01606 BOOL fRet = TRUE; 01607 PCSR_THREAD pcsrt = CSR_SERVER_QUERYCLIENTTHREAD(); 01608 PCSR_THREAD pcsrtKill; 01609 DWORD dwThreadId; 01610 DWORD dwProcessId; 01611 LPWSTR lpszMsg; 01612 BOOL fAllocated; 01613 DWORD dwCmd; 01614 USERTHREAD_USEDESKTOPINFO utudi; 01615 NTSTATUS Status; 01616 01617 /* 01618 * Note: fShutdown isn't used for anything in this routine! 01619 * They are still there because I haven't removed them: the old endtask 01620 * code relied on them. 01621 */ 01622 UNREFERENCED_PARAMETER(fShutdown); 01623 01624 /* 01625 * Set the current work thread to a desktop so we can 01626 * go safely into win32k.sys 01627 */ 01628 utudi.hThread = pcsrt->ThreadHandle; 01629 utudi.drdRestore.pdeskRestore = NULL; 01630 01631 Status = NtUserSetInformationThread(NtCurrentThread(), 01632 UserThreadUseDesktop, &utudi, sizeof(utudi)); 01633 if (!NT_SUCCESS(Status)) { 01634 /* 01635 * We were unable to get the thread's desktop. Game over 01636 */ 01637 return TRUE; 01638 } 01639 01640 01641 /* 01642 * Get the process and thread that owns hwnd. 01643 */ 01644 dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId); 01645 if (dwThreadId == 0) { 01646 goto RestoreDesktop; 01647 } 01648 01649 /* 01650 * Don't allow destruction of winlogon 01651 */ 01652 if (dwProcessId == gIdLogon) { 01653 goto RestoreDesktop; 01654 } 01655 01656 /* 01657 * If this is a console window, then just send the close message to 01658 * it, and let console clean up the processes in it. 01659 */ 01660 if ((HANDLE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE) == ghModuleWin) { 01661 PostMessage(hwnd, WM_CLOSE, 0, 0); 01662 goto RestoreDesktop; 01663 } 01664 01665 /* 01666 * Find the CSR_THREAD for the window. 01667 */ 01668 CsrLockThreadByClientId((HANDLE)LongToHandle( dwThreadId ), &pcsrtKill); 01669 if (pcsrtKill == NULL) { 01670 goto RestoreDesktop; 01671 } 01672 CsrReferenceThread(pcsrtKill); 01673 CsrUnlockThread(pcsrtKill); 01674 01675 /* 01676 * If this is a WOW app, then shutdown just this wow application. 01677 */ 01678 if (!fMeanKill) { 01679 /* 01680 * Find out what to do now - did the user cancel or the app cancel, 01681 * etc? Only allow cancelling if we are not forcing the app to 01682 * exit. 01683 */ 01684 dwCmd = ThreadShutdownNotify(WMCS_ENDTASK, (ULONG_PTR)pcsrtKill, (LPARAM)hwnd); 01685 01686 switch (dwCmd) { 01687 case TSN_APPSAYSNOTOK: 01688 /* 01689 * App says not ok - this'll let taskman bring up the "are you sure?" 01690 * dialog to the user. 01691 */ 01692 CsrDereferenceThread(pcsrtKill); 01693 fRet = FALSE; 01694 goto RestoreDesktop; 01695 01696 case TSN_USERSAYSCANCEL: 01697 /* 01698 * User hit cancel on the timeout dialog - so the user really meant 01699 * it. Let taskman know everything is ok by returning TRUE. 01700 */ 01701 CsrDereferenceThread(pcsrtKill); 01702 goto RestoreDesktop; 01703 } 01704 } 01705 01706 /* 01707 * Kill the application now. If the thread has not been destroyed, 01708 * nuke the task. If WowExitTask returns that the thread is not 01709 * a WOW task, terminate the process. 01710 */ 01711 if (!(pcsrtKill->Flags & CSR_THREAD_DESTROYED) && !WowExitTask(pcsrtKill)) { 01712 01713 BOOL bDoBlock; 01714 01715 /* 01716 * Calling ExitProcess() in the app's context will not always work 01717 * because the app may have .dll termination deadlocks: so the thread 01718 * will hang with the rest of the process. To ensure apps go away, 01719 * we terminate the process with NtTerminateProcess(). 01720 * 01721 * Pass this special value, DBG_TERMINATE_PROCESS, which tells 01722 * NtTerminateProcess() to return failure if it can't terminate the 01723 * process because the app is being debugged. 01724 */ 01725 if (ISTS()) { 01726 NTSTATUS ExitStatus; 01727 HANDLE DebugPort; 01728 01729 ExitStatus = DBG_TERMINATE_PROCESS; 01730 if (NT_SUCCESS(NtQueryInformationProcess(NtCurrentProcess(), 01731 ProcessDebugPort, 01732 &DebugPort, 01733 sizeof(HANDLE), 01734 NULL)) && 01735 (DebugPort != NULL)) { 01736 // Csr is being debugged - go ahead and kill the process 01737 ExitStatus = 0; 01738 } 01739 if (!NT_SUCCESS(NtTerminateProcess(pcsrtKill->Process->ProcessHandle, 01740 ExitStatus))) { 01741 01742 bDoBlock = TRUE; 01743 } else { 01744 bDoBlock = FALSE; 01745 } 01746 } else { 01747 if (!NT_SUCCESS(NtTerminateProcess(pcsrtKill->Process->ProcessHandle, 01748 DBG_TERMINATE_PROCESS))) { 01749 bDoBlock = TRUE; 01750 } else { 01751 bDoBlock = FALSE; 01752 } 01753 } 01754 01755 if (bDoBlock) { 01756 01757 /* 01758 * If the app is being debugged, don't close it - because that can 01759 * cause a hang to the NtTerminateProcess() call. 01760 */ 01761 lpszMsg = ServerLoadString(ghModuleWin, STR_APPDEBUGGED, 01762 NULL, &fAllocated); 01763 if (lpszMsg) { 01764 MessageBoxEx(NULL, lpszMsg, NULL, MB_OK | MB_SETFOREGROUND, 0); 01765 LocalFree(lpszMsg); 01766 } 01767 } else { 01768 pcsrtKill->Process->Flags |= CSR_PROCESS_TERMINATED; 01769 } 01770 } 01771 CsrDereferenceThread(pcsrtKill); 01772 01773 RestoreDesktop: 01774 utudi.hThread = NULL; 01775 Status = NtUserSetInformationThread(NtCurrentThread(), 01776 UserThreadUseDesktop, &utudi, sizeof(utudi)); 01777 UserAssert(NT_SUCCESS(Status)); 01778 01779 return fRet; 01780 }

NTSTATUS _ExitWindowsEx PCSR_THREAD  pcsrt,
UINT  dwFlags,
DWORD  dwReserved
 

Definition at line 50 of file server/exitwin.c.

References dwFlags, EnterCrit, FALSE, gdwThreadEndSession, gheventCancel, gheventCancelled, gIdLogon, LeaveCrit, NT_SUCCESS, NtClearEvent(), NtSetEvent(), NTSTATUS(), NtUserSetInformationThread(), NtWaitForSingleObject(), NULL, RtlNtStatusToDosError(), Status, and TRUE.

Referenced by SrvExitWindowsEx().

00054 { 00055 LUID luidCaller; 00056 NTSTATUS Status = STATUS_SUCCESS; 00057 00058 UNREFERENCED_PARAMETER(dwReserved); 00059 00060 if ((dwFlags & EWX_REBOOT) || (dwFlags & EWX_POWEROFF)) { 00061 dwFlags |= EWX_SHUTDOWN; 00062 } 00063 00064 // 00065 // Only winlogon gets to set the high flags: 00066 // 00067 00068 if ( ( dwFlags & ( ~ ( EWX_VALID ) ) ) != 0 ) 00069 { 00070 if ( HandleToUlong(pcsrt->ClientId.UniqueProcess) != gIdLogon ) 00071 { 00072 KdPrint(( "Process %x tried to call ExitWindowsEx with flags %x\n", 00073 pcsrt->ClientId.UniqueProcess, dwFlags )); 00074 00075 return STATUS_ACCESS_DENIED ; 00076 } 00077 } 00078 00079 /* 00080 * Find out the callers sid. Only want to shutdown processes in the 00081 * callers sid. 00082 */ 00083 if (!CsrImpersonateClient(NULL)) { 00084 return STATUS_BAD_IMPERSONATION_LEVEL; 00085 } 00086 00087 Status = CsrGetProcessLuid(NULL, &luidCaller); 00088 if (!NT_SUCCESS(Status)) { 00089 CsrRevertToSelf(); 00090 return Status; 00091 } 00092 00093 /* 00094 * Loop until we can do the shutdown; if we cannot do it, 00095 * we'll go to fastexit and bail. 00096 */ 00097 while (TRUE) { 00098 00099 LARGE_INTEGER li; 00100 00101 Status = NtUserSetInformationThread(pcsrt->ThreadHandle, 00102 UserThreadInitiateShutdown, 00103 &dwFlags, sizeof(dwFlags)); 00104 00105 switch (Status) { 00106 case STATUS_PENDING: 00107 /* 00108 * The logoff/shutdown is in progress and nothing 00109 * more needs to be done. 00110 */ 00111 goto fastexit; 00112 00113 case STATUS_RETRY: 00114 /* 00115 * Another logoff/shutdown is in progress and we need 00116 * to cancel it so we can do an override. 00117 * 00118 * if someone else is trying to cancel shutdown, exit 00119 */ 00120 EnterCrit(); 00121 li.QuadPart = 0; 00122 if (NtWaitForSingleObject(gheventCancel, FALSE, &li) == WAIT_OBJECT_0) { 00123 Status = STATUS_PENDING; 00124 LeaveCrit(); 00125 goto fastexit; 00126 } 00127 /* 00128 * If no one will set gheventCancelled, don't wait. 00129 */ 00130 if (gdwThreadEndSession == 0) { 00131 LeaveCrit(); 00132 continue; 00133 } 00134 00135 NtClearEvent(gheventCancelled); 00136 NtSetEvent(gheventCancel, NULL); 00137 LeaveCrit(); 00138 /* 00139 * Wait for the other guy to be cancelled 00140 */ 00141 NtWaitForSingleObject(gheventCancelled, FALSE, NULL); 00142 00143 EnterCrit(); 00144 /* 00145 * This signals that we are no longer trying to cancel a 00146 * shutdown 00147 */ 00148 NtClearEvent(gheventCancel); 00149 /* 00150 * If someone managed to start a shutdown again, exit 00151 * Can this happen? Let's assert to check it out. 00152 */ 00153 if (gdwThreadEndSession != 0) { 00154 UserAssert(gdwThreadEndSession == 0); 00155 Status = STATUS_PENDING; 00156 LeaveCrit(); 00157 goto fastexit; 00158 } 00159 LeaveCrit(); 00160 continue; 00161 00162 case STATUS_CANT_WAIT: 00163 00164 /* 00165 * There is no notify window and the calling thread has 00166 * windows that prevent this request from succeeding. 00167 * The client handles this by starting another thread 00168 * to recall ExitWindowsEx. 00169 */ 00170 goto fastexit; 00171 00172 default: 00173 if (!NT_SUCCESS(Status)) { 00174 SetLastError(RtlNtStatusToDosError(Status)); 00175 goto fastexit; 00176 } 00177 } 00178 break; 00179 } 00180 00181 /* 00182 * This thread is doing the shutdown 00183 */ 00184 EnterCrit(); 00185 UserAssert(gdwThreadEndSession == 0); 00186 gdwThreadEndSession = HandleToUlong(pcsrt->ClientId.UniqueThread); 00187 LeaveCrit(); 00188 00189 /* 00190 * Call csr to loop through the processes shutting them down. 00191 */ 00192 Status = CsrShutdownProcesses(&luidCaller, dwFlags); 00193 /* 00194 * Tell win32k.sys we're done. 00195 */ 00196 NtUserSetInformationThread(pcsrt->ThreadHandle, UserThreadEndShutdown, &Status, sizeof(Status)); 00197 00198 EnterCrit(); 00199 gdwThreadEndSession = 0; 00200 NtSetEvent(gheventCancelled, NULL); 00201 LeaveCrit(); 00202 00203 fastexit: 00204 CsrRevertToSelf(); 00205 00206 return Status; 00207 }

INT_PTR APIENTRY EndTaskDlgProc HWND  hwndDlg,
UINT  msg,
WPARAM  wParam,
LPARAM  lParam
 

Definition at line 1312 of file server/exitwin.c.

References APIENTRY, BeginPaint, BHE_TEST, BOOL, BoostHardError(), CCHBODYMAX, DestroyWindow, DrawEdge(), DrawIcon(), DWORD, EDPF_HUNG, EDPF_INPUT, EDPF_NODLG, EDPF_RESPONSE, EDPF_WAIT, ETD_XICON, ETD_YICON, FALSE, FillRect(), gdwHungToKillCount, GetApplicationText(), GetClassLongPtr(), GetDC, GetInputWindow(), GetProp(), GetSystemMetrics(), GetWindowLongPtr(), GetWindowText(), ghModuleWin, ICON_PROP_NAME, IDB_WARNING, IDI_CONSOLE, IDT_CHECKAPPSTATE, IDT_PROGRESS, InflateRect(), msg, NULL, ReleaseDC(), SetEndTaskDlgStatus(), SetWindowLongPtr(), SetWindowPos, SetWindowText(), TRUE, UINT, and WMCS_CONSOLE.

Referenced by ThreadShutdownNotify().

01317 { 01318 ENDDLGPARAMS* pedp; 01319 WCHAR achTitle[CCHBODYMAX]; 01320 WCHAR *pwcText, *pwcTemp; 01321 UINT uLen; 01322 UINT uStrId; 01323 PAINTSTRUCT ps; 01324 HDC hdc, hdcMem; 01325 BOOL fIsInput, fWasInput; 01326 #ifdef USE_MIRRORING 01327 int iOldLayout; 01328 #endif 01329 01330 switch (msg) { 01331 case WM_INITDIALOG: 01332 /* 01333 * Save parameters 01334 */ 01335 pedp = (ENDDLGPARAMS*)lParam; 01336 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (ULONG_PTR)pedp); 01337 /* 01338 * This tells the caller that the dialog is up 01339 */ 01340 pedp->dwFlags &= ~EDPF_NODLG; 01341 /* 01342 * Build the dialog title making sure that 01343 * we end up with a NULL terminated string. 01344 */ 01345 *(achTitle + CCHBODYMAX - 1) = (WCHAR)0; 01346 uLen = GetWindowText(hwndDlg, achTitle, CCHBODYMAX - 1); 01347 pwcText = achTitle + uLen; 01348 uLen = CCHBODYMAX - 1 - uLen; 01349 /* 01350 * Console provides the title; we figure it out for windows apps. 01351 */ 01352 if (pedp->dwClientFlags & WMCS_CONSOLE) { 01353 pwcTemp = (WCHAR *)pedp->lParam; 01354 while (uLen-- && (*pwcText++ = *pwcTemp++)); 01355 } else { 01356 GetApplicationText((HWND)pedp->lParam, pedp->pcsrt->ThreadHandle, pwcText, uLen); 01357 } 01358 01359 SetWindowText(hwndDlg, achTitle); 01360 /* 01361 * Get the app's icon: first look for atomIconProperty 01362 * if not available, try the class icon. 01363 * else, use the default icon. 01364 */ 01365 pedp->hIcon = (HICON)GetProp((HWND)pedp->lParam, ICON_PROP_NAME); 01366 01367 if (pedp->hIcon == NULL) { 01368 01369 pedp->hIcon = (HICON)GetClassLongPtr((HWND)pedp->lParam, GCLP_HICON); 01370 01371 if (pedp->hIcon == NULL) { 01372 01373 if (pedp->dwClientFlags & WMCS_CONSOLE) { 01374 pedp->hIcon = LoadIcon(ghModuleWin, MAKEINTRESOURCE(IDI_CONSOLE)); 01375 } 01376 else { 01377 pedp->hIcon = LoadIcon(NULL, IDI_APPLICATION); 01378 } 01379 } 01380 } 01381 01382 /* 01383 * Figure out what message the caller wants initially 01384 */ 01385 if (pedp->dwClientFlags & WMCS_CONSOLE) { 01386 uStrId = STR_ENDTASK_CONSOLE; 01387 } else if (pedp->dwFlags & EDPF_INPUT) { 01388 uStrId = STR_ENDTASK_INPUT; 01389 } else if (pedp->dwFlags & EDPF_WAIT) { 01390 uStrId = STR_ENDTASK_WAIT; 01391 } else { 01392 uStrId = STR_ENDTASK_HUNG; 01393 } 01394 /* 01395 * Display the message, set the focus and show the dialog 01396 */ 01397 SetEndTaskDlgStatus(pedp, hwndDlg, uStrId, TRUE); 01398 return FALSE; 01399 01400 01401 case WM_PAINT: 01402 pedp = (ENDDLGPARAMS*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 01403 if ((pedp == NULL) || (pedp->hIcon == NULL)) { 01404 break; 01405 } 01406 /* 01407 * Draw the icon 01408 */ 01409 hdc = BeginPaint(hwndDlg, &ps); 01410 #ifdef USE_MIRRORING 01411 iOldLayout = GetLayout(hdc); 01412 if (iOldLayout != GDI_ERROR) { 01413 SetLayout(hdc, iOldLayout|LAYOUT_BITMAPORIENTATIONPRESERVED); 01414 } 01415 #endif 01416 DrawIcon(hdc, ETD_XICON, ETD_YICON, pedp->hIcon); 01417 #ifdef USE_MIRRORING 01418 if (iOldLayout != GDI_ERROR) { 01419 SetLayout(hdc, iOldLayout); 01420 } 01421 #endif 01422 /* 01423 * If waiting, draw the progress bar; 01424 * else draw the warning sign 01425 */ 01426 if (pedp->dwFlags & EDPF_WAIT) { 01427 RECT rc; 01428 /* 01429 * Draw a client-edge-looking border. 01430 */ 01431 rc = pedp->rcBar; 01432 DrawEdge(hdc, &rc, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST); 01433 InflateRect(&rc, -1, -1); 01434 /* 01435 * Draw the blocks up to current position 01436 */ 01437 rc.right = rc.left + pedp->iProgressWidth - 1; 01438 while (rc.left < pedp->rcProgress.left) { 01439 if (rc.right > pedp->iProgressStop) { 01440 rc.right = pedp->iProgressStop; 01441 if (rc.left >= rc.right) { 01442 break; 01443 } 01444 } 01445 FillRect(hdc, &rc, pedp->hbrProgress); 01446 rc.left += pedp->iProgressWidth; 01447 rc.right += pedp->iProgressWidth; 01448 } 01449 } else { 01450 /* 01451 * Load the bitmap the first time around and 01452 * figure out where it goes 01453 */ 01454 if (pedp->hbmpWarning == NULL) { 01455 BITMAP bmp; 01456 pedp->hbmpWarning = LoadBitmap(ghModuleWin, MAKEINTRESOURCE(IDB_WARNING)); 01457 if (GetObject(pedp->hbmpWarning, sizeof(bmp), &bmp)) { 01458 pedp->rcWarning.left = ETD_XICON; 01459 pedp->rcWarning.top = ETD_XICON + 32 - bmp.bmHeight; 01460 pedp->rcWarning.right = bmp.bmWidth; 01461 pedp->rcWarning.bottom = bmp.bmHeight; 01462 } 01463 } 01464 /* 01465 * Blit it 01466 */ 01467 hdcMem = CreateCompatibleDC(hdc); 01468 SelectObject(hdcMem, pedp->hbmpWarning); 01469 GdiTransparentBlt(hdc, pedp->rcWarning.left, pedp->rcWarning.top, 01470 pedp->rcWarning.right, pedp->rcWarning.bottom, 01471 hdcMem, 0, 0, pedp->rcWarning.right, pedp->rcWarning.bottom, RGB(255, 0, 255)); 01472 DeleteDC(hdcMem); 01473 } 01474 01475 EndPaint(hwndDlg, &ps); 01476 return TRUE; 01477 01478 case WM_TIMER: 01479 pedp = (ENDDLGPARAMS*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 01480 if (pedp == NULL) { 01481 return TRUE; 01482 } 01483 switch (wParam) { 01484 case IDT_CHECKAPPSTATE: 01485 pedp->dwCheckTimerCount++; 01486 /* 01487 * Check if the app has switched from/to a waiting-for-input 01488 * mode. If so, update the dialog and wait a little longer 01489 */ 01490 fIsInput = (BoostHardError((ULONG_PTR)pedp->pcsrt->ClientId.UniqueProcess, BHE_TEST) 01491 || (GetInputWindow(pedp->pcsrt, (HWND)pedp->lParam) != NULL)); 01492 fWasInput = (pedp->dwFlags & EDPF_INPUT); 01493 if (fIsInput ^ fWasInput) { 01494 UINT uProgress; 01495 pedp->dwFlags &= ~(EDPF_INPUT | EDPF_WAIT); 01496 pedp->dwFlags |= (fIsInput ? EDPF_INPUT : EDPF_WAIT); 01497 SetEndTaskDlgStatus(pedp, hwndDlg, 01498 (fIsInput ? STR_ENDTASK_INPUT : STR_ENDTASK_WAIT), 01499 FALSE); 01500 pedp->dwCheckTimerCount /= 2; 01501 uProgress = pedp->rcProgress.left - pedp->rcBar.left - GetSystemMetrics(SM_CXEDGE); 01502 uProgress /= 2; 01503 pedp->rcProgress.left -= uProgress; 01504 pedp->rcProgress.right -= uProgress; 01505 } 01506 /* 01507 * Is it time to declare it hung? 01508 */ 01509 if (pedp->dwCheckTimerCount >= gdwHungToKillCount) { 01510 KillTimer(hwndDlg, IDT_CHECKAPPSTATE); 01511 pedp->dwFlags &= ~(EDPF_INPUT | EDPF_WAIT); 01512 pedp->dwFlags |= EDPF_HUNG; 01513 SetEndTaskDlgStatus(pedp, hwndDlg, STR_ENDTASK_HUNG, FALSE); 01514 } 01515 break; 01516 01517 case IDT_PROGRESS: 01518 /* 01519 * Draw the next block in the progress bar. 01520 */ 01521 if (pedp->rcProgress.right >= pedp->iProgressStop) { 01522 pedp->rcProgress.right = pedp->iProgressStop; 01523 if (pedp->rcProgress.left >= pedp->rcProgress.right) { 01524 break; 01525 } 01526 } 01527 hdc = GetDC(hwndDlg); 01528 FillRect(hdc, &pedp->rcProgress, pedp->hbrProgress); 01529 ReleaseDC(hwndDlg, hdc); 01530 pedp->rcProgress.left += pedp->iProgressWidth; 01531 pedp->rcProgress.right += pedp->iProgressWidth; 01532 break; 01533 } 01534 return TRUE; 01535 01536 01537 case WM_NCACTIVATE: 01538 /* 01539 * Make sure we're uncovered when active and not covering the app 01540 * when inactive 01541 */ 01542 pedp = (ENDDLGPARAMS*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 01543 if (pedp != NULL) { 01544 HWND hwnd; 01545 if (wParam) { 01546 hwnd = HWND_TOPMOST; 01547 } else if (pedp->dwClientFlags & WMCS_CONSOLE) { 01548 hwnd = HWND_TOP; 01549 } else { 01550 hwnd = (HWND)pedp->lParam; 01551 } 01552 SetWindowPos(hwndDlg, hwnd, 01553 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 01554 } 01555 break; 01556 01557 01558 case WM_COMMAND: 01559 /* 01560 * The user has made a choice, we're done. 01561 */ 01562 pedp = (ENDDLGPARAMS*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 01563 if (pedp != NULL) { 01564 pedp->dwRet = (DWORD)wParam; 01565 } 01566 DestroyWindow(hwndDlg); 01567 break; 01568 01569 01570 case WM_DESTROY: 01571 /* 01572 * We're dead. Make sure the caller knows we're history 01573 */ 01574 pedp = (ENDDLGPARAMS*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 01575 if (pedp != NULL) { 01576 pedp->dwFlags |= (EDPF_NODLG | EDPF_RESPONSE); 01577 if (pedp->hbmpWarning != NULL) { 01578 DeleteObject(pedp->hbmpWarning); 01579 } 01580 if (pedp->hbrProgress != NULL) { 01581 DeleteObject(pedp->hbrProgress); 01582 } 01583 } 01584 break; 01585 } 01586 01587 return FALSE; 01588 }

void GetApplicationText HWND  hwnd,
HANDLE  hThread,
WCHAR *  pwcText,
UINT  uLen
 

Definition at line 728 of file server/exitwin.c.

References GetWindowText(), NtUserQueryInformationThread(), and NULL.

Referenced by EndTaskDlgProc(), and ThreadShutdownNotify().

00729 { 00730 /* 00731 * GetWindowText doesn't call the hwnd's proc; otherwise, we could 00732 * get blocked here for good. 00733 */ 00734 GetWindowText(hwnd, pwcText, uLen); 00735 if (*pwcText == 0) { 00736 /* 00737 * We couldn't get window title; let's try thread name 00738 */ 00739 NtUserQueryInformationThread(hThread, UserThreadTaskName, 00740 pwcText, uLen * sizeof(WCHAR), NULL); 00741 } 00742 }

HWND GetInputWindow PCSR_THREAD  pcsrt,
HWND  hwnd
 

Definition at line 698 of file server/exitwin.c.

References DWORD, gCmsHungAppTimeout, GetWindow(), IsWindowEnabled(), NtUserQueryInformationThread(), and NULL.

Referenced by EndTaskDlgProc(), and ThreadShutdownNotify().

00699 { 00700 DWORD dwTimeout; 00701 HWND hwndPopup; 00702 /* 00703 * Ask the kernel if the thread is hung 00704 */ 00705 dwTimeout = gCmsHungAppTimeout; 00706 NtUserQueryInformationThread(pcsrt->ThreadHandle, 00707 UserThreadHungStatus, &dwTimeout, sizeof(dwTimeout), NULL); 00708 00709 /* 00710 * If not hung and disabled, see if it owns an enabled popup 00711 */ 00712 if (!dwTimeout && !IsWindowEnabled(hwnd)) { 00713 hwndPopup = GetWindow(hwnd, GW_ENABLEDPOPUP); 00714 if ((hwndPopup != NULL) && (hwndPopup != hwnd)) { 00715 return hwndPopup; 00716 } 00717 } 00718 00719 return NULL; 00720 }

HANDLE InternalCreateCallbackThread HANDLE  hProcess,
ULONG_PTR  lpfn,
ULONG_PTR  dwData
 

Definition at line 1865 of file server/exitwin.c.

References DWORD, FALSE, L, LPVOID, NT_SUCCESS, NtClose(), NtOpenProcessToken(), NtQueryInformationToken(), NtSetInformationThread(), NTSTATUS(), NULL, RtlCreateSecurityDescriptor(), RtlSetDaclSecurityDescriptor(), Status, and TRUE.

Referenced by CreateCtrlThread(), PropertiesDlgShow(), and WowExitTask().

01869 { 01870 LONG BasePriority; 01871 HANDLE hThread, hToken; 01872 PTOKEN_DEFAULT_DACL lpDaclDefault; 01873 TOKEN_DEFAULT_DACL daclDefault; 01874 ULONG cbDacl; 01875 SECURITY_ATTRIBUTES attrThread; 01876 SECURITY_DESCRIPTOR sd; 01877 DWORD idThread; 01878 NTSTATUS Status; 01879 01880 hThread = NULL; 01881 01882 Status = NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken); 01883 if (!NT_SUCCESS(Status)) { 01884 KdPrint(("NtOpenProcessToken failed, status = %x\n", Status)); 01885 return NULL; 01886 } 01887 01888 cbDacl = 0; 01889 NtQueryInformationToken(hToken, 01890 TokenDefaultDacl, 01891 &daclDefault, 01892 sizeof(daclDefault), 01893 &cbDacl); 01894 01895 lpDaclDefault = (PTOKEN_DEFAULT_DACL)LocalAlloc(LMEM_FIXED, cbDacl); 01896 if (lpDaclDefault == NULL) { 01897 KdPrint(("LocalAlloc failed for lpDaclDefault")); 01898 goto closeexit; 01899 } 01900 01901 Status = NtQueryInformationToken(hToken, 01902 TokenDefaultDacl, 01903 lpDaclDefault, 01904 cbDacl, 01905 &cbDacl); 01906 if (!NT_SUCCESS(Status)) { 01907 KdPrint(("NtQueryInformationToken failed, status = %x\n", Status)); 01908 goto freeexit; 01909 } 01910 01911 if (!NT_SUCCESS(RtlCreateSecurityDescriptor(&sd, 01912 SECURITY_DESCRIPTOR_REVISION1))) { 01913 UserAssert(FALSE); 01914 goto freeexit; 01915 } 01916 01917 RtlSetDaclSecurityDescriptor(&sd, TRUE, lpDaclDefault->DefaultDacl, TRUE); 01918 01919 attrThread.nLength = sizeof(attrThread); 01920 attrThread.lpSecurityDescriptor = &sd; 01921 attrThread.bInheritHandle = FALSE; 01922 01923 GetLastError(); 01924 hThread = CreateRemoteThread(hProcess, 01925 &attrThread, 01926 0L, 01927 (LPTHREAD_START_ROUTINE)lpfn, 01928 (LPVOID)dwData, 01929 0, 01930 &idThread); 01931 01932 if (hThread != NULL) { 01933 BasePriority = THREAD_PRIORITY_HIGHEST; 01934 NtSetInformationThread(hThread, 01935 ThreadBasePriority, 01936 &BasePriority, 01937 sizeof(LONG)); 01938 } 01939 01940 freeexit: 01941 LocalFree((HANDLE)lpDaclDefault); 01942 01943 closeexit: 01944 NtClose(hToken); 01945 01946 return hThread; 01947 }

DWORD InternalWaitCancel HANDLE  handle,
DWORD  dwMilliseconds
 

Definition at line 1842 of file server/exitwin.c.

References DWORD, FALSE, and gheventCancel.

Referenced by ConsoleClientShutdown(), and CreateCtrlThread().

01845 { 01846 HANDLE ahandle[2]; 01847 01848 ahandle[0] = handle; 01849 ahandle[1] = gheventCancel; 01850 01851 return WaitForMultipleObjects(2, ahandle, FALSE, dwMilliseconds); 01852 }

BOOL IsPrivileged PPRIVILEGE_SET  ppSet  ) 
 

Definition at line 2001 of file server/exitwin.c.

References BOOL, FALSE, L, NT_SUCCESS, NtClose(), NtOpenThreadToken(), NtPrivilegeCheck(), NtPrivilegeObjectAuditAlarm(), NTSTATUS(), NULL, RtlInitUnicodeString(), RtlNtStatusToDosError(), SeCaptureSubjectContext(), SeLockSubjectContext(), SePrivilegeCheck(), SePrivilegeObjectAuditAlarm(), SeReleaseSubjectContext(), SeUnlockSubjectContext(), Status, TRUE, and UserMode.

Referenced by _RegisterLogonProcess(), InitiateShutdown(), SrvRegisterServicesProcess(), and xxxWrapSendMessageBSM().

02003 { 02004 HANDLE hToken; 02005 NTSTATUS Status; 02006 BOOLEAN bResult = FALSE; 02007 UNICODE_STRING strSubSystem; 02008 02009 /* 02010 * Impersonate the client 02011 */ 02012 if (!CsrImpersonateClient(NULL)) 02013 return FALSE; 02014 02015 /* 02016 * Open the client's token 02017 */ 02018 RtlInitUnicodeString(&strSubSystem, L"USER32"); 02019 if (NT_SUCCESS(Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, 02020 (BOOLEAN)TRUE, &hToken))) { 02021 02022 /* 02023 * Perform the check 02024 */ 02025 Status = NtPrivilegeCheck(hToken, ppSet, &bResult); 02026 NtPrivilegeObjectAuditAlarm(&strSubSystem, NULL, hToken, 02027 0, ppSet, bResult); 02028 NtClose(hToken); 02029 if (!bResult) { 02030 SetLastError(ERROR_ACCESS_DENIED); 02031 } 02032 } 02033 CsrRevertToSelf(); 02034 if (!NT_SUCCESS(Status)) 02035 SetLastError(RtlNtStatusToDosError(Status)); 02036 02037 /* 02038 * Return result of privilege check 02039 */ 02040 return (BOOL)(bResult && NT_SUCCESS(Status)); 02041 }

void SetEndTaskDlgStatus ENDDLGPARAMS pedp,
HWND  hwndDlg,
UINT  uStrId,
BOOL  fInit
 

Definition at line 1151 of file server/exitwin.c.

References BOOL, _ENDDLGPARAMS::dwClientFlags, _ENDDLGPARAMS::dwFlags, DWORD, EDPF_HUNG, EDPF_WAIT, gCmsHungAppTimeout, gdwHungToKillCount, GetClientRect(), GetDlgItem(), GetSysColor(), GetSystemMetrics(), GetWindowRect(), ghModuleWin, _ENDDLGPARAMS::hbrProgress, IDC_ENDNOW, IDC_STATUSCANCEL, IDC_STATUSMSG, IDT_CHECKAPPSTATE, IDT_PROGRESS, InflateRect(), _ENDDLGPARAMS::iProgressStop, _ENDDLGPARAMS::iProgressWidth, MapWindowPoints(), NULL, OffsetRect(), _ENDDLGPARAMS::rcBar, _ENDDLGPARAMS::rcEndButton, _ENDDLGPARAMS::rcProgress, SendMessage(), ServerLoadString, SetDlgItemText(), SetFocus, SetForegroundWindow(), SetTimer, SetWindowPos, TRUE, UINT, _ENDDLGPARAMS::uStrId, and WMCS_CONSOLE.

Referenced by EndTaskDlgProc().

01152 { 01153 BOOL f, fIsWaiting, fWasWaiting; 01154 WCHAR *pwcText; 01155 01156 fWasWaiting = (pedp->uStrId == STR_ENDTASK_WAIT); 01157 fIsWaiting = (pedp->dwFlags & EDPF_WAIT); 01158 /* 01159 * Store the current message id, load it and show it 01160 */ 01161 pedp->uStrId = uStrId; 01162 pwcText = ServerLoadString(ghModuleWin, uStrId, NULL, &f); 01163 if (pwcText != NULL) { 01164 SetDlgItemText(hwndDlg, IDC_STATUSMSG, pwcText); 01165 LocalFree(pwcText); 01166 } 01167 /* 01168 * If we haven't decided that the app is hung, set a 01169 * timer to keep an eye on it. 01170 */ 01171 if (!(pedp->dwFlags & EDPF_HUNG) && !(pedp->dwClientFlags & WMCS_CONSOLE)) { 01172 SetTimer(hwndDlg, IDT_CHECKAPPSTATE, gCmsHungAppTimeout, NULL); 01173 } 01174 /* 01175 * If initializing or switching to/from the wait mode, 01176 * set the proper status for IDC_STATUSCANCEL, IDCANCEL, 01177 * IDC_ENDNOW and the start/stop the progress bar. 01178 * Invalidate paint if/as needed 01179 */ 01180 if (fInit || (fIsWaiting ^ fWasWaiting)) { 01181 RECT rc; 01182 HWND hwndStatusCancel = GetDlgItem(hwndDlg, IDC_STATUSCANCEL); 01183 HWND hwndCancelButton = GetDlgItem(hwndDlg, IDCANCEL); 01184 HWND hwndEndButton = GetDlgItem(hwndDlg, IDC_ENDNOW); 01185 DWORD dwSwpFlags; 01186 /* 01187 * If on wait mode, we hide the cancel button and its 01188 * explanatory text. The End button will be moved to 01189 * the cancel button position. 01190 */ 01191 dwSwpFlags = ((fIsWaiting ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) 01192 | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOMOVE 01193 | SWP_NOZORDER | SWP_NOSENDCHANGING 01194 | SWP_NOACTIVATE); 01195 /* 01196 * If we're hiding the cancel button, give focus/def id to 01197 * the End button. 01198 * Note that DM_SETDEIF won't do the right thing unless 01199 * both Cancel/End buttons are visible. 01200 */ 01201 if (fIsWaiting) { 01202 SendMessage(hwndDlg, DM_SETDEFID, IDC_ENDNOW, 0); 01203 SetFocus(hwndEndButton); 01204 } 01205 SetWindowPos(hwndStatusCancel, NULL, 0, 0, 0, 0, dwSwpFlags); 01206 SetWindowPos(hwndCancelButton, NULL, 0, 0, 0, 0, dwSwpFlags); 01207 /* 01208 * If the cancel button is visible, give it focus/def id. 01209 */ 01210 if (!fIsWaiting) { 01211 SendMessage(hwndDlg, DM_SETDEFID, IDCANCEL, 0); 01212 SetFocus(hwndCancelButton); 01213 } 01214 /* 01215 * Initialize progress bar (first time around) 01216 */ 01217 if (fIsWaiting && (pedp->hbrProgress == NULL)) { 01218 int iMagic; 01219 /* 01220 * Initialize progress bar stuff. 01221 * The size and location calculations below were made up 01222 * to make it look good(?). 01223 * We need that location on dialog coordiantes since the 01224 * progress bar is painted on the dialog's WM_PAINT. 01225 */ 01226 GetClientRect(hwndStatusCancel, &pedp->rcBar); 01227 iMagic = (pedp->rcBar.bottom - pedp->rcBar.top) / 4; 01228 InflateRect(&pedp->rcBar, 0, -iMagic + GetSystemMetrics(SM_CYEDGE)); 01229 pedp->rcBar.right -= (5 * iMagic); 01230 OffsetRect(&pedp->rcBar, 0, -iMagic); 01231 MapWindowPoints(hwndStatusCancel, hwndDlg, (LPPOINT)&pedp->rcBar, 2); 01232 /* 01233 * Calculate drawing rectangle and dimensions. 01234 * We kind of make it look like comctrl's progress bar. 01235 */ 01236 pedp->rcProgress = pedp->rcBar; 01237 InflateRect(&pedp->rcProgress, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE)); 01238 pedp->iProgressStop = pedp->rcProgress.right; 01239 pedp->iProgressWidth = ((2 * (pedp->rcProgress.bottom - pedp->rcProgress.top)) / 3); 01240 01241 pedp->rcProgress.right = pedp->rcProgress.left + pedp->iProgressWidth - 1; 01242 01243 pedp->hbrProgress = CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION)); 01244 /* 01245 * Remember the End button position. 01246 */ 01247 GetWindowRect(hwndEndButton, &pedp->rcEndButton); 01248 MapWindowPoints(NULL, hwndDlg, (LPPOINT)&pedp->rcEndButton, 2); 01249 } 01250 /* 01251 * Start/Stop progress bar and set End button position 01252 */ 01253 if (fIsWaiting) { 01254 RECT rcEndButton; 01255 UINT uTimeout = (gdwHungToKillCount * gCmsHungAppTimeout) 01256 / ((pedp->iProgressStop - pedp->rcProgress.left) / pedp->iProgressWidth); 01257 SetTimer(hwndDlg, IDT_PROGRESS, uTimeout, NULL); 01258 /* 01259 * The Cancel and the End buttons might have different widths when 01260 * localized. So make sure we position it inside the dialog and 01261 * to the right end of the dialog. 01262 */ 01263 GetWindowRect(hwndCancelButton, &rc); 01264 GetWindowRect(hwndEndButton, &rcEndButton); 01265 rc.left = rc.right - (rcEndButton.right - rcEndButton.left); 01266 MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc, 2); 01267 } else if (fWasWaiting) { 01268 KillTimer(hwndDlg, IDT_PROGRESS); 01269 rc = pedp->rcEndButton; 01270 } 01271 /* 01272 * Move the End button if needed 01273 */ 01274 if (fIsWaiting || fWasWaiting) { 01275 SetWindowPos(hwndEndButton, NULL, rc.left, rc.top, 0, 0, 01276 SWP_NOREDRAW | SWP_NOSIZE | SWP_NOACTIVATE 01277 | SWP_NOZORDER | SWP_NOSENDCHANGING); 01278 } 01279 /* 01280 * Make sure we repaint if needed 01281 */ 01282 if (!fInit) { 01283 InvalidateRect(hwndDlg, NULL, TRUE); 01284 } 01285 } /* if (fInit || (fIsWaiting ^ fWasWaiting)) */ 01286 /* 01287 * If initializing or in hung mode, make sure the user can 01288 * see the dialog; only bring it to the foreground on 01289 * initialization (no rude focus stealing) 01290 */ 01291 if (fInit || (pedp->dwFlags & EDPF_HUNG)) { 01292 SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, 01293 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW 01294 | SWP_NOACTIVATE | SWP_NOSENDCHANGING); 01295 01296 if (fInit) { 01297 SetForegroundWindow(hwndDlg); 01298 } 01299 } 01300 }

ULONG SrvEndTask IN OUT PCSR_API_MSG  m,
IN OUT PCSR_REPLY_STATUS  ReplyStatus
 

Definition at line 1963 of file server/exitwin.c.

References _EndTask(), _ENDTASKMSG::dwLastError, _ENDTASKMSG::fForce, _ENDTASKMSG::fShutdown, _ENDTASKMSG::fSuccess, _ENDTASKMSG::hwnd, NtReplyPort(), NULL, and TRUE.

01966 { 01967 PENDTASKMSG petm = (PENDTASKMSG)&m->u.ApiMessageData; 01968 PCSR_THREAD pcsrt; 01969 PTEB Teb = NtCurrentTeb(); 01970 01971 Teb->LastErrorValue = 0; 01972 pcsrt = CSR_SERVER_QUERYCLIENTTHREAD(); 01973 /* 01974 * Don't block the client so it can respond to messages while we 01975 * process this request -- we might bring up the End Application 01976 * dialog or the hwnd being shutdown might request some user action. 01977 */ 01978 if (pcsrt->Process->ClientPort != NULL) { 01979 m->ReturnValue = STATUS_SUCCESS; 01980 petm->dwLastError = 0; 01981 petm->fSuccess = TRUE; 01982 NtReplyPort(pcsrt->Process->ClientPort, (PPORT_MESSAGE)m); 01983 *ReplyStatus = CsrServerReplied; 01984 } 01985 01986 petm->fSuccess = _EndTask(petm->hwnd, petm->fShutdown, petm->fForce); 01987 01988 petm->dwLastError = Teb->LastErrorValue; 01989 return STATUS_SUCCESS; 01990 }

ULONG SrvExitWindowsEx IN OUT PCSR_API_MSG  m,
IN OUT PCSR_REPLY_STATUS  ReplyStatus
 

Definition at line 1950 of file server/exitwin.c.

References _ExitWindowsEx(), BEGIN_LPC_RECV, END_LPC_RECV, NT_SUCCESS, and Status.

01953 { 01954 BEGIN_LPC_RECV(EXITWINDOWSEX); 01955 01956 Status = _ExitWindowsEx(pcsrt, a->uFlags, a->dwReserved); 01957 a->fSuccess = NT_SUCCESS(Status); 01958 01959 END_LPC_RECV(); 01960 }

ULONG SrvRegisterServicesProcess IN OUT PCSR_API_MSG  m,
IN OUT PCSR_REPLY_STATUS  ReplyStatus
 

Definition at line 2053 of file server/exitwin.c.

References BEGIN_LPC_RECV, END_LPC_RECV, EnterCrit, FALSE, gdwServicesProcessId, IsPrivileged(), LeaveCrit, psTcb, and TRUE.

02056 { 02057 PRIVILEGE_SET psTcb = { 1, PRIVILEGE_SET_ALL_NECESSARY, 02058 { SE_TCB_PRIVILEGE, 0 } 02059 }; 02060 02061 BEGIN_LPC_RECV(REGISTERSERVICESPROCESS); 02062 02063 /* 02064 * Allow only one services process and then only if it has TCB 02065 * privilege. 02066 */ 02067 EnterCrit(); 02068 if ((gdwServicesProcessId != 0) || !IsPrivileged(&psTcb)) { 02069 SetLastError(ERROR_ACCESS_DENIED); 02070 a->fSuccess = FALSE; 02071 } else { 02072 gdwServicesProcessId = a->dwProcessId; 02073 a->fSuccess = TRUE; 02074 } 02075 LeaveCrit(); 02076 02077 END_LPC_RECV(); 02078 }

DWORD ThreadShutdownNotify DWORD  dwClientFlags,
ULONG_PTR  dwThread,
LPARAM  lParam
 

Definition at line 757 of file server/exitwin.c.

References BHE_FORCE, BHE_TEST, BOOL, BoostHardError(), CCHBODYMAX, DestroyWindow, DispatchMessage(), tagWMCSDATA::dwFlags, DWORD, tagWMCSDATA::dwRet, EDPF_HUNG, EDPF_INPUT, EDPF_NODLG, EDPF_RESPONSE, EDPF_WAIT, ENDDLGPARAMS, EndTaskDlgProc(), EnumThreadWindows(), ESMH_CANCELEVENT, ESMH_HANDLECOUNT, ESMH_THREAD, FALSE, FindWindowFromThread(), gCmsHungAppTimeout, GetApplicationText(), GetInputWindow(), GetWindow(), GetWindowLongPtr(), gfAutoEndTask, gheventCancel, ghModuleWin, IDC_ENDNOW, IDD_ENDTASK, IsDialogMessage, ISTS, IsWindowEnabled(), msg, MsgWaitForMultipleObjects(), NtUserQueryInformationThread(), NULL, PeekMessage(), PostMessage(), SendMessageCallback(), SendNotifyMessage(), SetForegroundWindow(), TranslateMessage(), TRUE, TSN_APPSAYSNOTOK, TSN_APPSAYSOK, TSN_NOWINDOW, TSN_USERSAYSCANCEL, TSN_USERSAYSKILL, WMCS_CONSOLE, WMCS_CONTEXTLOGOFF, WMCS_ENDTASK, WMCS_EXIT, WMCS_NODLGIFHUNG, WMCS_NORETRY, WMCS_QUERYEND, WMCSCallback(), WMCSD_IGNORE, WMCSD_REPLY, WMCSDATA, WMCSR_ALLOWSHUTDOWN, WMCSR_CANCEL, WMCSR_DONE, and WowExitTask().

Referenced by _EndTask(), CreateCtrlThread(), and UserClientShutdown().

00758 { 00759 HWND hwnd, hwndOwner; 00760 PWMCSDATA pwmcsd = NULL; 00761 HWND hwndDlg; 00762 ENDDLGPARAMS edp; 00763 DWORD dwRet, dwRealTimeout, dwTimeout, dwStartTiming, dwCmd; 00764 MSG msg; 00765 PCSR_THREAD pcsrt; 00766 HANDLE hThread; 00767 BOOL fEndTaskNow = FALSE; 00768 00769 #define ESMH_CANCELEVENT 0 00770 #define ESMH_THREAD 1 00771 #define ESMH_HANDLECOUNT 2 00772 HANDLE ahandles[ESMH_HANDLECOUNT]; 00773 00774 /* 00775 * If this is console, just set up the wait loop and 00776 * bring the dialog up right away. Otherwise, find 00777 * the notification window, notify it and go wait. 00778 */ 00779 if (dwClientFlags & WMCS_CONSOLE) { 00780 hThread = (HANDLE)dwThread; 00781 dwRealTimeout = 0; 00782 goto SetupWaitLoop; 00783 } else { 00784 pcsrt = (PCSR_THREAD)dwThread; 00785 hThread = pcsrt->ThreadHandle; 00786 hwnd = (HWND)lParam; 00787 } 00788 00789 /* 00790 * If no window was provided, 00791 * find a top-level window owned by the thread 00792 */ 00793 if (hwnd == NULL) { 00794 EnumThreadWindows(HandleToUlong(pcsrt->ClientId.UniqueThread), 00795 &FindWindowFromThread, (LPARAM)&hwnd); 00796 } 00797 if (hwnd == NULL) { 00798 return TSN_NOWINDOW; 00799 } 00800 /* 00801 * Find the root owner (we'll guess this is the "main" window) 00802 */ 00803 while ((hwndOwner = GetWindow(hwnd, GW_OWNER)) != NULL) { 00804 hwnd = hwndOwner; 00805 } 00806 00807 #if defined(FE_IME) 00808 /* 00809 * If this is a console window, then just returns TSN_APPSAYSOK. 00810 * In this routine: 00811 * Normally windows NT environment, hwnd never point to console window. 00812 * However, In ConIme process, its owner window point to console window. 00813 */ 00814 if (!(dwClientFlags & WMCS_ENDTASK)) { 00815 if ((HANDLE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE) == ghModuleWin) { 00816 return TSN_APPSAYSOK; 00817 } 00818 } 00819 #endif 00820 00821 /* 00822 * If this is an EndTask request but the window is disabled, 00823 * then we want to bring the dialog up right way (the app 00824 * is probably waiting for input). 00825 * Otherwise, we bring the window to the foreground, send/post 00826 * the request and wait 00827 */ 00828 00829 00830 /* 00831 * Bug 296188 - joejo 00832 * 00833 * Make sure we respond to the user ASAP when they 00834 * attempt to shutdown an application that we know is hung. 00835 */ 00836 00837 if ((dwClientFlags & WMCS_ENDTASK)) { 00838 00839 dwTimeout = gCmsHungAppTimeout; 00840 NtUserQueryInformationThread(pcsrt->ThreadHandle, UserThreadHungStatus, &dwTimeout, sizeof(dwTimeout), NULL); 00841 00842 if (!IsWindowEnabled(hwnd) || dwTimeout){ 00843 dwRealTimeout = 0; 00844 fEndTaskNow = TRUE; 00845 } 00846 00847 00848 } 00849 00850 if (!fEndTaskNow) { 00851 00852 SetForegroundWindow(hwnd); 00853 dwRealTimeout = gCmsHungAppTimeout; 00854 if (dwClientFlags & WMCS_ENDTASK) { 00855 PostMessage(hwnd, WM_CLOSE, 0, 0); 00856 } else { 00857 /* 00858 * If the shutdown was canceled, we don't need to wait. 00859 * (we're just sending the WM_ENDSESSION(FALSE)) 00860 */ 00861 if (!(dwClientFlags & (WMCS_QUERYEND | WMCS_EXIT))) { 00862 SendNotifyMessage(hwnd, WM_CLIENTSHUTDOWN, dwClientFlags, 0); 00863 return TSN_APPSAYSOK; 00864 } 00865 /* 00866 * Allocate callback data. If out of memory, kill it. 00867 */ 00868 pwmcsd = (PWMCSDATA)LocalAlloc(LPTR, sizeof(WMCSDATA)); 00869 if (pwmcsd == NULL) { 00870 return TSN_USERSAYSKILL; 00871 } 00872 00873 SendMessageCallback(hwnd, WM_CLIENTSHUTDOWN, dwClientFlags, 0, 00874 WMCSCallback, (ULONG_PTR)pwmcsd); 00875 } 00876 } 00877 00878 SetupWaitLoop: 00879 /* 00880 * This tells us if the hwndDlg is valid. This is set/cleared by 00881 * EndTaskDlgProc 00882 */ 00883 ZeroMemory(&edp, sizeof(edp)); 00884 edp.dwFlags = EDPF_NODLG; 00885 /* 00886 * Loop until the hwnd replies, the request is canceled 00887 * or the thread goes away. It time out, bring up the 00888 * dialog and wait until the user tells us what to do. 00889 */ 00890 *(ahandles + ESMH_CANCELEVENT) = gheventCancel; 00891 *(ahandles + ESMH_THREAD) = hThread; 00892 dwStartTiming = GetTickCount(); 00893 dwCmd = 0; 00894 while (dwCmd == 0) { 00895 /* 00896 * Calculate how long we have to wait. 00897 */ 00898 dwTimeout = dwRealTimeout; 00899 if ((dwTimeout != 0) && (dwTimeout != INFINITE)) { 00900 dwTimeout -= (GetTickCount() - dwStartTiming); 00901 if ((int)dwTimeout < 0) { 00902 dwTimeout = 0; 00903 } 00904 } 00905 00906 dwRet = MsgWaitForMultipleObjects(ESMH_HANDLECOUNT, ahandles, FALSE, dwTimeout, QS_ALLINPUT); 00907 00908 switch (dwRet) { 00909 case WAIT_OBJECT_0 + ESMH_CANCELEVENT: 00910 /* 00911 * The request has been canceled. 00912 */ 00913 dwCmd = TSN_USERSAYSCANCEL; 00914 break; 00915 00916 case WAIT_OBJECT_0 + ESMH_THREAD: 00917 /* 00918 * The thread is gone. 00919 */ 00920 dwCmd = TSN_APPSAYSOK; 00921 break; 00922 00923 case WAIT_OBJECT_0 + ESMH_HANDLECOUNT: 00924 /* 00925 * We got some input; process it. 00926 */ 00927 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 00928 if ((edp.dwFlags & EDPF_NODLG) 00929 || !IsDialogMessage(hwndDlg, &msg)) { 00930 00931 TranslateMessage(&msg); 00932 DispatchMessage(&msg); 00933 } 00934 } 00935 /* 00936 * If we got a reply to the message, act on it 00937 */ 00938 if ((pwmcsd != NULL) && (pwmcsd->dwFlags & WMCSD_REPLY)) { 00939 00940 switch (pwmcsd->dwRet) { 00941 default: 00942 /* 00943 * If the message was not processed (the thread 00944 * exited) or someone processed it and returned 00945 * a bogus value, just shut them down. 00946 * Fall through 00947 */ 00948 case WMCSR_ALLOWSHUTDOWN: 00949 /* 00950 * We're going to nuke this app, so get rid of 00951 * any pending harderror boxes he might have 00952 */ 00953 BoostHardError((ULONG_PTR)pcsrt->ClientId.UniqueProcess, BHE_FORCE); 00954 /* 00955 * Fall through. 00956 */ 00957 case WMCSR_DONE: 00958 dwCmd = TSN_APPSAYSOK; 00959 break; 00960 00961 case WMCSR_CANCEL: 00962 dwCmd = TSN_APPSAYSNOTOK; 00963 break; 00964 } 00965 } 00966 /* 00967 * Else if the dialog is still up, keep waiting for the user 00968 * to tell us what to do 00969 */ 00970 else if (!(edp.dwFlags & EDPF_NODLG)) { 00971 break; 00972 } 00973 /* 00974 * Else if the user dismissed the dialog, act on his response 00975 */ 00976 else if (edp.dwFlags & EDPF_RESPONSE) { 00977 switch(edp.dwRet) { 00978 case IDC_ENDNOW: 00979 /* 00980 * The user wants us to kill it 00981 */ 00982 dwCmd = TSN_USERSAYSKILL; 00983 break; 00984 00985 /* case IDCANCEL: */ 00986 default: 00987 dwCmd = TSN_USERSAYSCANCEL; 00988 break; 00989 } 00990 } 00991 break; 00992 00993 case WAIT_TIMEOUT: 00994 00995 if (dwClientFlags & WMCS_NORETRY) { 00996 00997 /* 00998 * We come here only for Terminal Server case. We return 00999 * TSN_APPSAYSOK as Terminal Server 4 did in this case. 01000 */ 01001 UserAssert(ISTS()); 01002 01003 dwCmd = TSN_APPSAYSOK; 01004 break; 01005 } 01006 01007 01008 /* 01009 * Once we time out, we bring up the dialog and let 01010 * its timer take over. 01011 */ 01012 dwRealTimeout = INFINITE; 01013 /* 01014 * Check if the windows app is waiting for input; 01015 * if not, we assume it is hung for EndTask; 01016 * otherwise we enter a wait mode that brings the 01017 * dialog up just to provide some (waiting) feedback 01018 * Console just gets the dialog right away 01019 */ 01020 if (!(dwClientFlags & WMCS_CONSOLE)) { 01021 if (BoostHardError((ULONG_PTR)pcsrt->ClientId.UniqueProcess, BHE_TEST) 01022 || (GetInputWindow(pcsrt, hwnd) != NULL)) { 01023 01024 edp.dwFlags |= EDPF_INPUT; 01025 } else { 01026 /* 01027 * EWX_FORCEIFHUNG support. 01028 * Also, if this is an ExitWindows call and the process is not in 01029 * the context being logged off, we won't kill it. 01030 * So don't bother asking the user what to do 01031 */ 01032 if ((dwClientFlags & WMCS_NODLGIFHUNG) 01033 || (!(dwClientFlags & WMCS_ENDTASK) 01034 && !(dwClientFlags & WMCS_CONTEXTLOGOFF))) { 01035 01036 dwCmd = TSN_USERSAYSKILL; 01037 break; 01038 } 01039 /* 01040 * Hung or Wait? 01041 */ 01042 if (dwClientFlags & WMCS_ENDTASK) { 01043 edp.dwFlags |= EDPF_HUNG; 01044 } else { 01045 edp.dwFlags |= EDPF_WAIT; 01046 } 01047 } 01048 } 01049 01050 /* 01051 * If the registry says no dialog, then tell the caller 01052 * the user wants to kill the app. 01053 */ 01054 if (gfAutoEndTask) { 01055 dwCmd = TSN_USERSAYSKILL; 01056 break; 01057 } 01058 /* 01059 * Setup the parameters needed by EndTaskDlgProc 01060 */ 01061 edp.dwRet = 0; 01062 edp.dwClientFlags = dwClientFlags; 01063 if (dwClientFlags & WMCS_CONSOLE) { 01064 edp.pcsrt = NULL; 01065 edp.lParam = lParam; 01066 } else { 01067 edp.pcsrt = pcsrt; 01068 edp.lParam = (LPARAM)hwnd; 01069 } 01070 01071 hwndDlg = CreateDialogParam (ghModuleWin, MAKEINTRESOURCE(IDD_ENDTASK), 01072 NULL, EndTaskDlgProc, (LPARAM)(&edp)); 01073 /* 01074 * If we cannot ask the user, then kill the app. 01075 */ 01076 if (hwndDlg == NULL) { 01077 edp.dwFlags |= EDPF_NODLG; 01078 dwCmd = TSN_USERSAYSKILL; 01079 break; 01080 } 01081 break; 01082 01083 default: 01084 /* 01085 * Unexpected return; something is wrong. Kill the app. 01086 */ 01087 UserAssert(dwRet != dwRet); 01088 dwCmd = TSN_USERSAYSKILL; 01089 break; 01090 } /* switch (dwRet) */ 01091 } /* while (dwCmd == 0) */ 01092 01093 01094 /* 01095 * If the dialog is up, nuke it. 01096 */ 01097 if (!(edp.dwFlags & EDPF_NODLG)) { 01098 DestroyWindow(hwndDlg); 01099 } 01100 /* 01101 * Make sure pwmcsd is freed or marked to be freed by WMCSCallback 01102 * when the reply comes 01103 */ 01104 if (pwmcsd != NULL) { 01105 if (pwmcsd->dwFlags & WMCSD_REPLY) { 01106 LocalFree(pwmcsd); 01107 } else { 01108 pwmcsd->dwFlags |= WMCSD_IGNORE; 01109 } 01110 } 01111 #if DBG 01112 /* 01113 * If Canceling, let's the name the app that doesn't let us log off 01114 */ 01115 if ((dwClientFlags & WMCS_EXIT) && (dwCmd == TSN_APPSAYSNOTOK)) { 01116 WCHAR achTitle[CCHBODYMAX]; 01117 WCHAR *pwcText; 01118 UserAssert(!(dwClientFlags & WMCS_CONSOLE)); 01119 pwcText = achTitle; 01120 *(achTitle + CCHBODYMAX - 1) = (WCHAR)0; 01121 GetApplicationText(hwnd, hThread, pwcText, CCHBODYMAX - 1); 01122 KdPrint(("Log off canceled by pid:%#lx tid:%#lx - '%ws'.\n", 01123 HandleToUlong(pcsrt->ClientId.UniqueProcess), 01124 HandleToUlong(pcsrt->ClientId.UniqueThread), 01125 pwcText)); 01126 } 01127 #endif 01128 /* 01129 * If we're killing this dude, clean any hard errors. 01130 * Also if wow takes care of it, then our caller doesn't need to 01131 */ 01132 if ((dwCmd == TSN_USERSAYSKILL) && !(dwClientFlags & WMCS_CONSOLE)) { 01133 01134 BoostHardError((ULONG_PTR)pcsrt->ClientId.UniqueProcess, BHE_FORCE); 01135 01136 if (!(pcsrt->Flags & CSR_THREAD_DESTROYED) && WowExitTask(pcsrt)) { 01137 dwCmd = TSN_APPSAYSOK; 01138 } 01139 } 01140 01141 return dwCmd; 01142 }

NTSTATUS UserClientShutdown PCSR_PROCESS  pcsrp,
ULONG  dwFlags,
BOOLEAN  fFirstPass
 

Definition at line 219 of file server/exitwin.c.

References BHE_FORCE, BOOL, BoostHardError(), CSR_THREAD_SHUTDOWNSKIP, DebugPort, dwFlags, DWORD, FALSE, gdwProcessTerminateTimeout, gdwThreadEndSession, gSessionId, ISTS, NT_SUCCESS, NtQueryInformationProcess(), NTSTATUS(), NtTerminateProcess(), NtUserQueryInformationThread(), NtUserSetInformationThread(), NtWaitForSingleObject(), NULL, SHUTDOWN_CANCEL, SHUTDOWN_KNOWN_PROCESS, SHUTDOWN_UNKNOWN_PROCESS, Status, ThreadShutdownNotify(), TRUE, TSN_APPSAYSNOTOK, TSN_APPSAYSOK, TSN_NOWINDOW, TSN_USERSAYSCANCEL, TSN_USERSAYSKILL, UINT, WMCS_CONTEXTLOGOFF, WMCS_EXIT, WMCS_LOGOFF, WMCS_NODLGIFHUNG, WMCS_NORETRY, and WMCS_QUERYEND.

Referenced by UserServerDllInitialization().

00223 { 00224 PLIST_ENTRY ListHead, ListNext; 00225 PCSR_PROCESS Process; 00226 PCSR_THREAD Thread; 00227 USERTHREAD_SHUTDOWN_INFORMATION ShutdownInfo; 00228 BOOL fNoMsgs; 00229 BOOL fNoMsgsEver = TRUE; 00230 BOOL Forced = FALSE; 00231 BOOL bDoBlock; 00232 BOOL fNoRetry; 00233 DWORD cmd = 0, dwClientFlags; 00234 NTSTATUS Status; 00235 NTSTATUS TerminateStatus = STATUS_ACCESS_DENIED; 00236 UINT cThreads; 00237 BOOL fSendEndSession = FALSE; 00238 00239 #if DBG 00240 DWORD dwLocalThreadEndSession = gdwThreadEndSession; 00241 #endif 00242 00243 /* 00244 * If this is a logoff and the process does not belong to 00245 * the account doing the logoff and is not LocalSystem, 00246 * do not send end-session messages. Console will notify 00247 * the app of the logoff. 00248 */ 00249 if (!(dwFlags & EWX_SHUTDOWN) && (pcsrp->ShutdownFlags & SHUTDOWN_OTHERCONTEXT)) { 00250 Status = SHUTDOWN_UNKNOWN_PROCESS; 00251 goto CleanupAndExit; 00252 } 00253 00254 /* 00255 * Calculate whether to allow exit and force-exit this process before 00256 * we unlock pcsrp. 00257 */ 00258 fNoRetry = (pcsrp->ShutdownFlags & SHUTDOWN_NORETRY) || 00259 (dwFlags & EWX_FORCE); 00260 00261 /* 00262 * Setup flags for WM_CLIENTSHUTDOWN 00263 * -Assume the process is going to OK the WM_QUERYENDSESSION (WMCS_EXIT) 00264 * -NT's shutdown always starts with a logoff. 00265 * -Shutdown or logoff? (WMCS_SHUTDOWN) 00266 * -Should display dialog for hung apps? (WMCS_NODLGIFHUNG) 00267 * -is this process in the context being logged off? (WMCS_CONTEXTLOGOFF) 00268 */ 00269 dwClientFlags = WMCS_EXIT | (fNoRetry ? WMCS_NORETRY : 0); 00270 //} 00271 00272 /* 00273 * Check the flags originally passed by the ExitWindows caller to see if we're 00274 * really just logging off. 00275 */ 00276 if (!(dwFlags & (EWX_WINLOGON_OLD_REBOOT | EWX_WINLOGON_OLD_SHUTDOWN))) { 00277 dwClientFlags |= WMCS_LOGOFF; 00278 } 00279 00280 if (dwFlags & EWX_FORCEIFHUNG) { 00281 dwClientFlags |= WMCS_NODLGIFHUNG; 00282 } 00283 if (!(pcsrp->ShutdownFlags & (SHUTDOWN_SYSTEMCONTEXT | SHUTDOWN_OTHERCONTEXT))) { 00284 dwClientFlags |= WMCS_CONTEXTLOGOFF; 00285 } 00286 00287 00288 /* 00289 * Lock the process while we walk the thread list. We know 00290 * that the process is valid and therefore do not need to 00291 * check the return status. 00292 */ 00293 CsrLockProcessByClientId(pcsrp->ClientId.UniqueProcess, &Process); 00294 00295 ShutdownInfo.StatusShutdown = SHUTDOWN_UNKNOWN_PROCESS; 00296 00297 /* 00298 * Go through the thread list and mark them as not 00299 * shutdown yet. 00300 */ 00301 ListHead = &pcsrp->ThreadList; 00302 ListNext = ListHead->Flink; 00303 while (ListNext != ListHead) { 00304 Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); 00305 Thread->Flags &= ~CSR_THREAD_SHUTDOWNSKIP; 00306 ListNext = ListNext->Flink; 00307 } 00308 00309 /* 00310 * Perform the proper shutdown operation on each thread. Keep 00311 * a count of the number of gui threads found. 00312 */ 00313 cThreads = 0; 00314 ShutdownInfo.drdRestore.pdeskRestore = NULL; 00315 ShutdownInfo.drdRestore.hdeskNew = NULL; 00316 while (TRUE) { 00317 ListNext = ListHead->Flink; 00318 while (ListNext != ListHead) { 00319 Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); 00320 /* 00321 * Skip the thread doing the shutdown. Assume that it's 00322 * ready. 00323 * gdwThreadEndSession shouldn't change while the shutdown 00324 * is in progress; so this should be thread safe. 00325 */ 00326 UserAssert(gdwThreadEndSession == dwLocalThreadEndSession); 00327 if (HandleToUlong(Thread->ClientId.UniqueThread) == gdwThreadEndSession) { 00328 Thread->Flags |= CSR_THREAD_SHUTDOWNSKIP; 00329 } 00330 00331 if (!(Thread->Flags & 00332 (CSR_THREAD_DESTROYED | CSR_THREAD_SHUTDOWNSKIP))) { 00333 break; 00334 } 00335 ListNext = ListNext->Flink; 00336 } 00337 if (ListNext == ListHead) 00338 break; 00339 00340 Thread->Flags |= CSR_THREAD_SHUTDOWNSKIP; 00341 ShutdownInfo.dwFlags = dwClientFlags; 00342 00343 Status = NtUserQueryInformationThread(Thread->ThreadHandle, 00344 UserThreadShutdownInformation, &ShutdownInfo, sizeof(ShutdownInfo), NULL); 00345 00346 if (!NT_SUCCESS(Status)) 00347 continue; 00348 if (ShutdownInfo.StatusShutdown == SHUTDOWN_UNKNOWN_PROCESS) 00349 continue; 00350 if (ShutdownInfo.StatusShutdown == SHUTDOWN_KNOWN_PROCESS) { 00351 CsrUnlockProcess(Process); 00352 Status = SHUTDOWN_KNOWN_PROCESS; 00353 goto RestoreDesktop; 00354 } 00355 00356 /* 00357 * If this process is not in the account being logged off and it 00358 * is not on the windowstation being logged off, don't send 00359 * the end session messages. 00360 */ 00361 if (!(dwClientFlags & WMCS_CONTEXTLOGOFF) && (ShutdownInfo.hwndDesktop == NULL)) { 00362 /* 00363 * This process is not in the context being logged off. Do 00364 * not terminate it and let console send an event to the process. 00365 */ 00366 ShutdownInfo.StatusShutdown = SHUTDOWN_UNKNOWN_PROCESS; 00367 continue; 00368 } 00369 00370 /* 00371 * Shut down this process. 00372 */ 00373 cThreads++; 00374 00375 if (ISTS()) { 00376 Forced = (dwFlags & EWX_FORCE); 00377 fNoMsgs = (pcsrp->ShutdownFlags & SHUTDOWN_NORETRY) || 00378 !(ShutdownInfo.dwFlags & USER_THREAD_GUI); 00379 fNoMsgsEver &= fNoMsgs; 00380 if (Forced && (!(dwFlags & EWX_NONOTIFY) || (gSessionId != 0))) { 00381 dwClientFlags &= ~WMCS_LOGOFF; // WinStation Reset or Shutdown. Don't do this for console session. 00382 } 00383 00384 if (fNoMsgs || Forced) { 00385 BoostHardError((ULONG_PTR)Thread->ClientId.UniqueProcess, BHE_FORCE); 00386 } 00387 bDoBlock = (fNoMsgs == FALSE); 00388 00389 } else { 00390 if (fNoRetry || !(ShutdownInfo.dwFlags & USER_THREAD_GUI)) { 00391 00392 /* 00393 * Dispose of any hard errors. 00394 */ 00395 BoostHardError((ULONG_PTR)Thread->ClientId.UniqueProcess, BHE_FORCE); 00396 bDoBlock = FALSE; 00397 } else { 00398 bDoBlock = TRUE; 00399 } 00400 } 00401 00402 if (bDoBlock) { 00403 CsrReferenceThread(Thread); 00404 CsrUnlockProcess(Process); 00405 00406 /* 00407 * There are problems in changing shutdown to send all the 00408 * QUERYENDSESSIONs at once before doing any ENDSESSIONs, like 00409 * Windows does. The whole machine needs to be modal if you do this. 00410 * If it isn't modal, then you have this problem. Imagine app 1 and 2. 00411 * 1 gets the queryendsession, no problem. 2 gets it and brings up a 00412 * dialog. Now being a simple user, you decide you need to change the 00413 * document in app 1. Now you switch back to app 2, hit ok, and 00414 * everything goes away - including app 1 without saving its changes. 00415 * Also, apps expect that once they've received the QUERYENDSESSION, 00416 * they are not going to get anything else of any particular interest 00417 * (unless it is a WM_ENDSESSION with FALSE) We had bugs pre 511 where 00418 * apps were blowing up because of this. 00419 * If this change is made, the entire system must be modal 00420 * while this is going on. - ScottLu 6/30/94 00421 */ 00422 cmd = ThreadShutdownNotify(dwClientFlags | WMCS_QUERYEND, (ULONG_PTR)Thread, 0); 00423 00424 CsrLockProcessByClientId(pcsrp->ClientId.UniqueProcess, &Process); 00425 CsrDereferenceThread(Thread); 00426 00427 /* 00428 * If shutdown has been cancelled, let csr know about it. 00429 */ 00430 switch (cmd) { 00431 case TSN_USERSAYSCANCEL: 00432 case TSN_APPSAYSNOTOK: 00433 if (!Forced) { 00434 dwClientFlags &= ~WMCS_EXIT; 00435 } 00436 00437 /* 00438 * Fall through. 00439 */ 00440 case TSN_APPSAYSOK: 00441 fSendEndSession = TRUE; 00442 break; 00443 00444 case TSN_USERSAYSKILL: 00445 /* 00446 * Since we cannot just kill one thread, the whole process 00447 * is going down. Hence, there is no point on continuing 00448 * checking other threads. Also, the user wants it killed 00449 * so we won't waste any time sending more messages 00450 */ 00451 dwClientFlags |= WMCS_EXIT; 00452 goto KillIt; 00453 00454 case TSN_NOWINDOW: 00455 /* 00456 * Did this process have a window? 00457 * If this is the second pass we terminate the process even if it did 00458 * not have any windows in case the app was just starting up. 00459 * WOW hits this often when because it takes so long to start up. 00460 * Logon (with WOW auto-starting) then logoff WOW won't die but will 00461 * lock some files open so you can't logon next time. 00462 */ 00463 if (fFirstPass) { 00464 cThreads--; 00465 } 00466 break; 00467 } 00468 } 00469 } 00470 00471 /* 00472 * If end session message need to be sent, do it now. 00473 */ 00474 if (fSendEndSession) { 00475 00476 /* 00477 * Go through the thread list and mark them as not 00478 * shutdown yet. 00479 */ 00480 ListNext = ListHead->Flink; 00481 while (ListNext != ListHead) { 00482 Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); 00483 Thread->Flags &= ~CSR_THREAD_SHUTDOWNSKIP; 00484 ListNext = ListNext->Flink; 00485 } 00486 00487 /* 00488 * Perform the proper shutdown operation on each thread. 00489 */ 00490 while (TRUE) { 00491 ListHead = &pcsrp->ThreadList; 00492 ListNext = ListHead->Flink; 00493 while (ListNext != ListHead) { 00494 Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); 00495 if (!(Thread->Flags & 00496 (CSR_THREAD_DESTROYED | CSR_THREAD_SHUTDOWNSKIP))) { 00497 break; 00498 } 00499 ListNext = ListNext->Flink; 00500 } 00501 if (ListNext == ListHead) 00502 break; 00503 00504 Thread->Flags |= CSR_THREAD_SHUTDOWNSKIP; 00505 ShutdownInfo.dwFlags = dwClientFlags; 00506 00507 Status = NtUserQueryInformationThread(Thread->ThreadHandle, 00508 UserThreadShutdownInformation, &ShutdownInfo, sizeof(ShutdownInfo), NULL); 00509 00510 if (!NT_SUCCESS(Status)) 00511 continue; 00512 00513 if (ShutdownInfo.StatusShutdown == SHUTDOWN_UNKNOWN_PROCESS || 00514 !(ShutdownInfo.dwFlags & USER_THREAD_GUI)) 00515 continue; 00516 00517 /* 00518 * Send the end session messages to the thread. 00519 */ 00520 CsrReferenceThread(Thread); 00521 CsrUnlockProcess(Process); 00522 00523 /* 00524 * If the user says kill it, the user wants it to go away now 00525 * no matter what. If the user didn't say kill, then call again 00526 * because we need to send WM_ENDSESSION messages. 00527 */ 00528 ThreadShutdownNotify(dwClientFlags, (ULONG_PTR)Thread, 0); 00529 00530 CsrLockProcessByClientId(pcsrp->ClientId.UniqueProcess, &Process); 00531 CsrDereferenceThread(Thread); 00532 } 00533 } 00534 00535 KillIt: 00536 CsrUnlockProcess(Process); 00537 00538 if (ISTS()) { 00539 bDoBlock = (!fNoMsgsEver && !(dwClientFlags & WMCS_EXIT)); 00540 } else { 00541 bDoBlock = (!fNoRetry && !(dwClientFlags & WMCS_EXIT)); 00542 } 00543 00544 if (bDoBlock) { 00545 Status = SHUTDOWN_CANCEL; 00546 goto RestoreDesktop; 00547 } 00548 00549 /* 00550 * Set the final shutdown status according to the number of gui 00551 * threads found. If the count is zero, we have an unknown process. 00552 */ 00553 if (cThreads == 0) 00554 ShutdownInfo.StatusShutdown = SHUTDOWN_UNKNOWN_PROCESS; 00555 else 00556 ShutdownInfo.StatusShutdown = SHUTDOWN_KNOWN_PROCESS; 00557 00558 if (ShutdownInfo.StatusShutdown == SHUTDOWN_UNKNOWN_PROCESS || 00559 !(dwClientFlags & WMCS_CONTEXTLOGOFF)) { 00560 00561 /* 00562 * This process is not in the context being logged off. Do 00563 * not terminate it and let console send an event to the process. 00564 */ 00565 Status = SHUTDOWN_UNKNOWN_PROCESS; 00566 00567 if (ShutdownInfo.drdRestore.hdeskNew) { 00568 goto RestoreDesktop; 00569 } 00570 goto CleanupAndExit; 00571 } 00572 00573 /* 00574 * Calling ExitProcess() in the app's context will not always work 00575 * because the app may have .dll termination deadlocks: so the thread 00576 * will hang with the rest of the process. To ensure apps go away, 00577 * we terminate the process with NtTerminateProcess(). 00578 * 00579 * Pass this special value, DBG_TERMINATE_PROCESS, which tells 00580 * NtTerminateProcess() to return failure if it can't terminate the 00581 * process because the app is being debugged. 00582 */ 00583 00584 if (ISTS()) { 00585 NTSTATUS ExitStatus; 00586 HANDLE DebugPort; 00587 00588 ExitStatus = DBG_TERMINATE_PROCESS; 00589 if (NT_SUCCESS(NtQueryInformationProcess(NtCurrentProcess(), 00590 ProcessDebugPort, 00591 &DebugPort, 00592 sizeof(HANDLE), 00593 NULL)) && 00594 (DebugPort != NULL)) { 00595 // Csr is being debugged - go ahead and kill the process 00596 ExitStatus = 0; 00597 } 00598 TerminateStatus = NtTerminateProcess(pcsrp->ProcessHandle, ExitStatus); 00599 } else { 00600 TerminateStatus = NtTerminateProcess(pcsrp->ProcessHandle, DBG_TERMINATE_PROCESS); 00601 } 00602 00603 pcsrp->Flags |= CSR_PROCESS_TERMINATED; 00604 00605 00606 /* 00607 * Let csr know we know about this process - meaning it was our 00608 * responsibility to shut it down. 00609 */ 00610 Status = SHUTDOWN_KNOWN_PROCESS; 00611 00612 RestoreDesktop: 00613 00614 /* 00615 * Release the desktop that was used. 00616 */ 00617 { 00618 USERTHREAD_USEDESKTOPINFO utudi; 00619 utudi.hThread = NULL; 00620 RtlCopyMemory(&(utudi.drdRestore), &(ShutdownInfo.drdRestore), sizeof(DESKRESTOREDATA)); 00621 00622 NtUserSetInformationThread(NtCurrentThread(), UserThreadUseDesktop, 00623 &utudi, sizeof(utudi)); 00624 } 00625 00626 /* 00627 * Now that we're done with the process handle, derefence the csr 00628 * process structure. 00629 */ 00630 if (Status != SHUTDOWN_UNKNOWN_PROCESS) { 00631 00632 /* 00633 * If TerminateProcess returned STATUS_ACCESS_DENIED, then the process 00634 * is being debugged and it wasn't terminated.Otherwise we need to wait 00635 * anyway since TerminateProcess might return failure when the process 00636 * is going away (ie STATUS_PROCESS_IS_TERMINATING).If termination 00637 * indeed fail, something is wrong anyway so waiting a bit won't 00638 * hurt much. 00639 * If we wait give the process whatever exit timeout value configured 00640 * in the registry, but no less than the 5 second Hung App timeout. 00641 00642 */ 00643 if (TerminateStatus != STATUS_ACCESS_DENIED) { 00644 LARGE_INTEGER li; 00645 00646 li.QuadPart = (LONGLONG)-10000 * gdwProcessTerminateTimeout; 00647 TerminateStatus = NtWaitForSingleObject(pcsrp->ProcessHandle, 00648 FALSE, 00649 &li); 00650 if (TerminateStatus != STATUS_WAIT_0) { 00651 RIPMSG2(RIP_WARNING, 00652 "UserClientShutdown: wait for process %x failed with status %x", 00653 pcsrp->ClientId.UniqueProcess, TerminateStatus); 00654 } 00655 } 00656 00657 CsrDereferenceProcess(pcsrp); 00658 } 00659 00660 00661 CleanupAndExit: 00662 00663 return Status; 00664 }

VOID CALLBACK WMCSCallback HWND  hwnd,
UINT  uMsg,
ULONG_PTR  dwData,
LRESULT  lResult
 

Definition at line 676 of file server/exitwin.c.

References tagWMCSDATA::dwFlags, DWORD, tagWMCSDATA::dwRet, PWMCSDATA, VOID(), WMCSD_IGNORE, and WMCSD_REPLY.

Referenced by ThreadShutdownNotify().

00677 { 00678 PWMCSDATA pwmcsd = (PWMCSDATA)dwData; 00679 if (pwmcsd->dwFlags & WMCSD_IGNORE) { 00680 LocalFree(pwmcsd); 00681 return; 00682 } 00683 00684 pwmcsd->dwFlags |= WMCSD_REPLY; 00685 pwmcsd->dwRet = (DWORD)lResult; 00686 00687 UNREFERENCED_PARAMETER(hwnd); 00688 UNREFERENCED_PARAMETER(uMsg); 00689 }

BOOL WowExitTask PCSR_THREAD  pcsrt  ) 
 

Definition at line 1791 of file server/exitwin.c.

References BOOL, FALSE, gheventCancel, InternalCreateCallbackThread(), NT_SUCCESS, NtClose(), NTSTATUS(), NtTerminateProcess(), NtUserQueryInformationThread(), NULL, Status, and TRUE.

Referenced by _EndTask(), and ThreadShutdownNotify().

01793 { 01794 HANDLE ahandle[2]; 01795 USERTHREAD_WOW_INFORMATION WowInfo; 01796 NTSTATUS Status; 01797 01798 ahandle[1] = gheventCancel; 01799 01800 /* 01801 * Query task id and exit function. 01802 */ 01803 Status = NtUserQueryInformationThread(pcsrt->ThreadHandle, 01804 UserThreadWOWInformation, &WowInfo, sizeof(WowInfo), NULL); 01805 if (!NT_SUCCESS(Status)) 01806 return FALSE; 01807 01808 /* 01809 * If no task id was returned, it is not a WOW task 01810 */ 01811 if (WowInfo.hTaskWow == 0) 01812 return FALSE; 01813 01814 /* 01815 * Try to make it exit itself. This will work most of the time. 01816 * If this doesn't work, terminate this process. 01817 */ 01818 ahandle[0] = InternalCreateCallbackThread(pcsrt->Process->ProcessHandle, 01819 (ULONG_PTR)WowInfo.lpfnWowExitTask, 01820 (ULONG_PTR)WowInfo.hTaskWow); 01821 if (ahandle[0] == NULL) { 01822 NtTerminateProcess(pcsrt->Process->ProcessHandle, 0); 01823 pcsrt->Process->Flags |= CSR_PROCESS_TERMINATED; 01824 goto Exit; 01825 } 01826 01827 WaitForMultipleObjects(2, ahandle, FALSE, INFINITE); 01828 NtClose(ahandle[0]); 01829 01830 Exit: 01831 return TRUE; 01832 }


Generated on Sat May 15 19:43:36 2004 for test by doxygen 1.3.7