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.

2120 lines
68 KiB

  1. /*****************************************************************************\
  2. FILE: ThemePg.cpp
  3. DESCRIPTION:
  4. This code will display a "Theme" tab in the
  5. "Display Properties" dialog (the base dialog, not the advanced dlg).
  6. BryanSt 3/23/2000 Updated and Converted to C++
  7. Copyright (C) Microsoft Corp 1993-2000. All rights reserved.
  8. \*****************************************************************************/
  9. #include "priv.h"
  10. #include "ThemePg.h"
  11. #include "AdvAppearPg.h"
  12. #include "ThSettingsPg.h"
  13. //============================================================================================================
  14. // *** Globals ***
  15. //============================================================================================================
  16. const static DWORD FAR aThemesHelpIds[] = {
  17. IDC_THPG_THEME_PREVIEW, IDH_DISPLAY_THEMES_PREVIEW, // Preview window
  18. IDC_THPG_THEMELIST, IDH_DISPLAY_THEMES_LIST, // Drop Down containing Plus! Themes
  19. IDC_THPG_THEMESETTINGS, IDH_DISPLAY_THEMES_SETTINGS, // "Properties" button to Advanced settings.
  20. IDC_THPG_THEMEDESCRIPTION, (DWORD)-1, //
  21. IDC_THPG_THEMENAME, IDH_DISPLAY_THEMES_LIST, // Title for Themes Drop Down
  22. IDC_THPG_SAMPLELABLE, IDH_DISPLAY_THEMES_PREVIEW, // Label for Preview
  23. IDC_THPG_SAVEAS, IDH_DISPLAY_THEMES_SAVEAS, // Button for Theme "Save As..."
  24. IDC_THPG_DELETETHEME, IDH_DISPLAY_THEMES_DELETETHEME, // Button for Theme "Delete"
  25. 0, 0
  26. };
  27. #define SZ_HELPFILE_THEMES TEXT("display.hlp")
  28. // EnableApplyButton() fails in WM_INITDIALOG so we need to do it later.
  29. #define WMUSER_DELAYENABLEAPPLY (WM_USER + 1)
  30. #define DelayEnableApplyButton(hDlg) PostMessage(hDlg, WMUSER_DELAYENABLEAPPLY, 0, 0)
  31. //===========================
  32. // *** Class Internals & Helpers ***
  33. //===========================
  34. BOOL CThemePage::_IsDirty(void)
  35. {
  36. BOOL fIsDirty = FALSE;
  37. if (m_pSelectedTheme)
  38. {
  39. fIsDirty = TRUE;
  40. }
  41. return fIsDirty;
  42. }
  43. INT_PTR CALLBACK CThemePage::ThemeDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  44. {
  45. CThemePage * pThis = (CThemePage *)GetWindowLongPtr(hDlg, DWLP_USER);
  46. if (WM_INITDIALOG == wMsg)
  47. {
  48. PROPSHEETPAGE * pPropSheetPage = (PROPSHEETPAGE *) lParam;
  49. if (pPropSheetPage)
  50. {
  51. SetWindowLongPtr(hDlg, DWLP_USER, pPropSheetPage->lParam);
  52. pThis = (CThemePage *)pPropSheetPage->lParam;
  53. }
  54. }
  55. if (pThis)
  56. return pThis->_ThemeDlgProc(hDlg, wMsg, wParam, lParam);
  57. return DefWindowProc(hDlg, wMsg, wParam, lParam);
  58. }
  59. HRESULT CThemePage::_OnOpenAdvSettingsDlg(HWND hDlg)
  60. {
  61. IAdvancedDialog * pAdvDialog;
  62. HRESULT hr = GetAdvancedDialog(&pAdvDialog);
  63. if (SUCCEEDED(hr))
  64. {
  65. BOOL fEnableApply = FALSE;
  66. IUnknown_SetSite(pAdvDialog, SAFECAST(this, IObjectWithSite *));
  67. hr = pAdvDialog->DisplayAdvancedDialog(hDlg, SAFECAST(this, IPropertyBag *), &fEnableApply);
  68. IUnknown_SetSite(pAdvDialog, NULL);
  69. if (SUCCEEDED(hr) && fEnableApply)
  70. {
  71. EnableApplyButton(hDlg);
  72. }
  73. pAdvDialog->Release();
  74. }
  75. return hr;
  76. }
  77. HRESULT CThemePage::_EnableDeleteIfAppropriate(void)
  78. {
  79. HRESULT hr = E_UNEXPECTED;
  80. BOOL fEnabled = FALSE;
  81. ITheme * pCurrent = m_pSelectedTheme;
  82. if (!pCurrent)
  83. {
  84. pCurrent = _GetThemeFile(ComboBox_GetCurSel(m_hwndThemeCombo));
  85. }
  86. if (pCurrent)
  87. {
  88. CComBSTR bstrPath;
  89. if (SUCCEEDED(pCurrent->GetPath(VARIANT_TRUE, &bstrPath)) &&
  90. bstrPath && bstrPath[0])
  91. {
  92. TCHAR szReadOnlyDir[MAX_PATH];
  93. TCHAR szCommonRoot[MAX_PATH];
  94. if (ExpandEnvironmentStrings(TEXT("%SystemRoot%\\Resources"), szReadOnlyDir, ARRAYSIZE(szReadOnlyDir)))
  95. {
  96. PathCommonPrefix(bstrPath, szReadOnlyDir, szCommonRoot);
  97. if (!StrStrI(szCommonRoot, szReadOnlyDir))
  98. {
  99. fEnabled = TRUE;
  100. }
  101. }
  102. }
  103. }
  104. EnableWindow(m_hwndDeleteButton, fEnabled);
  105. return hr;
  106. }
  107. HRESULT CThemePage::_DeleteTheme(void)
  108. {
  109. HRESULT hr = E_UNEXPECTED;
  110. if (m_pSelectedTheme)
  111. {
  112. CComBSTR bstrPath;
  113. if (SUCCEEDED(m_pSelectedTheme->GetPath(VARIANT_TRUE, &bstrPath)) &&
  114. bstrPath && bstrPath[0])
  115. {
  116. HCURSOR old = SetCursor(LoadCursor(NULL, IDC_WAIT));
  117. hr = HrSHFileOpDeleteFile(_hwnd, (FOF_NOCONFIRMATION | FOF_NOERRORUI), bstrPath); // We use SHFileOperation so it will go into the Recycle Bin for undo reasons.
  118. SetCursor(old);
  119. if (FAILED(hr))
  120. {
  121. if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
  122. {
  123. TCHAR szTitle[MAX_PATH];
  124. LoadString(HINST_THISDLL, IDS_ERROR_THEME_DELETE_TITLE, szTitle, ARRAYSIZE(szTitle));
  125. ErrorMessageBox(_hwnd, szTitle, IDS_ERROR_THEME_DELETE, hr, bstrPath, 0);
  126. }
  127. }
  128. else
  129. {
  130. int nIndex = ComboBox_GetCurSel(m_hwndThemeCombo);
  131. IUnknown_SetSite(m_pSelectedTheme, NULL); // Break any back pointers.
  132. ATOMICRELEASE(m_pSelectedTheme); // Indicate that we no longer need to apply anything.
  133. hr = _RemoveTheme(nIndex);
  134. if (SUCCEEDED(hr))
  135. {
  136. if (!_GetThemeFile(nIndex))
  137. {
  138. // Now we want to select the next item in the list. However we want to avoid
  139. // choosing "Browse..." because that will bring up the dialog.
  140. for (nIndex = 0; nIndex < ComboBox_GetCount(m_hwndThemeCombo); nIndex++)
  141. {
  142. if (_GetThemeFile(nIndex))
  143. {
  144. break;
  145. }
  146. }
  147. }
  148. if (_GetThemeFile(nIndex))
  149. {
  150. // We found something good.
  151. ComboBox_SetCurSel(m_hwndThemeCombo, nIndex);
  152. _OnThemeChange(_hwnd, FALSE);
  153. }
  154. }
  155. }
  156. }
  157. }
  158. return hr;
  159. }
  160. HRESULT CThemePage::_SaveAs(void)
  161. {
  162. TCHAR szFileName[MAX_PATH];
  163. TCHAR szPath[MAX_PATH];
  164. LoadString(HINST_THISDLL, IDS_DEFAULTTHEMENAME, szFileName, ARRAYSIZE(szFileName));
  165. HRESULT hr = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath);
  166. if (SUCCEEDED(hr) && _punkSite)
  167. {
  168. OPENFILENAME ofn = { 0 };
  169. TCHAR szFilter[MAX_PATH];
  170. LoadString(HINST_THISDLL, IDS_THEME_FILTER, szFilter, ARRAYSIZE(szFilter)-2);
  171. int nLen = lstrlen(szFilter);
  172. nLen += lstrlen(&szFilter[nLen+1]);
  173. szFilter[nLen+2] = szFilter[nLen+3] = 0;
  174. PathAppend(szPath, szFileName);
  175. ofn.lStructSize = sizeof(ofn);
  176. ofn.hwndOwner = _hwnd;
  177. ofn.hInstance = HINST_THISDLL;
  178. ofn.lpstrFilter = szFilter;
  179. ofn.nFilterIndex = 1;
  180. ofn.lpstrFile = szPath;
  181. ofn.nMaxFile = ARRAYSIZE(szPath);
  182. ofn.lpstrDefExt = TEXT("theme");
  183. ofn.Flags = (OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_ENABLESIZING);
  184. // 1. Display SaveAs... dialog
  185. if (GetSaveFileName(&ofn))
  186. {
  187. IPropertyBag * pPropertyBag = NULL;
  188. hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  189. if (SUCCEEDED(hr))
  190. {
  191. ITheme * pTheme;
  192. TCHAR szDisplayName[MAX_PATH];
  193. HCURSOR old = SetCursor(LoadCursor(NULL, IDC_WAIT));
  194. StrCpyN(szDisplayName, PathFindFileName(szPath), ARRAYSIZE(szPath));
  195. PathRemoveExtension(szDisplayName);
  196. hr = SnapShotLiveSettingsToTheme(pPropertyBag, szPath, &pTheme);
  197. SetCursor(old);
  198. if (SUCCEEDED(hr))
  199. {
  200. CComBSTR bstrName(szDisplayName);
  201. Str_SetPtr(&m_pszLastAppledTheme, szPath);
  202. hr = pTheme->put_DisplayName(NULL);
  203. if (SUCCEEDED(hr))
  204. {
  205. _ChooseOtherThemeFile(szPath, TRUE);
  206. }
  207. pTheme->Release();
  208. }
  209. pPropertyBag->Release();
  210. }
  211. }
  212. }
  213. return hr;
  214. }
  215. HRESULT CThemePage::_RemoveTheme(int nIndex)
  216. {
  217. HRESULT hr = E_FAIL;
  218. LPARAM lParam = ComboBox_GetItemData(m_hwndThemeCombo, nIndex);
  219. if (CB_ERR != lParam)
  220. {
  221. THEME_ITEM_BLOCK * pThemeItemBock = (THEME_ITEM_BLOCK *) lParam;
  222. if (pThemeItemBock && (pThemeItemBock != &m_Modified))
  223. {
  224. if (eThemeFile == pThemeItemBock->type)
  225. {
  226. ATOMICRELEASE(pThemeItemBock->pTheme);
  227. }
  228. else if (eThemeURL == pThemeItemBock->type)
  229. {
  230. Str_SetPtr(&(pThemeItemBock->pszUrl), NULL);
  231. }
  232. LocalFree(pThemeItemBock);
  233. }
  234. ComboBox_DeleteString(m_hwndThemeCombo, nIndex);
  235. hr = S_OK;
  236. }
  237. return hr;
  238. }
  239. HRESULT CThemePage::_FreeThemeDropdown(void)
  240. {
  241. HRESULT hr = S_OK;
  242. if (m_hwndThemeCombo)
  243. {
  244. do
  245. {
  246. // Remove the themes fromt he list..
  247. }
  248. while (SUCCEEDED(_RemoveTheme(0)));
  249. }
  250. return hr;
  251. }
  252. HRESULT IUnknown_GetBackground(IUnknown * punk, LPTSTR pszPath, DWORD cchSize)
  253. {
  254. HRESULT hr = E_FAIL;
  255. if (punk)
  256. {
  257. IPropertyBag * ppb;
  258. hr = punk->QueryInterface(IID_PPV_ARG(IPropertyBag, &ppb));
  259. if (SUCCEEDED(hr))
  260. {
  261. hr = SHPropertyBag_ReadStr(ppb, SZ_PBPROP_BACKGROUNDSRC_PATH, pszPath, cchSize);
  262. ppb->Release();
  263. }
  264. }
  265. return hr;
  266. }
  267. /*****************************************************************************\
  268. DESCRIPTION:
  269. This function will determine the currently applied theme. It will then
  270. have it selected from the list or select "Custom" if appropriate.
  271. STATES:
  272. When the CPL opens, the currently selected .theme can be:
  273. 1. "<Theme Name> (Modified)". This means the "ThemeFile" regkey will be empty
  274. and "DisplayName of Modified" will contain the name. In this case m_pszModifiedName
  275. will contain that display name.
  276. 2. Any .theme file. In this case, any .theme file is selected. "ThemeFile" will
  277. have the path to the file.
  278. \*****************************************************************************/
  279. HRESULT CThemePage::_LoadCustomizeValue(void)
  280. {
  281. HRESULT hr = S_OK;
  282. TCHAR szPath[MAX_PATH];
  283. DWORD cbSize = sizeof(szPath);
  284. DWORD dwType;
  285. // See if the user has choosen a value in the past.
  286. hr = HrRegGetPath(HKEY_CURRENT_USER, SZ_REGKEY_LASTTHEME, SZ_REGVALUE_LT_THEMEFILE, szPath, ARRAYSIZE(szPath));
  287. if (FAILED(hr))
  288. {
  289. // Get the global value.
  290. hr = HrRegGetPath(HKEY_LOCAL_MACHINE, SZ_REGKEY_LASTTHEME, SZ_REGVALUE_LT_THEMEFILE, szPath, ARRAYSIZE(szPath));
  291. }
  292. if (SUCCEEDED(hr))
  293. {
  294. // They have, so we use it as long as nothing has changed (like someone changing the background from the outside)
  295. TCHAR szWallpaper[MAX_PATH];
  296. if (szPath[0] &&
  297. SUCCEEDED(HrRegGetPath(HKEY_CURRENT_USER, SZ_REGKEY_LASTTHEME, SZ_REGVALUE_LT_WALLPAPER, szWallpaper, ARRAYSIZE(szWallpaper))) &&
  298. _punkSite)
  299. {
  300. TCHAR szCurrWallpaper[MAX_PATH];
  301. if (SUCCEEDED(IUnknown_GetBackground(_punkSite, szCurrWallpaper, ARRAYSIZE(szCurrWallpaper))))
  302. {
  303. PathExpandEnvStringsWrap(szCurrWallpaper, ARRAYSIZE(szCurrWallpaper));
  304. if (StrCmpI(szCurrWallpaper, szWallpaper))
  305. {
  306. TCHAR szName[MAX_PATH];
  307. cbSize = sizeof(szName);
  308. if (SUCCEEDED(HrSHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_LASTTHEME, SZ_REGVALUE_MODIFIED_DISPNAME, &dwType, (LPVOID) szName, &cbSize)) &&
  309. !szName[0])
  310. {
  311. // We don't have a good custom name so force one now. This happens when
  312. // We have a valid theme but someone makes a modification by using IE to
  313. // change the wallpaper.
  314. Str_SetPtr(&m_pszLastAppledTheme, szPath);
  315. _CustomizeTheme();
  316. }
  317. // Someone changed the wallpaper outside of our UI so we need to treat the theme as "Customized"
  318. szPath[0] = 0;
  319. }
  320. }
  321. }
  322. }
  323. if (FAILED(hr))
  324. {
  325. // Treat it as customized
  326. szPath[0] = 0;
  327. }
  328. if (!szPath[0])
  329. {
  330. TCHAR szName[MAX_PATH];
  331. szName[0] = 0;
  332. cbSize = sizeof(szName);
  333. if (FAILED(HrSHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_LASTTHEME, SZ_REGVALUE_MODIFIED_DISPNAME, &dwType, (LPVOID) szName, &cbSize)) || !szName[0])
  334. {
  335. LoadString(HINST_THISDLL, IDS_MODIFIED_FALLBACK, szName, ARRAYSIZE(szName));
  336. }
  337. Str_SetPtr(&m_pszModifiedName, szName); // This means the theme is customized.
  338. }
  339. Str_SetPtr(&m_pszLastAppledTheme, (szPath[0] ? szPath : NULL)); // This means the theme is customized.
  340. hr = _HandleCustomizedEntre();
  341. if (szPath[0])
  342. {
  343. // Now we need to select the item from the list.
  344. hr = _ChooseOtherThemeFile(szPath, TRUE);
  345. }
  346. m_fInited = TRUE;
  347. return hr;
  348. }
  349. /*****************************************************************************\
  350. DESCRIPTION:
  351. This function is called if someone modified a value in the theme. Since
  352. they have modified it, we want the display name to change so:
  353. a. They know that it's not the same, and
  354. b. They can switch back if they don't like the modifications.
  355. This function will create the new Display Name, normally "Football 200 (Modified)"
  356. and call to have it added to the drop down.
  357. \*****************************************************************************/
  358. HRESULT CThemePage::_CustomizeTheme(void)
  359. {
  360. // Are we already
  361. if (m_pszLastAppledTheme)
  362. {
  363. Str_SetPtr(&m_pszModifiedName, NULL);
  364. if (m_pSelectedTheme)
  365. {
  366. CComBSTR bstrDisplayName;
  367. if (SUCCEEDED(m_pSelectedTheme->get_DisplayName(&bstrDisplayName)))
  368. {
  369. TCHAR szTemplate[MAX_PATH];
  370. TCHAR szDisplayName[MAX_PATH];
  371. LoadStringW(HINST_THISDLL, IDS_MODIFIED_TEMPLATE, szTemplate, ARRAYSIZE(szTemplate));
  372. wnsprintf(szDisplayName, ARRAYSIZE(szDisplayName), szTemplate, bstrDisplayName);
  373. Str_SetPtr(&m_pszModifiedName, szDisplayName);
  374. }
  375. }
  376. if (!m_pszModifiedName)
  377. {
  378. TCHAR szDisplayName[MAX_PATH];
  379. LoadStringW(HINST_THISDLL, IDS_MODIFIED_FALLBACK, szDisplayName, ARRAYSIZE(szDisplayName));
  380. Str_SetPtr(&m_pszModifiedName, szDisplayName);
  381. }
  382. Str_SetPtr(&m_pszLastAppledTheme, NULL); // This means the theme is customized.
  383. }
  384. return _HandleCustomizedEntre();
  385. }
  386. /*****************************************************************************\
  387. DESCRIPTION:
  388. This function will add the "Modified" item to the menu if needed and select
  389. it. Or it will remove it if appropriate.
  390. \*****************************************************************************/
  391. HRESULT CThemePage::_HandleCustomizedEntre(void)
  392. {
  393. HRESULT hr = S_OK;
  394. // If m_pszLastAppledTheme is NULL, then we want to make sure "<ThemeName> (Modified)" is
  395. // in the list and is selected.
  396. if (!m_pszLastAppledTheme)
  397. {
  398. // We now know we want one to exist and to select it.
  399. THEME_ITEM_BLOCK * pThemeItemBock = (THEME_ITEM_BLOCK *) ComboBox_GetItemData(m_hwndThemeCombo, 0);
  400. if (m_pszModifiedName)
  401. {
  402. // We now need to update the name or add it.
  403. if (pThemeItemBock && ((THEME_ITEM_BLOCK *)CB_ERR != pThemeItemBock) && (eThemeModified == pThemeItemBock->type))
  404. {
  405. // It already exists so we need to update the title to make it up to date.
  406. _RemoveUserTheme();
  407. int nIndex = ComboBox_InsertString(m_hwndThemeCombo, 0, m_pszModifiedName);
  408. if ((CB_ERR != nIndex) && (CB_ERRSPACE != nIndex))
  409. {
  410. if (CB_ERR == ComboBox_SetItemData(m_hwndThemeCombo, 0, &m_Modified))
  411. {
  412. hr = E_FAIL;
  413. }
  414. }
  415. }
  416. else
  417. {
  418. // If it isn't found, so add it.
  419. int nIndex = ComboBox_InsertString(m_hwndThemeCombo, 0, m_pszModifiedName);
  420. if ((CB_ERR != nIndex) && (CB_ERRSPACE != nIndex))
  421. {
  422. if (CB_ERR == ComboBox_SetItemData(m_hwndThemeCombo, 0, &m_Modified))
  423. {
  424. hr = E_FAIL;
  425. }
  426. }
  427. }
  428. }
  429. _OnSetSelection(0);
  430. m_nPreviousSelected = 0;
  431. }
  432. return hr;
  433. }
  434. HRESULT CThemePage::_RemoveUserTheme(void)
  435. {
  436. HRESULT hr = S_OK;
  437. THEME_ITEM_BLOCK * pThemeItemBock = (THEME_ITEM_BLOCK *) ComboBox_GetItemData(m_hwndThemeCombo, 0);
  438. // We now need to update the name or add it.
  439. if (pThemeItemBock && ((THEME_ITEM_BLOCK *)CB_ERR != pThemeItemBock) && (eThemeModified == pThemeItemBock->type))
  440. {
  441. ComboBox_DeleteString(m_hwndThemeCombo, 0);
  442. }
  443. return hr;
  444. }
  445. ITheme * CThemePage::_GetThemeFile(int nIndex)
  446. {
  447. ITheme * pTheme = NULL;
  448. THEME_ITEM_BLOCK * pThemeItemBock = (THEME_ITEM_BLOCK *) ComboBox_GetItemData(m_hwndThemeCombo, nIndex);
  449. if (((THEME_ITEM_BLOCK *)CB_ERR != pThemeItemBock) && pThemeItemBock && (eThemeFile == pThemeItemBock->type))
  450. {
  451. pTheme = pThemeItemBock->pTheme;
  452. }
  453. return pTheme;
  454. }
  455. LPCWSTR CThemePage::_GetThemeUrl(int nIndex)
  456. {
  457. LPCWSTR pszUrl = NULL;
  458. THEME_ITEM_BLOCK * pThemeItemBock = (THEME_ITEM_BLOCK *) ComboBox_GetItemData(m_hwndThemeCombo, nIndex);
  459. if (((THEME_ITEM_BLOCK *)CB_ERR != pThemeItemBock) && pThemeItemBock && (eThemeURL == pThemeItemBock->type))
  460. {
  461. pszUrl = pThemeItemBock->pszUrl;
  462. }
  463. return pszUrl;
  464. }
  465. HRESULT CThemePage::_AddThemeFile(LPCTSTR pszDisplayName, int * pnIndex, ITheme * pTheme)
  466. {
  467. THEME_ITEM_BLOCK * pThemeItemBock = (THEME_ITEM_BLOCK *) LocalAlloc(LPTR, sizeof(*pThemeItemBock));
  468. HRESULT hr = (pThemeItemBock ? S_OK : E_OUTOFMEMORY);
  469. if (SUCCEEDED(hr))
  470. {
  471. int nAddIndex;
  472. if (!pnIndex)
  473. {
  474. nAddIndex = ComboBox_AddString(m_hwndThemeCombo, pszDisplayName);
  475. }
  476. else
  477. {
  478. nAddIndex = ComboBox_InsertString(m_hwndThemeCombo, *pnIndex, pszDisplayName);
  479. *pnIndex = nAddIndex;
  480. }
  481. pThemeItemBock->type = eThemeFile;
  482. pThemeItemBock->pTheme = pTheme;
  483. if ((CB_ERR != nAddIndex) && (CB_ERRSPACE != nAddIndex))
  484. {
  485. if (CB_ERR == ComboBox_SetItemData(m_hwndThemeCombo, nAddIndex, pThemeItemBock))
  486. {
  487. hr = E_FAIL;
  488. }
  489. }
  490. else
  491. {
  492. LocalFree(pThemeItemBock);
  493. }
  494. }
  495. return hr;
  496. }
  497. HRESULT CThemePage::_AddUrl(LPCTSTR pszDisplayName, LPCTSTR pszUrl)
  498. {
  499. THEME_ITEM_BLOCK * pThemeItemBock = (THEME_ITEM_BLOCK *) LocalAlloc(LPTR, sizeof(*pThemeItemBock));
  500. HRESULT hr = (pThemeItemBock ? S_OK : E_OUTOFMEMORY);
  501. if (SUCCEEDED(hr))
  502. {
  503. LPTSTR pszUrlDup = NULL;
  504. Str_SetPtr(&pszUrlDup, pszUrl);
  505. if (pszUrlDup)
  506. {
  507. int nAddIndex = ComboBox_AddString(m_hwndThemeCombo, pszDisplayName);
  508. pThemeItemBock->type = eThemeURL;
  509. pThemeItemBock->pszUrl = pszUrlDup;
  510. if ((CB_ERR != nAddIndex) && (CB_ERRSPACE != nAddIndex))
  511. {
  512. ComboBox_SetItemData(m_hwndThemeCombo, nAddIndex, pThemeItemBock);
  513. }
  514. else
  515. {
  516. LocalFree(pThemeItemBock);
  517. }
  518. }
  519. else
  520. {
  521. LocalFree(pThemeItemBock);
  522. }
  523. }
  524. return hr;
  525. }
  526. HRESULT CThemePage::_AddUrls(void)
  527. {
  528. HKEY hKey;
  529. DWORD dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_REGKEY_THEME_SITES, 0, KEY_READ, &hKey);
  530. HRESULT hr = HRESULT_FROM_WIN32(dwError);
  531. if (SUCCEEDED(hr))
  532. {
  533. for (DWORD dwIndex = 0; SUCCEEDED(hr); dwIndex++)
  534. {
  535. TCHAR szValue[MAXIMUM_SUB_KEY_LENGTH];
  536. dwError = RegEnumKey(hKey, dwIndex, szValue, ARRAYSIZE(szValue));
  537. hr = HRESULT_FROM_WIN32(dwError);
  538. if (SUCCEEDED(hr))
  539. {
  540. TCHAR szURL[MAX_URL_STRING];
  541. DWORD dwType;
  542. DWORD cbSize = sizeof(szURL);
  543. if ((ERROR_SUCCESS == SHGetValue(hKey, szValue, TEXT("URL"), &dwType, (void *)szURL, &cbSize)) &&
  544. (REG_SZ == dwType))
  545. {
  546. HKEY hKeyURL;
  547. if (ERROR_SUCCESS == RegOpenKeyEx(hKey, szValue, 0, KEY_READ, &hKeyURL))
  548. {
  549. TCHAR szDisplayName[MAX_PATH];
  550. if (SUCCEEDED(SHLoadRegUIString(hKeyURL, TEXT("DisplayName"), szDisplayName, ARRAYSIZE(szDisplayName))))
  551. {
  552. _AddUrl(szDisplayName, szURL);
  553. }
  554. RegCloseKey(hKeyURL);
  555. }
  556. }
  557. }
  558. }
  559. hr = S_OK;
  560. RegCloseKey(hKey);
  561. }
  562. return hr;
  563. }
  564. BOOL DoesThemeHaveAVisualStyle(ITheme * pTheme)
  565. {
  566. BOOL fHasVisualStyle = FALSE;
  567. CComBSTR bstrPath;
  568. if (SUCCEEDED(pTheme->get_VisualStyle(&bstrPath)) &&
  569. bstrPath && bstrPath[0])
  570. {
  571. fHasVisualStyle = TRUE;
  572. }
  573. return fHasVisualStyle;
  574. }
  575. HRESULT CThemePage::_OnInitThemesDlg(HWND hDlg)
  576. {
  577. HRESULT hr = E_FAIL;
  578. m_fInInit = TRUE;
  579. _FreeThemeDropdown(); // Purge any existing items.
  580. AssertMsg((NULL != _punkSite), TEXT("We need our site pointer in order to save the settings."));
  581. if (_punkSite)
  582. {
  583. IThemeManager * pThemeManager;
  584. _hwnd = hDlg;
  585. m_hwndThemeCombo = GetDlgItem(hDlg, IDC_THPG_THEMELIST);
  586. m_hwndDeleteButton = GetDlgItem(hDlg, IDC_THPG_DELETETHEME);
  587. hr = _punkSite->QueryInterface(IID_PPV_ARG(IThemeManager, &pThemeManager));
  588. if (SUCCEEDED(hr))
  589. {
  590. VARIANT varIndex;
  591. BOOL fVisualStylesSupported = (QueryThemeServicesWrap() & QTS_AVAILABLE);
  592. LogStatus("QueryThemeServices() returned %hs\r\n", (fVisualStylesSupported ? "TRUE" : "FALSE"));
  593. IUnknown_SetSite(m_pSelectedTheme, NULL); // Break any back pointers.
  594. ATOMICRELEASE(m_pSelectedTheme);
  595. varIndex.vt = VT_I4;
  596. for (varIndex.lVal = 0; SUCCEEDED(hr); varIndex.lVal++)
  597. {
  598. ITheme * pTheme;
  599. hr = pThemeManager->get_item(varIndex, &pTheme);
  600. if (SUCCEEDED(hr))
  601. {
  602. if (!fVisualStylesSupported && DoesThemeHaveAVisualStyle(pTheme))
  603. {
  604. // Filter out .theme files if they have a .msstyles file and the
  605. // system doesn't currently support visual styles.
  606. }
  607. else
  608. {
  609. CComBSTR bstrDisplayName;
  610. IUnknown_SetSite(pTheme, _punkSite);
  611. hr = pTheme->get_DisplayName(&bstrDisplayName);
  612. IUnknown_SetSite(pTheme, NULL); // This prevents leaking the site object.
  613. if (SUCCEEDED(hr))
  614. {
  615. hr = _AddThemeFile(bstrDisplayName, NULL, pTheme);
  616. if (SUCCEEDED(hr))
  617. {
  618. pTheme = NULL;
  619. }
  620. }
  621. }
  622. ATOMICRELEASE(pTheme);
  623. }
  624. }
  625. hr = S_OK;
  626. _UpdatePreview();
  627. pThemeManager->Release();
  628. }
  629. // Add Web URLs
  630. _AddUrls();
  631. // Add the "Other..." entre
  632. WCHAR szOtherTheme[MAX_PATH];
  633. LoadStringW(HINST_THISDLL, IDS_THEME_OTHER, szOtherTheme, ARRAYSIZE(szOtherTheme));
  634. ComboBox_AddString(m_hwndThemeCombo, szOtherTheme);
  635. _LoadCustomizeValue();
  636. m_nPreviousSelected = ComboBox_GetCurSel(m_hwndThemeCombo);
  637. if (m_pszThemeLaunched)
  638. {
  639. hr = _ChooseOtherThemeFile(m_pszThemeLaunched, FALSE);
  640. DelayEnableApplyButton(_hwnd);
  641. }
  642. _EnableDeleteIfAppropriate();
  643. }
  644. m_fInInit = FALSE;
  645. return hr;
  646. }
  647. #define SZ_EXTENSION L".Theme"
  648. HRESULT CThemePage::_ChooseOtherThemeFile(IN LPCWSTR pszFile, BOOL fOnlySelect)
  649. {
  650. HRESULT hr = E_FAIL;
  651. // Get results and check that it is a valid theme file
  652. if (!IsValidThemeFile(pszFile))
  653. {
  654. TCHAR szErrorMessage[MAX_URL_STRING];
  655. TCHAR szTitle[MAX_PATH];
  656. TCHAR szMessage[MAX_URL_STRING];
  657. // Bad file: post msg before going back to common open
  658. LoadString(HINST_THISDLL, IDS_ERROR_THEME_INVALID_TITLE, szTitle, ARRAYSIZE(szTitle));
  659. LoadString(HINST_THISDLL, IDS_ERROR_THEME_INVALID, szErrorMessage, ARRAYSIZE(szErrorMessage));
  660. wnsprintf(szMessage, ARRAYSIZE(szMessage), szErrorMessage, pszFile);
  661. MessageBox(m_hwndThemeCombo, szMessage, szTitle, (MB_OK | MB_ICONERROR | MB_APPLMODAL));
  662. }
  663. else
  664. {
  665. // Now we want to:
  666. int nSlot = -1;
  667. int nCount = ComboBox_GetCount(m_hwndThemeCombo);
  668. int nIndex;
  669. hr = S_OK;
  670. // 1. Is it in the list already?
  671. for (nIndex = 0; nIndex < nCount; nIndex++)
  672. {
  673. ITheme * pTheme = _GetThemeFile(nIndex);
  674. if (pTheme)
  675. {
  676. CComBSTR bstrPath;
  677. hr = pTheme->GetPath(VARIANT_TRUE, &bstrPath);
  678. if (SUCCEEDED(hr))
  679. {
  680. if (!StrCmpIW(bstrPath, pszFile))
  681. {
  682. // We found it, so stop looking.
  683. nSlot = nIndex;
  684. break;
  685. }
  686. }
  687. }
  688. }
  689. // 2. If it is not in the list, add it. We put it on the bottom, right above "Other...".
  690. if (-1 == nSlot)
  691. {
  692. ITheme * pThemeNew;
  693. hr = CThemeFile_CreateInstance(pszFile, &pThemeNew);
  694. if (SUCCEEDED(hr))
  695. {
  696. CComBSTR bstrDisplayName;
  697. hr = pThemeNew->get_DisplayName(&bstrDisplayName);
  698. if (SUCCEEDED(hr))
  699. {
  700. nIndex = ComboBox_GetCount(m_hwndThemeCombo);
  701. if (nIndex > 1)
  702. {
  703. nIndex -= 1;
  704. }
  705. hr = _AddThemeFile(bstrDisplayName, &nIndex, pThemeNew);
  706. nSlot = nIndex;
  707. }
  708. if (FAILED(hr))
  709. {
  710. pThemeNew->Release();
  711. }
  712. }
  713. }
  714. if (-1 != nSlot)
  715. {
  716. ComboBox_SetCurSel(m_hwndThemeCombo, nIndex);
  717. _EnableDeleteIfAppropriate();
  718. // 3. Select the theme from the list.
  719. if (CB_ERR != ComboBox_GetItemData(m_hwndThemeCombo, ComboBox_GetCurSel(m_hwndThemeCombo)))
  720. {
  721. // Okay, we now know we won't recurse infinitely, so let's recurse.
  722. hr = _OnThemeChange(_hwnd, fOnlySelect);
  723. }
  724. else
  725. {
  726. hr = E_FAIL;
  727. AssertMsg(0, TEXT("We should have correctly selected the item. Please investiate. -BryanSt"));
  728. }
  729. }
  730. else
  731. {
  732. hr = E_FAIL;
  733. }
  734. // POSSIBLE USABILITY REFINEMENT:
  735. // We want to add this directory to the MRU because it may have other themes or we should allow it to be available later.
  736. }
  737. return hr;
  738. }
  739. // This function is isolated in order to reduce stack space.
  740. HRESULT CThemePage::_DisplayThemeOpenErr(LPCTSTR pszOpenFile)
  741. {
  742. TCHAR szErrorMessage[MAX_PATH];
  743. TCHAR szTitle[MAX_PATH];
  744. TCHAR szMessage[MAX_PATH];
  745. // Bad file: post msg before going back to common open
  746. LoadString(HINST_THISDLL, IDS_ERROR_THEME_INVALID_TITLE, szTitle, ARRAYSIZE(szTitle));
  747. LoadString(HINST_THISDLL, IDS_ERROR_THEME_INVALID, szErrorMessage, ARRAYSIZE(szErrorMessage));
  748. wnsprintf(szMessage, ARRAYSIZE(szMessage), szErrorMessage, pszOpenFile);
  749. MessageBox(m_hwndThemeCombo, szMessage, szTitle, (MB_OK | MB_ICONERROR | MB_APPLMODAL));
  750. return HRESULT_FROM_WIN32(ERROR_CANCELLED); // We already displayed an error dialog so don't do it later.
  751. }
  752. HRESULT CThemePage::_OnSelectOther(void)
  753. {
  754. HRESULT hr = E_FAIL;
  755. OPENFILENAME ofnOpen = {0};
  756. WCHAR szOpenFile[MAX_PATH];
  757. WCHAR szFileSpec[MAX_PATH];
  758. WCHAR szCurrentDirectory[MAX_PATH];
  759. WCHAR szTitle[MAX_PATH];
  760. LoadStringW(HINST_THISDLL, IDS_THEME_OPENTITLE, szTitle, ARRAYSIZE(szTitle));
  761. LoadStringW(HINST_THISDLL, IDS_THEME_FILETYPE, szFileSpec, ARRAYSIZE(szFileSpec)-2);
  762. DWORD cchSize = lstrlenW(szFileSpec);
  763. szFileSpec[cchSize + 1] = szFileSpec[cchSize + 2] = 0; // Add the double NULLs to the end.
  764. LPWSTR pszEnd = StrChrW(szFileSpec, L'|');
  765. if (pszEnd)
  766. {
  767. pszEnd[0] = 0;
  768. }
  769. DWORD dwError = SHRegGetPath(HKEY_CURRENT_USER, SZ_REGKEY_IE_DOWNLOADDIR, SZ_REGVALUE_IE_DOWNLOADDIR, szCurrentDirectory, 0);
  770. if (ERROR_SUCCESS != dwError)
  771. {
  772. SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, 0, szCurrentDirectory);
  773. }
  774. hr = E_FAIL;
  775. do
  776. {
  777. StrCpyNW(szOpenFile, L"*" SZ_EXTENSION, ARRAYSIZE(szOpenFile)); // start w/ *.Theme
  778. ofnOpen.lStructSize = sizeof(OPENFILENAME);
  779. ofnOpen.hwndOwner = m_hwndThemeCombo;
  780. ofnOpen.lpstrFilter = szFileSpec;
  781. ofnOpen.lpstrCustomFilter = NULL;
  782. ofnOpen.nMaxCustFilter = 0;
  783. ofnOpen.nFilterIndex = 1;
  784. ofnOpen.lpstrFile = szOpenFile;
  785. ofnOpen.nMaxFile = ARRAYSIZE(szOpenFile);
  786. ofnOpen.lpstrFileTitle = NULL; // szFileTitle;
  787. ofnOpen.nMaxFileTitle = 0; // sizeof(szFileTitle);
  788. ofnOpen.lpstrInitialDir = szCurrentDirectory;
  789. ofnOpen.lpstrTitle = szTitle;
  790. ofnOpen.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  791. ofnOpen.lpstrDefExt = CharNextW(SZ_EXTENSION);
  792. // NOTE: We could make the UI much better by providing a OFNHookProc with the CDN_FILEOK flag. This would allow
  793. // us to verify the file without closing the dialog.
  794. // Display the File Open dialog.
  795. if (!GetOpenFileNameW(&ofnOpen))
  796. {
  797. // If they didn't open a file, could be hit cancel but
  798. // also check for lowmem return
  799. // select old theme in list
  800. ComboBox_SetCurSel(m_hwndThemeCombo, m_nPreviousSelected);
  801. _EnableDeleteIfAppropriate();
  802. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // We don't need to display any error dialogs later since the user cancelled.
  803. break;
  804. }
  805. else
  806. {
  807. // Get results and check that it is a valid theme file
  808. if (!IsValidThemeFile(szOpenFile))
  809. {
  810. hr = _DisplayThemeOpenErr(szOpenFile);
  811. }
  812. else
  813. {
  814. hr = S_OK;
  815. }
  816. }
  817. }
  818. while (FAILED(hr));
  819. if (SUCCEEDED(hr))
  820. {
  821. hr = _ChooseOtherThemeFile(szOpenFile, FALSE);
  822. }
  823. return hr;
  824. }
  825. HRESULT CThemePage::_LoadThemeFilterState(void)
  826. {
  827. HRESULT hr = _InitFilterKey();
  828. if (SUCCEEDED(hr))
  829. {
  830. DWORD dwType;
  831. WCHAR szEnabled[5];
  832. DWORD cbSize;
  833. COMPILETIME_ASSERT(ARRAYSIZE(g_szCBNames) == ARRAYSIZE(m_fFilters));
  834. for (int nIndex = 0; nIndex < ARRAYSIZE(g_szCBNames); nIndex++)
  835. {
  836. m_fFilters[nIndex] = TRUE; // Default to true.
  837. cbSize = sizeof(szEnabled);
  838. if (SUCCEEDED(HrRegQueryValueEx(m_hkeyFilter, &(g_szCBNames[nIndex][SIZE_THEME_FILTER_STR]), 0, &dwType, (LPBYTE) szEnabled, &cbSize)) &&
  839. !StrCmpIW(szEnabled, L"0"))
  840. {
  841. m_fFilters[nIndex] = FALSE;
  842. }
  843. }
  844. }
  845. return hr;
  846. }
  847. HRESULT CThemePage::_SaveThemeFilterState(void)
  848. {
  849. HRESULT hr = _InitFilterKey();
  850. if (SUCCEEDED(hr))
  851. {
  852. for (int nIndex = 0; nIndex < ARRAYSIZE(g_szCBNames); nIndex++)
  853. {
  854. hr = HrRegSetValueString(m_hkeyFilter, NULL, &(g_szCBNames[nIndex][SIZE_THEME_FILTER_STR]), (m_fFilters[nIndex] ? L"1" : L"0"));
  855. }
  856. }
  857. return hr;
  858. }
  859. HRESULT CThemePage::_UpdatePreview(void)
  860. {
  861. HRESULT hr = S_OK;
  862. if (!m_pThemePreview)
  863. {
  864. hr = CThemePreview_CreateInstance(NULL, IID_PPV_ARG(IThemePreview, &m_pThemePreview));
  865. if (SUCCEEDED(hr) && _punkSite)
  866. {
  867. IPropertyBag * pPropertyBag;
  868. hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  869. if (SUCCEEDED(hr))
  870. {
  871. HWND hwndParent = GetParent(m_hwndThemeCombo);
  872. HWND hwndPlaceHolder = GetDlgItem(hwndParent, IDC_THPG_THEME_PREVIEW);
  873. RECT rcPreview;
  874. AssertMsg((NULL != m_hwndThemeCombo), TEXT("We should have this window at this point. -BryanSt"));
  875. GetClientRect(hwndPlaceHolder, &rcPreview);
  876. MapWindowPoints(hwndPlaceHolder, hwndParent, (LPPOINT)&rcPreview, 2);
  877. hr = m_pThemePreview->CreatePreview(hwndParent, TMPREV_SHOWBKGND | TMPREV_SHOWICONS | TMPREV_SHOWVS, WS_VISIBLE | WS_CHILDWINDOW | WS_BORDER | WS_OVERLAPPED, WS_EX_CLIENTEDGE, rcPreview.left, rcPreview.top, RECTWIDTH(rcPreview), RECTHEIGHT(rcPreview), pPropertyBag, IDC_THPG_THEME_PREVIEW);
  878. if (SUCCEEDED(hr))
  879. {
  880. IPropertyBag * pPropertyBag;
  881. // If we succeeded, remove the dummy window.
  882. DestroyWindow(hwndPlaceHolder);
  883. hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  884. if (SUCCEEDED(hr))
  885. {
  886. hr = SHPropertyBag_WritePunk(pPropertyBag, SZ_PBPROP_PREVIEW1, m_pThemePreview);
  887. pPropertyBag->Release();
  888. }
  889. }
  890. pPropertyBag->Release();
  891. }
  892. }
  893. }
  894. else if (_punkSite)
  895. {
  896. IThemeUIPages * pThemeUIPages;
  897. hr = _punkSite->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUIPages));
  898. if (SUCCEEDED(hr))
  899. {
  900. hr = pThemeUIPages->UpdatePreview(0);
  901. }
  902. pThemeUIPages->Release();
  903. }
  904. return hr;
  905. }
  906. BOOL CThemePage::_IsFiltered(IN DWORD dwFilter)
  907. {
  908. BOOL fFiltered = FALSE;
  909. VARIANT varFilter;
  910. if (SUCCEEDED(Read(g_szCBNames[dwFilter], &varFilter, NULL)) &&
  911. (VT_BOOL == varFilter.vt))
  912. {
  913. fFiltered = (VARIANT_TRUE != varFilter.boolVal);
  914. }
  915. return fFiltered;
  916. }
  917. HRESULT CThemePage::_OnDestroy(HWND hDlg)
  918. {
  919. _FreeThemeDropdown();
  920. return S_OK;
  921. }
  922. HRESULT CThemePage::_InitScreenSaver(void)
  923. {
  924. HRESULT hr = S_OK;
  925. if (!m_pScreenSaverUI)
  926. {
  927. ATOMICRELEASE(m_pBackgroundUI);
  928. ATOMICRELEASE(m_pAppearanceUI);
  929. hr = E_FAIL;
  930. if (_punkSite)
  931. {
  932. IThemeUIPages * pThemeUI;
  933. hr = _punkSite->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  934. if (SUCCEEDED(hr))
  935. {
  936. IEnumUnknown * pEnumUnknown;
  937. hr = pThemeUI->GetBasePagesEnum(&pEnumUnknown);
  938. if (SUCCEEDED(hr))
  939. {
  940. IUnknown * punk;
  941. // This may not exit due to policy
  942. if (SUCCEEDED(IEnumUnknown_FindCLSID(pEnumUnknown, PPID_ScreenSaver, &punk)))
  943. {
  944. hr = punk->QueryInterface(IID_PPV_ARG(IPropertyBag, &m_pScreenSaverUI));
  945. punk->Release();
  946. }
  947. if (SUCCEEDED(hr))
  948. {
  949. // This may not exit due to policy
  950. if (SUCCEEDED(IEnumUnknown_FindCLSID(pEnumUnknown, PPID_Background, &punk)))
  951. {
  952. hr = punk->QueryInterface(IID_PPV_ARG(IPropertyBag, &m_pBackgroundUI));
  953. punk->Release();
  954. }
  955. }
  956. if (SUCCEEDED(hr))
  957. {
  958. // This may not exit due to policy
  959. if (SUCCEEDED(IEnumUnknown_FindCLSID(pEnumUnknown, PPID_BaseAppearance, &punk)))
  960. {
  961. hr = punk->QueryInterface(IID_PPV_ARG(IPropertyBag, &m_pAppearanceUI));
  962. punk->Release();
  963. }
  964. }
  965. pEnumUnknown->Release();
  966. }
  967. pThemeUI->Release();
  968. }
  969. }
  970. }
  971. return hr;
  972. }
  973. LPCWSTR s_Icons[SIZE_ICONS_ARRAY] =
  974. {
  975. L"CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\DefaultIcon:DefaultValue", // My Computer
  976. L"CLSID\\{450D8FBA-AD25-11D0-98A8-0800361B1103}\\DefaultIcon:DefaultValue", // My Documents
  977. L"CLSID\\{208D2C60-3AEA-1069-A2D7-08002B30309D}\\DefaultIcon:DefaultValue", // My Network Places
  978. L"CLSID\\{645FF040-5081-101B-9F08-00AA002F954E}\\DefaultIcon:full", // Recycle Bin (Full)
  979. L"CLSID\\{645FF040-5081-101B-9F08-00AA002F954E}\\DefaultIcon:empty", // Recycle Bin (Empty)
  980. };
  981. extern BOOL g_fDoNotInstallThemeWallpaper; // This is used to not install wallpaper.
  982. HRESULT CThemePage::_OnSetBackground(void)
  983. {
  984. HRESULT hr = S_OK;
  985. if (!_IsFiltered(THEMEFILTER_WALLPAPER) &&
  986. !SHGetRestriction(NULL, POLICY_KEY_ACTIVEDESKTOP, SZ_POLICY_NOCHANGEWALLPAPER) &&
  987. !g_fDoNotInstallThemeWallpaper)
  988. {
  989. // Get the screen saver from the theme and tell the Screen Saver page to use it.
  990. if (m_pSelectedTheme)
  991. {
  992. CComBSTR bstrPath;
  993. if (FAILED(m_pSelectedTheme->get_Background(&bstrPath))) // This will fail if the there isn't a wallpaper set.
  994. {
  995. bstrPath = L"";
  996. }
  997. // This call will fail if the hide background tab policies is enabled.
  998. if (SUCCEEDED(SHPropertyBag_WriteStr(m_pBackgroundUI, SZ_PBPROP_BACKGROUND_PATH, bstrPath)))
  999. {
  1000. enumBkgdTile nTile = BKDGT_STRECH;
  1001. if (FAILED(m_pSelectedTheme->get_BackgroundTile(&nTile)))
  1002. {
  1003. nTile = BKDGT_STRECH; // Default to stretch, it's good for you.
  1004. }
  1005. LPCWSTR pszExtension = PathFindExtensionW(bstrPath);
  1006. // If our wallpaper is an HTML page we need to force stretching on and tiling off
  1007. if (pszExtension &&
  1008. ((StrCmpIW(pszExtension, L".htm") == 0) ||
  1009. (StrCmpIW(pszExtension, L".html") == 0)))
  1010. {
  1011. nTile = BKDGT_STRECH;
  1012. }
  1013. hr = SHPropertyBag_WriteDWORD(m_pBackgroundUI, SZ_PBPROP_BACKGROUND_TILE, nTile);
  1014. }
  1015. }
  1016. }
  1017. return hr;
  1018. }
  1019. HRESULT CThemePage::_OnSetIcons(void)
  1020. {
  1021. HRESULT hr = S_OK;
  1022. if (!_IsFiltered(THEMEFILTER_ICONS) && m_pSelectedTheme)
  1023. {
  1024. int nForIndex;
  1025. for (nForIndex = 0; nForIndex < ARRAYSIZE(s_Icons); nForIndex++)
  1026. {
  1027. CComBSTR bstrPath;
  1028. CComBSTR bstrIconString(s_Icons[nForIndex]);
  1029. // We will probably want to reset any blank values to standard windows settings.
  1030. hr = m_pSelectedTheme->GetIcon(bstrIconString, &bstrPath);
  1031. // If the theme file doesn't specify the icon or specified "", we need to
  1032. // pass "" to SHPropertyBag_WriteStr() so it will delete the regkey. This will
  1033. // revert the icons back to their default value.
  1034. // We ignore error values because this will fail if the hide background tab
  1035. // policy is enabled
  1036. SHPropertyBag_WriteStr(m_pBackgroundUI, s_Icons[nForIndex], (bstrPath ? bstrPath : L""));
  1037. }
  1038. }
  1039. return hr;
  1040. }
  1041. HRESULT CThemePage::_OnSetSystemMetrics(void)
  1042. {
  1043. HRESULT hr = S_OK;
  1044. if (m_pSelectedTheme)
  1045. {
  1046. CComBSTR bstrPath;
  1047. HRESULT hrVisualStyle; // S_OK if we loaded a visual style, which is optional.
  1048. #ifndef ENABLE_IA64_VISUALSTYLES
  1049. // We use a different regkey for 64bit because we need to leave it off until the pre-Whistler
  1050. // 64-bit release forks from the Whistler code base.
  1051. if (SHRegGetBoolUSValue(SZ_REGKEY_APPEARANCE, SZ_REGVALUE_DISPLAYSCHEMES64, FALSE, FALSE))
  1052. {
  1053. hrVisualStyle = m_pSelectedTheme->get_VisualStyle(&bstrPath);
  1054. }
  1055. else
  1056. {
  1057. hrVisualStyle = E_FAIL; // In this case, themes are disabled so we ignore that value from the file.
  1058. }
  1059. #else // ENABLE_IA64_VISUALSTYLES
  1060. hrVisualStyle = m_pSelectedTheme->get_VisualStyle(&bstrPath);
  1061. #endif // ENABLE_IA64_VISUALSTYLES
  1062. if (SUCCEEDED(hrVisualStyle)) // It's fine if this isn't present.
  1063. {
  1064. hrVisualStyle = hr = SHPropertyBag_WriteStr(m_pAppearanceUI, SZ_PBPROP_VISUALSTYLE_PATH, bstrPath);
  1065. if (SUCCEEDED(hr))
  1066. {
  1067. hr = m_pSelectedTheme->get_VisualStyleColor(&bstrPath);
  1068. if (SUCCEEDED(hr))
  1069. {
  1070. hr = SHPropertyBag_WriteStr(m_pAppearanceUI, SZ_PBPROP_VISUALSTYLE_COLOR, bstrPath);
  1071. if (SUCCEEDED(hr))
  1072. {
  1073. hr = m_pSelectedTheme->get_VisualStyleSize(&bstrPath);
  1074. if (SUCCEEDED(hr))
  1075. {
  1076. hr = SHPropertyBag_WriteStr(m_pAppearanceUI, SZ_PBPROP_VISUALSTYLE_SIZE, bstrPath);
  1077. }
  1078. }
  1079. }
  1080. }
  1081. }
  1082. if (SUCCEEDED(hr))
  1083. {
  1084. IPropertyBag * pPropertyBag;
  1085. hr = m_pSelectedTheme->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  1086. if (SUCCEEDED(hr))
  1087. {
  1088. BOOL fHasSysMetricsSections = FALSE;
  1089. // If the .theme file specifies "[IconMetrics]" and "[NonclientMetrics]" sections, then load them.
  1090. // If a .theme file wants to use the values from the visual style, then these should be missing.
  1091. if (SUCCEEDED(SHPropertyBag_ReadBOOL(pPropertyBag, SZ_PBPROP_HASSYSMETRICS, &fHasSysMetricsSections)) &&
  1092. fHasSysMetricsSections)
  1093. {
  1094. SYSTEMMETRICSALL systemMetrics = {0};
  1095. // We want to copy the SYSTEMMETRICSALL structure from the file to the base Appearance page.
  1096. // If the user has a filter, these are the base values that may not get replaced.
  1097. hr = SHPropertyBag_ReadByRef(pPropertyBag, SZ_PBPROP_SYSTEM_METRICS, (void *)&systemMetrics, sizeof(systemMetrics));
  1098. if (SUCCEEDED(hr))
  1099. {
  1100. if (FAILED(hrVisualStyle)) // Skip setting the visual style drop down to a placeholder value if we set it to a real value above.
  1101. {
  1102. WCHAR szPath[MAX_PATH];
  1103. bstrPath = L"";
  1104. hr = SHPropertyBag_WriteStr(m_pAppearanceUI, SZ_PBPROP_VISUALSTYLE_PATH, bstrPath);
  1105. if (SUCCEEDED(hr))
  1106. {
  1107. LoadString(HINST_THISDLL, IDS_DEFAULT_APPEARANCES_SCHEME_CANONICAL, szPath, ARRAYSIZE(szPath));
  1108. hr = SHPropertyBag_WriteStr(m_pAppearanceUI, SZ_PBPROP_VISUALSTYLE_COLOR, szPath);
  1109. if (FAILED(hr))
  1110. {
  1111. // This call will fail on builds with EN+MUI because we fail to give the canonical names in
  1112. // the registry. This is an inherint problem with previous OSs putting the localized name
  1113. // in the registry. We can only upgrade and fix that name to be canonical if the strings we load
  1114. // from the registry (MUI) match that in the registry, which are from the base OS language (EN).
  1115. LoadString(HINST_THISDLL, IDS_DEFAULT_APPEARANCES_SCHEME, szPath, ARRAYSIZE(szPath));
  1116. hr = SHPropertyBag_WriteStr(m_pAppearanceUI, SZ_PBPROP_VISUALSTYLE_COLOR, szPath);
  1117. // MUI: We may still fail to select the string. The user can change MUI languages in such a way
  1118. // that we can't upgrade the DisplayName to be MUI complient, and the language in the DLL may
  1119. // not match the langauge in the registry.
  1120. hr = S_OK;
  1121. }
  1122. if (SUCCEEDED(hr))
  1123. {
  1124. LoadString(HINST_THISDLL, IDS_DEFAULT_APPEARANCES_SIZE_CANONICAL, szPath, ARRAYSIZE(szPath));
  1125. hr = SHPropertyBag_WriteStr(m_pAppearanceUI, SZ_PBPROP_VISUALSTYLE_SIZE, szPath);
  1126. if (FAILED(hr))
  1127. {
  1128. // This call will fail on builds with EN+MUI because we fail to give the canonical names in
  1129. // the registry. This is an inherint problem with previous OSs putting the localized name
  1130. // in the registry. We can only upgrade and fix that name to be canonical if the strings we load
  1131. // from the registry (MUI) match that in the registry, which are from the base OS language (EN).
  1132. LoadString(HINST_THISDLL, IDS_SIZE_NORMAL, szPath, ARRAYSIZE(szPath));
  1133. hr = SHPropertyBag_WriteStr(m_pAppearanceUI, SZ_PBPROP_VISUALSTYLE_SIZE, szPath);
  1134. // MUI: We may still fail to select the string. The user can change MUI languages in such a way
  1135. // that we can't upgrade the DisplayName to be MUI complient, and the language in the DLL may
  1136. // not match the langauge in the registry.
  1137. hr = S_OK;
  1138. }
  1139. }
  1140. }
  1141. }
  1142. // We want to force Flat Menu off because this .theme file does not specify a visual style.
  1143. // Flat Menu needs to be off because the .theme files can't specify the new system metrics for the
  1144. // flat menu colors. Now put the system metrics back.
  1145. systemMetrics.fFlatMenus = FALSE;
  1146. SHPropertyBag_WriteByRef(m_pAppearanceUI, SZ_PBPROP_SYSTEM_METRICS, (void *)&systemMetrics);
  1147. }
  1148. }
  1149. pPropertyBag->Release();
  1150. }
  1151. }
  1152. }
  1153. return hr;
  1154. }
  1155. HRESULT CThemePage::_OnSetSelection(IN int nIndex)
  1156. {
  1157. ComboBox_SetCurSel(m_hwndThemeCombo, nIndex);
  1158. m_pLastSelected = _GetThemeFile(nIndex);
  1159. _EnableDeleteIfAppropriate();
  1160. return S_OK;
  1161. }
  1162. HRESULT CThemePage::_OnThemeChange(HWND hDlg, BOOL fOnlySelect)
  1163. {
  1164. HRESULT hr = S_OK;
  1165. int nIndex = ComboBox_GetCurSel(m_hwndThemeCombo);
  1166. ITheme * pTheme = _GetThemeFile(nIndex);
  1167. ITheme * pThemePrevious = NULL;
  1168. if (-1 == nIndex)
  1169. {
  1170. nIndex = 0;
  1171. }
  1172. IUnknown_Set((IUnknown **)&pThemePrevious, pTheme);
  1173. if (pTheme)
  1174. {
  1175. if (m_pLastSelected != pTheme) // Don't bother if the selection hasn't changed.
  1176. {
  1177. if (-1 == nIndex)
  1178. {
  1179. nIndex = 0; // The caller may NOT select nothing.
  1180. }
  1181. _RemoveUserTheme();
  1182. Str_SetPtr(&m_pszModifiedName, NULL); // Remove the name so it's generated next time.
  1183. hr = _OnLoadThemeValues(pTheme, fOnlySelect);
  1184. if (!fOnlySelect)
  1185. {
  1186. PropSheet_Changed(GetParent(hDlg), hDlg);
  1187. _UpdatePreview();
  1188. if (!m_fInInit)
  1189. {
  1190. DelayEnableApplyButton(hDlg);
  1191. }
  1192. }
  1193. }
  1194. }
  1195. else
  1196. {
  1197. if (!fOnlySelect)
  1198. {
  1199. LPCWSTR pszUrl = _GetThemeUrl(nIndex);
  1200. if (pszUrl)
  1201. {
  1202. HrShellExecute(m_hwndThemeCombo, NULL, pszUrl, NULL, NULL, SW_SHOW);
  1203. ComboBox_SetCurSel(m_hwndThemeCombo, m_nPreviousSelected);
  1204. _EnableDeleteIfAppropriate();
  1205. hr = S_OK;
  1206. }
  1207. else
  1208. {
  1209. // This could be the "Other..." item or the "<UserName>'s Customer Theme".
  1210. // We can find out by seeing if it's the last one.
  1211. if ((ComboBox_GetCount(m_hwndThemeCombo) - 1) == nIndex)
  1212. {
  1213. // This means that it was the "Other..." entre.
  1214. hr = _OnSelectOther();
  1215. }
  1216. }
  1217. }
  1218. }
  1219. if (SUCCEEDED(hr))
  1220. {
  1221. m_nPreviousSelected = ComboBox_GetCurSel(m_hwndThemeCombo);
  1222. }
  1223. else
  1224. {
  1225. if (!fOnlySelect)
  1226. {
  1227. if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
  1228. {
  1229. TCHAR szTitle[MAX_PATH];
  1230. CComBSTR bstrPath;
  1231. if (pTheme)
  1232. {
  1233. pTheme->GetPath(VARIANT_TRUE, &bstrPath);
  1234. }
  1235. LoadString(HINST_THISDLL, IDS_ERROR_THEME_INVALID_TITLE, szTitle, ARRAYSIZE(szTitle));
  1236. if (HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE) == hr)
  1237. {
  1238. TCHAR szErrMsg[MAX_PATH * 2];
  1239. TCHAR szTemplate[MAX_PATH * 2];
  1240. // A common error will be that the service is not running. Let's customize
  1241. // that message to make it friendly.
  1242. LoadString(HINST_THISDLL, IDS_ERROR_THEME_SERVICE_NOTRUNNING, szTemplate, ARRAYSIZE(szTemplate));
  1243. wnsprintf(szErrMsg, ARRAYSIZE(szErrMsg), szTemplate, EMPTYSTR_FORNULL(bstrPath));
  1244. MessageBox(_hwnd, szErrMsg, szTitle, (MB_OK | MB_ICONERROR));
  1245. }
  1246. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1247. {
  1248. TCHAR szErrMsg[MAX_PATH * 2];
  1249. TCHAR szTemplate[MAX_PATH * 2];
  1250. // Often a .theme file will be incorrectly installed and we can't find the other files
  1251. // (like background, screensaver, icons, sounds, etc.). Let's give a better message.
  1252. LoadString(HINST_THISDLL, IDS_ERROR_THEME_FILE_NOTFOUND, szTemplate, ARRAYSIZE(szTemplate));
  1253. wnsprintf(szErrMsg, ARRAYSIZE(szErrMsg), szTemplate, EMPTYSTR_FORNULL(bstrPath));
  1254. MessageBox(_hwnd, szErrMsg, szTitle, (MB_OK | MB_ICONERROR));
  1255. }
  1256. else
  1257. {
  1258. ErrorMessageBox(_hwnd, szTitle, IDS_ERROR_THEME_LOADFAILED, hr, bstrPath, 0);
  1259. }
  1260. }
  1261. _OnLoadThemeValues(m_pSelectedTheme, TRUE);
  1262. ComboBox_SetCurSel(m_hwndThemeCombo, m_nPreviousSelected);
  1263. }
  1264. }
  1265. IUnknown_Set((IUnknown **)&pThemePrevious, NULL);
  1266. return hr;
  1267. }
  1268. HRESULT CThemePage::_OnLoadThemeValues(ITheme * pTheme, BOOL fOnlySelect)
  1269. {
  1270. HRESULT hr = S_OK;
  1271. if (pTheme)
  1272. {
  1273. if (m_pLastSelected != pTheme) // Don't bother if the selection hasn't changed.
  1274. {
  1275. IUnknown_SetSite(m_pSelectedTheme, NULL); // Break any back pointers.
  1276. IUnknown_Set((IUnknown **)&m_pSelectedTheme, pTheme);
  1277. IUnknown_SetSite(m_pSelectedTheme, _punkSite);
  1278. _RemoveUserTheme();
  1279. Str_SetPtr(&m_pszModifiedName, NULL); // Remove the name so it's generated next time.
  1280. if (!fOnlySelect)
  1281. {
  1282. CComBSTR bstrPath;
  1283. hr = _InitScreenSaver();
  1284. if (SUCCEEDED(hr))
  1285. {
  1286. // Set the Screen Saver: Get the screen saver from the theme and tell the Screen Saver page to use it.
  1287. if (!_IsFiltered(THEMEFILTER_SCREENSAVER) &&
  1288. !SHGetRestriction(NULL, POLICY_KEY_SYSTEM, SZ_POLICY_NODISPSCREENSAVERPG) &&
  1289. !SHGetRestriction(SZ_REGKEY_POLICIES_DESKTOP, NULL, SZ_POLICY_SCREENSAVEACTIVE))
  1290. {
  1291. m_pSelectedTheme->get_ScreenSaver(&bstrPath); // If this is not specified, we set the wallpaper to "NONE".
  1292. hr = SHPropertyBag_WriteStr(m_pScreenSaverUI, SZ_PBPROP_SCREENSAVER_PATH, (bstrPath ? bstrPath : L""));
  1293. }
  1294. if (SUCCEEDED(hr))
  1295. {
  1296. // Set the Background:
  1297. hr = _OnSetBackground();
  1298. if (SUCCEEDED(hr))
  1299. {
  1300. // Set the Icons:
  1301. hr = _OnSetIcons();
  1302. if (SUCCEEDED(hr))
  1303. {
  1304. // Set the System Metrics:
  1305. hr = _OnSetSystemMetrics();
  1306. if (SUCCEEDED(hr))
  1307. {
  1308. hr = m_pSelectedTheme->GetPath(VARIANT_TRUE, &bstrPath);
  1309. if (SUCCEEDED(hr))
  1310. {
  1311. Str_SetPtrW(&m_pszThemeToApply, bstrPath);
  1312. Str_SetPtrW(&m_pszLastAppledTheme, bstrPath);
  1313. m_pLastSelected = pTheme;
  1314. }
  1315. }
  1316. }
  1317. }
  1318. }
  1319. }
  1320. }
  1321. }
  1322. }
  1323. return hr;
  1324. }
  1325. INT_PTR CThemePage::_OnCommand(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1326. {
  1327. BOOL fHandled = 1; // Not handled (WM_COMMAND seems to be different)
  1328. const WORD idCtrl = GET_WM_COMMAND_ID(wParam, lParam);
  1329. switch (idCtrl)
  1330. {
  1331. case IDC_THPG_THEMESETTINGS:
  1332. _OnOpenAdvSettingsDlg(hDlg);
  1333. break;
  1334. case IDC_THPG_SAVEAS:
  1335. _SaveAs();
  1336. break;
  1337. case IDC_THPG_DELETETHEME:
  1338. _DeleteTheme();
  1339. break;
  1340. case IDC_THPG_THEMELIST:
  1341. if (HIWORD(wParam) == CBN_SELENDOK)
  1342. {
  1343. _OnThemeChange(hDlg, FALSE);
  1344. _EnableDeleteIfAppropriate();
  1345. }
  1346. break;
  1347. default:
  1348. break;
  1349. }
  1350. return fHandled;
  1351. }
  1352. HRESULT CThemePage::_OnSetActive(HWND hDlg)
  1353. {
  1354. return S_OK;
  1355. }
  1356. HRESULT CThemePage::_OnApply(HWND hDlg, LPARAM lParam)
  1357. {
  1358. // Our parent dialog will be notified of the Apply event and will call our
  1359. // IBasePropPage::OnApply() to do the real work.
  1360. return S_OK;
  1361. }
  1362. // This Property Sheet appear in the top level of the "Display Control Panel".
  1363. INT_PTR CThemePage::_ThemeDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1364. {
  1365. NMHDR FAR *lpnm;
  1366. switch(message)
  1367. {
  1368. case WM_NOTIFY:
  1369. lpnm = (NMHDR FAR *)lParam;
  1370. switch(lpnm->code)
  1371. {
  1372. case PSN_SETACTIVE:
  1373. _OnSetActive(hDlg);
  1374. break;
  1375. case PSN_APPLY:
  1376. _OnApply(hDlg, lParam);
  1377. break;
  1378. case PSN_RESET:
  1379. break;
  1380. }
  1381. break;
  1382. case WM_INITDIALOG:
  1383. _OnInitThemesDlg(hDlg);
  1384. break;
  1385. case WM_DESTROY:
  1386. _OnDestroy(hDlg);
  1387. break;
  1388. case WM_QUERYNEWPALETTE:
  1389. case WM_PALETTECHANGED:
  1390. SendDlgItemMessage(hDlg, IDC_THPG_THEME_PREVIEW, message, wParam, lParam);
  1391. return TRUE;
  1392. case WM_HELP:
  1393. WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, SZ_HELPFILE_THEMES, HELP_WM_HELP, (DWORD_PTR) aThemesHelpIds);
  1394. break;
  1395. case WM_CONTEXTMENU: // right mouse click
  1396. WinHelp((HWND) wParam, SZ_HELPFILE_THEMES, HELP_CONTEXTMENU, (DWORD_PTR) aThemesHelpIds);
  1397. break;
  1398. case WM_COMMAND:
  1399. _OnCommand(hDlg, message, wParam, lParam);
  1400. break;
  1401. case WMUSER_DELAYENABLEAPPLY:
  1402. EnableApplyButton(hDlg);
  1403. break;
  1404. }
  1405. return FALSE;
  1406. }
  1407. HRESULT CThemePage::_PersistState(void)
  1408. {
  1409. HRESULT hr = S_OK;
  1410. if (m_fInited)
  1411. {
  1412. LPCWSTR pszValue = (m_pszLastAppledTheme ? m_pszLastAppledTheme : L"");
  1413. TCHAR szCurrWallpaper[MAX_PATH];
  1414. HrRegSetPath(HKEY_CURRENT_USER, SZ_REGKEY_LASTTHEME, SZ_REGVALUE_LT_THEMEFILE, TRUE, pszValue);
  1415. if (SUCCEEDED(IUnknown_GetBackground(_punkSite, szCurrWallpaper, ARRAYSIZE(szCurrWallpaper))))
  1416. {
  1417. PathUnExpandEnvStringsWrap(szCurrWallpaper, ARRAYSIZE(szCurrWallpaper));
  1418. HrRegSetPath(HKEY_CURRENT_USER, SZ_REGKEY_LASTTHEME, SZ_REGVALUE_LT_WALLPAPER, TRUE, szCurrWallpaper);
  1419. }
  1420. pszValue = (m_pszModifiedName ? m_pszModifiedName : L"");
  1421. DWORD cbSize = (sizeof(pszValue[0]) * (lstrlen(pszValue) + 1));
  1422. HrSHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_LASTTHEME, SZ_REGVALUE_MODIFIED_DISPNAME, REG_SZ, (LPVOID) pszValue, cbSize);
  1423. }
  1424. return hr;
  1425. }
  1426. HRESULT CThemePage::_ApplyThemeFile(void)
  1427. {
  1428. HRESULT hr = S_OK;
  1429. if (m_pszThemeToApply)
  1430. {
  1431. if (m_pSelectedTheme)
  1432. {
  1433. IPropertyBag * pPropertyBag;
  1434. hr = m_pSelectedTheme->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  1435. if (SUCCEEDED(hr))
  1436. {
  1437. VARIANT varEmpty;
  1438. VariantInit(&varEmpty);
  1439. // Here we need to apply all the settings in the theme, like: Sounds, Cursors, Webview
  1440. // that haven't been pushed to the other tabs.
  1441. hr = pPropertyBag->Write(SZ_PBPROP_APPLY_THEMEFILE, &varEmpty);
  1442. pPropertyBag->Release();
  1443. }
  1444. }
  1445. }
  1446. return hr;
  1447. }
  1448. HRESULT CThemePage::_InitFilterKey(void)
  1449. {
  1450. HRESULT hr = S_OK;
  1451. if (!m_hkeyFilter)
  1452. {
  1453. hr = HrRegCreateKeyEx(HKEY_CURRENT_USER, SZ_REGKEY_THEME_FILTERS, 0, NULL, 0, (KEY_WRITE | KEY_READ), NULL, &m_hkeyFilter, NULL);
  1454. }
  1455. return hr;
  1456. }
  1457. //===========================
  1458. // *** IPropertyBag Interface ***
  1459. //===========================
  1460. HRESULT CThemePage::Read(IN LPCOLESTR pszPropName, IN VARIANT * pVar, IN IErrorLog *pErrorLog)
  1461. {
  1462. HRESULT hr = E_INVALIDARG;
  1463. if (pszPropName && pVar)
  1464. {
  1465. // We have a list of "ThemeFilter:" properties for all of the filter values on
  1466. // what part of themes to apply.
  1467. if (!StrCmpNIW(SZ_PBPROP_THEME_FILTER, pszPropName, SIZE_THEME_FILTER_STR))
  1468. {
  1469. pVar->vt = VT_BOOL;
  1470. pVar->boolVal = VARIANT_TRUE;
  1471. for (int nIndex = 0; nIndex < ARRAYSIZE(g_szCBNames); nIndex++)
  1472. {
  1473. if (!StrCmpIW(pszPropName, g_szCBNames[nIndex]))
  1474. {
  1475. pVar->boolVal = (m_fFilters[nIndex] ? VARIANT_TRUE : VARIANT_FALSE);
  1476. hr = S_OK;
  1477. break;
  1478. }
  1479. }
  1480. }
  1481. else if (!StrCmpIW(SZ_PBPROP_THEME_DISPLAYNAME, pszPropName))
  1482. {
  1483. WCHAR szDisplayName[MAX_PATH];
  1484. int nIndex = ComboBox_GetCurSel(m_hwndThemeCombo);
  1485. if ((ARRAYSIZE(szDisplayName) > ComboBox_GetLBTextLen(m_hwndThemeCombo, nIndex)) &&
  1486. (CB_ERR != ComboBox_GetLBText(m_hwndThemeCombo, nIndex, szDisplayName)))
  1487. {
  1488. pVar->vt = VT_BSTR;
  1489. hr = HrSysAllocStringW(szDisplayName, &pVar->bstrVal);
  1490. }
  1491. }
  1492. }
  1493. return hr;
  1494. }
  1495. HRESULT CThemePage::Write(IN LPCOLESTR pszPropName, IN VARIANT *pVar)
  1496. {
  1497. HRESULT hr = E_INVALIDARG;
  1498. if (pszPropName && pVar)
  1499. {
  1500. if (!StrCmpW(pszPropName, SZ_PBPROP_CUSTOMIZE_THEME))
  1501. {
  1502. // We don't care what the variant is.
  1503. // Note that we don't null out m_pSelectedTheme. This is because we still want to apply it.
  1504. hr = _CustomizeTheme();
  1505. }
  1506. // We have a list of "ThemeFilter:" properties for all of the filter values on
  1507. // what part of themes to apply.
  1508. else if (!StrCmpNIW(SZ_PBPROP_THEME_FILTER, pszPropName, SIZE_THEME_FILTER_STR) &&
  1509. (VT_BOOL == pVar->vt))
  1510. {
  1511. for (int nIndex = 0; nIndex < ARRAYSIZE(g_szCBNames); nIndex++)
  1512. {
  1513. if (!StrCmpIW(pszPropName, g_szCBNames[nIndex]))
  1514. {
  1515. m_fFilters[nIndex] = (VARIANT_TRUE == pVar->boolVal);
  1516. hr = S_OK;
  1517. break;
  1518. }
  1519. }
  1520. }
  1521. else if ((VT_LPWSTR == pVar->vt) &&
  1522. !StrCmpW(pszPropName, SZ_PBPROP_THEME_LAUNCHTHEME))
  1523. {
  1524. Str_SetPtrW(&m_pszThemeLaunched, pVar->bstrVal);
  1525. m_nPreviousSelected = ComboBox_GetCurSel(m_hwndThemeCombo);
  1526. hr = S_OK;
  1527. }
  1528. else if ((VT_BSTR == pVar->vt) &&
  1529. !StrCmpW(pszPropName, SZ_PBPROP_THEME_LOADTHEME) &&
  1530. pVar->bstrVal)
  1531. {
  1532. ITheme * pTheme;
  1533. hr = CThemeFile_CreateInstance(pVar->bstrVal, &pTheme);
  1534. if (SUCCEEDED(hr))
  1535. {
  1536. hr = _OnLoadThemeValues(pTheme, FALSE);
  1537. if (SUCCEEDED(hr) && !m_fInited)
  1538. {
  1539. m_fInited = TRUE;
  1540. }
  1541. pTheme->Release();
  1542. }
  1543. }
  1544. }
  1545. return hr;
  1546. }
  1547. //===========================
  1548. // *** IBasePropPage Interface ***
  1549. //===========================
  1550. HRESULT CThemePage::GetAdvancedDialog(OUT IAdvancedDialog ** ppAdvDialog)
  1551. {
  1552. #ifdef FEATURE_THEME_SETTINGS_DIALOG
  1553. return CThemeSettingsPage_CreateInstance(ppAdvDialog);
  1554. #else // FEATURE_THEME_SETTINGS_DIALOG
  1555. *ppAdvDialog = NULL;
  1556. return S_OK;
  1557. #endif // FEATURE_THEME_SETTINGS_DIALOG
  1558. }
  1559. HRESULT CThemePage::OnApply(IN PROPPAGEONAPPLY oaAction)
  1560. {
  1561. HRESULT hr = S_OK;
  1562. HCURSOR old = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1563. if ((PPOAACTION_CANCEL != oaAction))
  1564. {
  1565. hr = _SaveThemeFilterState();
  1566. AssertMsg((NULL != _punkSite), TEXT("We need our site pointer in order to save the settings."));
  1567. if (_IsDirty() && _punkSite)
  1568. {
  1569. // m_pSelectedTheme will be NULL if a Theme wasn't chosen to be applied.
  1570. if (m_pSelectedTheme)
  1571. {
  1572. IPropertyBag * pPropertyBag;
  1573. hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  1574. if (SUCCEEDED(hr))
  1575. {
  1576. CComBSTR bstrPath;
  1577. if (m_pSelectedTheme)
  1578. {
  1579. // Persist the filename to the registry.
  1580. hr = m_pSelectedTheme->GetPath(VARIANT_TRUE, &bstrPath);
  1581. }
  1582. hr = SHPropertyBag_WriteStr(pPropertyBag, SZ_PBPROP_THEME_SETSELECTION, bstrPath);
  1583. pPropertyBag->Release();
  1584. }
  1585. if (SUCCEEDED(hr))
  1586. {
  1587. hr = _ApplyThemeFile();
  1588. IUnknown_SetSite(m_pSelectedTheme, NULL); // Break any back pointers.
  1589. ATOMICRELEASE(m_pSelectedTheme); // Indicate that we no longer need to apply anything.
  1590. }
  1591. }
  1592. }
  1593. // We save the Theme selection even if the user didn't change themes. They may have caused
  1594. // the theme selection to become customized.
  1595. _PersistState();
  1596. }
  1597. SetCursor(old);
  1598. return hr;
  1599. }
  1600. #define FEATURE_SHOWTHEMEPAGE TRUE
  1601. //===========================
  1602. // *** IShellPropSheetExt Interface ***
  1603. //===========================
  1604. HRESULT CThemePage::AddPages(IN LPFNSVADDPROPSHEETPAGE pfnAddPage, IN LPARAM lParam)
  1605. {
  1606. HRESULT hr = S_OK;
  1607. // Does the policy say to add the Themes Tab?
  1608. if (SHRegGetBoolUSValue(SZ_REGKEY_APPEARANCE, SZ_REGVALUE_DISPLAYTHEMESPG, FALSE, FEATURE_SHOWTHEMEPAGE))
  1609. {
  1610. PROPSHEETPAGE psp = {0};
  1611. psp.dwSize = sizeof(psp);
  1612. psp.hInstance = HINST_THISDLL;
  1613. psp.dwFlags = PSP_DEFAULT;
  1614. psp.lParam = (LPARAM) this;
  1615. psp.pszTemplate = MAKEINTRESOURCE(DLG_THEMESPG);
  1616. psp.pfnDlgProc = CThemePage::ThemeDlgProc;
  1617. HPROPSHEETPAGE hpsp = CreatePropertySheetPage(&psp);
  1618. if (hpsp)
  1619. {
  1620. if (pfnAddPage(hpsp, lParam))
  1621. {
  1622. hr = S_OK;
  1623. }
  1624. else
  1625. {
  1626. DestroyPropertySheetPage(hpsp);
  1627. hr = E_FAIL;
  1628. }
  1629. }
  1630. else
  1631. {
  1632. hr = E_OUTOFMEMORY;
  1633. }
  1634. }
  1635. return hr;
  1636. }
  1637. //===========================
  1638. // *** IObjectWithSite Interface ***
  1639. //===========================
  1640. HRESULT CThemePage::SetSite(IN IUnknown * punkSite)
  1641. {
  1642. if (!punkSite)
  1643. {
  1644. // We need to break back pointers.
  1645. IUnknown_SetSite(m_pSelectedTheme, NULL);
  1646. }
  1647. return CObjectWithSite::SetSite(punkSite);
  1648. }
  1649. //===========================
  1650. // *** IUnknown Interface ***
  1651. //===========================
  1652. ULONG CThemePage::AddRef()
  1653. {
  1654. return InterlockedIncrement(&m_cRef);
  1655. }
  1656. ULONG CThemePage::Release()
  1657. {
  1658. if (InterlockedDecrement(&m_cRef))
  1659. return m_cRef;
  1660. delete this;
  1661. return 0;
  1662. }
  1663. HRESULT CThemePage::QueryInterface(REFIID riid, void **ppvObj)
  1664. {
  1665. static const QITAB qit[] = {
  1666. QITABENT(CThemePage, IObjectWithSite),
  1667. QITABENT(CThemePage, IOleWindow),
  1668. QITABENT(CThemePage, IPersist),
  1669. QITABENT(CThemePage, IPropertyBag),
  1670. QITABENT(CThemePage, IBasePropPage),
  1671. QITABENTMULTI(CThemePage, IShellPropSheetExt, IBasePropPage),
  1672. { 0 },
  1673. };
  1674. return QISearch(this, qit, riid, ppvObj);
  1675. }
  1676. //===========================
  1677. // *** Class Methods ***
  1678. //===========================
  1679. CThemePage::CThemePage() : m_cRef(1), CObjectCLSID(&PPID_Theme)
  1680. {
  1681. DllAddRef();
  1682. // This needs to be allocated in Zero Inited Memory.
  1683. // Assert that all Member Variables are inited to Zero.
  1684. ASSERT(!m_pSelectedTheme);
  1685. ASSERT(!m_pThemePreview);
  1686. ASSERT(!m_pScreenSaverUI);
  1687. ASSERT(!m_pBackgroundUI);
  1688. ASSERT(!m_pAppearanceUI);
  1689. ASSERT(!m_pszThemeToApply);
  1690. ASSERT(!m_hkeyFilter);
  1691. ASSERT(!m_pszLastAppledTheme);
  1692. ASSERT(!m_pszModifiedName);
  1693. ASSERT(!m_hwndDeleteButton);
  1694. m_fInited = FALSE;
  1695. m_fInInit = FALSE;
  1696. m_Modified.type = eThemeModified;
  1697. m_Modified.pszUrl = NULL;
  1698. // Load the Theme Filter state.
  1699. _LoadThemeFilterState();
  1700. }
  1701. CThemePage::~CThemePage()
  1702. {
  1703. IUnknown_SetSite(m_pSelectedTheme, NULL); // Break any back pointers.
  1704. ATOMICRELEASE(m_pSelectedTheme);
  1705. ATOMICRELEASE(m_pThemePreview);
  1706. ATOMICRELEASE(m_pScreenSaverUI);
  1707. ATOMICRELEASE(m_pBackgroundUI);
  1708. ATOMICRELEASE(m_pAppearanceUI);
  1709. Str_SetPtrW(&m_pszLastAppledTheme, NULL);
  1710. Str_SetPtrW(&m_pszModifiedName, NULL);
  1711. Str_SetPtrW(&m_pszThemeToApply, NULL);
  1712. Str_SetPtrW(&m_pszThemeLaunched, NULL);
  1713. if (m_hkeyFilter)
  1714. {
  1715. RegCloseKey(m_hkeyFilter);
  1716. }
  1717. DllRelease();
  1718. }