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.

1051 lines
35 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: SwitchUserDialog.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // Class that implements presentation of the Switch User dialog.
  7. //
  8. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  9. // --------------------------------------------------------------------------
  10. #include "shellprv.h"
  11. #include "SwitchUserDialog.h"
  12. #include <msginaexports.h>
  13. #include <shlwapi.h>
  14. #include "ids.h"
  15. #include "tooltip.h"
  16. #define DISPLAYMSG(x) ASSERTMSG(false, x)
  17. EXTERN_C HINSTANCE g_hinst;
  18. // --------------------------------------------------------------------------
  19. // CSwitchUserDialog::CSwitchUserDialog
  20. //
  21. // Arguments: hInstance = HINSTANCE of hosting process/DLL.
  22. //
  23. // Returns: <none>
  24. //
  25. // Purpose: Constructor for CSwitchUserDialog. This initializes member
  26. // variables and loads resources used by the dialog.
  27. //
  28. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  29. // --------------------------------------------------------------------------
  30. CSwitchUserDialog::CSwitchUserDialog (HINSTANCE hInstance) :
  31. _hInstance(hInstance),
  32. _hbmBackground(NULL),
  33. _hbmFlag(NULL),
  34. _hbmButtons(NULL),
  35. _hfntTitle(NULL),
  36. _hfntButton(NULL),
  37. _hpltShell(NULL),
  38. _lButtonHeight(0),
  39. _uiHoverID(0),
  40. _uiFocusID(0),
  41. _fSuccessfulInitialization(false),
  42. _fDialogEnded(false),
  43. _pTooltip(NULL)
  44. {
  45. bool fUse8BitDepth;
  46. HDC hdcScreen;
  47. LOGFONT logFont;
  48. char szPixelSize[10];
  49. BITMAP bitmap;
  50. TBOOL(SetRect(&_rcBackground, 0, 0, 0, 0));
  51. TBOOL(SetRect(&_rcFlag, 0, 0, 0, 0));
  52. TBOOL(SetRect(&_rcButtons, 0, 0, 0, 0));
  53. hdcScreen = GetDC(NULL);
  54. // 8-bit color?
  55. fUse8BitDepth = (GetDeviceCaps(hdcScreen, BITSPIXEL) <= 8);
  56. // Load the bitmaps.
  57. _hbmBackground = static_cast<HBITMAP>(LoadImage(_hInstance,
  58. MAKEINTRESOURCE(fUse8BitDepth ? IDB_BACKGROUND_8 : IDB_BACKGROUND_24),
  59. IMAGE_BITMAP,
  60. 0,
  61. 0,
  62. LR_CREATEDIBSECTION));
  63. if ((_hbmBackground != NULL) && (GetObject(_hbmBackground, sizeof(bitmap), &bitmap) >= sizeof(bitmap)))
  64. {
  65. TBOOL(SetRect(&_rcBackground, 0, 0, bitmap.bmWidth, bitmap.bmHeight));
  66. }
  67. _hbmFlag = static_cast<HBITMAP>(LoadImage(_hInstance,
  68. MAKEINTRESOURCE(fUse8BitDepth ? IDB_FLAG_8 : IDB_FLAG_24),
  69. IMAGE_BITMAP,
  70. 0,
  71. 0,
  72. LR_CREATEDIBSECTION));
  73. if ((_hbmFlag != NULL) && (GetObject(_hbmFlag, sizeof(bitmap), &bitmap) >= sizeof(bitmap)))
  74. {
  75. TBOOL(SetRect(&_rcFlag, 0, 0, bitmap.bmWidth, bitmap.bmHeight));
  76. }
  77. _hbmButtons = static_cast<HBITMAP>(LoadImage(_hInstance,
  78. MAKEINTRESOURCE(IDB_BUTTONS),
  79. IMAGE_BITMAP,
  80. 0,
  81. 0,
  82. LR_CREATEDIBSECTION));
  83. if ((_hbmButtons != NULL) && (GetObject(_hbmButtons, sizeof(bitmap), &bitmap) >= sizeof(bitmap)))
  84. {
  85. TBOOL(SetRect(&_rcButtons, 0, 0, bitmap.bmWidth, bitmap.bmHeight));
  86. _lButtonHeight = bitmap.bmHeight / (BUTTON_GROUP_MAX * BUTTON_STATE_MAX);
  87. }
  88. // Create fonts. Load the font name and size from resources.
  89. ZeroMemory(&logFont, sizeof(logFont));
  90. if (LoadStringA(_hInstance,
  91. IDS_SWITCHUSER_TITLE_FACESIZE,
  92. szPixelSize,
  93. ARRAYSIZE(szPixelSize)) != 0)
  94. {
  95. logFont.lfHeight = -MulDiv(atoi(szPixelSize), GetDeviceCaps(hdcScreen, LOGPIXELSY), 72);
  96. if (LoadString(_hInstance,
  97. IDS_SWITCHUSER_TITLE_FACENAME,
  98. logFont.lfFaceName,
  99. LF_FACESIZE) != 0)
  100. {
  101. logFont.lfWeight = FW_MEDIUM;
  102. logFont.lfQuality = DEFAULT_QUALITY;
  103. _hfntTitle = CreateFontIndirect(&logFont);
  104. }
  105. }
  106. ZeroMemory(&logFont, sizeof(logFont));
  107. if (LoadStringA(_hInstance,
  108. IDS_SWITCHUSER_BUTTON_FACESIZE,
  109. szPixelSize,
  110. ARRAYSIZE(szPixelSize)) != 0)
  111. {
  112. logFont.lfHeight = -MulDiv(atoi(szPixelSize), GetDeviceCaps(hdcScreen, LOGPIXELSY), 72);
  113. if (LoadString(_hInstance,
  114. IDS_SWITCHUSER_BUTTON_FACENAME,
  115. logFont.lfFaceName,
  116. LF_FACESIZE) != 0)
  117. {
  118. logFont.lfWeight = FW_BOLD;
  119. logFont.lfQuality = DEFAULT_QUALITY;
  120. _hfntButton = CreateFontIndirect(&logFont);
  121. }
  122. }
  123. // Load the shell palette.
  124. _hpltShell = SHCreateShellPalette(hdcScreen);
  125. TBOOL(ReleaseDC(NULL, hdcScreen));
  126. // Check for presence of all required resources.
  127. _fSuccessfulInitialization = ((_hfntTitle != NULL) &&
  128. (_hfntButton != NULL) &&
  129. (_hpltShell != NULL) &&
  130. (_hbmButtons != NULL) &&
  131. (_hbmFlag != NULL) &&
  132. (_hbmBackground != NULL));
  133. }
  134. // --------------------------------------------------------------------------
  135. // CSwitchUserDialog::~CSwitchUserDialog
  136. //
  137. // Arguments: <none>
  138. //
  139. // Returns: <none>
  140. //
  141. // Purpose: Destructor for CSwitchUserDialog. Release used resources and
  142. // unregister the window class.
  143. //
  144. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  145. // --------------------------------------------------------------------------
  146. CSwitchUserDialog::~CSwitchUserDialog (void)
  147. {
  148. ASSERTMSG(_pTooltip == NULL, "_pTooltip not released in CSwitchUserDialog::~CSwitchUserDialog");
  149. // Release everything we allocated/loaded.
  150. if (_hpltShell != NULL)
  151. {
  152. TBOOL(DeleteObject(_hpltShell));
  153. _hpltShell = NULL;
  154. }
  155. if (_hfntButton != NULL)
  156. {
  157. TBOOL(DeleteObject(_hfntButton));
  158. _hfntButton = NULL;
  159. }
  160. if (_hfntTitle != NULL)
  161. {
  162. TBOOL(DeleteObject(_hfntTitle));
  163. _hfntTitle = NULL;
  164. }
  165. if (_hbmButtons != NULL)
  166. {
  167. TBOOL(DeleteObject(_hbmButtons));
  168. _hbmButtons = NULL;
  169. }
  170. if (_hbmFlag != NULL)
  171. {
  172. TBOOL(DeleteObject(_hbmFlag));
  173. _hbmFlag = NULL;
  174. }
  175. if (_hbmBackground != NULL)
  176. {
  177. TBOOL(DeleteObject(_hbmBackground));
  178. _hbmBackground = NULL;
  179. }
  180. }
  181. // --------------------------------------------------------------------------
  182. // CSwitchUserDialog::Show
  183. //
  184. // Arguments: <none>
  185. //
  186. // Returns: DWORD
  187. //
  188. // Purpose: Presents the "Switch User" dialog to the user and returns the
  189. // result of the dialog back to the caller.
  190. //
  191. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  192. // --------------------------------------------------------------------------
  193. DWORD CSwitchUserDialog::Show (HWND hwndParent)
  194. {
  195. INT_PTR iResult;
  196. if (_fSuccessfulInitialization)
  197. {
  198. IUnknown *pIUnknown;
  199. // If no parent was given the create our own dimmed window.
  200. if (hwndParent == NULL)
  201. {
  202. if (FAILED(ShellDimScreen(&pIUnknown, &hwndParent)))
  203. {
  204. pIUnknown = NULL;
  205. hwndParent = NULL;
  206. }
  207. }
  208. else
  209. {
  210. pIUnknown = NULL;
  211. }
  212. // Show the dialog and get a result.
  213. iResult = DialogBoxParam(_hInstance,
  214. MAKEINTRESOURCE(DLG_SWITCHUSER),
  215. hwndParent,
  216. CB_DialogProc,
  217. reinterpret_cast<LPARAM>(this));
  218. if (pIUnknown != NULL)
  219. {
  220. pIUnknown->Release();
  221. }
  222. }
  223. else
  224. {
  225. iResult = 0;
  226. }
  227. return(static_cast<DWORD>(iResult));
  228. }
  229. // --------------------------------------------------------------------------
  230. // CSwitchUserDialog::PaintBitmap
  231. //
  232. // Arguments: hdcDestination = HDC to paint into.
  233. // prcDestination = RECT in HDC to paint into.
  234. // hbmSource = HBITMAP to paint.
  235. // prcSource = RECT from HBITMAP to paint from.
  236. //
  237. // Returns: <none>
  238. //
  239. // Purpose: Wraps blitting a bitmap.
  240. //
  241. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  242. // 2001-03-17 vtan added source RECT for strip blitting
  243. // --------------------------------------------------------------------------
  244. void CSwitchUserDialog::PaintBitmap (HDC hdcDestination, const RECT *prcDestination, HBITMAP hbmSource, const RECT *prcSource)
  245. {
  246. HDC hdcBitmap;
  247. hdcBitmap = CreateCompatibleDC(NULL);
  248. if (hdcBitmap != NULL)
  249. {
  250. bool fEqualWidthAndHeight;
  251. int iWidthSource, iHeightSource, iWidthDestination, iHeightDestination;
  252. int iStretchBltMode;
  253. DWORD dwLayout;
  254. HBITMAP hbmSelected;
  255. RECT rcSource;
  256. BITMAP bitmap;
  257. if (prcSource == NULL)
  258. {
  259. if (GetObject(hbmSource, sizeof(bitmap), &bitmap) == 0)
  260. {
  261. bitmap.bmWidth = prcDestination->right - prcDestination->left;
  262. bitmap.bmHeight = prcDestination->bottom - prcDestination->top;
  263. }
  264. TBOOL(SetRect(&rcSource, 0, 0, bitmap.bmWidth, bitmap.bmHeight));
  265. prcSource = &rcSource;
  266. }
  267. hbmSelected = static_cast<HBITMAP>(SelectObject(hdcBitmap, hbmSource));
  268. iWidthSource = prcSource->right - prcSource->left;
  269. iHeightSource = prcSource->bottom - prcSource->top;
  270. iWidthDestination = prcDestination->right - prcDestination->left;
  271. iHeightDestination = prcDestination->bottom - prcDestination->top;
  272. fEqualWidthAndHeight = (iWidthSource == iWidthDestination) && (iHeightSource == iHeightDestination);
  273. if (!fEqualWidthAndHeight)
  274. {
  275. iStretchBltMode = SetStretchBltMode(hdcDestination, HALFTONE);
  276. }
  277. else
  278. {
  279. iStretchBltMode = 0;
  280. }
  281. dwLayout = SetLayout(hdcDestination, LAYOUT_BITMAPORIENTATIONPRESERVED);
  282. TBOOL(TransparentBlt(hdcDestination,
  283. prcDestination->left,
  284. prcDestination->top,
  285. iWidthDestination,
  286. iHeightDestination,
  287. hdcBitmap,
  288. prcSource->left,
  289. prcSource->top,
  290. iWidthSource,
  291. iHeightSource,
  292. RGB(255, 0, 255)));
  293. (DWORD)SetLayout(hdcDestination, dwLayout);
  294. if (!fEqualWidthAndHeight)
  295. {
  296. (int)SetStretchBltMode(hdcDestination, iStretchBltMode);
  297. }
  298. (HGDIOBJ)SelectObject(hdcBitmap, hbmSelected);
  299. TBOOL(DeleteDC(hdcBitmap));
  300. }
  301. }
  302. // --------------------------------------------------------------------------
  303. // CSwitchUserDialog::RemoveTooltip
  304. //
  305. // Arguments: <none>
  306. //
  307. // Returns: <none>
  308. //
  309. // Purpose: Removes the tooltip if present. This can be accessed from two
  310. // different threads so make sure that it's serialized.
  311. //
  312. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  313. // --------------------------------------------------------------------------
  314. void CSwitchUserDialog::RemoveTooltip (void)
  315. {
  316. CTooltip *pTooltip;
  317. pTooltip = static_cast<CTooltip*>(InterlockedExchangePointer(reinterpret_cast<void**>(&_pTooltip), NULL));
  318. if (pTooltip != NULL)
  319. {
  320. delete pTooltip;
  321. }
  322. }
  323. // --------------------------------------------------------------------------
  324. // CSwitchUserDialog::FilterMetaCharacters
  325. //
  326. // Arguments: pszText = String to filter.
  327. //
  328. // Returns: <none>
  329. //
  330. // Purpose: Filters meta-characters from the given string.
  331. //
  332. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  333. // --------------------------------------------------------------------------
  334. void CSwitchUserDialog::FilterMetaCharacters (TCHAR *pszText)
  335. {
  336. TCHAR *pTC;
  337. pTC = pszText;
  338. while (*pTC != TEXT('\0'))
  339. {
  340. if (*pTC == TEXT('&'))
  341. {
  342. (TCHAR*)lstrcpy(pTC, pTC + 1);
  343. }
  344. else
  345. {
  346. ++pTC;
  347. }
  348. }
  349. }
  350. // --------------------------------------------------------------------------
  351. // CSwitchUserDialog::EndDialog
  352. //
  353. // Arguments: hwnd = HWND of dialog.
  354. // iResult = Result to end dialog with.
  355. //
  356. // Returns: <none>
  357. //
  358. // Purpose: Removes the tool tip if present. Ends the dialog.
  359. //
  360. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  361. // --------------------------------------------------------------------------
  362. void CSwitchUserDialog::EndDialog (HWND hwnd, INT_PTR iResult)
  363. {
  364. RemoveTooltip();
  365. // Set the dialog end member variable here. This will cause the WM_ACTIVATE
  366. // handler to ignore the deactivation associated with ending the dialog. If
  367. // it doesn't ignore it then it thinks the dialog is being deactivated
  368. // because another dialog is activating and ends the dialog with SHTDN_NONE.
  369. _fDialogEnded = true;
  370. TBOOL(::EndDialog(hwnd, iResult));
  371. }
  372. // --------------------------------------------------------------------------
  373. // CSwitchUserDialog::Handle_BN_CLICKED
  374. //
  375. // Arguments: hwnd = HWND of dialog.
  376. // wID = ID of control.
  377. //
  378. // Returns: <none>
  379. //
  380. // Purpose: Handles clicks in the bitmap buttons and sets the return
  381. // result according to the button pressed.
  382. //
  383. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  384. // --------------------------------------------------------------------------
  385. void CSwitchUserDialog::Handle_BN_CLICKED (HWND hwnd, WORD wID)
  386. {
  387. switch (wID)
  388. {
  389. case IDCANCEL:
  390. EndDialog(hwnd, SHTDN_NONE);
  391. break;
  392. case IDC_BUTTON_SWITCHUSER:
  393. EndDialog(hwnd, SHTDN_DISCONNECT);
  394. break;
  395. case IDC_BUTTON_LOGOFF:
  396. EndDialog(hwnd, SHTDN_LOGOFF);
  397. break;
  398. default:
  399. break;
  400. }
  401. }
  402. // --------------------------------------------------------------------------
  403. // CSwitchUserDialog::Handle_WM_INITDIALOG
  404. //
  405. // Arguments: hwnd = HWND of this window.
  406. //
  407. // Returns: <none>
  408. //
  409. // Purpose: Handles WM_INITDIALOG message. Centre the dialog on the main
  410. // monitor. Subclass the buttons so that we can get hover state
  411. // correctly implemented.
  412. //
  413. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  414. // --------------------------------------------------------------------------
  415. void CSwitchUserDialog::Handle_WM_INITDIALOG (HWND hwnd)
  416. {
  417. RECT rc;
  418. // Center the dialog on the main monitor.
  419. TBOOL(GetClientRect(hwnd, &rc));
  420. TBOOL(SetWindowPos(hwnd,
  421. HWND_TOP,
  422. (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2,
  423. (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 3,
  424. 0,
  425. 0,
  426. SWP_NOSIZE));
  427. // Subclass buttons for tooltips and cursor control.
  428. TBOOL(SetWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_SWITCHUSER), ButtonSubClassProc, IDC_BUTTON_SWITCHUSER, reinterpret_cast<DWORD_PTR>(this)));
  429. TBOOL(SetWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_LOGOFF), ButtonSubClassProc, IDC_BUTTON_LOGOFF, reinterpret_cast<DWORD_PTR>(this)));
  430. // Set the focus to the "Switch User" button.
  431. (HWND)SetFocus(GetDlgItem(hwnd, IDC_BUTTON_SWITCHUSER));
  432. _uiFocusID = IDC_BUTTON_SWITCHUSER;
  433. (LRESULT)SendMessage(hwnd, DM_SETDEFID, _uiFocusID, 0);
  434. }
  435. // --------------------------------------------------------------------------
  436. // CSwitchUserDialog::Handle_WM_DESTROY
  437. //
  438. // Arguments: hwnd = HWND of the dialog.
  439. //
  440. // Returns: <none>
  441. //
  442. // Purpose: Removes the subclassing of the button windows and can do any
  443. // other clean up required in WM_DESTROY.
  444. //
  445. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  446. // --------------------------------------------------------------------------
  447. void CSwitchUserDialog::Handle_WM_DESTROY (HWND hwnd)
  448. {
  449. TBOOL(RemoveWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_LOGOFF), ButtonSubClassProc, IDC_BUTTON_LOGOFF));
  450. TBOOL(RemoveWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_SWITCHUSER), ButtonSubClassProc, IDC_BUTTON_SWITCHUSER));
  451. }
  452. // --------------------------------------------------------------------------
  453. // CSwitchUserDialog::Handle_WM_ERASEBKGND
  454. //
  455. // Arguments: hwnd = HWND to erase.
  456. // hdcErase = HDC to paint.
  457. //
  458. // Returns: <none>
  459. //
  460. // Purpose: Erases the background.
  461. //
  462. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  463. // --------------------------------------------------------------------------
  464. void CSwitchUserDialog::Handle_WM_ERASEBKGND (HWND hwnd, HDC hdcErase)
  465. {
  466. RECT rc;
  467. TBOOL(GetClientRect(hwnd, &rc));
  468. PaintBitmap(hdcErase, &rc, _hbmBackground, &_rcBackground);
  469. }
  470. // --------------------------------------------------------------------------
  471. // CSwitchUserDialog::Handle_WM_PRINTCLIENT
  472. //
  473. // Arguments: hwnd = HWND to erase.
  474. // hdcErase = HDC to paint.
  475. // dwOptions = Options for drawing.
  476. //
  477. // Returns: <none>
  478. //
  479. // Purpose: Handles painting the client area for WM_PRINTCLIENT.
  480. //
  481. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  482. // --------------------------------------------------------------------------
  483. void CSwitchUserDialog::Handle_WM_PRINTCLIENT (HWND hwnd, HDC hdcPrint, DWORD dwOptions)
  484. {
  485. if ((dwOptions & (PRF_ERASEBKGND | PRF_CLIENT)) != 0)
  486. {
  487. Handle_WM_ERASEBKGND(hwnd, hdcPrint);
  488. }
  489. }
  490. // --------------------------------------------------------------------------
  491. // CSwitchUserDialog::Handle_WM_ACTIVATE
  492. //
  493. // Arguments: hwnd = HWND to erase.
  494. // dwState = Activate state.
  495. //
  496. // Returns: <none>
  497. //
  498. // Purpose: Detects if this window is becoming inactive. In this case
  499. // end the dialog.
  500. //
  501. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  502. // --------------------------------------------------------------------------
  503. void CSwitchUserDialog::Handle_WM_ACTIVATE (HWND hwnd, DWORD dwState)
  504. {
  505. if ((WA_INACTIVE == dwState) && !_fDialogEnded)
  506. {
  507. EndDialog(hwnd, SHTDN_NONE);
  508. }
  509. }
  510. // --------------------------------------------------------------------------
  511. // CSwitchUserDialog::Handle_WM_DRAWITEM
  512. //
  513. // Arguments: hwnd = HWND of the parent window.
  514. // pDIS = DRAWITEMSTRUCT defining what to draw.
  515. //
  516. // Returns: <none>
  517. //
  518. // Purpose: Draws several aspects of the turn off dialog. It handles the
  519. // title text, the owner draw bitmap buttons, the text for the
  520. // bitmap buttons and the separator line.
  521. //
  522. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  523. // --------------------------------------------------------------------------
  524. void CSwitchUserDialog::Handle_WM_DRAWITEM (HWND hwnd, const DRAWITEMSTRUCT *pDIS)
  525. {
  526. HPALETTE hPaletteOld;
  527. HFONT hfntSelected;
  528. int iBkMode;
  529. COLORREF colorText;
  530. RECT rc;
  531. SIZE size;
  532. TCHAR szText[256];
  533. hPaletteOld = SelectPalette(pDIS->hDC, _hpltShell, FALSE);
  534. (UINT)RealizePalette(pDIS->hDC);
  535. switch (pDIS->CtlID)
  536. {
  537. case IDC_BUTTON_SWITCHUSER:
  538. case IDC_BUTTON_LOGOFF:
  539. {
  540. int iState, iGroup;
  541. // Select the correct state index to use. Check for ODS_SELECTED first.
  542. // Then check for hover or ODS_FOCUS. Otherwise use the rest state.
  543. if ((pDIS->itemState & ODS_SELECTED) != 0)
  544. {
  545. iState = BUTTON_STATE_DOWN;
  546. }
  547. else if ((_uiHoverID == pDIS->CtlID) || ((pDIS->itemState & ODS_FOCUS) != 0))
  548. {
  549. iState = BUTTON_STATE_HOVER;
  550. }
  551. else
  552. {
  553. iState = BUTTON_STATE_REST;
  554. }
  555. // Now select the correct bitmap based on the state index.
  556. switch (pDIS->CtlID)
  557. {
  558. case IDC_BUTTON_SWITCHUSER:
  559. iGroup = BUTTON_GROUP_SWITCHUSER;
  560. break;
  561. case IDC_BUTTON_LOGOFF:
  562. iGroup = BUTTON_GROUP_LOGOFF;
  563. break;
  564. default:
  565. iGroup = -1;
  566. DISPLAYMSG("This should never be executed");
  567. break;
  568. }
  569. if (iGroup >= 0)
  570. {
  571. RECT rc;
  572. // Calculate which part of the background to blit into the DC.
  573. // Only blit the amount that's necessary to avoid excessive
  574. // blitting. Once blitted then blit the button BMP. The blit
  575. // uses msimg32!TransparentBlt with the magical magenta color.
  576. TBOOL(CopyRect(&rc, &_rcBackground));
  577. (int)MapWindowPoints(pDIS->hwndItem, hwnd, reinterpret_cast<POINT*>(&rc), sizeof(RECT) / sizeof(POINT));
  578. rc.right = rc.left + (_rcButtons.right - _rcButtons.left);
  579. rc.bottom = rc.top + _lButtonHeight;
  580. PaintBitmap(pDIS->hDC, &pDIS->rcItem, _hbmBackground, &rc);
  581. TBOOL(CopyRect(&rc, &_rcButtons));
  582. rc.top = ((iGroup * BUTTON_STATE_MAX) + iState) * _lButtonHeight;
  583. rc.bottom = rc.top + _lButtonHeight;
  584. PaintBitmap(pDIS->hDC, &pDIS->rcItem, _hbmButtons, &rc);
  585. }
  586. break;
  587. }
  588. case IDC_TITLE_FLAG:
  589. {
  590. BITMAP bitmap;
  591. TBOOL(GetClientRect(pDIS->hwndItem, &rc));
  592. if (GetObject(_hbmFlag, sizeof(bitmap), &bitmap) != 0)
  593. {
  594. rc.left += ((rc.right - rc.left) - bitmap.bmWidth) / 2;
  595. rc.right = rc.left + bitmap.bmWidth;
  596. rc.top += ((rc.bottom - rc.top) - bitmap.bmHeight) / 2;
  597. rc.bottom = rc.top + bitmap.bmHeight;
  598. }
  599. PaintBitmap(pDIS->hDC, &rc, _hbmFlag, &_rcFlag);
  600. break;
  601. }
  602. case IDC_TITLE_SWITCHUSER:
  603. {
  604. // Draw the title of the dialog "Log Off Windows".
  605. hfntSelected = static_cast<HFONT>(SelectObject(pDIS->hDC, _hfntTitle));
  606. colorText = SetTextColor(pDIS->hDC, 0x00FFFFFF);
  607. iBkMode = SetBkMode(pDIS->hDC, TRANSPARENT);
  608. (int)GetWindowText(GetDlgItem(hwnd, pDIS->CtlID), szText, ARRAYSIZE(szText));
  609. TBOOL(GetTextExtentPoint(pDIS->hDC, szText, lstrlen(szText), &size));
  610. TBOOL(CopyRect(&rc, &pDIS->rcItem));
  611. TBOOL(InflateRect(&rc, 0, -((rc.bottom - rc.top - size.cy) / 2)));
  612. (int)DrawText(pDIS->hDC, szText, -1, &rc, 0);
  613. (int)SetBkMode(pDIS->hDC, iBkMode);
  614. (COLORREF)SetTextColor(pDIS->hDC, colorText);
  615. (HGDIOBJ)SelectObject(pDIS->hDC, hfntSelected);
  616. break;
  617. }
  618. case IDC_TEXT_SWITCHUSER:
  619. case IDC_TEXT_LOGOFF:
  620. {
  621. int iPixelHeight, iButtonID;
  622. RECT rcText;
  623. // The text to display is based on the button title. Map the static
  624. // text ID to a "parent" button ID. Special case IDC_TEXT_STANDBY.
  625. switch (pDIS->CtlID)
  626. {
  627. case IDC_TEXT_SWITCHUSER:
  628. iButtonID = IDC_BUTTON_SWITCHUSER;
  629. break;
  630. case IDC_TEXT_LOGOFF:
  631. iButtonID = IDC_BUTTON_LOGOFF;
  632. break;
  633. default:
  634. iButtonID = 0;
  635. DISPLAYMSG("This should never be executed");
  636. break;
  637. }
  638. hfntSelected = static_cast<HFONT>(SelectObject(pDIS->hDC, _hfntButton));
  639. colorText = SetTextColor(pDIS->hDC, RGB(255, 255, 255));
  640. iBkMode = SetBkMode(pDIS->hDC, TRANSPARENT);
  641. (int)GetWindowText(GetDlgItem(hwnd, iButtonID), szText, ARRAYSIZE(szText));
  642. TBOOL(CopyRect(&rcText, &pDIS->rcItem));
  643. iPixelHeight = DrawText(pDIS->hDC, szText, -1, &rcText, DT_CALCRECT);
  644. TBOOL(CopyRect(&rc, &pDIS->rcItem));
  645. TBOOL(InflateRect(&rc, -((rc.right - rc.left - (rcText.right - rcText.left)) / 2), -((rc.bottom - rc.top - iPixelHeight) / 2)));
  646. (int)DrawText(pDIS->hDC, szText, -1, &rc, ((pDIS->itemState & ODS_NOACCEL ) != 0) ? DT_HIDEPREFIX : 0);
  647. (int)SetBkMode(pDIS->hDC, iBkMode);
  648. (COLORREF)SetTextColor(pDIS->hDC, colorText);
  649. (HGDIOBJ)SelectObject(pDIS->hDC, hfntSelected);
  650. break;
  651. }
  652. default:
  653. {
  654. DISPLAYMSG("Unknown control ID passed to CSwitchUserDialog::Handle_WM_DRAWITEM");
  655. break;
  656. }
  657. }
  658. (HGDIOBJ)SelectPalette(pDIS->hDC, hPaletteOld, FALSE);
  659. (UINT)RealizePalette(pDIS->hDC);
  660. }
  661. // --------------------------------------------------------------------------
  662. // CSwitchUserDialog::Handle_WM_COMMAND
  663. //
  664. // Arguments: hwnd = HWND of dialog.
  665. // wParam = WPARAM (see platform SDK under WM_COMMAND).
  666. //
  667. // Returns: <none>
  668. //
  669. // Purpose: Handles clicks in the bitmap buttons and sets the return
  670. // result according to the button pressed.
  671. //
  672. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  673. // --------------------------------------------------------------------------
  674. void CSwitchUserDialog::Handle_WM_COMMAND (HWND hwnd, WPARAM wParam)
  675. {
  676. switch (HIWORD(wParam))
  677. {
  678. case BN_CLICKED:
  679. Handle_BN_CLICKED(hwnd, LOWORD(wParam));
  680. break;
  681. default:
  682. break;
  683. }
  684. }
  685. // --------------------------------------------------------------------------
  686. // CSwitchUserDialog::Handle_WM_MOUSEMOVE
  687. //
  688. // Arguments: hwnd = HWND of the control.
  689. // uiID = ID of the control.
  690. //
  691. // Returns: <none>
  692. //
  693. // Purpose: Sets the cursor to a hand and tracks mouse movement in the
  694. // control. Refresh the control to show the hover state.
  695. //
  696. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  697. // --------------------------------------------------------------------------
  698. void CSwitchUserDialog::Handle_WM_MOUSEMOVE (HWND hwnd, UINT uiID)
  699. {
  700. (HCURSOR)SetCursor(LoadCursor(NULL, IDC_HAND));
  701. if (uiID != _uiHoverID)
  702. {
  703. TRACKMOUSEEVENT tme;
  704. _uiHoverID = uiID;
  705. tme.cbSize = sizeof(tme);
  706. tme.dwFlags = TME_HOVER | TME_LEAVE;
  707. tme.hwndTrack = hwnd;
  708. tme.dwHoverTime = HOVER_DEFAULT;
  709. TBOOL(TrackMouseEvent(&tme));
  710. TBOOL(InvalidateRect(hwnd, NULL, FALSE));
  711. }
  712. }
  713. // --------------------------------------------------------------------------
  714. // CSwitchUserDialog::Handle_WM_MOUSEHOVER
  715. //
  716. // Arguments: hwnd = HWND of the control.
  717. // uiID = ID of the control.
  718. //
  719. // Returns: <none>
  720. //
  721. // Purpose: Handles hovering over the control. Determine which tooltip to
  722. // bring up and show it.
  723. //
  724. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  725. // --------------------------------------------------------------------------
  726. void CSwitchUserDialog::Handle_WM_MOUSEHOVER (HWND hwnd, UINT uiID)
  727. {
  728. int iTextID;
  729. switch (uiID)
  730. {
  731. case IDC_BUTTON_SWITCHUSER:
  732. iTextID = IDS_SWITCHUSER_TOOLTIP_TEXT_SWITCHUSER;
  733. break;
  734. case IDC_BUTTON_LOGOFF:
  735. iTextID = IDS_SWITCHUSER_TOOLTIP_TEXT_LOGOFF;
  736. break;
  737. default:
  738. iTextID = 0;
  739. break;
  740. }
  741. // Construct the tooltip and show it.
  742. if (iTextID != 0)
  743. {
  744. int iCaptionLength;
  745. TCHAR *pszCaption;
  746. iCaptionLength = GetWindowTextLength(hwnd) + sizeof('\0');
  747. pszCaption = static_cast<TCHAR*>(LocalAlloc(LMEM_FIXED, iCaptionLength * sizeof(TCHAR)));
  748. if (pszCaption != NULL)
  749. {
  750. if (GetWindowText(hwnd, pszCaption, iCaptionLength) != 0)
  751. {
  752. _pTooltip = new CTooltip(_hInstance, hwnd);
  753. if (_pTooltip != NULL)
  754. {
  755. TCHAR szText[256];
  756. if (LoadString(_hInstance, iTextID, szText + sizeof('\r') + sizeof('\n'), ARRAYSIZE(szText) - sizeof('\r') - sizeof('\n')) != 0)
  757. {
  758. FilterMetaCharacters(pszCaption);
  759. szText[0] = TEXT('\r');
  760. szText[1] = TEXT('\n');
  761. _pTooltip->SetPosition();
  762. _pTooltip->SetCaption(0, pszCaption);
  763. _pTooltip->SetText(szText);
  764. _pTooltip->Show();
  765. }
  766. }
  767. }
  768. (HLOCAL)LocalFree(pszCaption);
  769. }
  770. }
  771. }
  772. // --------------------------------------------------------------------------
  773. // CSwitchUserDialog::Handle_WM_MOUSELEAVE
  774. //
  775. // Arguments: hwnd = HWND of the control.
  776. //
  777. // Returns: <none>
  778. //
  779. // Purpose: Removes the tooltip and clears the hover ID.
  780. //
  781. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  782. // --------------------------------------------------------------------------
  783. void CSwitchUserDialog::Handle_WM_MOUSELEAVE (HWND hwnd)
  784. {
  785. RemoveTooltip();
  786. _uiHoverID = 0;
  787. TBOOL(InvalidateRect(hwnd, NULL, FALSE));
  788. }
  789. // --------------------------------------------------------------------------
  790. // CSwitchUserDialog::CB_DialogProc
  791. //
  792. // Arguments: See the platform SDK under DialogProc.
  793. //
  794. // Returns: See the platform SDK under DialogProc.
  795. //
  796. // Purpose: Main DialogProc dispatch entry point for the turn off dialog.
  797. // To keep this simple it calls member functions.
  798. //
  799. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  800. // --------------------------------------------------------------------------
  801. INT_PTR CALLBACK CSwitchUserDialog::CB_DialogProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  802. {
  803. INT_PTR iResult;
  804. CSwitchUserDialog *pThis;
  805. pThis = reinterpret_cast<CSwitchUserDialog*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  806. switch (uMsg)
  807. {
  808. case WM_INITDIALOG:
  809. pThis = reinterpret_cast<CSwitchUserDialog*>(lParam);
  810. (LONG_PTR)SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
  811. pThis->Handle_WM_INITDIALOG(hwnd);
  812. iResult = FALSE;
  813. break;
  814. case WM_DESTROY:
  815. pThis->Handle_WM_DESTROY(hwnd);
  816. iResult = 0;
  817. break;
  818. case WM_ERASEBKGND:
  819. pThis->Handle_WM_ERASEBKGND(hwnd, reinterpret_cast<HDC>(wParam));
  820. iResult = 1;
  821. break;
  822. case WM_PRINTCLIENT:
  823. pThis->Handle_WM_PRINTCLIENT(hwnd, reinterpret_cast<HDC>(wParam), static_cast<DWORD>(lParam));
  824. iResult = 1; // This tells the button that it was handled.
  825. break;
  826. case WM_ACTIVATE:
  827. pThis->Handle_WM_ACTIVATE(hwnd, static_cast<DWORD>(wParam));
  828. iResult = 1;
  829. break;
  830. case WM_DRAWITEM:
  831. pThis->Handle_WM_DRAWITEM(hwnd, reinterpret_cast<DRAWITEMSTRUCT*>(lParam));
  832. iResult = TRUE;
  833. break;
  834. case WM_COMMAND:
  835. pThis->Handle_WM_COMMAND(hwnd, wParam);
  836. iResult = 0;
  837. break;
  838. default:
  839. iResult = 0;
  840. break;
  841. }
  842. return(iResult);
  843. }
  844. // --------------------------------------------------------------------------
  845. // CSwitchUserDialog::ButtonSubClassProc
  846. //
  847. // Arguments: hwnd = See the platform SDK under WindowProc.
  848. // uMsg = See the platform SDK under WindowProc.
  849. // wParam = See the platform SDK under WindowProc.
  850. // lParam = See the platform SDK under WindowProc.
  851. // uiID = ID assigned at subclass time.
  852. // dwRefData = reference data assigned at subclass time.
  853. //
  854. // Returns: LRESULT
  855. //
  856. // Purpose: comctl32 subclass callback function. This allows the bitmap
  857. // buttons to hover and track accordingly. This also allows our
  858. // BS_OWNERDRAW buttons to be pushed when the keyboard is used.
  859. //
  860. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  861. // --------------------------------------------------------------------------
  862. LRESULT CALLBACK CSwitchUserDialog::ButtonSubClassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uiID, DWORD_PTR dwRefData)
  863. {
  864. LRESULT lResult;
  865. CSwitchUserDialog *pThis;
  866. pThis = reinterpret_cast<CSwitchUserDialog*>(dwRefData);
  867. switch (uMsg)
  868. {
  869. // Do NOT allow BM_SETSTYLE to go thru to the default handler. This is
  870. // because DLGC_UNDEFPUSHBUTTON is returned for WM_GETDLGCODE. When the
  871. // dialog manager sees this it tries to set the focus style on the button.
  872. // Even though it's owner drawn the button window proc still draws the
  873. // focus state (because we returned DLGC_UNDEFPUSHBUTTON). Therefore to
  874. // ensure the bitmap isn't over-painted by the button window proc blow off
  875. // the BM_SETSTYLE and don't let it get to the button window proc.
  876. case BM_SETSTYLE:
  877. if (wParam == BS_DEFPUSHBUTTON)
  878. {
  879. pThis->_uiFocusID = static_cast<UINT>(uiID);
  880. }
  881. if (uiID != IDCANCEL)
  882. {
  883. lResult = 0;
  884. break;
  885. }
  886. // Fall thru
  887. default:
  888. // Otherwise in the default case let the default handler at the message
  889. // first. This implements tail-patching.
  890. lResult = DefSubclassProc(hwnd, uMsg, wParam, lParam);
  891. switch (uMsg)
  892. {
  893. case DM_GETDEFID:
  894. lResult = (DC_HASDEFID << 16) | static_cast<WORD>(pThis->_uiFocusID);
  895. break;
  896. case WM_GETDLGCODE:
  897. if (uiID == pThis->_uiFocusID)
  898. {
  899. lResult |= DLGC_DEFPUSHBUTTON;
  900. }
  901. else
  902. {
  903. lResult |= DLGC_UNDEFPUSHBUTTON;
  904. }
  905. break;
  906. case WM_MOUSEMOVE:
  907. pThis->Handle_WM_MOUSEMOVE(hwnd, static_cast<UINT>(uiID));
  908. break;
  909. case WM_MOUSEHOVER:
  910. pThis->Handle_WM_MOUSEHOVER(hwnd, static_cast<UINT>(uiID));
  911. break;
  912. case WM_MOUSELEAVE:
  913. pThis->Handle_WM_MOUSELEAVE(hwnd);
  914. break;
  915. default:
  916. break;
  917. }
  918. }
  919. return(lResult);
  920. }
  921. EXTERN_C DWORD SwitchUserDialog_Show (HWND hwndParent)
  922. {
  923. CSwitchUserDialog switchUserDialog(g_hinst);
  924. return(switchUserDialog.Show(hwndParent));
  925. }