Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

733 lines
20 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include <msginaexports.h>
  4. #include <ntddapmt.h>
  5. #include <lmcons.h> // Username length constant
  6. #include <winsta.h> // Hydra functions/constants
  7. #include <powrprof.h>
  8. #include "SwitchUserDialog.h"
  9. #include "filetbl.h"
  10. #define DOCKSTATE_DOCKED 0
  11. #define DOCKSTATE_UNDOCKED 1
  12. #define DOCKSTATE_UNKNOWN 2
  13. void FlushRunDlgMRU(void);
  14. // Disconnect API fn-ptr
  15. typedef BOOLEAN (WINAPI *PWINSTATION_DISCONNECT) (HANDLE hServer, ULONG SessionId, BOOL bWait);
  16. // Process all of the strange ExitWindowsEx codes and privileges.
  17. STDAPI_(BOOL) CommonRestart(DWORD dwExitWinCode, DWORD dwReasonCode)
  18. {
  19. BOOL fOk;
  20. DWORD dwExtraExitCode = 0;
  21. DWORD OldState;
  22. DWORD dwError;
  23. DebugMsg(DM_TRACE, TEXT("CommonRestart(0x%x, 0x%x)"), dwExitWinCode, dwReasonCode);
  24. IconCacheSave();
  25. if ((dwExitWinCode == EWX_SHUTDOWN) && IsPwrShutdownAllowed())
  26. {
  27. dwExtraExitCode = EWX_POWEROFF;
  28. }
  29. dwError = SetPrivilegeAttribute(SE_SHUTDOWN_NAME, SE_PRIVILEGE_ENABLED, &OldState);
  30. switch (dwExitWinCode)
  31. {
  32. case EWX_SHUTDOWN:
  33. case EWX_REBOOT:
  34. case EWX_LOGOFF:
  35. if (GetKeyState(VK_CONTROL) < 0)
  36. {
  37. dwExtraExitCode |= EWX_FORCE;
  38. }
  39. break;
  40. }
  41. fOk = ExitWindowsEx(dwExitWinCode | dwExtraExitCode, dwReasonCode);
  42. // If we were able to set the privilege, then reset it.
  43. if (dwError == ERROR_SUCCESS)
  44. {
  45. SetPrivilegeAttribute(SE_SHUTDOWN_NAME, OldState, NULL);
  46. }
  47. else
  48. {
  49. // Otherwise, if we failed, then it must have been some
  50. // security stuff.
  51. if (!fOk)
  52. {
  53. ShellMessageBox(HINST_THISDLL, NULL,
  54. dwExitWinCode == EWX_SHUTDOWN ?
  55. MAKEINTRESOURCE(IDS_NO_PERMISSION_SHUTDOWN) :
  56. MAKEINTRESOURCE(IDS_NO_PERMISSION_RESTART),
  57. dwExitWinCode == EWX_SHUTDOWN ?
  58. MAKEINTRESOURCE(IDS_SHUTDOWN) :
  59. MAKEINTRESOURCE(IDS_RESTART),
  60. MB_OK | MB_ICONSTOP);
  61. }
  62. }
  63. DebugMsg(DM_TRACE, TEXT("CommonRestart done"));
  64. return fOk;
  65. }
  66. void EarlySaveSomeShellState()
  67. {
  68. // We flush two MRU's here (RecentMRU and RunDlgMRU).
  69. // Note that they won't flush if there is any reference count.
  70. FlushRunDlgMRU();
  71. }
  72. /*
  73. * Display a dialog asking the user to restart Windows, with a button that
  74. * will do it for them if possible.
  75. */
  76. STDAPI_(int) RestartDialog(HWND hParent, LPCTSTR lpPrompt, DWORD dwReturn)
  77. {
  78. return RestartDialogEx(hParent, lpPrompt, dwReturn, 0);
  79. }
  80. STDAPI_(int) RestartDialogEx(HWND hParent, LPCTSTR lpPrompt, DWORD dwReturn, DWORD dwReasonCode)
  81. {
  82. UINT id;
  83. LPCTSTR pszMsg;
  84. EarlySaveSomeShellState();
  85. if (lpPrompt && *lpPrompt == TEXT('#'))
  86. {
  87. pszMsg = lpPrompt + 1;
  88. }
  89. else if (dwReturn == EWX_SHUTDOWN)
  90. {
  91. pszMsg = MAKEINTRESOURCE(IDS_RSDLG_SHUTDOWN);
  92. }
  93. else
  94. {
  95. pszMsg = MAKEINTRESOURCE(IDS_RSDLG_RESTART);
  96. }
  97. id = ShellMessageBox(HINST_THISDLL, hParent, pszMsg, MAKEINTRESOURCE(IDS_RSDLG_TITLE),
  98. MB_YESNO | MB_ICONQUESTION, lpPrompt ? lpPrompt : c_szNULL);
  99. if (id == IDYES)
  100. {
  101. CommonRestart(dwReturn, dwReasonCode);
  102. }
  103. return id;
  104. }
  105. const TCHAR c_szREGSTR_ROOT_APM[] = REGSTR_KEY_ENUM TEXT("\\") REGSTR_KEY_ROOTENUM TEXT("\\") REGSTR_KEY_APM TEXT("\\") REGSTR_DEFAULT_INSTANCE;
  106. const TCHAR c_szREGSTR_BIOS_APM[] = REGSTR_KEY_ENUM TEXT("\\") REGSTR_KEY_BIOSENUM TEXT("\\") REGSTR_KEY_APM;
  107. const TCHAR c_szREGSTR_VAL_APMMENUSUSPEND[] = REGSTR_VAL_APMMENUSUSPEND;
  108. /* Open the registry APM device key
  109. */
  110. BOOL OpenAPMKey(HKEY *phKey)
  111. {
  112. HKEY hBiosSys;
  113. BOOL rc = FALSE;
  114. TCHAR szInst[MAX_PATH+1];
  115. DWORD cchInst = ARRAYSIZE(szInst);
  116. // Open HKLM\Enum\Root\*PNP0C05\0000 - This is the APM key for
  117. // non-PnP BIOS machines.
  118. if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szREGSTR_ROOT_APM, phKey) == ERROR_SUCCESS)
  119. return TRUE;
  120. // Open HKLM\Enum\BIOS\*PNP0C05, Enum the 1st subkey, open that. Example:
  121. // HKLM\Enum\BIOS\*PNP0C05\03.
  122. if (RegOpenKey(HKEY_LOCAL_MACHINE,c_szREGSTR_BIOS_APM,&hBiosSys) == ERROR_SUCCESS)
  123. {
  124. if (RegEnumKey(hBiosSys, 0, szInst, cchInst) == ERROR_SUCCESS &&
  125. RegOpenKey(hBiosSys, szInst, phKey) == ERROR_SUCCESS)
  126. rc = TRUE;
  127. RegCloseKey(hBiosSys);
  128. }
  129. return rc;
  130. }
  131. BOOL CheckBIOS(void)
  132. {
  133. HKEY hkey;
  134. BOOL fRet = TRUE;
  135. BOOL fSuspendUndocked = TRUE;
  136. /* Check the Registry APM key for an APMMenuSuspend value.
  137. * APMMenuSuspend may have the following values: APMMENUSUSPEND_DISABLED,
  138. * APMMENUSUSPEND_ENABLED, or APMMENUSUSPEND_UNDOCKED.
  139. *
  140. * An APMMenuSuspend value of APMMENUSUSPEND_DISABLED means the
  141. * tray should never show the Suspend menu item on its menu.
  142. *
  143. * APMMENUSUSPEND_ENABLED means the Suspend menu item should be shown
  144. * if the machine has APM support enabled (VPOWERD is loaded). This is
  145. * the default.
  146. *
  147. * APMMENUSUSPEND_UNDOCKED means the Suspend menu item should be shown,
  148. * but only enabled when the machine is not in a docking station.
  149. *
  150. */
  151. if (OpenAPMKey(&hkey))
  152. {
  153. BYTE bMenuSuspend = APMMENUSUSPEND_ENABLED;
  154. DWORD dwType, cbSize = sizeof(bMenuSuspend);
  155. if (SHQueryValueEx(hkey, c_szREGSTR_VAL_APMMENUSUSPEND, 0,
  156. &dwType, &bMenuSuspend, &cbSize) == ERROR_SUCCESS)
  157. {
  158. bMenuSuspend &= ~(APMMENUSUSPEND_NOCHANGE); // don't care about nochange flag
  159. if (bMenuSuspend == APMMENUSUSPEND_UNDOCKED)
  160. fSuspendUndocked = TRUE;
  161. else
  162. {
  163. fSuspendUndocked = FALSE;
  164. if (bMenuSuspend == APMMENUSUSPEND_DISABLED)
  165. fRet = FALSE;
  166. }
  167. }
  168. RegCloseKey(hkey);
  169. }
  170. if (fRet)
  171. {
  172. // Disable Suspend menu item if 1) only wanted when undocked and
  173. // system is currently docked, 2) power mgnt level < advanced
  174. if (fSuspendUndocked && SHGetMachineInfo(GMI_DOCKSTATE) != GMID_UNDOCKED)
  175. fRet = FALSE;
  176. else
  177. {
  178. DWORD dwPmLevel, cbOut;
  179. BOOL fIoSuccess;
  180. HANDLE hVPowerD = CreateFile(TEXT("\\\\.\\APMTEST"),
  181. GENERIC_READ|GENERIC_WRITE,
  182. FILE_SHARE_READ|FILE_SHARE_WRITE,
  183. NULL, OPEN_EXISTING, 0, NULL);
  184. if (hVPowerD != INVALID_HANDLE_VALUE)
  185. {
  186. fIoSuccess = DeviceIoControl(hVPowerD, APM_IOCTL_GET_PM_LEVEL, NULL, 0, &dwPmLevel, sizeof(dwPmLevel), &cbOut, NULL);
  187. fRet = (fIoSuccess && (dwPmLevel == PMLEVEL_ADVANCED));
  188. CloseHandle (hVPowerD);
  189. }
  190. else
  191. {
  192. fRet = FALSE;
  193. }
  194. }
  195. }
  196. return fRet;
  197. }
  198. BOOL IsShutdownAllowed(void)
  199. {
  200. return SHTestTokenPrivilege(NULL, SE_SHUTDOWN_NAME);
  201. }
  202. // Determine if "Suspend" should appear in the shutdown dialog.
  203. // Returns: TRUE if Suspend should appear, FALSE if not.
  204. STDAPI_(BOOL) IsSuspendAllowed(void)
  205. {
  206. //
  207. // Suspend requires SE_SHUTDOWN_PRIVILEGE
  208. // Call IsShutdownAllowed() to test for this
  209. //
  210. return IsShutdownAllowed() && IsPwrSuspendAllowed();
  211. }
  212. BOOL _LogoffAvailable()
  213. {
  214. // If dwStartMenuLogoff is zero, then we remove it.
  215. BOOL fUpgradeFromIE4 = FALSE;
  216. BOOL fUserWantsLogoff = FALSE;
  217. DWORD dwStartMenuLogoff = 0;
  218. TCHAR sz[MAX_PATH];
  219. DWORD dwRestriction = SHRestricted(REST_STARTMENULOGOFF);
  220. DWORD cbData = sizeof(dwStartMenuLogoff);
  221. if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED,
  222. TEXT("StartMenuLogoff"), NULL, &dwStartMenuLogoff, &cbData))
  223. {
  224. fUserWantsLogoff = (dwStartMenuLogoff != 0);
  225. }
  226. cbData = ARRAYSIZE(sz);
  227. if (SUCCEEDED(SKGetValue(SHELLKEY_HKLM_EXPLORER, TEXT("WindowsUpdate"),
  228. TEXT("UpdateURL"), NULL, sz, &cbData)))
  229. {
  230. fUpgradeFromIE4 = (sz[0] != TEXT('\0'));
  231. }
  232. // Admin is forcing the logoff to be on the menu
  233. if (dwRestriction == 2)
  234. return FALSE;
  235. // The user does wants logoff on the start menu.
  236. // Or it's an upgrade from IE4
  237. if ((fUpgradeFromIE4 || fUserWantsLogoff) && dwRestriction != 1)
  238. return FALSE;
  239. return TRUE;
  240. }
  241. DWORD GetShutdownOptions()
  242. {
  243. LONG lResult = ERROR_SUCCESS + 1;
  244. DWORD dwOptions = SHTDN_SHUTDOWN;
  245. // No shutdown on terminal server
  246. if (!GetSystemMetrics(SM_REMOTESESSION))
  247. {
  248. dwOptions |= SHTDN_RESTART;
  249. }
  250. // Add logoff if supported
  251. if (_LogoffAvailable())
  252. {
  253. dwOptions |= SHTDN_LOGOFF;
  254. }
  255. // Add the hibernate option if it's supported.
  256. if (IsPwrHibernateAllowed())
  257. {
  258. dwOptions |= SHTDN_HIBERNATE;
  259. }
  260. if (IsSuspendAllowed())
  261. {
  262. HKEY hKey;
  263. DWORD dwAdvSuspend = 0;
  264. DWORD dwType, dwSize;
  265. // At least basic sleep is supported
  266. dwOptions |= SHTDN_SLEEP;
  267. //
  268. // Check if we should offer advanced suspend options
  269. //
  270. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  271. TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power"),
  272. 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  273. {
  274. dwSize = sizeof(dwAdvSuspend);
  275. SHQueryValueEx(hKey, TEXT("Shutdown"), NULL, &dwType,
  276. (LPBYTE) &dwAdvSuspend, &dwSize);
  277. RegCloseKey(hKey);
  278. }
  279. if (dwAdvSuspend != 0)
  280. {
  281. dwOptions |= SHTDN_SLEEP2;
  282. }
  283. }
  284. return dwOptions;
  285. }
  286. BOOL_PTR CALLBACK LogoffDlgProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
  287. {
  288. static BOOL s_fLogoffDialog = FALSE;
  289. HICON hIcon;
  290. switch (msg)
  291. {
  292. case WM_INITMENUPOPUP:
  293. EnableMenuItem((HMENU)wparam, SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
  294. break;
  295. case WM_INITDIALOG:
  296. // We could call them when the user actually selects the shutdown,
  297. // but I put them here to leave the shutdown process faster.
  298. //
  299. EarlySaveSomeShellState();
  300. s_fLogoffDialog = FALSE;
  301. hIcon = LoadImage (HINST_THISDLL, MAKEINTRESOURCE(IDI_STLOGOFF),
  302. IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
  303. if (hIcon)
  304. {
  305. SendDlgItemMessage (hdlg, IDD_LOGOFFICON, STM_SETICON, (WPARAM) hIcon, 0);
  306. }
  307. return TRUE;
  308. // Blow off moves (only really needed for 32bit land).
  309. case WM_SYSCOMMAND:
  310. if ((wparam & ~0x0F) == SC_MOVE)
  311. return TRUE;
  312. break;
  313. case WM_COMMAND:
  314. switch (LOWORD(wparam))
  315. {
  316. case IDOK:
  317. s_fLogoffDialog = TRUE;
  318. EndDialog(hdlg, SHTDN_LOGOFF);
  319. break;
  320. case IDCANCEL:
  321. s_fLogoffDialog = TRUE;
  322. EndDialog(hdlg, SHTDN_NONE);
  323. break;
  324. case IDHELP:
  325. WinHelp(hdlg, TEXT("windows.hlp>proc4"), HELP_CONTEXT, (DWORD) IDH_TRAY_SHUTDOWN_HELP);
  326. break;
  327. }
  328. break;
  329. case WM_ACTIVATE:
  330. // If we're loosing the activation for some other reason than
  331. // the user click OK/CANCEL then bail.
  332. if (LOWORD(wparam) == WA_INACTIVE && !s_fLogoffDialog)
  333. {
  334. s_fLogoffDialog = TRUE;
  335. EndDialog(hdlg, SHTDN_NONE);
  336. }
  337. break;
  338. }
  339. return FALSE;
  340. }
  341. // These dialog procedures more or less mirror the behavior of LogoffDlgProc.
  342. INT_PTR CALLBACK DisconnectDlgProc(HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
  343. {
  344. static BOOL s_fIgnoreActivate = FALSE;
  345. INT_PTR ipResult = FALSE;
  346. switch (uMsg)
  347. {
  348. case WM_INITMENUPOPUP:
  349. EnableMenuItem((HMENU)wParam, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
  350. break;
  351. case WM_INITDIALOG:
  352. {
  353. HICON hIcon;
  354. EarlySaveSomeShellState();
  355. s_fIgnoreActivate = FALSE;
  356. hIcon = LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_MU_DISCONN), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
  357. if (hIcon != NULL)
  358. {
  359. SendDlgItemMessage(hwndDialog, IDD_DISCONNECTICON, STM_SETICON, (WPARAM)hIcon, 0);
  360. }
  361. ipResult = TRUE;
  362. break;
  363. }
  364. case WM_SYSCOMMAND:
  365. ipResult = ((wParam & ~0x0F) == SC_MOVE);
  366. break;
  367. case WM_COMMAND:
  368. switch (LOWORD(wParam))
  369. {
  370. case IDOK:
  371. s_fIgnoreActivate = TRUE;
  372. TBOOL(EndDialog(hwndDialog, SHTDN_DISCONNECT));
  373. break;
  374. case IDCANCEL:
  375. s_fIgnoreActivate = TRUE;
  376. TBOOL(EndDialog(hwndDialog, SHTDN_NONE));
  377. break;
  378. }
  379. break;
  380. case WM_ACTIVATE:
  381. if ((WA_INACTIVE == LOWORD(wParam)) && !s_fIgnoreActivate)
  382. {
  383. s_fIgnoreActivate = TRUE;
  384. TBOOL(EndDialog(hwndDialog, SHTDN_NONE));
  385. }
  386. break;
  387. }
  388. return ipResult;
  389. }
  390. BOOL CanDoFastRestart()
  391. {
  392. return GetAsyncKeyState(VK_SHIFT) < 0;
  393. }
  394. // ---------------------------------------------------------------------------
  395. // Shutdown thread
  396. typedef struct
  397. {
  398. DWORD_PTR nCmd;
  399. HWND hwndParent;
  400. } SDTP_PARAMS;
  401. // Hydra-specific
  402. void Disconnect(void)
  403. {
  404. TW32(ShellSwitchUser(FALSE));
  405. }
  406. DWORD CALLBACK ShutdownThreadProc(void *pv)
  407. {
  408. SDTP_PARAMS *psdtp = (SDTP_PARAMS *)pv;
  409. BOOL fShutdownWorked = FALSE;
  410. // tell USER that anybody can steal foreground from us
  411. // This allows apps to put up UI during shutdown/suspend/etc.
  412. // AllowSetForegroundWindow(ASFW_ANY);
  413. switch (psdtp->nCmd)
  414. {
  415. case SHTDN_SHUTDOWN:
  416. fShutdownWorked = CommonRestart(EWX_SHUTDOWN, 0);
  417. break;
  418. case SHTDN_RESTART:
  419. fShutdownWorked = CommonRestart(CanDoFastRestart() ? EW_RESTARTWINDOWS : EWX_REBOOT, 0);
  420. break;
  421. case SHTDN_LOGOFF:
  422. fShutdownWorked = CommonRestart(EWX_LOGOFF, 0);
  423. break;
  424. case SHTDN_RESTART_DOS: // Special hack to mean exit to dos
  425. case SHTDN_SLEEP:
  426. case SHTDN_SLEEP2:
  427. case SHTDN_HIBERNATE:
  428. SetSuspendState((psdtp->nCmd == SHTDN_HIBERNATE) ? TRUE : FALSE,
  429. (GetKeyState(VK_CONTROL) < 0) ? TRUE : FALSE,
  430. (psdtp->nCmd == SHTDN_SLEEP2) ? TRUE : FALSE);
  431. break;
  432. }
  433. LocalFree(psdtp);
  434. return fShutdownWorked;
  435. }
  436. #define DIALOG_LOGOFF 1
  437. #define DIALOG_EXIT 2
  438. #define DIALOG_DISCONNECT 3
  439. void CloseWindowsDialog(HWND hwndParent, int iDialogType)
  440. {
  441. INT_PTR nCmd = SHTDN_NONE;
  442. IUnknown* pIUnknown;
  443. HWND hwndBackground;
  444. if (FAILED(ShellDimScreen(&pIUnknown, &hwndBackground)))
  445. {
  446. pIUnknown = NULL;
  447. hwndBackground = NULL;
  448. }
  449. switch (iDialogType)
  450. {
  451. LPCTSTR pszDialogID;
  452. DLGPROC pfnDialogProc;
  453. case DIALOG_LOGOFF:
  454. case DIALOG_DISCONNECT:
  455. {
  456. if (!GetSystemMetrics(SM_REMOTESESSION) && IsOS(OS_FRIENDLYLOGONUI) && IsOS(OS_FASTUSERSWITCHING))
  457. {
  458. // If not remote with friendly UI and FUS show the licky button dialog.
  459. nCmd = SwitchUserDialog_Show(hwndBackground);
  460. pszDialogID = 0;
  461. pfnDialogProc = NULL;
  462. }
  463. else if (iDialogType == DIALOG_LOGOFF)
  464. {
  465. // Otherwise show the Win32 log off dialog if log off.
  466. pszDialogID = MAKEINTRESOURCE(DLG_LOGOFFWINDOWS);
  467. pfnDialogProc = LogoffDlgProc;
  468. }
  469. else if (iDialogType == DIALOG_DISCONNECT)
  470. {
  471. // Or the Win32 disconnect dialog if disconnect.
  472. pszDialogID = MAKEINTRESOURCE(DLG_DISCONNECTWINDOWS);
  473. pfnDialogProc = DisconnectDlgProc;
  474. }
  475. else
  476. {
  477. ASSERTMSG(FALSE, "Unexpected case hit in CloseWindowsDialog");
  478. }
  479. if ((pszDialogID != 0) && (pfnDialogProc != NULL))
  480. {
  481. nCmd = DialogBoxParam(HINST_THISDLL, pszDialogID, hwndBackground, pfnDialogProc, 0);
  482. }
  483. if (nCmd == SHTDN_DISCONNECT)
  484. {
  485. Disconnect();
  486. nCmd = SHTDN_NONE;
  487. }
  488. break;
  489. }
  490. case DIALOG_EXIT:
  491. {
  492. BOOL fGinaShutdownCalled = FALSE;
  493. HINSTANCE hGina;
  494. TCHAR szUsername[UNLEN];
  495. DWORD cchUsernameLength = UNLEN;
  496. DWORD dwOptions;
  497. if (WNetGetUser(NULL, szUsername, &cchUsernameLength) != NO_ERROR)
  498. {
  499. szUsername[0] = TEXT('\0');
  500. }
  501. EarlySaveSomeShellState();
  502. // Load MSGINA.DLL and get appropriate shutdown function
  503. hGina = LoadLibrary(TEXT("msgina.dll"));
  504. if (hGina != NULL)
  505. {
  506. if (IsOS(OS_FRIENDLYLOGONUI))
  507. {
  508. nCmd = ShellTurnOffDialog(hwndBackground);
  509. fGinaShutdownCalled = TRUE;
  510. }
  511. else
  512. {
  513. PFNSHELLSHUTDOWNDIALOG pfnShellShutdownDialog = (PFNSHELLSHUTDOWNDIALOG)
  514. GetProcAddress(hGina, "ShellShutdownDialog");
  515. if (pfnShellShutdownDialog != NULL)
  516. {
  517. nCmd = pfnShellShutdownDialog(hwndBackground,
  518. szUsername, 0);
  519. // Handle disconnect right now
  520. if (nCmd == SHTDN_DISCONNECT)
  521. {
  522. Disconnect();
  523. // No other action
  524. nCmd = SHTDN_NONE;
  525. }
  526. fGinaShutdownCalled = TRUE;
  527. }
  528. }
  529. FreeLibrary(hGina);
  530. }
  531. if (!fGinaShutdownCalled)
  532. {
  533. dwOptions = GetShutdownOptions();
  534. // Gina call failed; use our cheesy private version
  535. nCmd = DownlevelShellShutdownDialog(hwndBackground,
  536. dwOptions, szUsername);
  537. }
  538. break;
  539. }
  540. }
  541. if (hwndBackground)
  542. SetForegroundWindow(hwndBackground);
  543. if (nCmd == SHTDN_NONE)
  544. {
  545. if (hwndBackground)
  546. {
  547. ShowWindow(hwndBackground, SW_HIDE);
  548. PostMessage(hwndBackground, WM_CLOSE, 0, 0);
  549. }
  550. }
  551. else
  552. {
  553. SDTP_PARAMS *psdtp = LocalAlloc(LPTR, sizeof(*psdtp));
  554. if (psdtp)
  555. {
  556. DWORD dw;
  557. HANDLE h;
  558. psdtp->nCmd = nCmd;
  559. psdtp->hwndParent = hwndParent;
  560. // have another thread call ExitWindows() so our
  561. // main pump keeps running durring shutdown.
  562. //
  563. h = CreateThread(NULL, 0, ShutdownThreadProc, psdtp, 0, &dw);
  564. if (h)
  565. {
  566. CloseHandle(h);
  567. }
  568. else
  569. {
  570. if (hwndBackground)
  571. ShowWindow(hwndBackground, SW_HIDE);
  572. ShutdownThreadProc(psdtp);
  573. }
  574. }
  575. }
  576. if (pIUnknown != NULL)
  577. {
  578. pIUnknown->lpVtbl->Release(pIUnknown);
  579. }
  580. }
  581. // API functions
  582. STDAPI_(void) ExitWindowsDialog(HWND hwndParent)
  583. {
  584. if (!IsOS(OS_FRIENDLYLOGONUI) || IsShutdownAllowed())
  585. {
  586. CloseWindowsDialog (hwndParent, DIALOG_EXIT);
  587. }
  588. else
  589. {
  590. LogoffWindowsDialog(hwndParent);
  591. }
  592. }
  593. STDAPI_(void) LogoffWindowsDialog(HWND hwndParent)
  594. {
  595. CloseWindowsDialog (hwndParent, DIALOG_LOGOFF);
  596. }
  597. STDAPI_(void) DisconnectWindowsDialog(HWND hwndParent)
  598. {
  599. CloseWindowsDialog(hwndParent, DIALOG_DISCONNECT);
  600. }