Leaked source code of windows server 2003
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.

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