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.

1061 lines
37 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* pszSrc;
  337. TCHAR* pszDest = StrChr(pszText, TEXT('&'));
  338. if (pszDest)
  339. {
  340. pszSrc = pszDest + 1;
  341. // remove any '&' characters from the string
  342. while (*pszSrc != TEXT('\0'))
  343. {
  344. if (*pszDest != TEXT('&'))
  345. {
  346. *pszDest++ = *pszSrc++;
  347. }
  348. else
  349. {
  350. pszSrc++;
  351. }
  352. }
  353. pszDest = TEXT('\0');
  354. }
  355. }
  356. // --------------------------------------------------------------------------
  357. // CSwitchUserDialog::EndDialog
  358. //
  359. // Arguments: hwnd = HWND of dialog.
  360. // iResult = Result to end dialog with.
  361. //
  362. // Returns: <none>
  363. //
  364. // Purpose: Removes the tool tip if present. Ends the dialog.
  365. //
  366. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  367. // --------------------------------------------------------------------------
  368. void CSwitchUserDialog::EndDialog (HWND hwnd, INT_PTR iResult)
  369. {
  370. RemoveTooltip();
  371. // Set the dialog end member variable here. This will cause the WM_ACTIVATE
  372. // handler to ignore the deactivation associated with ending the dialog. If
  373. // it doesn't ignore it then it thinks the dialog is being deactivated
  374. // because another dialog is activating and ends the dialog with SHTDN_NONE.
  375. _fDialogEnded = true;
  376. TBOOL(::EndDialog(hwnd, iResult));
  377. }
  378. // --------------------------------------------------------------------------
  379. // CSwitchUserDialog::Handle_BN_CLICKED
  380. //
  381. // Arguments: hwnd = HWND of dialog.
  382. // wID = ID of control.
  383. //
  384. // Returns: <none>
  385. //
  386. // Purpose: Handles clicks in the bitmap buttons and sets the return
  387. // result according to the button pressed.
  388. //
  389. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  390. // --------------------------------------------------------------------------
  391. void CSwitchUserDialog::Handle_BN_CLICKED (HWND hwnd, WORD wID)
  392. {
  393. switch (wID)
  394. {
  395. case IDCANCEL:
  396. EndDialog(hwnd, SHTDN_NONE);
  397. break;
  398. case IDC_BUTTON_SWITCHUSER:
  399. EndDialog(hwnd, SHTDN_DISCONNECT);
  400. break;
  401. case IDC_BUTTON_LOGOFF:
  402. EndDialog(hwnd, SHTDN_LOGOFF);
  403. break;
  404. default:
  405. break;
  406. }
  407. }
  408. // --------------------------------------------------------------------------
  409. // CSwitchUserDialog::Handle_WM_INITDIALOG
  410. //
  411. // Arguments: hwnd = HWND of this window.
  412. //
  413. // Returns: <none>
  414. //
  415. // Purpose: Handles WM_INITDIALOG message. Centre the dialog on the main
  416. // monitor. Subclass the buttons so that we can get hover state
  417. // correctly implemented.
  418. //
  419. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  420. // --------------------------------------------------------------------------
  421. void CSwitchUserDialog::Handle_WM_INITDIALOG (HWND hwnd)
  422. {
  423. RECT rc;
  424. // Center the dialog on the main monitor.
  425. TBOOL(GetClientRect(hwnd, &rc));
  426. TBOOL(SetWindowPos(hwnd,
  427. HWND_TOP,
  428. (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2,
  429. (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 3,
  430. 0,
  431. 0,
  432. SWP_NOSIZE));
  433. // Subclass buttons for tooltips and cursor control.
  434. TBOOL(SetWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_SWITCHUSER), ButtonSubClassProc, IDC_BUTTON_SWITCHUSER, reinterpret_cast<DWORD_PTR>(this)));
  435. TBOOL(SetWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_LOGOFF), ButtonSubClassProc, IDC_BUTTON_LOGOFF, reinterpret_cast<DWORD_PTR>(this)));
  436. // Set the focus to the "Switch User" button.
  437. (HWND)SetFocus(GetDlgItem(hwnd, IDC_BUTTON_SWITCHUSER));
  438. _uiFocusID = IDC_BUTTON_SWITCHUSER;
  439. (LRESULT)SendMessage(hwnd, DM_SETDEFID, _uiFocusID, 0);
  440. }
  441. // --------------------------------------------------------------------------
  442. // CSwitchUserDialog::Handle_WM_DESTROY
  443. //
  444. // Arguments: hwnd = HWND of the dialog.
  445. //
  446. // Returns: <none>
  447. //
  448. // Purpose: Removes the subclassing of the button windows and can do any
  449. // other clean up required in WM_DESTROY.
  450. //
  451. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  452. // --------------------------------------------------------------------------
  453. void CSwitchUserDialog::Handle_WM_DESTROY (HWND hwnd)
  454. {
  455. TBOOL(RemoveWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_LOGOFF), ButtonSubClassProc, IDC_BUTTON_LOGOFF));
  456. TBOOL(RemoveWindowSubclass(GetDlgItem(hwnd, IDC_BUTTON_SWITCHUSER), ButtonSubClassProc, IDC_BUTTON_SWITCHUSER));
  457. }
  458. // --------------------------------------------------------------------------
  459. // CSwitchUserDialog::Handle_WM_ERASEBKGND
  460. //
  461. // Arguments: hwnd = HWND to erase.
  462. // hdcErase = HDC to paint.
  463. //
  464. // Returns: <none>
  465. //
  466. // Purpose: Erases the background.
  467. //
  468. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  469. // --------------------------------------------------------------------------
  470. void CSwitchUserDialog::Handle_WM_ERASEBKGND (HWND hwnd, HDC hdcErase)
  471. {
  472. RECT rc;
  473. TBOOL(GetClientRect(hwnd, &rc));
  474. PaintBitmap(hdcErase, &rc, _hbmBackground, &_rcBackground);
  475. }
  476. // --------------------------------------------------------------------------
  477. // CSwitchUserDialog::Handle_WM_PRINTCLIENT
  478. //
  479. // Arguments: hwnd = HWND to erase.
  480. // hdcErase = HDC to paint.
  481. // dwOptions = Options for drawing.
  482. //
  483. // Returns: <none>
  484. //
  485. // Purpose: Handles painting the client area for WM_PRINTCLIENT.
  486. //
  487. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  488. // --------------------------------------------------------------------------
  489. void CSwitchUserDialog::Handle_WM_PRINTCLIENT (HWND hwnd, HDC hdcPrint, DWORD dwOptions)
  490. {
  491. if ((dwOptions & (PRF_ERASEBKGND | PRF_CLIENT)) != 0)
  492. {
  493. Handle_WM_ERASEBKGND(hwnd, hdcPrint);
  494. }
  495. }
  496. // --------------------------------------------------------------------------
  497. // CSwitchUserDialog::Handle_WM_ACTIVATE
  498. //
  499. // Arguments: hwnd = HWND to erase.
  500. // dwState = Activate state.
  501. //
  502. // Returns: <none>
  503. //
  504. // Purpose: Detects if this window is becoming inactive. In this case
  505. // end the dialog.
  506. //
  507. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  508. // --------------------------------------------------------------------------
  509. void CSwitchUserDialog::Handle_WM_ACTIVATE (HWND hwnd, DWORD dwState)
  510. {
  511. if ((WA_INACTIVE == dwState) && !_fDialogEnded)
  512. {
  513. EndDialog(hwnd, SHTDN_NONE);
  514. }
  515. }
  516. // --------------------------------------------------------------------------
  517. // CSwitchUserDialog::Handle_WM_DRAWITEM
  518. //
  519. // Arguments: hwnd = HWND of the parent window.
  520. // pDIS = DRAWITEMSTRUCT defining what to draw.
  521. //
  522. // Returns: <none>
  523. //
  524. // Purpose: Draws several aspects of the turn off dialog. It handles the
  525. // title text, the owner draw bitmap buttons, the text for the
  526. // bitmap buttons and the separator line.
  527. //
  528. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  529. // --------------------------------------------------------------------------
  530. void CSwitchUserDialog::Handle_WM_DRAWITEM (HWND hwnd, const DRAWITEMSTRUCT *pDIS)
  531. {
  532. HPALETTE hPaletteOld;
  533. HFONT hfntSelected;
  534. int iBkMode;
  535. COLORREF colorText;
  536. RECT rc;
  537. SIZE size;
  538. TCHAR szText[256];
  539. hPaletteOld = SelectPalette(pDIS->hDC, _hpltShell, FALSE);
  540. (UINT)RealizePalette(pDIS->hDC);
  541. switch (pDIS->CtlID)
  542. {
  543. case IDC_BUTTON_SWITCHUSER:
  544. case IDC_BUTTON_LOGOFF:
  545. {
  546. int iState, iGroup;
  547. // Select the correct state index to use. Check for ODS_SELECTED first.
  548. // Then check for hover or ODS_FOCUS. Otherwise use the rest state.
  549. if ((pDIS->itemState & ODS_SELECTED) != 0)
  550. {
  551. iState = BUTTON_STATE_DOWN;
  552. }
  553. else if ((_uiHoverID == pDIS->CtlID) || ((pDIS->itemState & ODS_FOCUS) != 0))
  554. {
  555. iState = BUTTON_STATE_HOVER;
  556. }
  557. else
  558. {
  559. iState = BUTTON_STATE_REST;
  560. }
  561. // Now select the correct bitmap based on the state index.
  562. switch (pDIS->CtlID)
  563. {
  564. case IDC_BUTTON_SWITCHUSER:
  565. iGroup = BUTTON_GROUP_SWITCHUSER;
  566. break;
  567. case IDC_BUTTON_LOGOFF:
  568. iGroup = BUTTON_GROUP_LOGOFF;
  569. break;
  570. default:
  571. iGroup = -1;
  572. DISPLAYMSG("This should never be executed");
  573. break;
  574. }
  575. if (iGroup >= 0)
  576. {
  577. RECT rc;
  578. // Calculate which part of the background to blit into the DC.
  579. // Only blit the amount that's necessary to avoid excessive
  580. // blitting. Once blitted then blit the button BMP. The blit
  581. // uses msimg32!TransparentBlt with the magical magenta color.
  582. TBOOL(CopyRect(&rc, &_rcBackground));
  583. (int)MapWindowPoints(pDIS->hwndItem, hwnd, reinterpret_cast<POINT*>(&rc), sizeof(RECT) / sizeof(POINT));
  584. rc.right = rc.left + (_rcButtons.right - _rcButtons.left);
  585. rc.bottom = rc.top + _lButtonHeight;
  586. PaintBitmap(pDIS->hDC, &pDIS->rcItem, _hbmBackground, &rc);
  587. TBOOL(CopyRect(&rc, &_rcButtons));
  588. rc.top = ((iGroup * BUTTON_STATE_MAX) + iState) * _lButtonHeight;
  589. rc.bottom = rc.top + _lButtonHeight;
  590. PaintBitmap(pDIS->hDC, &pDIS->rcItem, _hbmButtons, &rc);
  591. }
  592. break;
  593. }
  594. case IDC_TITLE_FLAG:
  595. {
  596. BITMAP bitmap;
  597. TBOOL(GetClientRect(pDIS->hwndItem, &rc));
  598. if (GetObject(_hbmFlag, sizeof(bitmap), &bitmap) != 0)
  599. {
  600. rc.left += ((rc.right - rc.left) - bitmap.bmWidth) / 2;
  601. rc.right = rc.left + bitmap.bmWidth;
  602. rc.top += ((rc.bottom - rc.top) - bitmap.bmHeight) / 2;
  603. rc.bottom = rc.top + bitmap.bmHeight;
  604. }
  605. PaintBitmap(pDIS->hDC, &rc, _hbmFlag, &_rcFlag);
  606. break;
  607. }
  608. case IDC_TITLE_SWITCHUSER:
  609. {
  610. // Draw the title of the dialog "Log Off Windows".
  611. hfntSelected = static_cast<HFONT>(SelectObject(pDIS->hDC, _hfntTitle));
  612. colorText = SetTextColor(pDIS->hDC, 0x00FFFFFF);
  613. iBkMode = SetBkMode(pDIS->hDC, TRANSPARENT);
  614. (int)GetWindowText(GetDlgItem(hwnd, pDIS->CtlID), szText, ARRAYSIZE(szText));
  615. TBOOL(GetTextExtentPoint(pDIS->hDC, szText, lstrlen(szText), &size));
  616. TBOOL(CopyRect(&rc, &pDIS->rcItem));
  617. TBOOL(InflateRect(&rc, 0, -((rc.bottom - rc.top - size.cy) / 2)));
  618. (int)DrawText(pDIS->hDC, szText, -1, &rc, 0);
  619. (int)SetBkMode(pDIS->hDC, iBkMode);
  620. (COLORREF)SetTextColor(pDIS->hDC, colorText);
  621. (HGDIOBJ)SelectObject(pDIS->hDC, hfntSelected);
  622. break;
  623. }
  624. case IDC_TEXT_SWITCHUSER:
  625. case IDC_TEXT_LOGOFF:
  626. {
  627. int iPixelHeight, iButtonID;
  628. RECT rcText;
  629. // The text to display is based on the button title. Map the static
  630. // text ID to a "parent" button ID. Special case IDC_TEXT_STANDBY.
  631. switch (pDIS->CtlID)
  632. {
  633. case IDC_TEXT_SWITCHUSER:
  634. iButtonID = IDC_BUTTON_SWITCHUSER;
  635. break;
  636. case IDC_TEXT_LOGOFF:
  637. iButtonID = IDC_BUTTON_LOGOFF;
  638. break;
  639. default:
  640. iButtonID = 0;
  641. DISPLAYMSG("This should never be executed");
  642. break;
  643. }
  644. hfntSelected = static_cast<HFONT>(SelectObject(pDIS->hDC, _hfntButton));
  645. colorText = SetTextColor(pDIS->hDC, RGB(255, 255, 255));
  646. iBkMode = SetBkMode(pDIS->hDC, TRANSPARENT);
  647. (int)GetWindowText(GetDlgItem(hwnd, iButtonID), szText, ARRAYSIZE(szText));
  648. TBOOL(CopyRect(&rcText, &pDIS->rcItem));
  649. iPixelHeight = DrawText(pDIS->hDC, szText, -1, &rcText, DT_CALCRECT);
  650. TBOOL(CopyRect(&rc, &pDIS->rcItem));
  651. TBOOL(InflateRect(&rc, -((rc.right - rc.left - (rcText.right - rcText.left)) / 2), -((rc.bottom - rc.top - iPixelHeight) / 2)));
  652. (int)DrawText(pDIS->hDC, szText, -1, &rc, ((pDIS->itemState & ODS_NOACCEL ) != 0) ? DT_HIDEPREFIX : 0);
  653. (int)SetBkMode(pDIS->hDC, iBkMode);
  654. (COLORREF)SetTextColor(pDIS->hDC, colorText);
  655. (HGDIOBJ)SelectObject(pDIS->hDC, hfntSelected);
  656. break;
  657. }
  658. default:
  659. {
  660. DISPLAYMSG("Unknown control ID passed to CSwitchUserDialog::Handle_WM_DRAWITEM");
  661. break;
  662. }
  663. }
  664. (HGDIOBJ)SelectPalette(pDIS->hDC, hPaletteOld, FALSE);
  665. (UINT)RealizePalette(pDIS->hDC);
  666. }
  667. // --------------------------------------------------------------------------
  668. // CSwitchUserDialog::Handle_WM_COMMAND
  669. //
  670. // Arguments: hwnd = HWND of dialog.
  671. // wParam = WPARAM (see platform SDK under WM_COMMAND).
  672. //
  673. // Returns: <none>
  674. //
  675. // Purpose: Handles clicks in the bitmap buttons and sets the return
  676. // result according to the button pressed.
  677. //
  678. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  679. // --------------------------------------------------------------------------
  680. void CSwitchUserDialog::Handle_WM_COMMAND (HWND hwnd, WPARAM wParam)
  681. {
  682. switch (HIWORD(wParam))
  683. {
  684. case BN_CLICKED:
  685. Handle_BN_CLICKED(hwnd, LOWORD(wParam));
  686. break;
  687. default:
  688. break;
  689. }
  690. }
  691. // --------------------------------------------------------------------------
  692. // CSwitchUserDialog::Handle_WM_MOUSEMOVE
  693. //
  694. // Arguments: hwnd = HWND of the control.
  695. // uiID = ID of the control.
  696. //
  697. // Returns: <none>
  698. //
  699. // Purpose: Sets the cursor to a hand and tracks mouse movement in the
  700. // control. Refresh the control to show the hover state.
  701. //
  702. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  703. // --------------------------------------------------------------------------
  704. void CSwitchUserDialog::Handle_WM_MOUSEMOVE (HWND hwnd, UINT uiID)
  705. {
  706. (HCURSOR)SetCursor(LoadCursor(NULL, IDC_HAND));
  707. if (uiID != _uiHoverID)
  708. {
  709. TRACKMOUSEEVENT tme;
  710. _uiHoverID = uiID;
  711. tme.cbSize = sizeof(tme);
  712. tme.dwFlags = TME_HOVER | TME_LEAVE;
  713. tme.hwndTrack = hwnd;
  714. tme.dwHoverTime = HOVER_DEFAULT;
  715. TBOOL(TrackMouseEvent(&tme));
  716. TBOOL(InvalidateRect(hwnd, NULL, FALSE));
  717. }
  718. }
  719. // --------------------------------------------------------------------------
  720. // CSwitchUserDialog::Handle_WM_MOUSEHOVER
  721. //
  722. // Arguments: hwnd = HWND of the control.
  723. // uiID = ID of the control.
  724. //
  725. // Returns: <none>
  726. //
  727. // Purpose: Handles hovering over the control. Determine which tooltip to
  728. // bring up and show it.
  729. //
  730. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  731. // --------------------------------------------------------------------------
  732. void CSwitchUserDialog::Handle_WM_MOUSEHOVER (HWND hwnd, UINT uiID)
  733. {
  734. int iTextID;
  735. switch (uiID)
  736. {
  737. case IDC_BUTTON_SWITCHUSER:
  738. iTextID = IDS_SWITCHUSER_TOOLTIP_TEXT_SWITCHUSER;
  739. break;
  740. case IDC_BUTTON_LOGOFF:
  741. iTextID = IDS_SWITCHUSER_TOOLTIP_TEXT_LOGOFF;
  742. break;
  743. default:
  744. iTextID = 0;
  745. break;
  746. }
  747. // Construct the tooltip and show it.
  748. if (iTextID != 0)
  749. {
  750. TCHAR* pszCaption;
  751. DWORD cchCaption;
  752. cchCaption = GetWindowTextLength(hwnd) + 1; // +1 for null terminator
  753. pszCaption = (TCHAR*)LocalAlloc(LMEM_FIXED, cchCaption * sizeof(TCHAR));
  754. if (pszCaption)
  755. {
  756. if (GetWindowText(hwnd, pszCaption, cchCaption) != 0)
  757. {
  758. _pTooltip = new CTooltip(_hInstance, hwnd);
  759. if (_pTooltip != NULL)
  760. {
  761. TCHAR szText[256];
  762. if (LoadString(_hInstance, iTextID, szText + 2, ARRAYSIZE(szText) - 2) != 0) // 2 for "\r\n"
  763. {
  764. FilterMetaCharacters(pszCaption);
  765. szText[0] = TEXT('\r');
  766. szText[1] = TEXT('\n');
  767. _pTooltip->SetPosition();
  768. _pTooltip->SetCaption(0, pszCaption);
  769. _pTooltip->SetText(szText);
  770. _pTooltip->Show();
  771. }
  772. }
  773. }
  774. LocalFree(pszCaption);
  775. }
  776. }
  777. }
  778. // --------------------------------------------------------------------------
  779. // CSwitchUserDialog::Handle_WM_MOUSELEAVE
  780. //
  781. // Arguments: hwnd = HWND of the control.
  782. //
  783. // Returns: <none>
  784. //
  785. // Purpose: Removes the tooltip and clears the hover ID.
  786. //
  787. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  788. // --------------------------------------------------------------------------
  789. void CSwitchUserDialog::Handle_WM_MOUSELEAVE (HWND hwnd)
  790. {
  791. RemoveTooltip();
  792. _uiHoverID = 0;
  793. TBOOL(InvalidateRect(hwnd, NULL, FALSE));
  794. }
  795. // --------------------------------------------------------------------------
  796. // CSwitchUserDialog::CB_DialogProc
  797. //
  798. // Arguments: See the platform SDK under DialogProc.
  799. //
  800. // Returns: See the platform SDK under DialogProc.
  801. //
  802. // Purpose: Main DialogProc dispatch entry point for the turn off dialog.
  803. // To keep this simple it calls member functions.
  804. //
  805. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  806. // --------------------------------------------------------------------------
  807. INT_PTR CALLBACK CSwitchUserDialog::CB_DialogProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  808. {
  809. INT_PTR iResult;
  810. CSwitchUserDialog *pThis;
  811. pThis = reinterpret_cast<CSwitchUserDialog*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  812. switch (uMsg)
  813. {
  814. case WM_INITDIALOG:
  815. pThis = reinterpret_cast<CSwitchUserDialog*>(lParam);
  816. (LONG_PTR)SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
  817. pThis->Handle_WM_INITDIALOG(hwnd);
  818. iResult = FALSE;
  819. break;
  820. case WM_DESTROY:
  821. pThis->Handle_WM_DESTROY(hwnd);
  822. iResult = 0;
  823. break;
  824. case WM_ERASEBKGND:
  825. pThis->Handle_WM_ERASEBKGND(hwnd, reinterpret_cast<HDC>(wParam));
  826. iResult = 1;
  827. break;
  828. case WM_PRINTCLIENT:
  829. pThis->Handle_WM_PRINTCLIENT(hwnd, reinterpret_cast<HDC>(wParam), static_cast<DWORD>(lParam));
  830. iResult = 1; // This tells the button that it was handled.
  831. break;
  832. case WM_ACTIVATE:
  833. pThis->Handle_WM_ACTIVATE(hwnd, static_cast<DWORD>(wParam));
  834. iResult = 1;
  835. break;
  836. case WM_DRAWITEM:
  837. pThis->Handle_WM_DRAWITEM(hwnd, reinterpret_cast<DRAWITEMSTRUCT*>(lParam));
  838. iResult = TRUE;
  839. break;
  840. case WM_COMMAND:
  841. pThis->Handle_WM_COMMAND(hwnd, wParam);
  842. iResult = 0;
  843. break;
  844. default:
  845. iResult = 0;
  846. break;
  847. }
  848. return(iResult);
  849. }
  850. // --------------------------------------------------------------------------
  851. // CSwitchUserDialog::ButtonSubClassProc
  852. //
  853. // Arguments: hwnd = See the platform SDK under WindowProc.
  854. // uMsg = See the platform SDK under WindowProc.
  855. // wParam = See the platform SDK under WindowProc.
  856. // lParam = See the platform SDK under WindowProc.
  857. // uiID = ID assigned at subclass time.
  858. // dwRefData = reference data assigned at subclass time.
  859. //
  860. // Returns: LRESULT
  861. //
  862. // Purpose: comctl32 subclass callback function. This allows the bitmap
  863. // buttons to hover and track accordingly. This also allows our
  864. // BS_OWNERDRAW buttons to be pushed when the keyboard is used.
  865. //
  866. // History: 2001-01-23 vtan created (form Turn Off Dialog)
  867. // --------------------------------------------------------------------------
  868. LRESULT CALLBACK CSwitchUserDialog::ButtonSubClassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uiID, DWORD_PTR dwRefData)
  869. {
  870. LRESULT lResult;
  871. CSwitchUserDialog *pThis;
  872. pThis = reinterpret_cast<CSwitchUserDialog*>(dwRefData);
  873. switch (uMsg)
  874. {
  875. // Do NOT allow BM_SETSTYLE to go thru to the default handler. This is
  876. // because DLGC_UNDEFPUSHBUTTON is returned for WM_GETDLGCODE. When the
  877. // dialog manager sees this it tries to set the focus style on the button.
  878. // Even though it's owner drawn the button window proc still draws the
  879. // focus state (because we returned DLGC_UNDEFPUSHBUTTON). Therefore to
  880. // ensure the bitmap isn't over-painted by the button window proc blow off
  881. // the BM_SETSTYLE and don't let it get to the button window proc.
  882. case BM_SETSTYLE:
  883. if (wParam == BS_DEFPUSHBUTTON)
  884. {
  885. pThis->_uiFocusID = static_cast<UINT>(uiID);
  886. }
  887. if (uiID != IDCANCEL)
  888. {
  889. lResult = 0;
  890. break;
  891. }
  892. // Fall thru
  893. default:
  894. // Otherwise in the default case let the default handler at the message
  895. // first. This implements tail-patching.
  896. lResult = DefSubclassProc(hwnd, uMsg, wParam, lParam);
  897. switch (uMsg)
  898. {
  899. case DM_GETDEFID:
  900. lResult = (DC_HASDEFID << 16) | static_cast<WORD>(pThis->_uiFocusID);
  901. break;
  902. case WM_GETDLGCODE:
  903. if (uiID == pThis->_uiFocusID)
  904. {
  905. lResult |= DLGC_DEFPUSHBUTTON;
  906. }
  907. else
  908. {
  909. lResult |= DLGC_UNDEFPUSHBUTTON;
  910. }
  911. break;
  912. case WM_MOUSEMOVE:
  913. pThis->Handle_WM_MOUSEMOVE(hwnd, static_cast<UINT>(uiID));
  914. break;
  915. case WM_MOUSEHOVER:
  916. pThis->Handle_WM_MOUSEHOVER(hwnd, static_cast<UINT>(uiID));
  917. break;
  918. case WM_MOUSELEAVE:
  919. pThis->Handle_WM_MOUSELEAVE(hwnd);
  920. break;
  921. default:
  922. break;
  923. }
  924. }
  925. return(lResult);
  926. }
  927. EXTERN_C DWORD SwitchUserDialog_Show (HWND hwndParent)
  928. {
  929. CSwitchUserDialog switchUserDialog(g_hinst);
  930. return(switchUserDialog.Show(hwndParent));
  931. }