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.

1460 lines
44 KiB

  1. #include "msgina.h"
  2. // This gives me a yucky feeling, but we
  3. // use CRT all over the place in gina.
  4. #include <stdio.h>
  5. #include <windowsx.h>
  6. #include <regstr.h>
  7. #include <help.h>
  8. #include <Wtsapi32.h>
  9. #include "shtdnp.h"
  10. #define MAX_SHTDN_OPTIONS 8
  11. typedef struct _SHUTDOWNOPTION
  12. {
  13. DWORD dwOption;
  14. TCHAR szName[MAX_REASON_NAME_LEN + 1];
  15. TCHAR szDesc[MAX_REASON_DESC_LEN + 1];
  16. } SHUTDOWNOPTION, *PSHUTDOWNOPTION;
  17. typedef struct _SHUTDOWNDLGDATA
  18. {
  19. SHUTDOWNOPTION rgShutdownOptions[MAX_SHTDN_OPTIONS];
  20. int cShutdownOptions;
  21. DWORD dwItemSelect;
  22. REASONDATA ReasonData;
  23. BOOL fShowReasons;
  24. DWORD dwFlags;
  25. BOOL fEndDialogOnActivate;
  26. } SHUTDOWNDLGDATA, *PSHUTDOWNDLGDATA;
  27. // Internal function prototypes
  28. void SetShutdownOptionDescription(HWND hwndCombo, HWND hwndStatic);
  29. BOOL LoadShutdownOptionStrings(int idStringName, int idStringDesc,
  30. PSHUTDOWNOPTION pOption);
  31. BOOL BuildShutdownOptionArray(DWORD dwItems, LPCTSTR szUsername,
  32. PSHUTDOWNDLGDATA pdata);
  33. BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  34. DWORD GetOptionSelection(HWND hwndCombo);
  35. void SetShutdownOptionDescription(HWND hwndCombo, HWND hwndStatic);
  36. BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  37. BOOL Shutdown_OnEraseBkgnd(HWND hwnd, HDC hdc);
  38. INT_PTR CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  39. LPARAM lParam);
  40. INT_PTR DialogItemToGinaResult(DWORD dwDialogItem, BOOL fAutoPowerdown);
  41. BOOL LoadShutdownOptionStrings(int idStringName, int idStringDesc,
  42. PSHUTDOWNOPTION pOption)
  43. {
  44. BOOL fSuccess = (LoadString(hDllInstance, idStringName, pOption->szName,
  45. ARRAYSIZE(pOption->szName)) != 0);
  46. fSuccess &= (LoadString(hDllInstance, idStringDesc, pOption->szDesc,
  47. ARRAYSIZE(pOption->szDesc)) != 0);
  48. return fSuccess;
  49. }
  50. BOOL BuildShutdownOptionArray(DWORD dwItems, LPCTSTR szUsername,
  51. PSHUTDOWNDLGDATA pdata)
  52. {
  53. BOOL fSuccess = TRUE;
  54. pdata->cShutdownOptions = 0;
  55. if (dwItems & SHTDN_LOGOFF)
  56. {
  57. pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_LOGOFF;
  58. // Note that logoff is a special case: format using a user name ala
  59. // "log off <username>".
  60. fSuccess &= LoadShutdownOptionStrings(IDS_LOGOFF_NAME,
  61. IDS_LOGOFF_DESC,
  62. &(pdata->rgShutdownOptions[pdata->cShutdownOptions]));
  63. if (fSuccess)
  64. {
  65. TCHAR szTemp[ARRAYSIZE(pdata->rgShutdownOptions[pdata->cShutdownOptions].szName)];
  66. BOOL fFormatSuccessful = FALSE;
  67. // If we have a username, format the "log off <username>" string
  68. if (szUsername != NULL)
  69. {
  70. fFormatSuccessful = (_snwprintf(szTemp, ARRAYSIZE(szTemp),
  71. pdata->rgShutdownOptions[pdata->cShutdownOptions].szName,
  72. szUsername) > 0);
  73. }
  74. // If we didn't have a username or if the buffer got overrun, just use
  75. // "log off "
  76. if (!fFormatSuccessful)
  77. {
  78. fFormatSuccessful = (_snwprintf(szTemp, ARRAYSIZE(szTemp),
  79. pdata->rgShutdownOptions[pdata->cShutdownOptions].szName,
  80. TEXT("")) > 0);
  81. }
  82. // Now we have the real logoff title in szTemp; copy is back
  83. if (fFormatSuccessful)
  84. {
  85. lstrcpy(pdata->rgShutdownOptions[pdata->cShutdownOptions].szName,
  86. szTemp);
  87. }
  88. else
  89. {
  90. // Should never happen! There should always be enough room in szTemp to hold
  91. // "log off ".
  92. ASSERT(FALSE);
  93. }
  94. // Success!
  95. pdata->cShutdownOptions ++;
  96. }
  97. }
  98. if (dwItems & SHTDN_SHUTDOWN)
  99. {
  100. pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_SHUTDOWN;
  101. fSuccess &= LoadShutdownOptionStrings(IDS_SHUTDOWN_NAME,
  102. IDS_SHUTDOWN_DESC,
  103. &(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
  104. }
  105. if (dwItems & SHTDN_RESTART)
  106. {
  107. pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_RESTART;
  108. fSuccess &= LoadShutdownOptionStrings(IDS_RESTART_NAME,
  109. IDS_RESTART_DESC,
  110. &(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
  111. }
  112. if (dwItems & SHTDN_RESTART_DOS)
  113. {
  114. pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_RESTART_DOS;
  115. fSuccess &= LoadShutdownOptionStrings(IDS_RESTARTDOS_NAME,
  116. IDS_RESTARTDOS_DESC,
  117. &(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
  118. }
  119. if (dwItems & SHTDN_SLEEP)
  120. {
  121. pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_SLEEP;
  122. fSuccess &= LoadShutdownOptionStrings(IDS_SLEEP_NAME,
  123. IDS_SLEEP_DESC,
  124. &(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
  125. }
  126. if (dwItems & SHTDN_SLEEP2)
  127. {
  128. pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_SLEEP2;
  129. fSuccess &= LoadShutdownOptionStrings(IDS_SLEEP2_NAME,
  130. IDS_SLEEP2_DESC,
  131. &(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
  132. }
  133. if (dwItems & SHTDN_HIBERNATE)
  134. {
  135. pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_HIBERNATE;
  136. fSuccess &= LoadShutdownOptionStrings(IDS_HIBERNATE_NAME,
  137. IDS_HIBERNATE_DESC,
  138. &(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
  139. }
  140. if (dwItems & SHTDN_DISCONNECT)
  141. {
  142. pdata->rgShutdownOptions[pdata->cShutdownOptions].dwOption = SHTDN_DISCONNECT;
  143. fSuccess &= LoadShutdownOptionStrings(IDS_DISCONNECT_NAME,
  144. IDS_DISCONNECT_DESC,
  145. &(pdata->rgShutdownOptions[pdata->cShutdownOptions ++]));
  146. }
  147. return fSuccess;
  148. }
  149. void DisableReasons( HWND hwnd, BOOL fEnable ) {
  150. EnableWindow(GetDlgItem(hwnd, IDC_EXITREASONS_COMBO), fEnable);
  151. EnableWindow(GetDlgItem(hwnd, IDC_EXITREASONS_COMMENT), fEnable);
  152. EnableWindow(GetDlgItem(hwnd, IDC_EXITREASONS_CHECK), fEnable);
  153. }
  154. BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  155. {
  156. PSHUTDOWNDLGDATA pdata = (PSHUTDOWNDLGDATA) lParam;
  157. HWND hwndCombo;
  158. int iOption;
  159. int iComboItem;
  160. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) lParam);
  161. if (!(pdata->dwFlags & SHTDN_NOBRANDINGBITMAP))
  162. {
  163. // Move all our controls down so the branding fits
  164. SizeForBranding(hwnd, FALSE);
  165. }
  166. // Hide the help button and move over OK and Cancel if applicable
  167. if (pdata->dwFlags & SHTDN_NOHELP)
  168. {
  169. static UINT rgidNoHelp[] = {IDOK, IDCANCEL};
  170. RECT rc1, rc2;
  171. int dx;
  172. HWND hwndHelp = GetDlgItem(hwnd, IDHELP);
  173. EnableWindow(hwndHelp, FALSE);
  174. ShowWindow(hwndHelp, SW_HIDE);
  175. GetWindowRect(hwndHelp, &rc1);
  176. GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc2);
  177. dx = rc1.left - rc2.left;
  178. MoveControls(hwnd, rgidNoHelp, ARRAYSIZE(rgidNoHelp), dx, 0, FALSE);
  179. }
  180. // Add the items specified to the combo box
  181. hwndCombo = GetDlgItem(hwnd, IDC_EXITOPTIONS_COMBO);
  182. for (iOption = 0; iOption < pdata->cShutdownOptions; iOption ++)
  183. {
  184. // Add the option
  185. iComboItem = ComboBox_AddString(hwndCombo,
  186. pdata->rgShutdownOptions[iOption].szName);
  187. if (iComboItem != (int) CB_ERR)
  188. {
  189. // Store a pointer to the option
  190. ComboBox_SetItemData(hwndCombo, iComboItem,
  191. &(pdata->rgShutdownOptions[iOption]));
  192. // See if we should select this option
  193. if (pdata->rgShutdownOptions[iOption].dwOption == pdata->dwItemSelect)
  194. {
  195. ComboBox_SetCurSel(hwndCombo, iComboItem);
  196. }
  197. }
  198. }
  199. // If we don't have a selection in the combo, do a default selection
  200. if (ComboBox_GetCurSel(hwndCombo) == CB_ERR)
  201. {
  202. ComboBox_SetCurSel(hwndCombo, 0);
  203. }
  204. SetShutdownOptionDescription(hwndCombo,
  205. GetDlgItem(hwnd, IDC_EXITOPTIONS_DESCRIPTION));
  206. // Set up the reason data.
  207. if( pdata->fShowReasons )
  208. {
  209. DWORD iOption;
  210. DWORD iComboItem;
  211. HWND hwndCombo;
  212. HWND hwndCheck;
  213. DWORD dwCheckState = 0x0;
  214. //
  215. // Get the window handles we need.
  216. //
  217. hwndCombo = GetDlgItem(hwnd, IDC_EXITREASONS_COMBO);
  218. hwndCheck = GetDlgItem(hwnd, IDC_EXITREASONS_CHECK);
  219. //
  220. // Set the default to be planned.
  221. //
  222. CheckDlgButton(hwnd, IDC_EXITREASONS_CHECK, BST_CHECKED);
  223. dwCheckState = SHTDN_REASON_FLAG_PLANNED;
  224. //
  225. // Now populate the combo according the current check state.
  226. //
  227. for (iOption = 0; iOption < (DWORD)pdata->ReasonData.cReasons; iOption++)
  228. {
  229. if(((pdata->ReasonData.rgReasons[iOption]->dwCode) & SHTDN_REASON_FLAG_PLANNED) == dwCheckState)
  230. {
  231. iComboItem = ComboBox_AddString(hwndCombo,
  232. pdata->ReasonData.rgReasons[iOption]->szName);
  233. if (iComboItem != (int) CB_ERR)
  234. {
  235. // Store a pointer to the option
  236. ComboBox_SetItemData(hwndCombo, iComboItem,
  237. pdata->ReasonData.rgReasons[iOption]);
  238. // See if we should select this option
  239. if (pdata->ReasonData.rgReasons[iOption]->dwCode == pdata->ReasonData.dwReasonSelect)
  240. {
  241. ComboBox_SetCurSel(hwndCombo, iComboItem);
  242. }
  243. }
  244. }
  245. }
  246. // If we don't have a selection in the combo, do a default selection
  247. if (ComboBox_GetCount(hwndCombo) && (ComboBox_GetCurSel(hwndCombo) == CB_ERR))
  248. {
  249. PREASON pr = (PREASON)ComboBox_GetItemData(hwndCombo, 0);
  250. if(pr != (PREASON)CB_ERR)
  251. {
  252. pdata->ReasonData.dwReasonSelect = pr->dwCode;
  253. ComboBox_SetCurSel(hwndCombo, 0);
  254. }
  255. }
  256. SetReasonDescription(hwndCombo,
  257. GetDlgItem(hwnd, IDC_EXITREASONS_DESCRIPTION));
  258. // Disable the reasons if applicable
  259. DisableReasons( hwnd, pdata->dwItemSelect & (SHTDN_SHUTDOWN | SHTDN_RESTART));
  260. // Disable the ok button if a comment is required.
  261. EnableWindow(GetDlgItem(hwnd, IDOK), !( pdata->dwItemSelect & (SHTDN_SHUTDOWN | SHTDN_RESTART)) || !ReasonCodeNeedsComment( pdata->ReasonData.dwReasonSelect ));
  262. // Setup the comment box.
  263. // We must fix the maximum characters.
  264. SendMessage( GetDlgItem(hwnd, IDC_EXITREASONS_COMMENT), EM_LIMITTEXT, (WPARAM)MAX_REASON_COMMENT_LEN, (LPARAM)0 );
  265. }
  266. else {
  267. // Hide the reasons, move the buttons up and shrink the dialog.
  268. HWND hwndCtl;
  269. hwndCtl = GetDlgItem(hwnd, IDC_EXITREASONS_CHECK);
  270. EnableWindow(hwndCtl, FALSE);
  271. ShowWindow(hwndCtl, SW_HIDE);
  272. hwndCtl = GetDlgItem(hwnd, IDC_EXITREASONS_COMBO);
  273. EnableWindow(hwndCtl, FALSE);
  274. ShowWindow(hwndCtl, SW_HIDE);
  275. hwndCtl = GetDlgItem(hwnd, IDC_EXITREASONS_DESCRIPTION);
  276. ShowWindow(hwndCtl, SW_HIDE);
  277. hwndCtl = GetDlgItem(hwnd, IDC_EXITREASONS_COMMENT);
  278. EnableWindow(hwndCtl, FALSE);
  279. ShowWindow(hwndCtl, SW_HIDE);
  280. hwndCtl = GetDlgItem(hwnd, IDC_EXITREASONS_HEADER);
  281. ShowWindow(hwndCtl, SW_HIDE);
  282. hwndCtl = GetDlgItem(hwnd, IDC_STATIC_REASON_OPTION);
  283. ShowWindow(hwndCtl, SW_HIDE);
  284. hwndCtl = GetDlgItem(hwnd, IDC_STATIC_REASON_COMMENT);
  285. ShowWindow(hwndCtl, SW_HIDE);
  286. hwndCtl = GetDlgItem(hwnd, IDC_RESTARTEVENTTRACKER_GRPBX);
  287. ShowWindow(hwndCtl, SW_HIDE);
  288. // Move controls and shrink window
  289. {
  290. static UINT rgid[] = {IDOK, IDCANCEL, IDHELP};
  291. RECT rc, rc1, rc2;
  292. int dy;
  293. HWND hwndHelp = GetDlgItem(hwnd, IDHELP);
  294. GetWindowRect(hwndHelp, &rc1);
  295. GetWindowRect(GetDlgItem(hwnd, IDC_EXITOPTIONS_DESCRIPTION), &rc2);
  296. dy = rc1.top - rc2.bottom;
  297. MoveControls(hwnd, rgid, ARRAYSIZE(rgid), 0, -dy, FALSE);
  298. // Shrink
  299. GetWindowRect(hwnd, &rc);
  300. SetWindowPos(hwnd, NULL, 0, 0, rc.right - rc.left, ( rc.bottom - rc.top ) - dy, SWP_NOZORDER|SWP_NOMOVE);
  301. }
  302. }
  303. // If we get an activate message, dismiss the dialog, since we just lost
  304. // focus
  305. pdata->fEndDialogOnActivate = TRUE;
  306. CentreWindow(hwnd);
  307. return TRUE;
  308. }
  309. DWORD GetOptionSelection(HWND hwndCombo)
  310. {
  311. DWORD dwResult;
  312. PSHUTDOWNOPTION pOption;
  313. int iItem = ComboBox_GetCurSel(hwndCombo);
  314. if (iItem != (int) CB_ERR)
  315. {
  316. pOption = (PSHUTDOWNOPTION) ComboBox_GetItemData(hwndCombo, iItem);
  317. dwResult = pOption->dwOption;
  318. }
  319. else
  320. {
  321. dwResult = SHTDN_NONE;
  322. }
  323. return dwResult;
  324. }
  325. void SetShutdownOptionDescription(HWND hwndCombo, HWND hwndStatic)
  326. {
  327. int iItem;
  328. PSHUTDOWNOPTION pOption;
  329. iItem = ComboBox_GetCurSel(hwndCombo);
  330. if (iItem != CB_ERR)
  331. {
  332. pOption = (PSHUTDOWNOPTION) ComboBox_GetItemData(hwndCombo, iItem);
  333. SetWindowText(hwndStatic, pOption->szDesc);
  334. }
  335. }
  336. BOOL WillCauseShutdown(DWORD dwOption)
  337. {
  338. switch (dwOption)
  339. {
  340. case SHTDN_SHUTDOWN:
  341. case SHTDN_RESTART:
  342. case SHTDN_RESTART_DOS:
  343. case SHTDN_HIBERNATE:
  344. case SHTDN_SLEEP:
  345. case SHTDN_SLEEP2:
  346. return TRUE;
  347. break;
  348. case SHTDN_LOGOFF:
  349. case SHTDN_DISCONNECT:
  350. default:
  351. break;
  352. }
  353. return FALSE;
  354. }
  355. BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  356. {
  357. BOOL fHandled = FALSE;
  358. DWORD dwDlgResult;
  359. PSHUTDOWNDLGDATA pdata = (PSHUTDOWNDLGDATA)
  360. GetWindowLongPtr(hwnd, GWLP_USERDATA);
  361. switch (id)
  362. {
  363. case IDOK:
  364. if (codeNotify == BN_CLICKED)
  365. {
  366. pdata->ReasonData.dwReasonSelect = 0;
  367. dwDlgResult = GetOptionSelection(GetDlgItem(hwnd, IDC_EXITOPTIONS_COMBO));
  368. // Are the reasons enabled?
  369. if( pdata->fShowReasons && ( dwDlgResult & (SHTDN_SHUTDOWN | SHTDN_RESTART))) {
  370. pdata->ReasonData.dwReasonSelect = GetReasonSelection(GetDlgItem(hwnd, IDC_EXITREASONS_COMBO));
  371. if (pdata->ReasonData.dwReasonSelect == SHTDN_REASON_UNKNOWN ) {
  372. break;
  373. }
  374. // Fill the comment
  375. pdata->ReasonData.cCommentLen = GetWindowText( GetDlgItem(hwnd, IDC_EXITREASONS_COMMENT), pdata->ReasonData.szComment, MAX_REASON_COMMENT_LEN );
  376. }
  377. if (dwDlgResult != SHTDN_NONE)
  378. {
  379. pdata->fEndDialogOnActivate = FALSE;
  380. fHandled = TRUE;
  381. EndDialog(hwnd, (int) dwDlgResult);
  382. }
  383. }
  384. break;
  385. case IDCANCEL:
  386. if (codeNotify == BN_CLICKED)
  387. {
  388. pdata->fEndDialogOnActivate = FALSE;
  389. EndDialog(hwnd, (int) SHTDN_NONE);
  390. fHandled = TRUE;
  391. }
  392. break;
  393. case IDC_EXITOPTIONS_COMBO:
  394. if (codeNotify == CBN_SELCHANGE)
  395. {
  396. SetShutdownOptionDescription(hwndCtl,
  397. GetDlgItem(hwnd, IDC_EXITOPTIONS_DESCRIPTION));
  398. // Does this change the status of the reasons.
  399. if( pdata->fShowReasons ) {
  400. BOOL fEnabled = GetOptionSelection(hwndCtl) & (SHTDN_SHUTDOWN | SHTDN_RESTART);
  401. DisableReasons( hwnd, fEnabled );
  402. // Make sure that we have a comment if we need one.
  403. if( fEnabled ) {
  404. EnableWindow(GetDlgItem(hwnd, IDOK), !(ReasonCodeNeedsComment( pdata->ReasonData.dwReasonSelect ) && ( pdata->ReasonData.cCommentLen == 0 )));
  405. }
  406. else {
  407. EnableWindow(GetDlgItem(hwnd, IDOK), TRUE);
  408. }
  409. }
  410. fHandled = TRUE;
  411. }
  412. break;
  413. case IDC_EXITREASONS_CHECK:
  414. //
  415. // We assume that if the user can click on the check button.
  416. // we are required to show the shutdown reasons.
  417. //
  418. if (codeNotify == BN_CLICKED)
  419. {
  420. DWORD iOption;
  421. DWORD iComboItem;
  422. HWND hwndCombo;
  423. HWND hwndCheck;
  424. DWORD dwCheckState = 0x0;
  425. //
  426. // Get the window handles we need.
  427. //
  428. hwndCombo = GetDlgItem(hwnd, IDC_EXITREASONS_COMBO);
  429. hwndCheck = GetDlgItem(hwnd, IDC_EXITREASONS_CHECK);
  430. //
  431. // Set the planned flag according to the check state.
  432. //
  433. if ( BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_EXITREASONS_CHECK) )
  434. dwCheckState = SHTDN_REASON_FLAG_PLANNED;
  435. //
  436. // Remove all items from combo
  437. //
  438. while (ComboBox_GetCount(hwndCombo))
  439. ComboBox_DeleteString(hwndCombo, 0);
  440. //
  441. // Now populate the combo according the current check state.
  442. //
  443. for (iOption = 0; iOption < (DWORD)pdata->ReasonData.cReasons; iOption ++)
  444. {
  445. if(((pdata->ReasonData.rgReasons[iOption]->dwCode) & SHTDN_REASON_FLAG_PLANNED) == dwCheckState)
  446. {
  447. iComboItem = ComboBox_AddString(hwndCombo,
  448. pdata->ReasonData.rgReasons[iOption]->szName);
  449. if (iComboItem != (int) CB_ERR)
  450. {
  451. // Store a pointer to the option
  452. ComboBox_SetItemData(hwndCombo, iComboItem,
  453. pdata->ReasonData.rgReasons[iOption]);
  454. // See if we should select this option
  455. if (pdata->ReasonData.rgReasons[iOption]->dwCode == pdata->ReasonData.dwReasonSelect)
  456. {
  457. ComboBox_SetCurSel(hwndCombo, iComboItem);
  458. }
  459. }
  460. }
  461. }
  462. // If we don't have a selection in the combo, do a default selection
  463. if (ComboBox_GetCount(hwndCombo) && (ComboBox_GetCurSel(hwndCombo) == CB_ERR))
  464. {
  465. PREASON pr = (PREASON)ComboBox_GetItemData(hwndCombo, 0);
  466. if(pr != (PREASON)CB_ERR)
  467. {
  468. pdata->ReasonData.dwReasonSelect = pr->dwCode;
  469. ComboBox_SetCurSel(hwndCombo, 0);
  470. }
  471. }
  472. SetReasonDescription(hwndCombo,
  473. GetDlgItem(hwnd, IDC_EXITREASONS_DESCRIPTION));
  474. // Disable the ok button if a comment is required.
  475. EnableWindow(GetDlgItem(hwnd, IDOK), !(ReasonCodeNeedsComment( pdata->ReasonData.dwReasonSelect ) && ( pdata->ReasonData.cCommentLen == 0 )));
  476. }
  477. break;
  478. case IDC_EXITREASONS_COMBO:
  479. if (codeNotify == CBN_SELCHANGE)
  480. {
  481. SetReasonDescription(hwndCtl,
  482. GetDlgItem(hwnd, IDC_EXITREASONS_DESCRIPTION));
  483. pdata->ReasonData.dwReasonSelect = GetReasonSelection(hwndCtl);
  484. EnableWindow(GetDlgItem(hwnd, IDOK), !(ReasonCodeNeedsComment( pdata->ReasonData.dwReasonSelect ) && ( pdata->ReasonData.cCommentLen == 0 )));
  485. fHandled = TRUE;
  486. }
  487. break;
  488. case IDC_EXITREASONS_COMMENT:
  489. if( codeNotify == EN_CHANGE)
  490. {
  491. pdata->ReasonData.cCommentLen = GetWindowTextLength( GetDlgItem(hwnd, IDC_EXITREASONS_COMMENT));
  492. EnableWindow(GetDlgItem(hwnd, IDOK), !(ReasonCodeNeedsComment( pdata->ReasonData.dwReasonSelect ) && ( pdata->ReasonData.cCommentLen == 0 )));
  493. fHandled = TRUE;
  494. }
  495. break;
  496. case IDHELP:
  497. if (codeNotify == BN_CLICKED)
  498. {
  499. WinHelp(hwnd, TEXT("windows.hlp>proc4"), HELP_CONTEXT, (DWORD) IDH_TRAY_SHUTDOWN_HELP);
  500. }
  501. break;
  502. }
  503. return fHandled;
  504. }
  505. BOOL Shutdown_OnEraseBkgnd(HWND hwnd, HDC hdc)
  506. {
  507. BOOL fRet;
  508. PSHUTDOWNDLGDATA pdata = (PSHUTDOWNDLGDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  509. // Draw the branding bitmap
  510. if (!(pdata->dwFlags & SHTDN_NOBRANDINGBITMAP))
  511. {
  512. fRet = PaintBranding(hwnd, hdc, 0, FALSE, FALSE, COLOR_BTNFACE);
  513. }
  514. else
  515. {
  516. fRet = FALSE;
  517. }
  518. return fRet;
  519. }
  520. INT_PTR CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  521. LPARAM lParam)
  522. {
  523. switch (uMsg)
  524. {
  525. HANDLE_MSG(hwnd, WM_INITDIALOG, Shutdown_OnInitDialog);
  526. HANDLE_MSG(hwnd, WM_COMMAND, Shutdown_OnCommand);
  527. HANDLE_MSG(hwnd, WM_ERASEBKGND, Shutdown_OnEraseBkgnd);
  528. case WLX_WM_SAS:
  529. {
  530. // If this is someone hitting C-A-D, swallow it.
  531. if (wParam == WLX_SAS_TYPE_CTRL_ALT_DEL)
  532. return TRUE;
  533. // Other SAS's (like timeout), return FALSE and let winlogon
  534. // deal with it.
  535. return FALSE;
  536. }
  537. break;
  538. case WM_INITMENUPOPUP:
  539. {
  540. EnableMenuItem((HMENU)wParam, SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
  541. }
  542. break;
  543. case WM_SYSCOMMAND:
  544. // Blow off moves (only really needed for 32bit land).
  545. if ((wParam & ~0x0F) == SC_MOVE)
  546. return TRUE;
  547. break;
  548. case WM_ACTIVATE:
  549. // If we're loosing the activation for some other reason than
  550. // the user click OK/CANCEL then bail.
  551. if (LOWORD(wParam) == WA_INACTIVE)
  552. {
  553. PSHUTDOWNDLGDATA pdata = (PSHUTDOWNDLGDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  554. if (pdata->fEndDialogOnActivate)
  555. {
  556. pdata->fEndDialogOnActivate = FALSE;
  557. EndDialog(hwnd, SHTDN_NONE);
  558. }
  559. }
  560. break;
  561. }
  562. return FALSE;
  563. }
  564. /****************************************************************************
  565. ShutdownDialogEx
  566. --------------
  567. Launches the shutdown dialog.
  568. If hWlx and pfnWlxDialogBoxParam are non-null, pfnWlxDialogBoxParam will
  569. be used to launch the dialog box so we can intelligently respond to WLX
  570. messages. Only if WinLogon is the caller should this be done.
  571. Other flags are listed in shtdndlg.h.
  572. ****************************************************************************/
  573. DWORD ShutdownDialogEx(HWND hwndParent, DWORD dwItems, DWORD dwItemSelect,
  574. LPCTSTR szUsername, DWORD dwFlags, HANDLE hWlx,
  575. PWLX_DIALOG_BOX_PARAM pfnWlxDialogBoxParam,
  576. DWORD dwReasonSelect, PDWORD pdwReasonResult )
  577. {
  578. // Array of shutdown options - the dialog data
  579. PSHUTDOWNDLGDATA pData;
  580. DWORD dwResult;
  581. pData = (PSHUTDOWNDLGDATA)LocalAlloc(LMEM_FIXED, sizeof(*pData));
  582. if (pData == NULL)
  583. {
  584. return SHTDN_NONE;
  585. }
  586. // Set the flags
  587. pData->dwFlags = dwFlags;
  588. // Set the initially selected item
  589. pData->dwItemSelect = dwItemSelect;
  590. pData->ReasonData.dwReasonSelect = dwReasonSelect;
  591. pData->ReasonData.rgReasons = 0;
  592. pData->ReasonData.cReasons = 0;
  593. pData->ReasonData.cReasonCapacity = 0;
  594. // Read in the strings for the shutdown option names and descriptions
  595. if (BuildShutdownOptionArray(dwItems, szUsername, pData))
  596. {
  597. HKEY hKey = 0;
  598. DWORD rc;
  599. DWORD ShowReasonUI = 0x0;
  600. DWORD ValueSize = sizeof (DWORD);
  601. BOOL fFromPolicy = FALSE;
  602. // See if we should display the shutdown reason dialog
  603. pData->fShowReasons = FALSE;
  604. pData->ReasonData.szComment[ 0 ] = 0;
  605. pData->ReasonData.cCommentLen = 0;
  606. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RELIABILITY_POLICY_KEY, 0, KEY_ALL_ACCESS, &hKey);
  607. if(rc == ERROR_SUCCESS)
  608. {
  609. rc = RegQueryValueEx (hKey, RELIABILITY_POLICY_SHUTDOWNREASONUI, NULL, NULL, (UCHAR *)&ShowReasonUI, &ValueSize);
  610. RegCloseKey (hKey);
  611. hKey = 0;
  612. //
  613. // Now check the sku to decide whether we should show the dialog
  614. //
  615. if(rc == ERROR_SUCCESS)
  616. {
  617. OSVERSIONINFOEX osVersionInfoEx;
  618. osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  619. if(ShowReasonUI == POLICY_SHOWREASONUI_NEVER || ShowReasonUI == POLICY_SHOWREASONUI_ALWAYS)
  620. {
  621. //do nothing.
  622. }
  623. else if(GetVersionEx( (LPOSVERSIONINFOW) &osVersionInfoEx ))
  624. {
  625. //
  626. // if ShowReasonUI is anything other than 2 or 3, we think it is 0.
  627. //
  628. switch ( osVersionInfoEx.wProductType )
  629. {
  630. case VER_NT_WORKSTATION:
  631. if(ShowReasonUI == POLICY_SHOWREASONUI_WORKSTATIONONLY)
  632. ShowReasonUI = 1;
  633. else
  634. ShowReasonUI = 0;
  635. break;
  636. default:
  637. if(ShowReasonUI == POLICY_SHOWREASONUI_SERVERONLY)
  638. ShowReasonUI = 1;
  639. else
  640. ShowReasonUI = 0;
  641. break;
  642. }
  643. }
  644. else
  645. {
  646. //
  647. // If we fail, assume not showing.
  648. //
  649. ShowReasonUI = 0;
  650. }
  651. }
  652. }
  653. if(rc != ERROR_SUCCESS)
  654. {
  655. rc = RegCreateKeyEx (HKEY_LOCAL_MACHINE, REGSTR_PATH_RELIABILITY, 0, NULL, REG_OPTION_NON_VOLATILE,
  656. KEY_ALL_ACCESS, NULL, &hKey, NULL);
  657. }
  658. else
  659. {
  660. fFromPolicy = TRUE;
  661. }
  662. if (rc == ERROR_SUCCESS) {
  663. if(!fFromPolicy)
  664. rc = RegQueryValueEx (hKey, REGSTR_VAL_SHOWREASONUI, NULL, NULL, (UCHAR *)&ShowReasonUI, &ValueSize);
  665. if ( (rc == ERROR_SUCCESS) && (ShowReasonUI) ) {
  666. // See if any of the shutdown options will cause an actual shutdown. If not then don't show the reasons at all.
  667. int i;
  668. for( i = 0; i < pData->cShutdownOptions; ++i ) {
  669. pData->fShowReasons |= pData->rgShutdownOptions[ i ].dwOption & SHTDN_RESTART;
  670. pData->fShowReasons |= pData->rgShutdownOptions[ i ].dwOption & SHTDN_SHUTDOWN;
  671. }
  672. // Read in the strings for the shutdown option names and descriptions
  673. if( pData->fShowReasons && BuildReasonArray( &pData->ReasonData, TRUE, FALSE )) {
  674. // Set the initial reason to display.
  675. if( dwReasonSelect >= ( DWORD )pData->ReasonData.cReasons ) {
  676. dwReasonSelect = 0;
  677. }
  678. }
  679. else {
  680. pData->fShowReasons = FALSE;
  681. }
  682. }
  683. }
  684. // Display the dialog and return the user's selection
  685. // ..if the caller wants, use a Wlx dialog box function
  686. if ((hWlx != NULL) && (pfnWlxDialogBoxParam != NULL))
  687. {
  688. // Caller must be winlogon - they want us to display the
  689. // shutdown dialog using a Wlx function
  690. dwResult = (DWORD) pfnWlxDialogBoxParam(hWlx,
  691. hDllInstance, MAKEINTRESOURCE(IDD_EXITWINDOWS_DIALOG),
  692. hwndParent, Shutdown_DialogProc, (LPARAM) pData);
  693. }
  694. else
  695. {
  696. // Use standard dialog box
  697. dwResult = (DWORD) DialogBoxParam(hDllInstance, MAKEINTRESOURCE(IDD_EXITWINDOWS_DIALOG), hwndParent,
  698. Shutdown_DialogProc, (LPARAM) pData);
  699. }
  700. // Record shutdown reasons
  701. if( dwResult & (SHTDN_SHUTDOWN | SHTDN_RESTART)) {
  702. if( pData->fShowReasons ) {
  703. SHUTDOWN_REASON sr;
  704. sr.cbSize = sizeof(SHUTDOWN_REASON);
  705. sr.uFlags = dwResult == SHTDN_SHUTDOWN ? EWX_SHUTDOWN : EWX_REBOOT;
  706. sr.dwReasonCode = pData->ReasonData.dwReasonSelect;
  707. sr.dwEventType = SR_EVENT_INITIATE_CLEAN;
  708. sr.lpszComment = pData->ReasonData.szComment;
  709. RecordShutdownReason(&sr);
  710. }
  711. }
  712. if( hKey != 0 )
  713. {
  714. RegCloseKey (hKey);
  715. }
  716. }
  717. else
  718. {
  719. dwResult = SHTDN_NONE;
  720. }
  721. DestroyReasons( &pData->ReasonData );
  722. LocalFree(pData);
  723. return dwResult;
  724. }
  725. DWORD ShutdownDialog(HWND hwndParent, DWORD dwItems, DWORD dwItemSelect,
  726. LPCTSTR szUsername, DWORD dwFlags, HANDLE hWlx,
  727. PWLX_DIALOG_BOX_PARAM pfnWlxDialogBoxParam )
  728. {
  729. DWORD dummy;
  730. return ShutdownDialogEx(hwndParent, dwItems, dwItemSelect,
  731. szUsername, dwFlags, hWlx,
  732. pfnWlxDialogBoxParam,
  733. 0, &dummy );
  734. }
  735. INT_PTR DialogItemToGinaResult(DWORD dwDialogItem, BOOL fAutoPowerdown)
  736. {
  737. INT_PTR Result;
  738. // Map the return value from ShutdownDialog into
  739. // our internal shutdown values
  740. switch (dwDialogItem)
  741. {
  742. case SHTDN_LOGOFF:
  743. Result = MSGINA_DLG_USER_LOGOFF;
  744. break;
  745. case SHTDN_SHUTDOWN:
  746. if (fAutoPowerdown)
  747. Result = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_POWEROFF_FLAG;
  748. else
  749. Result = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_SHUTDOWN_FLAG;
  750. break;
  751. case SHTDN_RESTART:
  752. Result = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_REBOOT_FLAG;
  753. break;
  754. case SHTDN_SLEEP:
  755. Result = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_SLEEP_FLAG;
  756. break;
  757. case SHTDN_SLEEP2:
  758. Result = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_SLEEP2_FLAG;
  759. break;
  760. case SHTDN_HIBERNATE:
  761. Result = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_HIBERNATE_FLAG;
  762. break;
  763. case SHTDN_DISCONNECT:
  764. Result = MSGINA_DLG_DISCONNECT;
  765. break;
  766. default:
  767. // Cancel click, or else invalid item was selected
  768. Result = MSGINA_DLG_FAILURE;
  769. break;
  770. }
  771. return Result;
  772. }
  773. BOOL GetBoolPolicy(HKEY hkeyCurrentUser, LPCTSTR pszPolicyKey, LPCTSTR pszPolicyValue, BOOL fDefault)
  774. {
  775. HKEY hkeyMachinePolicy = NULL;
  776. HKEY hkeyUserPolicy = NULL;
  777. BOOL fPolicy = fDefault;
  778. BOOL fMachinePolicyRead = FALSE;
  779. DWORD dwType;
  780. DWORD dwValue;
  781. DWORD cbData;
  782. LRESULT res;
  783. // Check machine policy first
  784. res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszPolicyKey, 0, KEY_READ, &hkeyMachinePolicy);
  785. if (ERROR_SUCCESS == res)
  786. {
  787. cbData = sizeof(dwValue);
  788. res = RegQueryValueEx(hkeyMachinePolicy, pszPolicyValue, 0, &dwType, (LPBYTE)&dwValue, &cbData);
  789. if (ERROR_SUCCESS == res)
  790. {
  791. fPolicy = (dwValue != 0);
  792. fMachinePolicyRead = TRUE;
  793. }
  794. RegCloseKey(hkeyMachinePolicy);
  795. }
  796. if (!fMachinePolicyRead)
  797. {
  798. // Machine policy check failed, check user policy
  799. res = RegOpenKeyEx(hkeyCurrentUser, pszPolicyKey, 0, KEY_READ, &hkeyUserPolicy);
  800. if (ERROR_SUCCESS == res)
  801. {
  802. cbData = sizeof(dwValue);
  803. res = RegQueryValueEx(hkeyUserPolicy, pszPolicyValue, 0, &dwType, (LPBYTE)&dwValue, &cbData);
  804. if (ERROR_SUCCESS == res)
  805. {
  806. fPolicy = (dwValue != 0);
  807. }
  808. RegCloseKey(hkeyUserPolicy);
  809. }
  810. }
  811. return fPolicy;
  812. }
  813. DWORD GetAllowedShutdownOptions(HKEY hkeyCurrentUser, HANDLE UserToken, BOOL fRemoteSession)
  814. {
  815. DWORD dwItemsToAdd = 0;
  816. BOOL fNoDisconnect = TRUE;
  817. // Does computer automatically shut off on shutdown
  818. BOOL fAutoPowerdown = FALSE;
  819. SYSTEM_POWER_CAPABILITIES spc = {0};
  820. // See if we should add Logoff and/or disconnect to the dialog
  821. // - don't even try if we don't have a current user!
  822. BOOL fNoLogoff = GetBoolPolicy(hkeyCurrentUser, EXPLORER_POLICY_KEY, NOLOGOFF, FALSE);
  823. if (!fNoLogoff)
  824. {
  825. dwItemsToAdd |= SHTDN_LOGOFF;
  826. }
  827. // Do not allow disconnects by default. Allow disconnects when either this is
  828. // a remote session or terminal server is enabled on Workstation (PTS).
  829. {
  830. // The disconnect menu can be disabled by policy. Respect that. It should
  831. // also be removed in the friendly UI case WITHOUT multiple users.
  832. fNoDisconnect = ( IsActiveConsoleSession() ||
  833. GetBoolPolicy(hkeyCurrentUser, EXPLORER_POLICY_KEY, NODISCONNECT, FALSE) ||
  834. (ShellIsFriendlyUIActive() && !ShellIsMultipleUsersEnabled()) );
  835. }
  836. if (!fNoDisconnect)
  837. {
  838. dwItemsToAdd |= SHTDN_DISCONNECT;
  839. }
  840. // All items besides logoff and disconnect require SE_SHUTDOWN
  841. if (TestUserPrivilege(UserToken, SE_SHUTDOWN_PRIVILEGE))
  842. {
  843. // Add shutdown and restart
  844. dwItemsToAdd |= SHTDN_RESTART | SHTDN_SHUTDOWN;
  845. NtPowerInformation (SystemPowerCapabilities,
  846. NULL, 0, &spc, sizeof(spc));
  847. if (spc.SystemS5)
  848. fAutoPowerdown = TRUE;
  849. else
  850. fAutoPowerdown = GetProfileInt(APPLICATION_NAME, POWER_DOWN_AFTER_SHUTDOWN, 0);
  851. // Is hibernate option supported?
  852. //
  853. if ((spc.SystemS4 && spc.HiberFilePresent))
  854. {
  855. dwItemsToAdd |= SHTDN_HIBERNATE;
  856. }
  857. //
  858. // If one of the SystemS* values is true, then the machine
  859. // has ACPI suspend support.
  860. //
  861. if (spc.SystemS1 || spc.SystemS2 || spc.SystemS3)
  862. {
  863. HKEY hKey;
  864. DWORD dwAdvSuspend = 0;
  865. DWORD dwType, dwSize;
  866. // Check if we should offer advanced suspend options
  867. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  868. TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power"),
  869. 0, KEY_READ, &hKey) == ERROR_SUCCESS)
  870. {
  871. dwSize = sizeof(dwAdvSuspend);
  872. RegQueryValueEx (hKey, TEXT("Shutdown"), NULL, &dwType,
  873. (LPBYTE) &dwAdvSuspend, &dwSize);
  874. RegCloseKey (hKey);
  875. }
  876. if (dwAdvSuspend != 0)
  877. {
  878. dwItemsToAdd |= SHTDN_SLEEP2 | SHTDN_SLEEP;
  879. }
  880. else
  881. {
  882. // Only basic suspend support
  883. dwItemsToAdd |= SHTDN_SLEEP;
  884. }
  885. }
  886. }
  887. return dwItemsToAdd;
  888. }
  889. // Helper function for calling ShutdownDialog within winlogon
  890. // This function handles all the registry goop, power management
  891. // settings goop, and translating of codes into MSGINA's system
  892. // of shutdown codes and flags. Ack.
  893. INT_PTR WinlogonShutdownDialog(HWND hwndParent, PGLOBALS pGlobals, DWORD dwExcludeItems)
  894. {
  895. INT_PTR Result = MSGINA_DLG_FAILURE;
  896. DWORD dwDialogResult = IDCANCEL;
  897. DWORD dwReasonResult = SHTDN_REASON_UNKNOWN;
  898. DWORD dwItemsToAdd = 0;
  899. DWORD dwFlags = 0;
  900. // Items to add to the shutdown dialog
  901. if (OpenHKeyCurrentUser(pGlobals))
  902. {
  903. dwItemsToAdd = GetAllowedShutdownOptions(pGlobals->UserProcessData.hCurrentUser,
  904. pGlobals->UserProcessData.UserToken, !g_Console);
  905. CloseHKeyCurrentUser(pGlobals);
  906. }
  907. dwItemsToAdd &= (~dwExcludeItems);
  908. if (0 != dwItemsToAdd)
  909. {
  910. // Item to select
  911. DWORD dwItemToSelect = 0;
  912. DWORD dwReasonToSelect = 0;
  913. // Does computer automatically shut off on shutdown
  914. BOOL fAutoPowerdown = FALSE;
  915. SYSTEM_POWER_CAPABILITIES spc = {0};
  916. NtPowerInformation (SystemPowerCapabilities,
  917. NULL, 0, &spc, sizeof(spc));
  918. if (spc.SystemS5)
  919. fAutoPowerdown = TRUE;
  920. else
  921. fAutoPowerdown = GetProfileInt(APPLICATION_NAME, POWER_DOWN_AFTER_SHUTDOWN, 0);
  922. // Get the default item from the registry
  923. if (OpenHKeyCurrentUser(pGlobals))
  924. {
  925. LONG lResult;
  926. HKEY hkeyShutdown;
  927. DWORD dwType = 0;
  928. //
  929. // Check the button which was the users last shutdown selection.
  930. //
  931. if (RegCreateKeyEx(pGlobals->UserProcessData.hCurrentUser,
  932. SHUTDOWN_SETTING_KEY, 0, 0, 0,
  933. KEY_READ | KEY_WRITE,
  934. NULL, &hkeyShutdown, &dwType) == ERROR_SUCCESS)
  935. {
  936. DWORD cbData = sizeof(dwItemToSelect);
  937. lResult = RegQueryValueEx(hkeyShutdown,
  938. SHUTDOWN_SETTING,
  939. 0,
  940. &dwType,
  941. (LPBYTE) &dwItemToSelect,
  942. &cbData);
  943. RegQueryValueEx(hkeyShutdown,
  944. REASON_SETTING,
  945. 0,
  946. &dwType,
  947. (LPBYTE) &dwReasonToSelect,
  948. &cbData);
  949. RegCloseKey(hkeyShutdown);
  950. }
  951. CloseHKeyCurrentUser(pGlobals);
  952. }
  953. // Figure out what flags to pass
  954. // for sure no help button
  955. dwFlags = SHTDN_NOHELP;
  956. // On terminal server, no branding bitmap either
  957. if (GetSystemMetrics(SM_REMOTESESSION))
  958. {
  959. dwFlags |= SHTDN_NOBRANDINGBITMAP;
  960. }
  961. // Call ShutdownDialog
  962. dwDialogResult = ShutdownDialogEx(hwndParent, dwItemsToAdd,
  963. dwItemToSelect, pGlobals->UserName, dwFlags, pGlobals->hGlobalWlx,
  964. pWlxFuncs->WlxDialogBoxParam,
  965. dwReasonToSelect, &dwReasonResult );
  966. Result = DialogItemToGinaResult(dwDialogResult, fAutoPowerdown);
  967. // If everything is okay so far, write the selection to the registry
  968. // for next time.
  969. if (Result != MSGINA_DLG_FAILURE)
  970. {
  971. HKEY hkeyShutdown;
  972. DWORD dwDisposition;
  973. //
  974. // Get in the correct context before we reference the registry
  975. //
  976. if (OpenHKeyCurrentUser(pGlobals))
  977. {
  978. if (RegCreateKeyEx(pGlobals->UserProcessData.hCurrentUser, SHUTDOWN_SETTING_KEY, 0, 0, 0,
  979. KEY_READ | KEY_WRITE,
  980. NULL, &hkeyShutdown, &dwDisposition) == ERROR_SUCCESS)
  981. {
  982. RegSetValueEx(hkeyShutdown, SHUTDOWN_SETTING, 0, REG_DWORD, (LPBYTE)&dwDialogResult, sizeof(dwDialogResult));
  983. RegSetValueEx(hkeyShutdown, REASON_SETTING, 0, REG_DWORD, (LPBYTE)&dwReasonResult, sizeof(dwDialogResult));
  984. RegCloseKey(hkeyShutdown);
  985. }
  986. CloseHKeyCurrentUser(pGlobals);
  987. }
  988. }
  989. }
  990. return Result;
  991. }
  992. STDAPI_(DWORD) ShellShutdownDialog(HWND hwndParent, LPCTSTR szUnused, DWORD dwExcludeItems)
  993. {
  994. DWORD dwSelect = 0;
  995. DWORD dwReasonToSelect = 0;
  996. DWORD dwDialogResult = 0;
  997. DWORD dwReasonResult = SHTDN_REASON_UNKNOWN;
  998. DWORD dwFlags = 0;
  999. BOOL fTextOnLarge;
  1000. BOOL fTextOnSmall;
  1001. GINAFONTS fonts = {0};
  1002. HKEY hkeyShutdown;
  1003. DWORD dwType;
  1004. DWORD dwDisposition;
  1005. LONG lResult;
  1006. // De facto limit for usernames is 127 due to clunky gina 'encryption'
  1007. TCHAR szUsername[127];
  1008. DWORD dwItems = GetAllowedShutdownOptions(HKEY_CURRENT_USER,
  1009. NULL, (BOOL) GetSystemMetrics(SM_REMOTESESSION));
  1010. dwItems &= (~dwExcludeItems);
  1011. // Create the bitmaps we need
  1012. LoadBrandingImages(TRUE, &fTextOnLarge, &fTextOnSmall);
  1013. CreateFonts(&fonts);
  1014. PaintBitmapText(&fonts, fTextOnLarge, fTextOnSmall);
  1015. // get the User's last selection.
  1016. lResult = RegCreateKeyEx(HKEY_CURRENT_USER, SHUTDOWN_SETTING_KEY,
  1017. 0, 0, 0, KEY_READ, NULL, &hkeyShutdown, &dwDisposition);
  1018. if (lResult == ERROR_SUCCESS)
  1019. {
  1020. DWORD cbData = sizeof(dwSelect);
  1021. lResult = RegQueryValueEx(hkeyShutdown, SHUTDOWN_SETTING,
  1022. 0, &dwType, (LPBYTE)&dwSelect, &cbData);
  1023. RegQueryValueEx(hkeyShutdown, REASON_SETTING,
  1024. 0, &dwType, (LPBYTE)&dwReasonToSelect, &cbData);
  1025. cbData = sizeof(szUsername);
  1026. if (ERROR_SUCCESS != RegQueryValueEx(hkeyShutdown, LOGON_USERNAME_SETTING,
  1027. 0, &dwType, (LPBYTE)szUsername, &cbData))
  1028. {
  1029. // Default to "Log off" with no username if this fails.
  1030. *szUsername = 0;
  1031. }
  1032. // Ensure null-termination
  1033. szUsername[ARRAYSIZE(szUsername) - 1] = 0;
  1034. RegCloseKey(hkeyShutdown);
  1035. }
  1036. if (dwSelect == SHTDN_NONE)
  1037. {
  1038. dwSelect = SHTDN_SHUTDOWN;
  1039. }
  1040. // Figure out what flags to pass
  1041. // for sure we don't want any palette changes - this means
  1042. // force 16-colors for 256 color displays.
  1043. dwFlags = SHTDN_NOPALETTECHANGE;
  1044. // On TS, don't show bitmap
  1045. if (GetSystemMetrics(SM_REMOTESESSION))
  1046. {
  1047. dwFlags |= SHTDN_NOBRANDINGBITMAP;
  1048. }
  1049. dwDialogResult = ShutdownDialogEx(hwndParent, dwItems, dwSelect,
  1050. szUsername, dwFlags, NULL, NULL,
  1051. dwReasonToSelect, &dwReasonResult );
  1052. if (dwDialogResult != SHTDN_NONE)
  1053. {
  1054. // Save back the user's choice to the registry
  1055. if (RegCreateKeyEx(HKEY_CURRENT_USER, SHUTDOWN_SETTING_KEY,
  1056. 0, 0, 0, KEY_WRITE, NULL, &hkeyShutdown, &dwDisposition) == ERROR_SUCCESS)
  1057. {
  1058. RegSetValueEx(hkeyShutdown, SHUTDOWN_SETTING,
  1059. 0, REG_DWORD, (LPBYTE)&dwDialogResult, sizeof(dwDialogResult));
  1060. RegSetValueEx(hkeyShutdown, REASON_SETTING,
  1061. 0, REG_DWORD, (LPBYTE)&dwReasonResult, sizeof(dwReasonResult));
  1062. RegCloseKey(hkeyShutdown);
  1063. }
  1064. }
  1065. // Clean up fonts and bitmaps we created
  1066. if (g_hpalBranding)
  1067. {
  1068. DeleteObject(g_hpalBranding);
  1069. }
  1070. if (g_hbmOtherDlgBrand)
  1071. {
  1072. DeleteObject(g_hbmOtherDlgBrand);
  1073. }
  1074. if (g_hbmLogonBrand)
  1075. {
  1076. DeleteObject(g_hbmLogonBrand);
  1077. }
  1078. if (g_hbmBand)
  1079. {
  1080. DeleteObject(g_hbmBand);
  1081. }
  1082. if (fonts.hWelcomeFont)
  1083. {
  1084. DeleteObject(fonts.hWelcomeFont);
  1085. }
  1086. if (fonts.hCopyrightFont)
  1087. {
  1088. DeleteObject(fonts.hCopyrightFont);
  1089. }
  1090. if (fonts.hBuiltOnNtFont)
  1091. {
  1092. DeleteObject(fonts.hBuiltOnNtFont);
  1093. }
  1094. if (fonts.hBetaFont)
  1095. {
  1096. DeleteObject(fonts.hBetaFont);
  1097. }
  1098. return dwDialogResult;
  1099. }
  1100. /****************************************************************************
  1101. Function: GetSessionCount
  1102. Returns: The number of user sessions that are active
  1103. on your terminal server. If this value is more than 1, then
  1104. operations such as shutdown or restart will end these other
  1105. sessions.
  1106. History: dsheldon 04/23/99 - created
  1107. ****************************************************************************/
  1108. // Termsrv dll delayload stuff
  1109. #define WTSDLLNAME TEXT("WTSAPI32.DLL")
  1110. HINSTANCE g_hWTSDll = NULL;
  1111. typedef BOOL (WINAPI*WTSEnumerateSessionsW_t)(IN HANDLE hServer,
  1112. IN DWORD Reserved,
  1113. IN DWORD Version,
  1114. OUT PWTS_SESSION_INFOW * ppSessionInfo,
  1115. OUT DWORD * pCount
  1116. );
  1117. WTSEnumerateSessionsW_t g_pfnWTSEnumerateSessions = NULL;
  1118. typedef VOID (WINAPI*WTSFreeMemory_t)(IN PVOID pMemory);
  1119. WTSFreeMemory_t g_pfnWTSFreeMemory = NULL;
  1120. typedef BOOL (WINAPI*WTSQuerySessionInformationW_t)(IN HANDLE hServer,
  1121. IN DWORD SessionId,
  1122. IN WTS_INFO_CLASS WtsInfoClass,
  1123. OUT LPWSTR * ppBuffer,
  1124. OUT DWORD * pCount
  1125. );
  1126. WTSQuerySessionInformationW_t g_pfnWTSQuerySessionInformation = NULL;
  1127. DWORD GetSessionCount()
  1128. {
  1129. BOOL fSessionsEnumerated;
  1130. PWTS_SESSION_INFO pSessionInfo;
  1131. DWORD cSessionInfo;
  1132. // Return value
  1133. DWORD nOtherSessions = 0;
  1134. // Try to load termsrv dll if necessary
  1135. if (NULL == g_hWTSDll)
  1136. {
  1137. g_hWTSDll = LoadLibrary(WTSDLLNAME);
  1138. if (g_hWTSDll)
  1139. {
  1140. g_pfnWTSEnumerateSessions = (WTSEnumerateSessionsW_t) GetProcAddress(g_hWTSDll, "WTSEnumerateSessionsW");
  1141. g_pfnWTSQuerySessionInformation = (WTSQuerySessionInformationW_t) GetProcAddress(g_hWTSDll, "WTSQuerySessionInformationW");
  1142. g_pfnWTSFreeMemory = (WTSFreeMemory_t) GetProcAddress(g_hWTSDll, "WTSFreeMemory");
  1143. }
  1144. }
  1145. // Continue only if we have the functions we need
  1146. if (g_pfnWTSEnumerateSessions && g_pfnWTSFreeMemory && g_pfnWTSQuerySessionInformation)
  1147. {
  1148. // Enumerate all sessions on this machine
  1149. pSessionInfo = NULL;
  1150. cSessionInfo = 0;
  1151. fSessionsEnumerated = g_pfnWTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &cSessionInfo);
  1152. if (fSessionsEnumerated)
  1153. {
  1154. DWORD iSession;
  1155. ASSERT((pSessionInfo != NULL) || (cSessionInfo == 0));
  1156. // Check each session to see if it is one we should count
  1157. for (iSession = 0; iSession < cSessionInfo; iSession ++)
  1158. {
  1159. switch (pSessionInfo[iSession].State)
  1160. {
  1161. // We count these cases:
  1162. case WTSActive:
  1163. case WTSShadow:
  1164. {
  1165. nOtherSessions ++;
  1166. }
  1167. break;
  1168. case WTSDisconnected:
  1169. {
  1170. LPWSTR pUserName = NULL;
  1171. DWORD cSize;
  1172. // Only count the disconnected sessions that have a user logged on
  1173. if (g_pfnWTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, pSessionInfo[iSession].SessionId,
  1174. WTSUserName, &pUserName, &cSize)) {
  1175. if (pUserName && (pUserName[0] != L'\0')) {
  1176. nOtherSessions ++;
  1177. }
  1178. if (pUserName != NULL)
  1179. {
  1180. g_pfnWTSFreeMemory(pUserName);
  1181. }
  1182. }
  1183. }
  1184. break;
  1185. // And ignore the rest:
  1186. default:
  1187. break;
  1188. }
  1189. }
  1190. if (pSessionInfo != NULL)
  1191. {
  1192. g_pfnWTSFreeMemory(pSessionInfo);
  1193. }
  1194. }
  1195. }
  1196. return nOtherSessions;
  1197. }