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.

1441 lines
43 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: TipDay.cpp
  5. //
  6. // PURPOSE: Implements the CTipOfTheDay object
  7. //
  8. #include "pch.hxx"
  9. #include "strconst.h"
  10. #include "resource.h"
  11. #include "fldrview.h"
  12. #include "tipday.h"
  13. #include "hotlinks.h"
  14. #ifdef WIN16
  15. // At this moment, these definitions are restricted to this file only
  16. #define GetProp GetProp32
  17. #define SetProp SetProp32
  18. #define RemoveProp RemoveProp32
  19. #define BS_NOTIFY 0L
  20. #endif
  21. CTipOfTheDay::CTipOfTheDay()
  22. {
  23. m_cRef = 1;
  24. m_hwnd = 0;
  25. m_hwndParent = 0;
  26. m_hwndNext = 0;
  27. m_ftType = FOLDER_TYPESMAX;
  28. m_szTitle[0] = 0;
  29. m_szNextTip[0] = 0;
  30. m_pszTip = NULL;
  31. m_dwCurrentTip = 0;
  32. m_clrBack = 0;
  33. m_clrText = RGB(255, 255, 255);
  34. m_clrLink = RGB(255, 255, 255);
  35. m_hfLink = 0;
  36. m_hfTitle = 0;
  37. m_hfTip = 0;
  38. m_cyTitleHeight = TIP_ICON_HEIGHT;
  39. m_cxTitleWidth = 0;
  40. m_hbrBack = 0;
  41. }
  42. CTipOfTheDay::~CTipOfTheDay()
  43. {
  44. if (IsWindow(m_hwnd))
  45. {
  46. AssertSz(!IsWindow(m_hwnd), _T("CTipOfTheDay::~CTipOfTheDay() - The ")
  47. _T("tip window should have already been destroyed."));
  48. DestroyWindow(m_hwnd);
  49. }
  50. SafeMemFree(m_pszTip);
  51. FreeLinkInfo();
  52. if (m_hfLink)
  53. DeleteFont(m_hfLink);
  54. if (m_hfTitle)
  55. DeleteFont(m_hfTitle);
  56. if (m_hfTip)
  57. DeleteFont(m_hfTip);
  58. if (m_hbrBack)
  59. DeleteBrush(m_hbrBack);
  60. UnregisterClass(c_szTipOfTheDayClass, g_hLocRes /* g_hInst*/);
  61. UnregisterClass(BUTTON_CLASS, g_hLocRes /* g_hInst*/);
  62. }
  63. ULONG CTipOfTheDay::AddRef(void)
  64. {
  65. return (++m_cRef);
  66. }
  67. ULONG CTipOfTheDay::Release(void)
  68. {
  69. ULONG cRef = m_cRef--;
  70. if (m_cRef == 0)
  71. delete this;
  72. return (cRef);
  73. }
  74. //
  75. // FUNCTION: CTipOfTheDay::HrCreate()
  76. //
  77. // PURPOSE: Creates the TipOfTheDay control.
  78. //
  79. // PARAMETERS:
  80. // <in> hwndParent - Handle of the window that will be the parent of
  81. // the control.
  82. // <in> ftType - Type of folder this is for.
  83. //
  84. // RETURN VALUE:
  85. // E_UNEXPECTED - Failed to register a required window class
  86. // E_OUTOFMEMORY - Could not create the window
  87. // S_OK - Everything succeeded.
  88. //
  89. HRESULT CTipOfTheDay::HrCreate(HWND hwndParent, FOLDER_TYPE ftType)
  90. {
  91. #ifndef WIN16
  92. WNDCLASSEX wc;
  93. #else
  94. WNDCLASS wc;
  95. #endif
  96. m_hwndParent = hwndParent;
  97. m_ftType = ftType;
  98. // Check to see if we need to register the window class for this control
  99. #ifndef WIN16
  100. wc.cbSize = sizeof(WNDCLASSEX);
  101. if (!GetClassInfoEx(g_hLocRes /* g_hInst*/, c_szTipOfTheDayClass, &wc))
  102. #else
  103. if ( !GetClassInfo( g_hLocRes /* g_hInst*/, c_szTipOfTheDayClass, &wc ) )
  104. #endif
  105. {
  106. wc.style = 0;
  107. wc.lpfnWndProc = TipWndProc;
  108. wc.cbClsExtra = 0;
  109. wc.cbWndExtra = 0;
  110. wc.hInstance = g_hLocRes /* g_hInst*/;
  111. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  112. wc.hbrBackground = NULL; // CreateSolidBrush(GetSysColor(COLOR_INFOBK));
  113. wc.lpszMenuName = NULL;
  114. wc.lpszClassName = c_szTipOfTheDayClass;
  115. wc.hIcon = NULL;
  116. #ifndef WIN16
  117. wc.hIconSm = NULL;
  118. if (0 == RegisterClassEx(&wc))
  119. #else
  120. if ( 0 == RegisterClass( &wc ) )
  121. #endif
  122. {
  123. AssertSz(FALSE, _T("CTipOfTheDay::HrCreate() - RegiserClassEx() failed."));
  124. return (E_UNEXPECTED);
  125. }
  126. }
  127. // We also want to superclass the buttons so we change change the cursor
  128. // to the Hand people are used to from their web browser
  129. #ifndef WIN16
  130. wc.cbSize = sizeof(WNDCLASSEX);
  131. if (!GetClassInfoEx(g_hLocRes /* g_hInst*/, BUTTON_CLASS, &wc))
  132. {
  133. if (GetClassInfoEx(g_hLocRes /* g_hInst*/, _T("Button"), &wc))
  134. #else
  135. if ( !GetClassInfo( g_hLocRes /* g_hInst*/, BUTTON_CLASS, &wc ) )
  136. {
  137. if ( GetClassInfo( NULL, "Button", &wc ) )
  138. #endif
  139. {
  140. wc.hCursor = LoadCursor(g_hLocRes, MAKEINTRESOURCE(idcurHand));
  141. wc.lpszClassName = BUTTON_CLASS;
  142. #ifndef WIN16
  143. if (0 == RegisterClassEx(&wc))
  144. #else
  145. wc.hInstance = g_hLocRes /* g_hInst*/;
  146. if ( 0 == RegisterClass( &wc ) )
  147. #endif
  148. {
  149. AssertSz(FALSE, _T("CTipOfTheDay::HrCreate() - RegisterClassEx() failed."));
  150. return (E_UNEXPECTED);
  151. }
  152. }
  153. }
  154. // Create the tip control window
  155. m_hwnd = CreateWindowEx(WS_EX_CONTROLPARENT, c_szTipOfTheDayClass,
  156. _T("Tip of the Day"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS,
  157. 0, 0, 100, 100, hwndParent, (HMENU) IDC_TIPCONTROL,
  158. g_hLocRes, this);
  159. if (!m_hwnd)
  160. {
  161. GetLastError();
  162. AssertSz(m_hwnd, _T("CTipOfTheDay::HrCreate() - Failed to create window."));
  163. return (E_OUTOFMEMORY);
  164. }
  165. return (S_OK);
  166. }
  167. LRESULT CALLBACK EXPORT_16 CTipOfTheDay::TipWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  168. LPARAM lParam)
  169. {
  170. CTipOfTheDay *pThis = (CTipOfTheDay *) GetProp(hwnd, TIPINFO_PROP);
  171. switch (uMsg)
  172. {
  173. case WM_NCCREATE:
  174. // Get the this pointer that was passed in
  175. pThis = (CTipOfTheDay *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
  176. Assert(pThis);
  177. // Stuff the this pointer for the object into a property
  178. SetProp(hwnd, TIPINFO_PROP, pThis);
  179. pThis->AddRef(); // Released in WM_DESTROY
  180. return (TRUE);
  181. HANDLE_MSG(hwnd, WM_CREATE, pThis->OnCreate);
  182. HANDLE_MSG(hwnd, WM_SIZE, pThis->OnSize);
  183. HANDLE_MSG(hwnd, WM_COMMAND, pThis->OnCommand);
  184. HANDLE_MSG(hwnd, WM_DRAWITEM, pThis->OnDrawItem);
  185. HANDLE_MSG(hwnd, WM_DESTROY, pThis->OnDestroy);
  186. HANDLE_MSG(hwnd, WM_SYSCOLORCHANGE, pThis->OnSysColorChange);
  187. HANDLE_MSG(hwnd, WM_PAINT, pThis->OnPaint);
  188. case WM_SETTINGCHANGE:
  189. pThis->OnSysColorChange(hwnd);
  190. break;
  191. case WM_SETFOCUS:
  192. if (pThis && IsWindow(pThis->m_hwndNext))
  193. SetFocus(pThis->m_hwndNext);
  194. return (0);
  195. HANDLE_MSG(hwnd, WM_CTLCOLORSTATIC, pThis->OnCtlColor);
  196. }
  197. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  198. }
  199. //
  200. // FUNCTION: CTipOfTheDay::OnCreate()
  201. //
  202. // PURPOSE: Does all of the initialization of the control, including loading
  203. // the tip string, creating child windows, etc.
  204. //
  205. // PARAMETERS:
  206. // <in> hwnd - Handle of the tip window
  207. // <in> lpCreateStruct - Information from the CreateWindow() call
  208. //
  209. // RETURN VALUE:
  210. // TRUE - Allows the window to be created
  211. // FALSE - Prevents the window from being created.
  212. //
  213. BOOL CTipOfTheDay::OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
  214. {
  215. HRESULT hr;
  216. // First load the tip
  217. if (FAILED(HrLoadTipInfo()))
  218. return (FALSE);
  219. // Create the child windows
  220. if (FAILED(HrCreateChildWindows(hwnd)))
  221. return (FALSE);
  222. // Load the string we should be using for the title - ie "Tip of the Day"
  223. AthLoadString(idsTipOfTheDay, m_szTitle, ARRAYSIZE(m_szTitle));
  224. m_hiTip = LoadIcon(g_hLocRes, MAKEINTRESOURCE(idiTipIcon));
  225. AthLoadString(idsNextTip, m_szNextTip, ARRAYSIZE(m_szNextTip));
  226. // Build our GDI objects/info
  227. OnSysColorChange(hwnd);
  228. return (TRUE);
  229. }
  230. //
  231. // FUNCTION: CTipOfTheDay::HrLoadTipInfo()
  232. //
  233. // PURPOSE: Loads the appropriate tip string into m_pszTip.
  234. //
  235. // RETURN VALUE:
  236. // E_UNEXPECTED - For some reason we couldn't find the string in the registry.
  237. // E_OUTOFMEMORY - Not enough memory to allocate a buffer to store the string.
  238. // S_OK - The string was loaded.
  239. //
  240. HRESULT CTipOfTheDay::HrLoadTipInfo(void)
  241. {
  242. HKEY hKeyUser = 0, hKey;
  243. LPCTSTR pszKey, pszKeyUser;
  244. TCHAR szValue[16];
  245. DWORD cValues;
  246. DWORD cValueLen;
  247. HRESULT hr = S_OK;
  248. DWORD dwType;
  249. DWORD cbData;
  250. // Preset some default values first
  251. m_dwCurrentTip = 0;
  252. SafeMemFree(m_pszTip);
  253. // First load which tip the user should see next
  254. if (FOLDER_NEWS == m_ftType)
  255. pszKeyUser = c_szRegNews;
  256. else
  257. pszKeyUser = c_szMailPath;
  258. // Now load the tip string
  259. if (FOLDER_NEWS == m_ftType)
  260. pszKey = c_szRegTipStringsNews;
  261. else
  262. pszKey = c_szRegTipStringsMail;
  263. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, KEY_READ, &hKey))
  264. {
  265. if (ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, 0, 0, NULL, NULL, NULL,
  266. &cValues, NULL, &cValueLen, NULL, NULL))
  267. {
  268. AssertSz(FALSE, _T("CTipOfTheDay::LoadTipInfo() - Failed call to RegQueryInfoKey()."));
  269. hr = E_UNEXPECTED;
  270. goto exit;
  271. }
  272. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, pszKeyUser, 0,
  273. KEY_READ | KEY_WRITE, &hKeyUser))
  274. {
  275. cbData = sizeof(DWORD);
  276. RegQueryValueEx(hKeyUser, c_szRegCurrentTip, 0, &dwType, (LPBYTE) &m_dwCurrentTip,
  277. &cbData);
  278. m_dwCurrentTip++;
  279. if (m_dwCurrentTip > cValues)
  280. m_dwCurrentTip = 1;
  281. RegSetValueEx(hKeyUser, c_szRegCurrentTip, 0, REG_DWORD, (const LPBYTE)
  282. &m_dwCurrentTip, sizeof(DWORD));
  283. RegCloseKey(hKeyUser);
  284. }
  285. else
  286. m_dwCurrentTip++;
  287. // Allocate the buffer for the string
  288. if (!MemAlloc((LPVOID*) &m_pszTip, sizeof(TCHAR) * (cValueLen + 1)))
  289. {
  290. AssertSz(FALSE, _T("CTipOfTheDay::LoadTipInfo() - MemAlloc() failed."));
  291. hr = E_OUTOFMEMORY;
  292. goto exit;
  293. }
  294. // Now load the actual tip string
  295. wnsprintf(szValue, ARRAYSIZE(szValue), _T("%d"), m_dwCurrentTip);
  296. if (ERROR_SUCCESS != RegQueryValueEx(hKey, szValue, 0, &dwType,
  297. (LPBYTE) m_pszTip, &cValueLen))
  298. {
  299. AssertSz(FALSE, _T("CTipOfTheDay::LoadTipInfo() - Failed to load tip string."));
  300. hr = E_UNEXPECTED;
  301. goto exit;
  302. }
  303. RegCloseKey(hKey);
  304. }
  305. return (hr);
  306. exit:
  307. SafeMemFree(m_pszTip);
  308. RegCloseKey(hKey);
  309. return (hr);
  310. }
  311. //
  312. // FUNCTION: CTipOfTheDay::HrLoadLinkInfo()
  313. //
  314. // PURPOSE: Loads the links that we will display at the bottom of our page
  315. // into the m_rgLinkInfo array.
  316. //
  317. // RETURN VALUE:
  318. // E_UNEXPECTED - For some reason we failed to find the link information
  319. // in the registry.
  320. // E_OUTOFMEMORY - Not enough memory to allocate m_rgLinkInfo.
  321. // S_OK - m_rgLinkInfo and m_cLinks are set correctly.
  322. //
  323. HRESULT CTipOfTheDay::HrLoadLinkInfo(void)
  324. {
  325. #if 0
  326. HKEY hKey;
  327. LPCTSTR pszKey;
  328. DWORD cValues;
  329. DWORD cValueLen;
  330. DWORD iLink;
  331. DWORD iLinkIndex;
  332. HRESULT hr = S_OK;
  333. DWORD dwType;
  334. DWORD cbData;
  335. TCHAR szValue[64];
  336. // Open the appropriate key for the tip links
  337. if (FOLDER_NEWS == m_ftType)
  338. pszKey = c_szRegTipLinksNews;
  339. else
  340. pszKey = c_szRegTipLinksMail;
  341. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, KEY_READ, &hKey))
  342. return (E_UNEXPECTED);
  343. // Get the number of values in this key
  344. if (ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, 0, 0, NULL, NULL, NULL,
  345. &cValues, NULL, &cValueLen, NULL, NULL))
  346. {
  347. AssertSz(FALSE, _T("CTipOfTheDay::HrLoadLinkInfo() - Failed call to RegQueryInfoKey()."));
  348. hr = E_UNEXPECTED;
  349. goto exit;
  350. }
  351. // There should always be an even number of values in this key since each
  352. // link should have a link text and link addr value.
  353. m_cLinks = (cValues / 2) + (cValues % 2);
  354. Assert(0 == (cValues % 2));
  355. // Allocate the m_rgLinkInfo array. If the below assert fails, we are
  356. // leaking the m_rgLinkInfo array.
  357. AssertSz(NULL == m_rgLinkInfo, _T("CTipOfTheDay::HrLoadLinkInfo() - We should only call this once."));
  358. if (!MemAlloc((LPVOID *) &m_rgLinkInfo, sizeof(LINKINFO) * m_cLinks))
  359. {
  360. AssertSz(FALSE, _T("CTipOfTheDay::HrLoadLinkInfo() - Failed to allocate memory."));
  361. hr = E_OUTOFMEMORY;
  362. goto exit;
  363. }
  364. ZeroMemory(m_rgLinkInfo, sizeof(LINKINFO) * m_cLinks);
  365. // Loop through the items and load each string
  366. iLink = 0;
  367. for (iLinkIndex = 1; iLinkIndex <= m_cLinks; iLinkIndex++)
  368. {
  369. // Allocate the link text array
  370. if (!MemAlloc((LPVOID*) &(m_rgLinkInfo[iLink].pszLinkText), cValueLen))
  371. {
  372. AssertSz(FALSE, _T("CTipOfTheDay::HrLoadLinkInfo() - Failed to allocate memory."));
  373. hr = E_OUTOFMEMORY;
  374. goto exit;
  375. }
  376. // Allocate the link address array
  377. if (!MemAlloc((LPVOID*) &(m_rgLinkInfo[iLink].pszLinkAddr), cValueLen))
  378. {
  379. AssertSz(FALSE, _T("CTipOfTheDay::HrLoadLinkInfo() - Failed to allocate memory."));
  380. hr = E_OUTOFMEMORY;
  381. goto exit;
  382. }
  383. // Load the link text
  384. wnsprintf(szValue, ARRAYSIZE(szValue), c_szRegLinkText, iLinkIndex);
  385. cbData = cValueLen;
  386. m_rgLinkInfo[iLink].pszLinkText[0] = 0;
  387. RegQueryValueEx(hKey, szValue, 0, &dwType, (LPBYTE) m_rgLinkInfo[iLink].pszLinkText, &cbData);
  388. Assert(0 != lstrlen(m_rgLinkInfo[iLink].pszLinkText));
  389. // Load the link addr
  390. wnsprintf(szValue, ARRAYSIZE(szValue), c_szRegLinkAddr, iLinkIndex);
  391. cbData = cValueLen;
  392. m_rgLinkInfo[iLink].pszLinkAddr[0] = 0;
  393. RegQueryValueEx(hKey, szValue, 0, &dwType, (LPBYTE) m_rgLinkInfo[iLink].pszLinkAddr, &cbData);
  394. Assert(0 != lstrlen(m_rgLinkInfo[iLink].pszLinkAddr));
  395. // Make sure we have values. If not, we dump this data and go on.
  396. if (0 == lstrlen(m_rgLinkInfo[iLink].pszLinkAddr) ||
  397. 0 == lstrlen(m_rgLinkInfo[iLink].pszLinkText))
  398. {
  399. SafeMemFree(m_rgLinkInfo[iLink].pszLinkText);
  400. SafeMemFree(m_rgLinkInfo[iLink].pszLinkAddr);
  401. }
  402. else
  403. iLink++;
  404. }
  405. // Store the number of links we actually loaded.
  406. m_cLinks = iLink;
  407. RegCloseKey(hKey);
  408. return (hr);
  409. exit:
  410. // Free the linkinfo array
  411. FreeLinkInfo();
  412. // Close the registry
  413. RegCloseKey(hKey);
  414. return (hr);
  415. #endif
  416. return (E_NOTIMPL);
  417. }
  418. //
  419. // FUNCTION: CTipOfTheDay::FreeLinkInfo()
  420. //
  421. // PURPOSE: Frees the m_rgLinkInfo array.
  422. //
  423. void CTipOfTheDay::FreeLinkInfo(void)
  424. {
  425. #if 0
  426. if (m_rgLinkInfo && m_cLinks)
  427. {
  428. for (DWORD i = 0; i < m_cLinks; i++)
  429. {
  430. SafeMemFree(m_rgLinkInfo[i].pszLinkText);
  431. SafeMemFree(m_rgLinkInfo[i].pszLinkAddr);
  432. }
  433. SafeMemFree(m_rgLinkInfo);
  434. m_cLinks = 0;
  435. }
  436. #endif
  437. }
  438. //
  439. // FUNCTION: CTipOfTheDay::HrCreateChildWindows()
  440. //
  441. // PURPOSE: Creates the child windows needed for the tip and the link
  442. // buttons.
  443. //
  444. // RETURN VALUE:
  445. // E_OUTOFMEMORY - Could not create the tip window
  446. // S_OK - Everything was created OK
  447. //
  448. HRESULT CTipOfTheDay::HrCreateChildWindows(HWND hwnd)
  449. {
  450. // Create the "Next Tip" button
  451. m_hwndNext = CreateWindowEx(WS_EX_TRANSPARENT, BUTTON_CLASS, m_szNextTip,
  452. WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | BS_PUSHBUTTON | BS_NOTIFY | BS_OWNERDRAW | WS_TABSTOP | WS_VISIBLE,
  453. 0, 0, 10, 10, hwnd,
  454. (HMENU) IDC_NEXTTIP_BUTTON, g_hLocRes, 0);
  455. return (S_OK);
  456. }
  457. //
  458. // FUNCTION: CTipOfTheDay::OnDestroy()
  459. //
  460. // PURPOSE: This is sent as the tip control is being destroyed. In
  461. // response, we remove the properties we set on any of our
  462. // windows, including the link buttons.
  463. //
  464. // PARAMETERS:
  465. // <in> hwnd - Handle of the tip control.
  466. //
  467. void CTipOfTheDay::OnDestroy(HWND hwnd)
  468. {
  469. #if 0
  470. // Loop through the tip windows removing their properties
  471. for (DWORD i = 0; i < m_cLinks; i++)
  472. {
  473. Assert(IsWindow(m_rgLinkInfo[i].hwndCtl));
  474. RemoveProp(m_rgLinkInfo[i].hwndCtl, LINKINFO_PROP);
  475. }
  476. #endif
  477. // Now remove and Release() our 'this' pointer. These were AddRef()'d
  478. // in WM_NCCREATE.
  479. Assert(IsWindow(m_hwnd));
  480. RemoveProp(m_hwnd, TIPINFO_PROP);
  481. Release();
  482. }
  483. //
  484. // FUNCTION: CTipOfTheDay::OnDrawItem()
  485. //
  486. // PURPOSE: Draws the link buttons
  487. //
  488. // PARAMETERS:
  489. // <in> hwnd - Handle of the tip control window
  490. // <in> lpDrawItem - Pointer to a DRAWITEMSTRUCT with the info needed to
  491. // draw the button.
  492. //
  493. void CTipOfTheDay::OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem)
  494. {
  495. HDC hdc = lpDrawItem->hDC;
  496. COLORREF clrText;
  497. UINT uAlign;
  498. HFONT hf;
  499. RECT rcBtn;
  500. int yText;
  501. LPTSTR pszText;
  502. Assert(lpDrawItem->CtlType == ODT_BUTTON);
  503. Assert(lpDrawItem->CtlID >= IDC_LINKBASE_BUTTON ||
  504. lpDrawItem->CtlID == IDC_NEXTTIP_BUTTON);
  505. // Get the LINKINFO struct from the button prop
  506. if (lpDrawItem->CtlID == IDC_NEXTTIP_BUTTON)
  507. pszText = m_szNextTip;
  508. else
  509. {
  510. PLINKINFO pLinkInfo = (PLINKINFO) GetProp(lpDrawItem->hwndItem, LINKINFO_PROP);
  511. Assert(pLinkInfo);
  512. Assert(pLinkInfo->hwndCtl == lpDrawItem->hwndItem);
  513. pszText = pLinkInfo->pszLinkText;
  514. }
  515. // Set up the DC
  516. SetBkMode(hdc, TRANSPARENT);
  517. clrText = SetTextColor(hdc, m_clrLink);
  518. hf = SelectFont(hdc, m_hfLink);
  519. // Draw the text
  520. FillRect(hdc, &lpDrawItem->rcItem, m_hbrBack);
  521. rcBtn = lpDrawItem->rcItem;
  522. DrawText(hdc, pszText, lstrlen(pszText), &rcBtn, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  523. // Check to see if we should have a focus rect
  524. if (lpDrawItem->itemState & ODS_FOCUS)
  525. {
  526. InflateRect(&rcBtn, -1, -1);
  527. DrawFocusRect(hdc, &rcBtn);
  528. }
  529. // Restore the DC
  530. SetTextColor(hdc, clrText);
  531. SelectFont(hdc, hf);
  532. }
  533. //
  534. // FUNCTION: CTipOfTheDay::OnSysColorChange()
  535. //
  536. // PURPOSE: Reloads our colors and fonts to match the system settings.
  537. //
  538. void CTipOfTheDay::OnSysColorChange(HWND hwnd)
  539. {
  540. NONCLIENTMETRICS ncm;
  541. HDC hdc;
  542. HFONT hf;
  543. SIZE size;
  544. #ifndef WIN16
  545. // Get the colors that we need
  546. #if 1
  547. m_clrBack = GetSysColor(COLOR_INFOBK);
  548. m_clrText = GetSysColor(COLOR_INFOTEXT);
  549. #else
  550. m_clrBack = GetSysColor(COLOR_BTNFACE);
  551. m_clrText = GetSysColor(COLOR_BTNTEXT);
  552. #endif
  553. #else //!WIN16
  554. m_clrBack = GetSysColor(COLOR_BTNFACE);
  555. m_clrText = GetSysColor(COLOR_BTNTEXT);
  556. #endif //!WIN16
  557. // Get the border size
  558. m_dwBorder = GetSystemMetrics(SM_CXBORDER) * 8;
  559. if (!LookupLinkColors(&m_clrLink, NULL))
  560. m_clrLink = m_clrText;
  561. // Get a new background brush
  562. if (m_hbrBack)
  563. {
  564. DeleteBrush(m_hbrBack);
  565. m_hbrBack = 0;
  566. }
  567. m_hbrBack = CreateSolidBrush(m_clrBack);
  568. // Get the fonts
  569. ZeroMemory(&ncm, sizeof(NONCLIENTMETRICS));
  570. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  571. #ifndef WIN16
  572. if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, FALSE))
  573. #else
  574. {
  575. HFONT hfSys;
  576. hfSys = (HFONT)GetStockObject( ANSI_VAR_FONT );
  577. GetObject( hfSys, sizeof( LOGFONT ), &ncm.lfMessageFont );
  578. }
  579. #endif
  580. {
  581. m_hfTip = CreateFontIndirect(&ncm.lfMessageFont);
  582. ncm.lfMessageFont.lfUnderline = TRUE;
  583. m_hfLink = CreateFontIndirect(&ncm.lfMessageFont);
  584. // Adjust the font for the title text
  585. ncm.lfMessageFont.lfHeight = -16;
  586. ncm.lfMessageFont.lfWeight = FW_BOLD;
  587. ncm.lfMessageFont.lfUnderline = FALSE;
  588. m_hfTitle = CreateFontIndirect(&ncm.lfMessageFont);
  589. // Get the text metrics as well
  590. hdc = GetDC(m_hwnd);
  591. hf = SelectFont(hdc, m_hfLink);
  592. GetTextMetrics(hdc, &m_tmLink);
  593. SelectFont(hdc, m_hfTitle);
  594. GetTextMetrics(hdc, &m_tmTitle);
  595. // Calculate how big the title area is
  596. GetTextExtentPoint32(hdc, m_szTitle, lstrlen(m_szTitle), &size);
  597. m_cxTitleWidth = TIP_ICON_WIDTH + (1 * m_dwBorder);
  598. m_cyTitleHeight = max(TIP_ICON_HEIGHT, m_tmTitle.tmHeight * 2) + (2 * m_dwBorder);
  599. SelectFont(hdc, hf);
  600. ReleaseDC(m_hwnd, hdc);
  601. }
  602. InvalidateRect(hwnd, NULL, TRUE);
  603. }
  604. //
  605. // FUNCTION: CTipOfTheDay::OnCommand()
  606. //
  607. // PURPOSE: Used to handle commands from our controls. More specificly,
  608. // we launch URL's when the user clicks a button link.
  609. //
  610. void CTipOfTheDay::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  611. {
  612. SHELLEXECUTEINFO rShellExec;
  613. PLINKINFO pLinkInfo;
  614. RECT rcClient;
  615. switch (codeNotify)
  616. {
  617. // The user clicked on one of our links. We need to launch the URL.
  618. case BN_CLICKED:
  619. if (IDC_NEXTTIP_BUTTON == id)
  620. {
  621. if (SUCCEEDED(HrLoadTipInfo()))
  622. {
  623. InvalidateRect(hwnd, NULL, TRUE);
  624. }
  625. }
  626. else
  627. {
  628. // First get the PLINKINFO for the button
  629. if (NULL == (pLinkInfo = (PLINKINFO) GetProp(hwndCtl, LINKINFO_PROP)))
  630. return;
  631. ZeroMemory (&rShellExec, sizeof (rShellExec));
  632. rShellExec.cbSize = sizeof (rShellExec);
  633. rShellExec.fMask = SEE_MASK_NOCLOSEPROCESS;
  634. rShellExec.hwnd = GetParent(m_hwnd);
  635. rShellExec.nShow = SW_SHOWNORMAL;
  636. rShellExec.lpFile = pLinkInfo->pszLinkAddr;
  637. rShellExec.lpVerb = NULL; // i.e. "Open"
  638. ShellExecuteEx (&rShellExec);
  639. }
  640. return;
  641. }
  642. return;
  643. }
  644. //
  645. // FUNCTION: CTipOfTheDay::OnSize()
  646. //
  647. // PURPOSE: Handles moving and sizing our child windows when the control
  648. // size is changed.
  649. //
  650. // PARAMETERS:
  651. // <in> hwnd - Handle of the control window.
  652. // <in> state - Type of sizing that occured.
  653. // <in> cx, cy - New width and height of the client area.
  654. //
  655. void CTipOfTheDay::OnSize(HWND hwnd, UINT state, int cx, int cy)
  656. {
  657. HFONT hf;
  658. SIZE size;
  659. HDC hdc;
  660. DWORD i;
  661. RECT rc;
  662. BOOL fShow = FALSE;
  663. m_cyNextHeight = m_tmLink.tmHeight + (2 * LINK_BUTTON_BORDER);
  664. hdc = GetDC(m_hwnd);
  665. hf = SelectFont(hdc, m_hfLink);
  666. // Position the "Next Tip" button in the bottom right corner
  667. if (GetTextExtentPoint32(hdc, m_szNextTip, lstrlen(m_szNextTip), &size))
  668. m_cxNextWidth = size.cx + (2 * LINK_BUTTON_BORDER);
  669. else
  670. m_cxNextWidth = 0;
  671. // If the "Next Tip" button would overlap the title, then hide it
  672. fShow = ((int)(cx - m_dwBorder - m_cxNextWidth) > (int) m_cxTitleWidth);
  673. ShowWindow(m_hwndNext, fShow ? SW_SHOW : SW_HIDE);
  674. SetWindowPos(m_hwndNext, 0, cx - m_dwBorder - m_cxNextWidth,
  675. cy - m_dwBorder - m_cyNextHeight,
  676. m_cxNextWidth, m_cyNextHeight, SWP_NOACTIVATE | SWP_NOZORDER);
  677. SelectFont(hdc, hf);
  678. ReleaseDC(m_hwnd, hdc);
  679. // Calculate the new rectangle for the tip text
  680. m_rcTip.left = m_cxTitleWidth + m_dwBorder;
  681. m_rcTip.top = m_dwBorder;
  682. m_rcTip.right = cx - (2 * m_dwBorder) - m_cxNextWidth;
  683. m_rcTip.bottom = cy - m_dwBorder;
  684. SetRect(&rc, m_cxTitleWidth + m_dwBorder, 0, cx, cy);
  685. InvalidateRect(hwnd, &rc, TRUE);
  686. }
  687. //
  688. // FUNCTION: CTipOfTheDay::GetRequiredWidth()
  689. //
  690. // PURPOSE: Returns the minimum width the control requires to display
  691. // itself correctly.
  692. //
  693. // RETURN VALUE:
  694. // Returns the minimum width required for the control in pixels.
  695. //
  696. DWORD CTipOfTheDay::GetRequiredWidth(void)
  697. {
  698. // No longer used
  699. return (0);
  700. }
  701. //
  702. // FUNCTION: CTipOfTheDay::GetRequiredWidth()
  703. //
  704. // PURPOSE: Returns the minimum width the control requires to display
  705. // itself correctly.
  706. //
  707. // RETURN VALUE:
  708. // Returns the minimum width required for the control in pixels.
  709. //
  710. DWORD CTipOfTheDay::GetRequiredHeight(void)
  711. {
  712. return (m_cyTitleHeight);
  713. }
  714. void CTipOfTheDay::OnPaint(HWND hwnd)
  715. {
  716. PAINTSTRUCT ps;
  717. HDC hdc;
  718. HFONT hf;
  719. COLORREF clrBack;
  720. COLORREF clrText;
  721. UINT uAlign;
  722. RECT rc;
  723. RECT rcClient;
  724. GetClientRect(m_hwnd, &rcClient);
  725. hdc = BeginPaint(hwnd, &ps);
  726. // See if we need to erase the background
  727. if (ps.fErase)
  728. {
  729. FillRect(hdc, &ps.rcPaint, m_hbrBack);
  730. }
  731. // Set up the DC
  732. clrBack = SetBkColor(hdc, m_clrBack);
  733. clrText = SetTextColor(hdc, m_clrText);
  734. SetBkMode(hdc, TRANSPARENT);
  735. uAlign = SetTextAlign(hdc, TA_TOP);
  736. hf = SelectFont(hdc, m_hfTitle);
  737. // Draw the tip icon
  738. DrawIcon(hdc, m_dwBorder, max(((m_cyTitleHeight - 32) / 2), 0), m_hiTip);
  739. // A little line to make it look nice
  740. MoveToEx(hdc, m_cxTitleWidth, m_dwBorder, NULL);
  741. LineTo(hdc, m_cxTitleWidth, m_cyTitleHeight - m_dwBorder);
  742. // Figure out how big the "Tip of the Day" rect is going to be
  743. rc.left = TIP_ICON_WIDTH + m_dwBorder;
  744. rc.top = m_dwBorder;
  745. rc.right = m_cxTitleWidth - m_dwBorder;
  746. rc.bottom = m_cyTitleHeight;
  747. // "Tip of the Day" title
  748. // DrawText(hdc, m_szTitle, lstrlen(m_szTitle), &rc, DT_CENTER | DT_NOPREFIX | DT_NOCLIP | DT_WORDBREAK);
  749. // Draw the tip text
  750. SelectFont(hdc, m_hfTip);
  751. rc = m_rcTip;
  752. rc.right = rcClient.right;
  753. FillRect(hdc, &rc, m_hbrBack);
  754. DrawText(hdc, m_pszTip, lstrlen(m_pszTip), &m_rcTip, DT_CENTER | DT_NOPREFIX | DT_WORDBREAK);
  755. // Restore the DC
  756. SetBkColor(hdc, clrBack);
  757. SetTextColor(hdc, clrText);
  758. SetTextAlign(hdc, uAlign);
  759. SelectFont(hdc, hf);
  760. EndPaint(hwnd, &ps);
  761. }
  762. HBRUSH CTipOfTheDay::OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild, int type)
  763. {
  764. Assert(type == CTLCOLOR_STATIC);
  765. SetBkColor(hdc, m_clrBack);
  766. SetTextColor(hdc, m_clrText);
  767. SetBkMode(hdc, TRANSPARENT);
  768. return (m_hbrBack);
  769. }
  770. //////////////////////////////////////////////////////////////////////////////
  771. CLinkButton::CLinkButton()
  772. {
  773. m_cRef = 1;
  774. m_hwnd = 0;
  775. m_hwndParent = 0;
  776. m_pszCaption = NULL;
  777. m_pszLink = NULL;
  778. m_clrLink = RGB(0, 0, 0);
  779. m_clrBack = RGB(255, 255, 255);
  780. m_hfLink = NULL;
  781. ZeroMemory(&m_tmLink, sizeof(TEXTMETRIC));
  782. m_hbrBack = NULL;
  783. m_dwBorder = 0;
  784. m_cxWidth = 0;
  785. m_cyHeight = 0;
  786. m_cxImage = 0;
  787. m_cyImage = 0;
  788. #ifdef WIN16
  789. m_hbmButtons = NULL;
  790. #endif
  791. }
  792. CLinkButton::~CLinkButton()
  793. {
  794. if (m_hfLink)
  795. DeleteFont(m_hfLink);
  796. if (m_hbrBack)
  797. DeleteBrush(m_hbrBack);
  798. #if IMAGELIST
  799. if (m_himl)
  800. ImageList_Destroy(m_himl);
  801. #endif
  802. SafeMemFree(m_pszCaption);
  803. SafeMemFree(m_pszLink);
  804. }
  805. ULONG CLinkButton::AddRef(void)
  806. {
  807. return (++m_cRef);
  808. }
  809. ULONG CLinkButton::Release(void)
  810. {
  811. ULONG cRef = m_cRef--;
  812. if (m_cRef == 0)
  813. delete this;
  814. return (cRef);
  815. }
  816. //
  817. // FUNCTION: CLinkButton::HrCreate()
  818. //
  819. // PURPOSE: Creates the owner drawn button and initializes the class
  820. // members with the correct caption and link information.
  821. //
  822. // PARAMETERS:
  823. // <in> hwndParent - Handle of the button's parent window
  824. // <in> pszCaption - Text to display on the button
  825. // <in> pszLink - URL to execute when the user clicks on the button
  826. // <in> uID - Command ID for the button
  827. //
  828. // RETURNS:
  829. // Returns S_OK if everything succeeds.
  830. //
  831. HRESULT CLinkButton::HrCreate(HWND hwndParent, LPTSTR pszCaption, LPTSTR pszLink,
  832. UINT uID)
  833. {
  834. Assert(IsWindow(hwndParent));
  835. Assert(pszCaption);
  836. Assert(pszLink);
  837. // Copy down the provided information
  838. m_hwndParent = hwndParent;
  839. m_pszCaption = PszDup(pszCaption);
  840. m_pszLink = PszDup(pszLink);
  841. m_uID = uID;
  842. // Create the button window
  843. m_hwnd = CreateWindowEx(0, BUTTON_CLASS, m_pszCaption,
  844. WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE
  845. | BS_PUSHBUTTON | BS_NOTIFY | BS_OWNERDRAW | WS_TABSTOP,
  846. 0, 0, 10, 10, hwndParent, (HMENU) uID, g_hLocRes, 0);
  847. if (!m_hwnd)
  848. return (E_OUTOFMEMORY);
  849. // Set our this pointer as a property of the button so we can retrieve
  850. // it later
  851. SetProp(m_hwnd, LINKINFO_PROP, this);
  852. // Subclass the button so we can clean ourselves up correctly when it
  853. // gets destroyed
  854. WNDPROC pfn = (WNDPROC) SetWindowLong(m_hwnd, GWL_WNDPROC,
  855. (LONG) ButtonSubClass);
  856. SetProp(m_hwnd, WNDPROC_PROP, pfn);
  857. OnSysColorChange();
  858. return (S_OK);
  859. }
  860. //
  861. // FUNCTION: CLinkButton::HrCreate()
  862. //
  863. // PURPOSE: Creates the owner drawn button and initializes the class
  864. // members with the correct caption and link information.
  865. //
  866. // PARAMETERS:
  867. // <in> hwndParent - Handle of the button's parent window
  868. // <in> pszCaption - Text to display on the button
  869. // <in> uID - Command ID for the button
  870. // <in> idBmp - Id for the bitmap that contains the button image
  871. // <in> index - Index of the image in idBmp for this button
  872. //
  873. // RETURNS:
  874. // Returns S_OK if everything succeeds.
  875. //
  876. HRESULT CLinkButton::HrCreate(HWND hwndParent, LPTSTR pszCaption, UINT uID,
  877. UINT index, HBITMAP hbmButton, HBITMAP hbmMask, HPALETTE hpal)
  878. {
  879. Assert(IsWindow(hwndParent));
  880. Assert(pszCaption);
  881. Assert(uID);
  882. // Copy down the provided information
  883. m_hwndParent = hwndParent;
  884. m_pszCaption = PszDup(pszCaption);
  885. m_uID = uID;
  886. m_index = index;
  887. m_cxImage = CX_BUTTON_IMAGE;
  888. m_cyImage = CY_BUTTON_IMAGE;
  889. m_hbmButtons = hbmButton;
  890. m_hbmMask = hbmMask;
  891. m_hpalButtons = hpal;
  892. // Create the button window
  893. m_hwnd = CreateWindowEx(0, BUTTON_CLASS, m_pszCaption,
  894. WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE
  895. | BS_PUSHBUTTON | BS_NOTIFY | BS_OWNERDRAW | WS_TABSTOP,
  896. 0, 0, 10, 10, hwndParent, (HMENU) uID, g_hLocRes, 0);
  897. if (!m_hwnd)
  898. return (E_OUTOFMEMORY);
  899. // Set our this pointer as a property of the button so we can retrieve
  900. // it later
  901. SetProp(m_hwnd, LINKINFO_PROP, this);
  902. // Subclass the button so we can clean ourselves up correctly when it
  903. // gets destroyed
  904. WNDPROC pfn = (WNDPROC) SetWindowLong(m_hwnd, GWL_WNDPROC,
  905. (LONG) ButtonSubClass);
  906. SetProp(m_hwnd, WNDPROC_PROP, pfn);
  907. OnSysColorChange();
  908. return (S_OK);
  909. }
  910. //
  911. // FUNCTION: CLinkButton::OnDrawItem()
  912. //
  913. // PURPOSE: Draws the link button
  914. //
  915. // PARAMETERS:
  916. // <in> hwnd - Handle of the tip control window
  917. // <in> lpDrawItem - Pointer to a DRAWITEMSTRUCT with the info needed to
  918. // draw the button.
  919. //
  920. #define ROP_PatMask 0x00E20746 // D <- S==1 ? P : D
  921. #define DESTINATION 0x00AA0029
  922. void CLinkButton::OnDraw(HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem)
  923. {
  924. HDC hdc = lpDrawItem->hDC;
  925. COLORREF clrText, clrBack;
  926. UINT uAlign;
  927. HFONT hf;
  928. RECT rcBtn;
  929. int yText;
  930. HBRUSH hbr;
  931. HPALETTE hpalOld;
  932. Assert(lpDrawItem->CtlType == ODT_BUTTON);
  933. Assert(lpDrawItem->CtlID == m_uID);
  934. // Set up the DC
  935. clrText = SetTextColor(hdc, m_clrLink);
  936. clrBack = SetBkColor(hdc, m_clrBack);
  937. hf = SelectFont(hdc, m_hfLink);
  938. // Draw the text
  939. rcBtn = lpDrawItem->rcItem;
  940. FillRect(hdc, &rcBtn, m_hbrBack);
  941. // If there was an image set, then draw that first
  942. #if IMAGELIST
  943. if (m_himl)
  944. {
  945. ImageList_Draw(m_himl, m_index, hdc, rcBtn.left, rcBtn.top, ILD_TRANSPARENT);
  946. rcBtn.top += m_cyImage;
  947. }
  948. #endif
  949. // If we're supposed to paint button images, do so now
  950. if (m_hbmButtons)
  951. {
  952. HBRUSH hbrWhite;
  953. HDC hdcMem;
  954. HBITMAP hbmMemOld;
  955. HBRUSH hbrOld;
  956. HDC hdcMask;
  957. HBITMAP hbmMaskOld;
  958. Assert(m_hpalButtons);
  959. // Select and realize the palette
  960. hpalOld = SelectPalette(hdc, m_hpalButtons, TRUE);
  961. RealizePalette(hdc);
  962. hbrWhite = CreateSolidBrush(0x00FFFFFF);
  963. #ifndef WIN16
  964. SetTextColor(hdc, RGB(255, 255, 255));
  965. SetBkColor(hdc, RGB(0, 0, 0));
  966. #else
  967. SetTextColor( hdc, RGB( 0, 0, 0 ) );
  968. SetBkColor( hdc, RGB( 255, 255, 255 ) );
  969. #endif
  970. // Set up a memory DC for the button bitmap
  971. hdcMem = CreateCompatibleDC(hdc);
  972. hbmMemOld = SelectBitmap(hdcMem, m_hbmButtons);
  973. hbrOld = SelectBrush(hdcMem, /* hbrWhite */ m_hbrBack);
  974. #if 1
  975. // Set up a memory DC for the mask
  976. hdcMask = CreateCompatibleDC(hdc);
  977. hbmMaskOld = SelectBitmap(hdcMask, m_hbmMask);
  978. BitBlt(hdc, 0, rcBtn.top, CX_BUTTON_IMAGE, CY_BUTTON_IMAGE, hdcMem, CX_BUTTON_IMAGE * m_index, 0, SRCINVERT);
  979. BitBlt(hdc, 0, rcBtn.top, CX_BUTTON_IMAGE, CY_BUTTON_IMAGE, hdcMask, CX_BUTTON_IMAGE * m_index, 0, SRCAND);
  980. BitBlt(hdc, 0, rcBtn.top, CX_BUTTON_IMAGE, CY_BUTTON_IMAGE, hdcMem, CX_BUTTON_IMAGE * m_index, 0, SRCINVERT);
  981. /*
  982. // Combine the mask and the button bitmaps
  983. BitBlt(hdcMem, 0, 0, CX_BUTTON_IMAGE * 6, CY_BUTTON_IMAGE, hdcMask, 0, 0,
  984. ROP_PatMask);
  985. // Paint the final button image on the screen
  986. BitBlt(hdc, 0, rcBtn.top, CX_BUTTON_IMAGE, CY_BUTTON_IMAGE, hdcMem,
  987. CX_BUTTON_IMAGE * m_index, 0, SRCCOPY);
  988. */
  989. // Clean up the mask memory DC
  990. SelectBitmap(hdcMask, hbmMaskOld);
  991. DeleteDC(hdcMask);
  992. #else
  993. MaskBlt(hdc,
  994. 0,
  995. rcBtn.top,
  996. CX_BUTTON_IMAGE,
  997. CY_BUTTON_IMAGE,
  998. hdcMem,
  999. CX_BUTTON_IMAGE * m_index,
  1000. 0,
  1001. m_hbmMask,
  1002. CX_BUTTON_IMAGE * m_index,
  1003. 0,
  1004. MAKEROP4(DESTINATION, SRCCOPY));
  1005. #endif
  1006. // Clean up the button memory DC
  1007. SelectBrush(hdcMem, hbrOld);
  1008. SelectBitmap(hdcMem, hbmMemOld);
  1009. DeleteDC(hdcMem);
  1010. DeleteBrush(hbrWhite);
  1011. // Reset the palette
  1012. if (hpalOld != NULL)
  1013. SelectPalette(hdc, hpalOld, TRUE);
  1014. rcBtn.top += m_cyImage;
  1015. }
  1016. clrText = SetTextColor(hdc, m_clrLink);
  1017. clrBack = SetBkColor(hdc, m_clrBack);
  1018. DrawText(hdc, m_pszCaption, lstrlen(m_pszCaption), &rcBtn, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  1019. // Check to see if we should have a focus rect
  1020. if (lpDrawItem->itemState & ODS_FOCUS)
  1021. {
  1022. rcBtn = lpDrawItem->rcItem;
  1023. InflateRect(&rcBtn, -1, -1);
  1024. DrawFocusRect(hdc, &rcBtn);
  1025. }
  1026. // Restore the DC
  1027. SetTextColor(hdc, clrText);
  1028. SetBkColor(hdc, clrBack);
  1029. SelectFont(hdc, hf);
  1030. }
  1031. //
  1032. // FUNCTION: CLinkButton::OnSysColorChange()
  1033. //
  1034. // PURPOSE: Reloads our colors and fonts to match the system settings.
  1035. //
  1036. void CLinkButton::OnSysColorChange(void)
  1037. {
  1038. NONCLIENTMETRICS ncm;
  1039. HDC hdc;
  1040. HFONT hf;
  1041. SIZE size;
  1042. COLORREF clrText;
  1043. // Get the colors that we need
  1044. clrText = GetSysColor(COLOR_BTNTEXT);
  1045. if (!LookupLinkColors(&m_clrLink, NULL))
  1046. m_clrLink = clrText;
  1047. m_clrBack = GetSysColor(COLOR_WINDOW);
  1048. if (m_hbrBack)
  1049. DeleteBrush(m_hbrBack);
  1050. m_hbrBack = CreateSolidBrush(m_clrBack);
  1051. // Get the border size
  1052. m_dwBorder = GetSystemMetrics(SM_CXBORDER) * 8;
  1053. // Get the fonts
  1054. ZeroMemory(&ncm, sizeof(NONCLIENTMETRICS));
  1055. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  1056. #ifndef WIN16
  1057. if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, FALSE))
  1058. #else
  1059. {
  1060. HFONT hfSys;
  1061. hfSys = (HFONT)GetStockObject( ANSI_VAR_FONT );
  1062. GetObject( hfSys, sizeof( LOGFONT ), &ncm.lfMessageFont );
  1063. }
  1064. #endif
  1065. {
  1066. ncm.lfMessageFont.lfUnderline = TRUE;
  1067. m_hfLink = CreateFontIndirect(&ncm.lfMessageFont);
  1068. // Get the text metrics as well
  1069. hdc = GetDC(m_hwnd);
  1070. hf = SelectFont(hdc, m_hfLink);
  1071. GetTextMetrics(hdc, &m_tmLink);
  1072. // Calculate how big the link text area is
  1073. GetTextExtentPoint32(hdc, m_pszCaption, lstrlen(m_pszCaption), &size);
  1074. m_cxWidth = max((DWORD) m_cxImage, (DWORD) (size.cx + (2 * LINK_BUTTON_BORDER)));
  1075. // If we have an image, we don't next the extra spacing
  1076. if (m_cyImage)
  1077. m_cyHeight = m_tmLink.tmHeight + m_cyImage + LINK_BUTTON_BORDER;
  1078. else
  1079. m_cyHeight = m_tmLink.tmHeight + (2 * LINK_BUTTON_BORDER);
  1080. SelectFont(hdc, hf);
  1081. ReleaseDC(m_hwnd, hdc);
  1082. }
  1083. InvalidateRect(m_hwnd, NULL, TRUE);
  1084. }
  1085. void CLinkButton::Move(DWORD x, DWORD y)
  1086. {
  1087. SetWindowPos(m_hwnd, 0, x, y, m_cxWidth, m_cyHeight,
  1088. SWP_NOZORDER | SWP_NOACTIVATE);
  1089. }
  1090. void CLinkButton::OnCommand(void)
  1091. {
  1092. #ifndef WIN16
  1093. SHELLEXECUTEINFO rShellExec;
  1094. ZeroMemory (&rShellExec, sizeof (rShellExec));
  1095. rShellExec.cbSize = sizeof (rShellExec);
  1096. rShellExec.fMask = SEE_MASK_NOCLOSEPROCESS;
  1097. rShellExec.hwnd = m_hwndParent;
  1098. rShellExec.nShow = SW_SHOWNORMAL;
  1099. rShellExec.lpFile = m_pszLink;
  1100. rShellExec.lpVerb = NULL; // i.e. "Open"
  1101. ShellExecuteEx (&rShellExec);
  1102. #else
  1103. RunBrowser( m_pszLink, FALSE );
  1104. #endif //!WIN16
  1105. }
  1106. void CLinkButton::Show(BOOL fShow)
  1107. {
  1108. ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE);
  1109. }
  1110. LRESULT CALLBACK EXPORT_16 ButtonSubClass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1111. {
  1112. // If the message is WM_DESTROY, then we need to free the CLinkButton
  1113. // class associated with the button.
  1114. if (uMsg == WM_DESTROY)
  1115. {
  1116. CLinkButton *pLink = (CLinkButton*) GetProp(hwnd, LINKINFO_PROP);
  1117. if (pLink)
  1118. pLink->Release();
  1119. SetProp(hwnd, LINKINFO_PROP, 0);
  1120. }
  1121. // Pass the message on to the original window procedure
  1122. WNDPROC pfn = (WNDPROC) GetProp(hwnd, WNDPROC_PROP);
  1123. if (pfn)
  1124. return CallWindowProc(pfn, hwnd, uMsg, wParam, lParam);
  1125. else
  1126. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1127. }
  1128. /////////////////////////////////////////////////////////////////////////////
  1129. HRESULT HrLoadButtonBitmap(HWND hwnd, int idBmp, int idMask, HBITMAP* phBtns,
  1130. HBITMAP *phMask, HPALETTE *phPalette)
  1131. {
  1132. HRESULT hr = S_OK;
  1133. HBITMAP hbmBtn = 0;
  1134. HBITMAP hbmMask = 0;
  1135. BITMAP bm;
  1136. HDC hdc = 0;
  1137. HDC hdcBitmap = 0;
  1138. DWORD adw[257];
  1139. int i, n;
  1140. HPALETTE hPal = 0;
  1141. // Load the button bitmap
  1142. hbmBtn = (HBITMAP) LoadImage(g_hLocRes, MAKEINTRESOURCE(idBmp), IMAGE_BITMAP,
  1143. 0, 0, LR_CREATEDIBSECTION);
  1144. if (!hbmBtn)
  1145. {
  1146. Assert(hbmBtn);
  1147. hr = E_INVALIDARG;
  1148. goto exit;
  1149. }
  1150. // Load the mask bitmap
  1151. hbmMask = (HBITMAP) LoadImage(g_hLocRes, MAKEINTRESOURCE(idMask), IMAGE_BITMAP,
  1152. 0, 0, LR_CREATEDIBSECTION);
  1153. if (!hbmMask)
  1154. {
  1155. Assert(hbmMask);
  1156. hr = E_INVALIDARG;
  1157. goto exit;
  1158. }
  1159. #ifndef WIN16
  1160. // Get the dimensions of the bitmaps
  1161. GetObject((HGDIOBJ) hbmBtn, sizeof(BITMAP), &bm);
  1162. // Set up the DC's with the bitmap
  1163. hdc = GetDC(hwnd);
  1164. Assert(hdc != NULL);
  1165. hdcBitmap = CreateCompatibleDC(hdc);
  1166. Assert(hdcBitmap != NULL);
  1167. SelectBitmap(hdcBitmap, hbmBtn);
  1168. // Create a palette for the bitmap
  1169. n = GetDIBColorTable(hdcBitmap, 0, 256, (LPRGBQUAD) &adw[1]);
  1170. for (i = 1; i <= n; i++)
  1171. adw[i] = RGB(GetBValue(adw[i]), GetGValue(adw[i]), GetRValue(adw[i]));
  1172. adw[0] = MAKELONG(0x300, n);
  1173. hPal = CreatePalette((LPLOGPALETTE) &adw[0]);
  1174. Assert(hPal);
  1175. // Clean up
  1176. DeleteDC(hdcBitmap);
  1177. ReleaseDC(hwnd, hdc);
  1178. #else
  1179. hPal = (HPALETTE)GetStockObject( DEFAULT_PALETTE );
  1180. Assert( hPal );
  1181. #endif
  1182. // Set up the return values
  1183. *phBtns = hbmBtn;
  1184. *phMask = hbmMask;
  1185. *phPalette = hPal;
  1186. return (S_OK);
  1187. exit:
  1188. // Delete the button bitmap
  1189. if (hbmBtn)
  1190. DeleteBitmap(hbmBtn);
  1191. // Delete the mask
  1192. if (hbmMask)
  1193. DeleteBitmap(hbmMask);
  1194. return (hr);
  1195. }
  1196. //
  1197. // FUNCTION: CLinkButton::OnPaletteChanged()
  1198. //
  1199. // PURPOSE: Sent when another window changes the palette on us.
  1200. //
  1201. // PARAMETERS:
  1202. // <in> hwnd - Handle of the folderview window
  1203. // <in> hwndPaletteChange - The window that changed the palette.
  1204. //
  1205. void CLinkButton::OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange)
  1206. {
  1207. if (hwnd != hwndPaletteChange)
  1208. InvalidateRect(m_hwnd, NULL, FALSE);
  1209. }