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.

1470 lines
50 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: TurnOffDialog.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // Class that implements presentation of the Turn Off Computer dialog.
  7. //
  8. // History: 2000-04-18 vtan created
  9. // 2000-05-17 vtan updated with new dialog
  10. // --------------------------------------------------------------------------
  11. #include "StandardHeader.h"
  12. #include "TurnOffDialog.h"
  13. #include <ginarcid.h>
  14. #include <msginaexports.h>
  15. #include <shlobj.h>
  16. #include <shlobjp.h>
  17. #include <shlwapi.h>
  18. #include "DimmedWindow.h"
  19. #include "PrivilegeEnable.h"
  20. // --------------------------------------------------------------------------
  21. // CTurnOffDialog::CTurnOffDialog
  22. //
  23. // Arguments: hInstance = HINSTANCE of hosting process/DLL.
  24. //
  25. // Returns: <none>
  26. //
  27. // Purpose: Constructor for CTurnOffDialog. This initializes member
  28. // variables and loads resources used by the dialog.
  29. //
  30. // History: 2000-05-17 vtan created
  31. // 2001-01-18 vtan update with new visuals
  32. // --------------------------------------------------------------------------
  33. CTurnOffDialog::CTurnOffDialog (HINSTANCE hInstance) :
  34. _hInstance(hInstance),
  35. _hbmBackground(NULL),
  36. _hbmFlag(NULL),
  37. _hbmButtons(NULL),
  38. _hfntTitle(NULL),
  39. _hfntButton(NULL),
  40. _hpltShell(NULL),
  41. _lButtonHeight(0),
  42. _hwndDialog(NULL),
  43. _uiHoverID(0),
  44. _uiFocusID(0),
  45. _iStandByButtonResult(SHTDN_NONE),
  46. _fSuccessfulInitialization(false),
  47. _fSupportsStandBy(false),
  48. _fSupportsHibernate(false),
  49. _fShiftKeyDown(false),
  50. _fDialogEnded(false),
  51. _pTooltip(NULL)
  52. {
  53. bool fUse8BitDepth;
  54. HDC hdcScreen;
  55. LOGFONT logFont;
  56. char szPixelSize[10];
  57. BITMAP bitmap;
  58. TBOOL(SetRect(&_rcBackground, 0, 0, 0, 0));
  59. TBOOL(SetRect(&_rcFlag, 0, 0, 0, 0));
  60. TBOOL(SetRect(&_rcButtons, 0, 0, 0, 0));
  61. hdcScreen = GetDC(NULL);
  62. // 8-bit color?
  63. fUse8BitDepth = (GetDeviceCaps(hdcScreen, BITSPIXEL) <= 8);
  64. // Load the bitmaps.
  65. _hbmBackground = static_cast<HBITMAP>(LoadImage(_hInstance,
  66. MAKEINTRESOURCE(fUse8BitDepth ? IDB_BACKGROUND_8 : IDB_BACKGROUND_24),
  67. IMAGE_BITMAP,
  68. 0,
  69. 0,
  70. LR_CREATEDIBSECTION));
  71. if ((_hbmBackground != NULL) && (GetObject(_hbmBackground, sizeof(bitmap), &bitmap) >= sizeof(bitmap)))
  72. {
  73. TBOOL(SetRect(&_rcBackground, 0, 0, bitmap.bmWidth, bitmap.bmHeight));
  74. }
  75. _hbmFlag = static_cast<HBITMAP>(LoadImage(_hInstance,
  76. MAKEINTRESOURCE(fUse8BitDepth ? IDB_FLAG_8 : IDB_FLAG_24),
  77. IMAGE_BITMAP,
  78. 0,
  79. 0,
  80. LR_CREATEDIBSECTION));
  81. if ((_hbmFlag != NULL) && (GetObject(_hbmFlag, sizeof(bitmap), &bitmap) >= sizeof(bitmap)))
  82. {
  83. TBOOL(SetRect(&_rcFlag, 0, 0, bitmap.bmWidth, bitmap.bmHeight));
  84. }
  85. _hbmButtons = static_cast<HBITMAP>(LoadImage(_hInstance,
  86. MAKEINTRESOURCE(IDB_BUTTONS),
  87. IMAGE_BITMAP,
  88. 0,
  89. 0,
  90. LR_CREATEDIBSECTION));
  91. if ((_hbmButtons != NULL) && (GetObject(_hbmButtons, sizeof(bitmap), &bitmap) >= sizeof(bitmap)))
  92. {
  93. TBOOL(SetRect(&_rcButtons, 0, 0, bitmap.bmWidth, bitmap.bmHeight));
  94. _lButtonHeight = bitmap.bmHeight / ((BUTTON_GROUP_MAX * BUTTON_STATE_MAX) + 1);
  95. }
  96. // Create fonts. Load the font name and size from resources.
  97. ZeroMemory(&logFont, sizeof(logFont));
  98. if (LoadStringA(_hInstance,
  99. IDS_TURNOFF_TITLE_FACESIZE,
  100. szPixelSize,
  101. ARRAYSIZE(szPixelSize)) != 0)
  102. {
  103. logFont.lfHeight = -MulDiv(atoi(szPixelSize), GetDeviceCaps(hdcScreen, LOGPIXELSY), 72);
  104. if (LoadString(_hInstance,
  105. IDS_TURNOFF_TITLE_FACENAME,
  106. logFont.lfFaceName,
  107. LF_FACESIZE) != 0)
  108. {
  109. logFont.lfWeight = FW_MEDIUM;
  110. logFont.lfQuality = DEFAULT_QUALITY;
  111. _hfntTitle = CreateFontIndirect(&logFont);
  112. }
  113. }
  114. ZeroMemory(&logFont, sizeof(logFont));
  115. if (LoadStringA(_hInstance,
  116. IDS_TURNOFF_BUTTON_FACESIZE,
  117. szPixelSize,
  118. ARRAYSIZE(szPixelSize)) != 0)
  119. {
  120. logFont.lfHeight = -MulDiv(atoi(szPixelSize), GetDeviceCaps(hdcScreen, LOGPIXELSY), 72);
  121. if (LoadString(_hInstance,
  122. IDS_TURNOFF_BUTTON_FACENAME,
  123. logFont.lfFaceName,
  124. LF_FACESIZE) != 0)
  125. {
  126. logFont.lfWeight = FW_BOLD;
  127. logFont.lfQuality = DEFAULT_QUALITY;
  128. _hfntButton = CreateFontIndirect(&logFont);
  129. }
  130. }
  131. // Load the shell palette.
  132. _hpltShell = SHCreateShellPalette(hdcScreen);
  133. TBOOL(ReleaseDC(NULL, hdcScreen));
  134. // Check for presence of all required resources.
  135. _fSuccessfulInitialization = ((_hfntTitle != NULL) &&
  136. (_hfntButton != NULL) &&
  137. (_hpltShell != NULL) &&
  138. (_hbmButtons != NULL) &&
  139. (_hbmFlag != NULL) &&
  140. (_hbmBackground != NULL));
  141. }
  142. // --------------------------------------------------------------------------
  143. // CTurnOffDialog::~CTurnOffDialog
  144. //
  145. // Arguments: <none>
  146. //
  147. // Returns: <none>
  148. //
  149. // Purpose: Destructor for CTurnOffDialog. Release used resources and
  150. // unregister the window class.
  151. //
  152. // History: 2000-05-17 vtan created
  153. // 2001-01-18 vtan update with new visuals
  154. // --------------------------------------------------------------------------
  155. CTurnOffDialog::~CTurnOffDialog (void)
  156. {
  157. ASSERTMSG(_pTooltip == NULL, "_pTooltip not released in CTurnOffDialog::~CTurnOffDialog");
  158. // Release everything we allocated/loaded.
  159. ReleaseGDIObject(_hpltShell);
  160. ReleaseGDIObject(_hfntButton);
  161. ReleaseGDIObject(_hfntTitle);
  162. ReleaseGDIObject(_hbmButtons);
  163. ReleaseGDIObject(_hbmFlag);
  164. ReleaseGDIObject(_hbmBackground);
  165. }
  166. // --------------------------------------------------------------------------
  167. // CTurnOffDialog::Show
  168. //
  169. // Arguments: <none>
  170. //
  171. // Returns: DWORD
  172. //
  173. // Purpose: Presents the "Turn Off Computer" dialog to the user and
  174. // returns the result of the dialog back to the caller.
  175. //
  176. // History: 2000-05-17 vtan created
  177. // 2001-01-18 vtan update with new visuals
  178. // --------------------------------------------------------------------------
  179. DWORD CTurnOffDialog::Show (HWND hwndParent)
  180. {
  181. INT_PTR iResult;
  182. if (_fSuccessfulInitialization)
  183. {
  184. CDimmedWindow *pDimmedWindow;
  185. // If no parent was given the create our own dimmed window.
  186. if (hwndParent == NULL)
  187. {
  188. pDimmedWindow = new CDimmedWindow(_hInstance);
  189. if (pDimmedWindow != NULL)
  190. {
  191. hwndParent = pDimmedWindow->Create();
  192. }
  193. else
  194. {
  195. hwndParent = NULL;
  196. }
  197. }
  198. else
  199. {
  200. pDimmedWindow = NULL;
  201. }
  202. // Show the dialog and get a result.
  203. iResult = DialogBoxParam(_hInstance,
  204. MAKEINTRESOURCE(IDD_TURNOFFCOMPUTER),
  205. hwndParent,
  206. CB_DialogProc,
  207. reinterpret_cast<LPARAM>(this));
  208. if (pDimmedWindow != NULL)
  209. {
  210. pDimmedWindow->Release();
  211. }
  212. }
  213. else
  214. {
  215. iResult = SHTDN_NONE;
  216. }
  217. return(static_cast<DWORD>(iResult));
  218. }
  219. // --------------------------------------------------------------------------
  220. // CTurnOffDialog::Destroy
  221. //
  222. // Arguments: <none>
  223. //
  224. // Returns: <none>
  225. //
  226. // Purpose: Force destroys the Turn Off Computer dialog. This is done in
  227. // cases such as a screen saver is becoming active.
  228. //
  229. // History: 2000-06-06 vtan created
  230. // --------------------------------------------------------------------------
  231. void CTurnOffDialog::Destroy (void)
  232. {
  233. if (_hwndDialog != NULL)
  234. {
  235. EndDialog(_hwndDialog, SHTDN_NONE);
  236. }
  237. }
  238. // --------------------------------------------------------------------------
  239. // CTurnOffDialog::ShellCodeToGinaCode
  240. //
  241. // Arguments: dwShellCode = SHTDN_xxx result code.
  242. //
  243. // Returns: DWORD
  244. //
  245. // Purpose: Converts SHTDN_xxx dialog result code back to a GINA
  246. // MSGINA_DLG_xxx code so that it's consistent for both the
  247. // classic UI and friendly UI functionality.
  248. //
  249. // History: 2000-06-05 vtan created
  250. // 2001-04-10 vtan moved from CPowerButton
  251. // --------------------------------------------------------------------------
  252. DWORD CTurnOffDialog::ShellCodeToGinaCode (DWORD dwShellCode)
  253. {
  254. DWORD dwGinaCode = 0;
  255. switch (dwShellCode)
  256. {
  257. case SHTDN_NONE:
  258. dwGinaCode = MSGINA_DLG_FAILURE;
  259. break;
  260. case SHTDN_LOGOFF:
  261. dwGinaCode = MSGINA_DLG_USER_LOGOFF;
  262. break;
  263. case SHTDN_SHUTDOWN:
  264. {
  265. SYSTEM_POWER_CAPABILITIES spc;
  266. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  267. (NTSTATUS)NtPowerInformation(SystemPowerCapabilities,
  268. NULL,
  269. 0,
  270. &spc,
  271. sizeof(spc));
  272. dwGinaCode = MSGINA_DLG_SHUTDOWN | (spc.SystemS5 ? MSGINA_DLG_POWEROFF_FLAG : MSGINA_DLG_SHUTDOWN_FLAG);
  273. break;
  274. }
  275. case SHTDN_RESTART:
  276. dwGinaCode = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_REBOOT_FLAG;
  277. break;
  278. case SHTDN_SLEEP:
  279. dwGinaCode = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_SLEEP_FLAG;
  280. break;
  281. case SHTDN_HIBERNATE:
  282. dwGinaCode = MSGINA_DLG_SHUTDOWN | MSGINA_DLG_HIBERNATE_FLAG;
  283. break;
  284. case SHTDN_DISCONNECT:
  285. dwGinaCode = MSGINA_DLG_DISCONNECT;
  286. break;
  287. default:
  288. WARNINGMSG("Unexpected (ignored) shell code passed to CTurnOffDialog::ShellCodeToGinaCode");
  289. dwGinaCode = MSGINA_DLG_FAILURE;
  290. break;
  291. }
  292. return(dwGinaCode);
  293. }
  294. // --------------------------------------------------------------------------
  295. // CTurnOffDialog::GinaCodeToExitWindowsFlags
  296. //
  297. // Arguments: dwGinaCode = GINA dialog return code.
  298. //
  299. // Returns: DWORD
  300. //
  301. // Purpose: Converts internal MSGINA dialog return code to standard
  302. // ExitWindowsEx flags.
  303. //
  304. // History: 2001-05-23 vtan created
  305. // --------------------------------------------------------------------------
  306. DWORD CTurnOffDialog::GinaCodeToExitWindowsFlags (DWORD dwGinaCode)
  307. {
  308. DWORD dwResult;
  309. dwResult = 0;
  310. if ((dwGinaCode & ~MSGINA_DLG_FLAG_MASK) == MSGINA_DLG_SHUTDOWN)
  311. {
  312. switch (dwGinaCode & MSGINA_DLG_FLAG_MASK)
  313. {
  314. case MSGINA_DLG_REBOOT_FLAG:
  315. dwResult = EWX_REBOOT;
  316. break;
  317. case MSGINA_DLG_POWEROFF_FLAG:
  318. dwResult = EWX_POWEROFF;
  319. break;
  320. case MSGINA_DLG_SHUTDOWN_FLAG:
  321. dwResult = EWX_SHUTDOWN;
  322. break;
  323. default:
  324. break;
  325. }
  326. }
  327. return(dwResult);
  328. }
  329. // --------------------------------------------------------------------------
  330. // CTurnOffDialog::IsShiftKeyDown
  331. //
  332. // Arguments: <none>
  333. //
  334. // Returns: bool
  335. //
  336. // Purpose: Returns whether the shift key is down for input on this
  337. // thread.
  338. //
  339. // History: 2001-01-20 vtan created
  340. // --------------------------------------------------------------------------
  341. bool CTurnOffDialog::IsShiftKeyDown (void) const
  342. {
  343. return((GetKeyState(VK_SHIFT) & 0x8000) != 0);
  344. }
  345. // --------------------------------------------------------------------------
  346. // CTurnOffDialog::PaintBitmap
  347. //
  348. // Arguments: hdcDestination = HDC to paint into.
  349. // prcDestination = RECT in HDC to paint into.
  350. // hbmSource = HBITMAP to paint.
  351. // prcSource = RECT from HBITMAP to paint from.
  352. //
  353. // Returns: <none>
  354. //
  355. // Purpose: Wraps blitting a bitmap.
  356. //
  357. // History: 2001-01-19 vtan created
  358. // 2001-03-17 vtan added source RECT for strip blitting
  359. // --------------------------------------------------------------------------
  360. void CTurnOffDialog::PaintBitmap (HDC hdcDestination, const RECT *prcDestination, HBITMAP hbmSource, const RECT *prcSource)
  361. {
  362. HDC hdcBitmap;
  363. hdcBitmap = CreateCompatibleDC(NULL);
  364. if (hdcBitmap != NULL)
  365. {
  366. bool fEqualWidthAndHeight;
  367. int iWidthSource, iHeightSource, iWidthDestination, iHeightDestination;
  368. int iStretchBltMode;
  369. DWORD dwLayout;
  370. HBITMAP hbmSelected;
  371. RECT rcSource;
  372. BITMAP bitmap;
  373. if (prcSource == NULL)
  374. {
  375. if (GetObject(hbmSource, sizeof(bitmap), &bitmap) == 0)
  376. {
  377. bitmap.bmWidth = prcDestination->right - prcDestination->left;
  378. bitmap.bmHeight = prcDestination->bottom - prcDestination->top;
  379. }
  380. TBOOL(SetRect(&rcSource, 0, 0, bitmap.bmWidth, bitmap.bmHeight));
  381. prcSource = &rcSource;
  382. }
  383. hbmSelected = static_cast<HBITMAP>(SelectObject(hdcBitmap, hbmSource));
  384. iWidthSource = prcSource->right - prcSource->left;
  385. iHeightSource = prcSource->bottom - prcSource->top;
  386. iWidthDestination = prcDestination->right - prcDestination->left;
  387. iHeightDestination = prcDestination->bottom - prcDestination->top;
  388. fEqualWidthAndHeight = (iWidthSource == iWidthDestination) && (iHeightSource == iHeightDestination);
  389. if (!fEqualWidthAndHeight)
  390. {
  391. iStretchBltMode = SetStretchBltMode(hdcDestination, HALFTONE);
  392. }
  393. else
  394. {
  395. iStretchBltMode = 0;
  396. }
  397. dwLayout = SetLayout(hdcDestination, LAYOUT_BITMAPORIENTATIONPRESERVED);
  398. TBOOL(TransparentBlt(hdcDestination,
  399. prcDestination->left,
  400. prcDestination->top,
  401. iWidthDestination,
  402. iHeightDestination,
  403. hdcBitmap,
  404. prcSource->left,
  405. prcSource->top,
  406. iWidthSource,
  407. iHeightSource,
  408. RGB(255, 0, 255)));
  409. (DWORD)SetLayout(hdcDestination, dwLayout);
  410. if (!fEqualWidthAndHeight)
  411. {
  412. (int)SetStretchBltMode(hdcDestination, iStretchBltMode);
  413. }
  414. (HGDIOBJ)SelectObject(hdcBitmap, hbmSelected);
  415. TBOOL(DeleteDC(hdcBitmap));
  416. }
  417. }
  418. // --------------------------------------------------------------------------
  419. // CTurnOffDialog::IsStandByButtonEnabled
  420. //
  421. // Arguments: <none>
  422. //
  423. // Returns: bool
  424. //
  425. // Purpose: Returns whether the Stand By button is enabled.
  426. //
  427. // History: 2001-01-20 vtan created
  428. // --------------------------------------------------------------------------
  429. bool CTurnOffDialog::IsStandByButtonEnabled (void) const
  430. {
  431. return(_iStandByButtonResult != SHTDN_NONE);
  432. }
  433. // --------------------------------------------------------------------------
  434. // CTurnOffDialog::RemoveTooltip
  435. //
  436. // Arguments: <none>
  437. //
  438. // Returns: <none>
  439. //
  440. // Purpose: Removes the tooltip if present. This can be accessed from two
  441. // different threads so make sure that it's serialized.
  442. //
  443. // History: 2001-01-20 vtan created
  444. // --------------------------------------------------------------------------
  445. void CTurnOffDialog::RemoveTooltip (void)
  446. {
  447. CTooltip *pTooltip;
  448. pTooltip = static_cast<CTooltip*>(InterlockedExchangePointer(reinterpret_cast<void**>(&_pTooltip), NULL));
  449. if (pTooltip != NULL)
  450. {
  451. pTooltip->Release();
  452. }
  453. }
  454. // --------------------------------------------------------------------------
  455. // CTurnOffDialog::FilterMetaCharacters
  456. //
  457. // Arguments: pszText = String to filter.
  458. //
  459. // Returns: <none>
  460. //
  461. // Purpose: Filters meta-characters from the given string.
  462. //
  463. // History: 2000-06-13 vtan created
  464. // --------------------------------------------------------------------------
  465. void CTurnOffDialog::FilterMetaCharacters (TCHAR *pszText)
  466. {
  467. TCHAR *pTC;
  468. pTC = pszText;
  469. while (*pTC != TEXT('\0'))
  470. {
  471. if (*pTC == TEXT('&'))
  472. {
  473. (TCHAR*)lstrcpy(pTC, pTC + 1);
  474. }
  475. else
  476. {
  477. ++pTC;
  478. }
  479. }
  480. }
  481. // --------------------------------------------------------------------------
  482. // CTurnOffDialog::EndDialog
  483. //
  484. // Arguments: hwnd = HWND of dialog.
  485. // iResult = Result to end dialog with.
  486. //
  487. // Returns: <none>
  488. //
  489. // Purpose: Removes the tool tip if present. Ends the dialog.
  490. //
  491. // History: 2001-01-20 vtan created
  492. // --------------------------------------------------------------------------
  493. void CTurnOffDialog::EndDialog (HWND hwnd, INT_PTR iResult)
  494. {
  495. RemoveTooltip();
  496. // Set the dialog end member variable here. This will cause the WM_ACTIVATE
  497. // handler to ignore the deactivation associated with ending the dialog. If
  498. // it doesn't ignore it then it thinks the dialog is being deactivated
  499. // because another dialog is activating and ends the dialog with SHTDN_NONE.
  500. _fDialogEnded = true;
  501. TBOOL(::EndDialog(hwnd, iResult));
  502. }
  503. // --------------------------------------------------------------------------
  504. // CTurnOffDialog::Handle_BN_CLICKED
  505. //
  506. // Arguments: hwnd = HWND of dialog.
  507. // wID = ID of control.
  508. //
  509. // Returns: <none>
  510. //
  511. // Purpose: Handles clicks in the bitmap buttons and sets the return
  512. // result according to the button pressed.
  513. //
  514. // History: 2000-05-17 vtan created
  515. // 2001-01-18 vtan update with new visuals
  516. // --------------------------------------------------------------------------
  517. void CTurnOffDialog::Handle_BN_CLICKED (HWND hwnd, WORD wID)
  518. {
  519. switch (wID)
  520. {
  521. case IDCANCEL:
  522. EndDialog(hwnd, SHTDN_NONE);
  523. break;
  524. case IDC_BUTTON_TURNOFF:
  525. EndDialog(hwnd, SHTDN_SHUTDOWN);
  526. break;
  527. case IDC_BUTTON_STANDBY:
  528. // IDC_BUTTON_STANDBY is the visual button. Return whatever the current
  529. // result is back (this could be SHTDN_SLEEP or SHTDN_HIBERNATE.
  530. ASSERTMSG(_iStandByButtonResult != SHTDN_NONE, "No result for Stand By button in CTurnOffDialog::Handle_BN_CLICKED");
  531. EndDialog(hwnd, _iStandByButtonResult);
  532. break;
  533. case IDC_BUTTON_RESTART:
  534. EndDialog(hwnd, SHTDN_RESTART);
  535. break;
  536. case IDC_BUTTON_HIBERNATE:
  537. // IDC_BUTTON_HIBERNATE is the regular button that is 30000+ pixels to
  538. // the right of the dialog and not visible. It's present to allow the
  539. // "&Hibernate" accelerator to work when hibernate is supported.
  540. EndDialog(hwnd, SHTDN_HIBERNATE);
  541. break;
  542. default:
  543. break;
  544. }
  545. }
  546. // --------------------------------------------------------------------------
  547. // CTurnOffDialog::Handle_WM_INITDIALOG
  548. //
  549. // Arguments: hwnd = HWND of this window.
  550. //
  551. // Returns: <none>
  552. //
  553. // Purpose: Handles WM_INITDIALOG message. Centre the dialog on the main
  554. // monitor. Subclass the buttons so that we can get hover state
  555. // correctly implemented. Correctly set up whether the Stand By
  556. // button is allowed and what the action of the button is.
  557. //
  558. // If the machine supports S1-S3 then S1 is the default action.
  559. // Holding down the shift key will convert this to S4. If the
  560. // machine does not support S1-S3 but supports S4 then S4 is the
  561. // default action and the shift key feature is disabled.
  562. // Otherwise the machine doesn't support any lower power state
  563. // at which case we disable the button entirely.
  564. //
  565. // History: 2000-05-17 vtan created
  566. // 2001-01-18 vtan update with new visuals
  567. // 2001-01-19 vtan rework for shift behavior
  568. // --------------------------------------------------------------------------
  569. void CTurnOffDialog::Handle_WM_INITDIALOG (HWND hwnd)
  570. {
  571. HWND hwndButtonStandBy, hwndButtonHibernate;
  572. RECT rc;
  573. _hwndDialog = hwnd;
  574. // Center the dialog on the main monitor.
  575. TBOOL(GetClientRect(hwnd, &rc));
  576. TBOOL(SetWindowPos(hwnd,
  577. HWND_TOP,
  578. (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2,
  579. (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 3,
  580. 0,
  581. 0,
  582. SWP_NOSIZE));
  583. // Subclass buttons for tooltips and cursor control.
  584. TBOOL(SetWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_TURNOFF), ButtonSubClassProc, IDC_BUTTON_TURNOFF, reinterpret_cast<DWORD_PTR>(this)));
  585. TBOOL(SetWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_STANDBY), ButtonSubClassProc, IDC_BUTTON_STANDBY, reinterpret_cast<DWORD_PTR>(this)));
  586. TBOOL(SetWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_RESTART), ButtonSubClassProc, IDC_BUTTON_RESTART, reinterpret_cast<DWORD_PTR>(this)));
  587. // What does this machine support?
  588. {
  589. SYSTEM_POWER_CAPABILITIES spc;
  590. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  591. (NTSTATUS)NtPowerInformation(SystemPowerCapabilities,
  592. NULL,
  593. 0,
  594. &spc,
  595. sizeof(spc));
  596. _fSupportsHibernate = (spc.SystemS4 && spc.HiberFilePresent);
  597. _fSupportsStandBy = (spc.SystemS1 || spc.SystemS2 || spc.SystemS3);
  598. }
  599. hwndButtonStandBy = GetDlgItem(hwnd, IDC_BUTTON_STANDBY);
  600. hwndButtonHibernate = GetDlgItem(hwnd, IDC_BUTTON_HIBERNATE);
  601. if (_fSupportsStandBy)
  602. {
  603. _iStandByButtonResult = SHTDN_SLEEP;
  604. if (_fSupportsHibernate)
  605. {
  606. // Machine supports Stand By AND Hibernate.
  607. _fShiftKeyDown = false;
  608. _uiTimerID = static_cast<UINT>(SetTimer(hwnd, MAGIC_NUMBER, 50, NULL));
  609. }
  610. else
  611. {
  612. // Machine supports Stand By ONLY.
  613. (BOOL)EnableWindow(hwndButtonHibernate, FALSE);
  614. }
  615. }
  616. else if (_fSupportsHibernate)
  617. {
  618. int iCaptionLength;
  619. TCHAR *pszCaption;
  620. // Machine supports Hibernate ONLY.
  621. _iStandByButtonResult = SHTDN_HIBERNATE;
  622. // Replace the text on IDC_BUTTON_STANDBY with the text from
  623. // IDC_BUTTON_HIBERNATE. This will allow the dialog to keep
  624. // the visual button enabled and behave just like the button
  625. // should in the Stand By case but results in hibernate.
  626. // Once the text has been transferred disable IDC_BUTTON_HIBERNATE.
  627. iCaptionLength = GetWindowTextLength(hwndButtonHibernate) + sizeof('\0');
  628. pszCaption = static_cast<TCHAR*>(LocalAlloc(LMEM_FIXED, iCaptionLength * sizeof(TCHAR)));
  629. if (pszCaption != NULL)
  630. {
  631. if (GetWindowText(hwndButtonHibernate, pszCaption, iCaptionLength) != 0)
  632. {
  633. TBOOL(SetWindowText(hwndButtonStandBy, pszCaption));
  634. (BOOL)EnableWindow(hwndButtonHibernate, FALSE);
  635. }
  636. (HLOCAL)LocalFree(pszCaption);
  637. }
  638. }
  639. else
  640. {
  641. // Machine does NOT support Stand By NOR Hibernate.
  642. (BOOL)EnableWindow(hwndButtonStandBy, FALSE);
  643. (BOOL)EnableWindow(hwndButtonHibernate, FALSE);
  644. _iStandByButtonResult = SHTDN_NONE;
  645. }
  646. if (_fSupportsStandBy || _fSupportsHibernate)
  647. {
  648. // Set the focus to the "Stand By" button.
  649. (HWND)SetFocus(GetDlgItem(hwnd, IDC_BUTTON_STANDBY));
  650. _uiFocusID = IDC_BUTTON_STANDBY;
  651. }
  652. else
  653. {
  654. // If that button isn' available set to "Turn Off" button.
  655. (HWND)SetFocus(GetDlgItem(hwnd, IDC_BUTTON_TURNOFF));
  656. _uiFocusID = IDC_BUTTON_TURNOFF;
  657. }
  658. (LRESULT)SendMessage(hwnd, DM_SETDEFID, _uiFocusID, 0);
  659. }
  660. // --------------------------------------------------------------------------
  661. // CTurnOffDialog::Handle_WM_DESTROY
  662. //
  663. // Arguments: hwnd = HWND of the dialog.
  664. //
  665. // Returns: <none>
  666. //
  667. // Purpose: Removes the subclassing of the button windows and can do any
  668. // other clean up required in WM_DESTROY.
  669. //
  670. // History: 2000-05-18 vtan created
  671. // 2001-01-18 vtan update with new visuals
  672. // --------------------------------------------------------------------------
  673. void CTurnOffDialog::Handle_WM_DESTROY (HWND hwnd)
  674. {
  675. TBOOL(RemoveWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_RESTART), ButtonSubClassProc, IDC_BUTTON_RESTART));
  676. TBOOL(RemoveWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_STANDBY), ButtonSubClassProc, IDC_BUTTON_STANDBY));
  677. TBOOL(RemoveWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_TURNOFF), ButtonSubClassProc, IDC_BUTTON_TURNOFF));
  678. _hwndDialog = NULL;
  679. }
  680. // --------------------------------------------------------------------------
  681. // CTurnOffDialog::Handle_WM_ERASEBKGND
  682. //
  683. // Arguments: hwnd = HWND to erase.
  684. // hdcErase = HDC to paint.
  685. //
  686. // Returns: <none>
  687. //
  688. // Purpose: Erases the background.
  689. //
  690. // History: 2001-01-19 vtan created
  691. // --------------------------------------------------------------------------
  692. void CTurnOffDialog::Handle_WM_ERASEBKGND (HWND hwnd, HDC hdcErase)
  693. {
  694. RECT rc;
  695. TBOOL(GetClientRect(hwnd, &rc));
  696. PaintBitmap(hdcErase, &rc, _hbmBackground, &_rcBackground);
  697. }
  698. // --------------------------------------------------------------------------
  699. // CTurnOffDialog::Handle_WM_PRINTCLIENT
  700. //
  701. // Arguments: hwnd = HWND to erase.
  702. // hdcErase = HDC to paint.
  703. // dwOptions = Options for drawing.
  704. //
  705. // Returns: <none>
  706. //
  707. // Purpose: Handles painting the client area for WM_PRINTCLIENT.
  708. //
  709. // History: 2001-01-20 vtan created
  710. // --------------------------------------------------------------------------
  711. void CTurnOffDialog::Handle_WM_PRINTCLIENT (HWND hwnd, HDC hdcPrint, DWORD dwOptions)
  712. {
  713. if ((dwOptions & (PRF_ERASEBKGND | PRF_CLIENT)) != 0)
  714. {
  715. Handle_WM_ERASEBKGND(hwnd, hdcPrint);
  716. }
  717. }
  718. // --------------------------------------------------------------------------
  719. // CTurnOffDialog::Handle_WM_ACTIVATE
  720. //
  721. // Arguments: hwnd = HWND to erase.
  722. // dwState = Activate state.
  723. //
  724. // Returns: <none>
  725. //
  726. // Purpose: Detects if this window is becoming inactive. In this case
  727. // end the dialog.
  728. //
  729. // History: 2001-01-20 vtan created
  730. // --------------------------------------------------------------------------
  731. void CTurnOffDialog::Handle_WM_ACTIVATE (HWND hwnd, DWORD dwState)
  732. {
  733. if ((WA_INACTIVE == dwState) && !_fDialogEnded)
  734. {
  735. EndDialog(hwnd, SHTDN_NONE);
  736. }
  737. }
  738. // --------------------------------------------------------------------------
  739. // CTurnOffDialog::Handle_WM_DRAWITEM
  740. //
  741. // Arguments: hwnd = HWND of the parent window.
  742. // pDIS = DRAWITEMSTRUCT defining what to draw.
  743. //
  744. // Returns: <none>
  745. //
  746. // Purpose: Draws several aspects of the turn off dialog. It handles the
  747. // title text, the owner draw bitmap buttons, the text for the
  748. // bitmap buttons and the separator line.
  749. //
  750. // History: 2000-05-17 vtan created
  751. // 2001-01-18 vtan update with new visuals
  752. // --------------------------------------------------------------------------
  753. void CTurnOffDialog::Handle_WM_DRAWITEM (HWND hwnd, const DRAWITEMSTRUCT *pDIS)
  754. {
  755. HPALETTE hPaletteOld;
  756. HFONT hfntSelected;
  757. int iBkMode;
  758. COLORREF colorText;
  759. RECT rc;
  760. SIZE size;
  761. TCHAR szText[256];
  762. hPaletteOld = SelectPalette(pDIS->hDC, _hpltShell, FALSE);
  763. (UINT)RealizePalette(pDIS->hDC);
  764. switch (pDIS->CtlID)
  765. {
  766. case IDC_BUTTON_TURNOFF:
  767. case IDC_BUTTON_STANDBY:
  768. case IDC_BUTTON_RESTART:
  769. {
  770. int iState, iGroup;
  771. // Select the correct state index to use. Check for ODS_SELECTED first.
  772. // Then check for hover or ODS_FOCUS. Otherwise use the rest state.
  773. if ((pDIS->itemState & ODS_SELECTED) != 0)
  774. {
  775. iState = BUTTON_STATE_DOWN;
  776. }
  777. else if ((_uiHoverID == pDIS->CtlID) || ((pDIS->itemState & ODS_FOCUS) != 0))
  778. {
  779. iState = BUTTON_STATE_HOVER;
  780. }
  781. else
  782. {
  783. iState = BUTTON_STATE_REST;
  784. }
  785. // Now select the correct bitmap based on the state index. Special case
  786. // IDC_BUTTON_STANDBY because if it's disabled then select the special
  787. // disabled button.
  788. switch (pDIS->CtlID)
  789. {
  790. case IDC_BUTTON_TURNOFF:
  791. iGroup = BUTTON_GROUP_TURNOFF;
  792. break;
  793. case IDC_BUTTON_STANDBY:
  794. if (IsStandByButtonEnabled())
  795. {
  796. iGroup = BUTTON_GROUP_STANDBY;
  797. }
  798. else
  799. {
  800. iGroup = BUTTON_GROUP_MAX;
  801. iState = 0;
  802. }
  803. break;
  804. case IDC_BUTTON_RESTART:
  805. iGroup = BUTTON_GROUP_RESTART;
  806. break;
  807. default:
  808. iGroup = -1;
  809. DISPLAYMSG("This should never be executed");
  810. break;
  811. }
  812. if (iGroup >= 0)
  813. {
  814. RECT rc;
  815. // Calculate which part of the background to blit into the DC.
  816. // Only blit the amount that's necessary to avoid excessive
  817. // blitting. Once blitted then blit the button BMP. The blit
  818. // uses msimg32!TransparentBlt with the magical magenta color.
  819. TBOOL(CopyRect(&rc, &_rcBackground));
  820. (int)MapWindowPoints(pDIS->hwndItem, hwnd, reinterpret_cast<POINT*>(&rc), sizeof(RECT) / sizeof(POINT));
  821. rc.right = rc.left + (_rcButtons.right - _rcButtons.left);
  822. rc.bottom = rc.top + _lButtonHeight;
  823. PaintBitmap(pDIS->hDC, &pDIS->rcItem, _hbmBackground, &rc);
  824. TBOOL(CopyRect(&rc, &_rcButtons));
  825. rc.top = ((iGroup * BUTTON_STATE_MAX) + iState) * _lButtonHeight;
  826. rc.bottom = rc.top + _lButtonHeight;
  827. PaintBitmap(pDIS->hDC, &pDIS->rcItem, _hbmButtons, &rc);
  828. }
  829. break;
  830. }
  831. case IDC_TITLE_FLAG:
  832. {
  833. BITMAP bitmap;
  834. GetClientRect(pDIS->hwndItem, &rc);
  835. if (GetObject(_hbmFlag, sizeof(bitmap), &bitmap) != 0)
  836. {
  837. rc.left += ((rc.right - rc.left) - bitmap.bmWidth) / 2;
  838. rc.right = rc.left + bitmap.bmWidth;
  839. rc.top += ((rc.bottom - rc.top) - bitmap.bmHeight) / 2;
  840. rc.bottom = rc.top + bitmap.bmHeight;
  841. }
  842. PaintBitmap(pDIS->hDC, &rc, _hbmFlag, &_rcFlag);
  843. break;
  844. }
  845. case IDC_TITLE_TURNOFF:
  846. {
  847. // Draw the title of the dialog "Turn Off Computer".
  848. hfntSelected = static_cast<HFONT>(SelectObject(pDIS->hDC, _hfntTitle));
  849. colorText = SetTextColor(pDIS->hDC, 0x00FFFFFF);
  850. iBkMode = SetBkMode(pDIS->hDC, TRANSPARENT);
  851. (int)GetWindowText(GetDlgItem(hwnd, pDIS->CtlID), szText, ARRAYSIZE(szText));
  852. TBOOL(GetTextExtentPoint(pDIS->hDC, szText, lstrlen(szText), &size));
  853. TBOOL(CopyRect(&rc, &pDIS->rcItem));
  854. TBOOL(InflateRect(&rc, 0, -((rc.bottom - rc.top - size.cy) / 2)));
  855. (int)DrawText(pDIS->hDC, szText, -1, &rc, 0);
  856. (int)SetBkMode(pDIS->hDC, iBkMode);
  857. (COLORREF)SetTextColor(pDIS->hDC, colorText);
  858. (HGDIOBJ)SelectObject(pDIS->hDC, hfntSelected);
  859. break;
  860. }
  861. case IDC_TEXT_TURNOFF:
  862. case IDC_TEXT_STANDBY:
  863. case IDC_TEXT_RESTART:
  864. {
  865. int iPixelHeight, iButtonID;
  866. COLORREF colorButtonText;
  867. RECT rcText;
  868. // The text to display is based on the button title. Map the static
  869. // text ID to a "parent" button ID. Special case IDC_TEXT_STANDBY.
  870. switch (pDIS->CtlID)
  871. {
  872. case IDC_TEXT_TURNOFF:
  873. iButtonID = IDC_BUTTON_TURNOFF;
  874. break;
  875. case IDC_TEXT_STANDBY:
  876. // For Stand By base it on the button result.
  877. switch (_iStandByButtonResult)
  878. {
  879. case SHTDN_HIBERNATE:
  880. iButtonID = IDC_BUTTON_HIBERNATE;
  881. break;
  882. case SHTDN_SLEEP:
  883. default:
  884. iButtonID = IDC_BUTTON_STANDBY;
  885. break;
  886. }
  887. break;
  888. case IDC_TEXT_RESTART:
  889. iButtonID = IDC_BUTTON_RESTART;
  890. break;
  891. default:
  892. iButtonID = 0;
  893. DISPLAYMSG("This should never be executed");
  894. break;
  895. }
  896. hfntSelected = static_cast<HFONT>(SelectObject(pDIS->hDC, _hfntButton));
  897. // If the text field is not Stand By or supports S1-S3 or supports S4
  898. // use the regular text color. Otherwise the button is disabled.
  899. if ((pDIS->CtlID != IDC_TEXT_STANDBY) || _fSupportsStandBy || _fSupportsHibernate)
  900. {
  901. colorButtonText = RGB(255, 255, 255);
  902. }
  903. else
  904. {
  905. colorButtonText = RGB(160, 160, 160);
  906. }
  907. colorText = SetTextColor(pDIS->hDC, colorButtonText);
  908. iBkMode = SetBkMode(pDIS->hDC, TRANSPARENT);
  909. (int)GetWindowText(GetDlgItem(hwnd, iButtonID), szText, ARRAYSIZE(szText));
  910. TBOOL(CopyRect(&rcText, &pDIS->rcItem));
  911. iPixelHeight = DrawText(pDIS->hDC, szText, -1, &rcText, DT_CALCRECT);
  912. TBOOL(CopyRect(&rc, &pDIS->rcItem));
  913. TBOOL(InflateRect(&rc, -((rc.right - rc.left - (rcText.right - rcText.left)) / 2), -((rc.bottom - rc.top - iPixelHeight) / 2)));
  914. (int)DrawText(pDIS->hDC, szText, -1, &rc, ((pDIS->itemState & ODS_NOACCEL ) != 0) ? DT_HIDEPREFIX : 0);
  915. (int)SetBkMode(pDIS->hDC, iBkMode);
  916. (COLORREF)SetTextColor(pDIS->hDC, colorText);
  917. (HGDIOBJ)SelectObject(pDIS->hDC, hfntSelected);
  918. break;
  919. }
  920. default:
  921. {
  922. DISPLAYMSG("Unknown control ID passed to CTurnOffDialog::Handle_WM_DRAWITEM");
  923. break;
  924. }
  925. }
  926. (HGDIOBJ)SelectPalette(pDIS->hDC, hPaletteOld, FALSE);
  927. (UINT)RealizePalette(pDIS->hDC);
  928. }
  929. // --------------------------------------------------------------------------
  930. // CTurnOffDialog::Handle_WM_COMMAND
  931. //
  932. // Arguments: hwnd = HWND of dialog.
  933. // wParam = WPARAM (see platform SDK under WM_COMMAND).
  934. //
  935. // Returns: <none>
  936. //
  937. // Purpose: Handles clicks in the bitmap buttons and sets the return
  938. // result according to the button pressed.
  939. //
  940. // History: 2000-05-17 vtan created
  941. // --------------------------------------------------------------------------
  942. void CTurnOffDialog::Handle_WM_COMMAND (HWND hwnd, WPARAM wParam)
  943. {
  944. switch (HIWORD(wParam))
  945. {
  946. case BN_CLICKED:
  947. Handle_BN_CLICKED(hwnd, LOWORD(wParam));
  948. break;
  949. default:
  950. break;
  951. }
  952. }
  953. // --------------------------------------------------------------------------
  954. // CTurnOffDialog::Handle_WM_TIMER
  955. //
  956. // Arguments: hwnd = HWND of the dialog.
  957. //
  958. // Returns: <none>
  959. //
  960. // Purpose: Handles WM_TIMER. This periodically checks for the state of
  961. // shift key. The dialog manager doesn't give the DialogProc
  962. // events for the shift key. This appears to be the only way to
  963. // accomplish this for Win32 dialogs.
  964. //
  965. // History: 2001-01-20 vtan created
  966. // --------------------------------------------------------------------------
  967. void CTurnOffDialog::Handle_WM_TIMER (HWND hwnd)
  968. {
  969. bool fShiftKeyDown;
  970. fShiftKeyDown = IsShiftKeyDown();
  971. // Has the shift key state changed since the last time?
  972. if (_fShiftKeyDown != fShiftKeyDown)
  973. {
  974. HWND hwndText;
  975. RECT rc;
  976. // Save the shift key state.
  977. _fShiftKeyDown = fShiftKeyDown;
  978. // Toggle the result.
  979. switch (_iStandByButtonResult)
  980. {
  981. case SHTDN_SLEEP:
  982. _iStandByButtonResult = SHTDN_HIBERNATE;
  983. break;
  984. case SHTDN_HIBERNATE:
  985. _iStandByButtonResult = SHTDN_SLEEP;
  986. break;
  987. default:
  988. DISPLAYMSG("Unexpect _iStandByButtonResult in CTurnOffDialog::Handle_WM_TIMER");
  989. break;
  990. }
  991. // Get the client rectangle of the text for the button (IDC_TEXT_STANDBY).
  992. // Map the rectangle to co-ordinates in the parent HWND. Invalidate that
  993. // rectangle for the parent HWND. It's important to invalidate the parent
  994. // so that the background for the text is also drawn by sending a
  995. // WM_ERASEBKGND to the parent of the button.
  996. hwndText = GetDlgItem(hwnd, IDC_TEXT_STANDBY);
  997. TBOOL(GetClientRect(hwndText, &rc));
  998. (int)MapWindowPoints(hwndText, hwnd, reinterpret_cast<POINT*>(&rc), sizeof(rc) / sizeof(POINT));
  999. TBOOL(InvalidateRect(hwnd, &rc, TRUE));
  1000. // If there was a tooltip for the Stand By button then
  1001. // remove it and reshow it. Only do this for Stand By.
  1002. if ((_pTooltip != NULL) && (_uiHoverID == IDC_BUTTON_STANDBY))
  1003. {
  1004. RemoveTooltip();
  1005. _uiHoverID = 0;
  1006. }
  1007. }
  1008. }
  1009. // --------------------------------------------------------------------------
  1010. // CTurnOffDialog::Handle_WM_MOUSEMOVE
  1011. //
  1012. // Arguments: hwnd = HWND of the control.
  1013. // uiID = ID of the control.
  1014. //
  1015. // Returns: <none>
  1016. //
  1017. // Purpose: Sets the cursor to a hand and tracks mouse movement in the
  1018. // control. Refresh the control to show the hover state.
  1019. //
  1020. // History: 2000-06-09 vtan created
  1021. // 2001-01-18 vtan update with new visuals
  1022. // --------------------------------------------------------------------------
  1023. void CTurnOffDialog::Handle_WM_MOUSEMOVE (HWND hwnd, UINT uiID)
  1024. {
  1025. (HCURSOR)SetCursor(LoadCursor(NULL, IDC_HAND));
  1026. if (uiID != _uiHoverID)
  1027. {
  1028. TRACKMOUSEEVENT tme;
  1029. _uiHoverID = uiID;
  1030. tme.cbSize = sizeof(tme);
  1031. tme.dwFlags = TME_HOVER | TME_LEAVE;
  1032. tme.hwndTrack = hwnd;
  1033. tme.dwHoverTime = HOVER_DEFAULT;
  1034. TBOOL(TrackMouseEvent(&tme));
  1035. TBOOL(InvalidateRect(hwnd, NULL, FALSE));
  1036. }
  1037. }
  1038. // --------------------------------------------------------------------------
  1039. // CTurnOffDialog::Handle_WM_MOUSEHOVER
  1040. //
  1041. // Arguments: hwnd = HWND of the control.
  1042. // uiID = ID of the control.
  1043. //
  1044. // Returns: <none>
  1045. //
  1046. // Purpose: Handles hovering over the control. Determine which tooltip to
  1047. // bring up and show it.
  1048. //
  1049. // History: 2000-06-09 vtan created
  1050. // 2001-01-18 vtan update with new visuals
  1051. // --------------------------------------------------------------------------
  1052. void CTurnOffDialog::Handle_WM_MOUSEHOVER (HWND hwnd, UINT uiID)
  1053. {
  1054. int iTextID;
  1055. HWND hwndCaption;
  1056. hwndCaption = hwnd;
  1057. // The tooltip is based on the button being hovered over. Special case
  1058. // IDC_BUTTON_STANDBY. Based on the intended result if clicked bring
  1059. // up the appropriate tooltip text. This will be one of three states:
  1060. // 1) Stand By (with shift key toggling).
  1061. // 2) Stand By (shift key is disabled - nothing extra).
  1062. // 3) Hibernate.
  1063. // In the case of hibernate make sure to use IDC_BUTTON_HIBERNATE as the
  1064. // button for the tooltip caption. In the case of hibernate only even
  1065. // though the button is disabled the text is still correct.
  1066. switch (uiID)
  1067. {
  1068. case IDC_BUTTON_TURNOFF:
  1069. iTextID = IDS_TURNOFF_TOOLTIP_TEXT_TURNOFF;
  1070. break;
  1071. case IDC_BUTTON_STANDBY:
  1072. switch (_iStandByButtonResult)
  1073. {
  1074. case SHTDN_SLEEP:
  1075. if (_fSupportsHibernate)
  1076. {
  1077. iTextID = IDS_TURNOFF_TOOLTIP_TEXT_STANDBY_HIBERNATE;
  1078. }
  1079. else
  1080. {
  1081. iTextID = IDS_TURNOFF_TOOLTIP_TEXT_STANDBY;
  1082. }
  1083. break;
  1084. case SHTDN_HIBERNATE:
  1085. hwndCaption = GetDlgItem(GetParent(hwnd), IDC_BUTTON_HIBERNATE);
  1086. iTextID = IDS_TURNOFF_TOOLTIP_TEXT_HIBERNATE;
  1087. break;
  1088. default:
  1089. iTextID = 0;
  1090. DISPLAYMSG("Unexpected _iStandByButtonResult in CTurnOffDialog::Handle_WM_MOUSEHOVER");
  1091. break;
  1092. }
  1093. break;
  1094. case IDC_BUTTON_RESTART:
  1095. iTextID = IDS_TURNOFF_TOOLTIP_TEXT_RESTART;
  1096. break;
  1097. default:
  1098. iTextID = 0;
  1099. break;
  1100. }
  1101. // Construct the tooltip and show it.
  1102. if (iTextID != 0)
  1103. {
  1104. int iCaptionLength;
  1105. TCHAR *pszCaption;
  1106. iCaptionLength = GetWindowTextLength(hwndCaption) + sizeof('\0');
  1107. pszCaption = static_cast<TCHAR*>(LocalAlloc(LMEM_FIXED, iCaptionLength * sizeof(TCHAR)));
  1108. if (pszCaption != NULL)
  1109. {
  1110. if (GetWindowText(hwndCaption, pszCaption, iCaptionLength) != 0)
  1111. {
  1112. _pTooltip = new CTooltip(_hInstance, hwnd);
  1113. if (_pTooltip != NULL)
  1114. {
  1115. TCHAR szText[256];
  1116. if (LoadString(_hInstance, iTextID, szText + sizeof('\r') + sizeof('\n'), ARRAYSIZE(szText) - sizeof('\r') - sizeof('\n')) != 0)
  1117. {
  1118. FilterMetaCharacters(pszCaption);
  1119. szText[0] = TEXT('\r');
  1120. szText[1] = TEXT('\n');
  1121. _pTooltip->SetPosition();
  1122. _pTooltip->SetCaption(0, pszCaption);
  1123. _pTooltip->SetText(szText);
  1124. _pTooltip->Show();
  1125. }
  1126. }
  1127. }
  1128. (HLOCAL)LocalFree(pszCaption);
  1129. }
  1130. }
  1131. }
  1132. // --------------------------------------------------------------------------
  1133. // CTurnOffDialog::Handle_WM_MOUSELEAVE
  1134. //
  1135. // Arguments: hwnd = HWND of the control.
  1136. //
  1137. // Returns: <none>
  1138. //
  1139. // Purpose: Removes the tooltip and clears the hover ID.
  1140. //
  1141. // History: 2000-06-09 vtan created
  1142. // 2001-01-18 vtan update with new visuals
  1143. // --------------------------------------------------------------------------
  1144. void CTurnOffDialog::Handle_WM_MOUSELEAVE (HWND hwnd)
  1145. {
  1146. RemoveTooltip();
  1147. _uiHoverID = 0;
  1148. TBOOL(InvalidateRect(hwnd, NULL, FALSE));
  1149. }
  1150. // --------------------------------------------------------------------------
  1151. // CTurnOffDialog::CB_DialogProc
  1152. //
  1153. // Arguments: See the platform SDK under DialogProc.
  1154. //
  1155. // Returns: See the platform SDK under DialogProc.
  1156. //
  1157. // Purpose: Main DialogProc dispatch entry point for the turn off dialog.
  1158. // To keep this simple it calls member functions.
  1159. //
  1160. // History: 2000-05-17 vtan created
  1161. // 2001-01-18 vtan update with new visuals
  1162. // --------------------------------------------------------------------------
  1163. INT_PTR CALLBACK CTurnOffDialog::CB_DialogProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1164. {
  1165. INT_PTR iResult;
  1166. CTurnOffDialog *pThis;
  1167. pThis = reinterpret_cast<CTurnOffDialog*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  1168. switch (uMsg)
  1169. {
  1170. case WM_INITDIALOG:
  1171. pThis = reinterpret_cast<CTurnOffDialog*>(lParam);
  1172. (LONG_PTR)SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
  1173. pThis->Handle_WM_INITDIALOG(hwnd);
  1174. iResult = FALSE;
  1175. break;
  1176. case WM_DESTROY:
  1177. pThis->Handle_WM_DESTROY(hwnd);
  1178. iResult = 0;
  1179. break;
  1180. case WM_ERASEBKGND:
  1181. pThis->Handle_WM_ERASEBKGND(hwnd, reinterpret_cast<HDC>(wParam));
  1182. iResult = 1;
  1183. break;
  1184. case WM_PRINTCLIENT:
  1185. pThis->Handle_WM_PRINTCLIENT(hwnd, reinterpret_cast<HDC>(wParam), static_cast<DWORD>(lParam));
  1186. iResult = 1; // This tells the button that it was handled.
  1187. break;
  1188. case WM_ACTIVATE:
  1189. pThis->Handle_WM_ACTIVATE(hwnd, static_cast<DWORD>(wParam));
  1190. iResult = 1;
  1191. break;
  1192. case WM_DRAWITEM:
  1193. pThis->Handle_WM_DRAWITEM(hwnd, reinterpret_cast<DRAWITEMSTRUCT*>(lParam));
  1194. iResult = TRUE;
  1195. break;
  1196. case WM_COMMAND:
  1197. pThis->Handle_WM_COMMAND(hwnd, wParam);
  1198. iResult = 0;
  1199. break;
  1200. case WM_TIMER:
  1201. ASSERTMSG(static_cast<UINT>(wParam) == pThis->_uiTimerID, "Unexpected timer ID mismatch in CTurnOffDialog::CB_DialogProc");
  1202. pThis->Handle_WM_TIMER(hwnd);
  1203. iResult = 0;
  1204. break;
  1205. default:
  1206. iResult = 0;
  1207. break;
  1208. }
  1209. return(iResult);
  1210. }
  1211. // --------------------------------------------------------------------------
  1212. // CTurnOffDialog::ButtonSubClassProc
  1213. //
  1214. // Arguments: hwnd = See the platform SDK under WindowProc.
  1215. // uMsg = See the platform SDK under WindowProc.
  1216. // wParam = See the platform SDK under WindowProc.
  1217. // lParam = See the platform SDK under WindowProc.
  1218. // uiID = ID assigned at subclass time.
  1219. // dwRefData = reference data assigned at subclass time.
  1220. //
  1221. // Returns: LRESULT
  1222. //
  1223. // Purpose: comctl32 subclass callback function. This allows the bitmap
  1224. // buttons to hover and track accordingly. This also allows our
  1225. // BS_OWNERDRAW buttons to be pushed when the keyboard is used.
  1226. //
  1227. // History: 2000-05-17 vtan created
  1228. // 2001-01-18 vtan update with new visuals
  1229. // --------------------------------------------------------------------------
  1230. LRESULT CALLBACK CTurnOffDialog::ButtonSubClassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uiID, DWORD_PTR dwRefData)
  1231. {
  1232. LRESULT lResult;
  1233. CTurnOffDialog *pThis;
  1234. pThis = reinterpret_cast<CTurnOffDialog*>(dwRefData);
  1235. switch (uMsg)
  1236. {
  1237. // Do NOT allow BM_SETSTYLE to go thru to the default handler. This is
  1238. // because DLGC_UNDEFPUSHBUTTON is returned for WM_GETDLGCODE. When the
  1239. // dialog manager sees this it tries to set the focus style on the button.
  1240. // Even though it's owner drawn the button window proc still draws the
  1241. // focus state (because we returned DLGC_UNDEFPUSHBUTTON). Therefore to
  1242. // ensure the bitmap isn't over-painted by the button window proc blow off
  1243. // the BM_SETSTYLE and don't let it get to the button window proc.
  1244. case BM_SETSTYLE:
  1245. if (wParam == BS_DEFPUSHBUTTON)
  1246. {
  1247. pThis->_uiFocusID = static_cast<UINT>(uiID);
  1248. }
  1249. if (uiID != IDCANCEL)
  1250. {
  1251. lResult = 0;
  1252. break;
  1253. }
  1254. // Fall thru
  1255. default:
  1256. // Otherwise in the default case let the default handler at the message
  1257. // first. This implements tail-patching.
  1258. lResult = DefSubclassProc(hwnd, uMsg, wParam, lParam);
  1259. switch (uMsg)
  1260. {
  1261. case DM_GETDEFID:
  1262. lResult = (DC_HASDEFID << 16) | static_cast<WORD>(pThis->_uiFocusID);
  1263. break;
  1264. case WM_GETDLGCODE:
  1265. if (uiID == pThis->_uiFocusID)
  1266. {
  1267. lResult |= DLGC_DEFPUSHBUTTON;
  1268. }
  1269. else
  1270. {
  1271. lResult |= DLGC_UNDEFPUSHBUTTON;
  1272. }
  1273. break;
  1274. case WM_MOUSEMOVE:
  1275. pThis->Handle_WM_MOUSEMOVE(hwnd, static_cast<UINT>(uiID));
  1276. break;
  1277. case WM_MOUSEHOVER:
  1278. pThis->Handle_WM_MOUSEHOVER(hwnd, static_cast<UINT>(uiID));
  1279. break;
  1280. case WM_MOUSELEAVE:
  1281. pThis->Handle_WM_MOUSELEAVE(hwnd);
  1282. break;
  1283. default:
  1284. break;
  1285. }
  1286. }
  1287. return(lResult);
  1288. }