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.

817 lines
26 KiB

  1. /*****************************************************************************\
  2. FILE: appScheme.cpp
  3. DESCRIPTION:
  4. This is the Autmation Object to theme scheme object.
  5. BryanSt 4/3/2000 (Bryan Starbuck)
  6. Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
  7. \*****************************************************************************/
  8. #include "priv.h"
  9. #include <cowsite.h>
  10. #include <atlbase.h>
  11. #include "util.h"
  12. #include "theme.h"
  13. #include "appstyle.h"
  14. #include "appscheme.h"
  15. //===========================
  16. // *** Class Internals & Helpers ***
  17. //===========================
  18. APPEARANCESCHEME_UPGRADE_MAPPINGS g_UpgradeMapping[MAX_LEGACY_UPGRADE_SCENARIOS] = {0};
  19. HRESULT LoadConversionMappings(void)
  20. {
  21. if (0 == g_UpgradeMapping[0].szLegacyName[0]) // Only set the settings if it's the first time.
  22. {
  23. // This is custom user created scheme.
  24. TCHAR szTempState[10];
  25. for (int nIndex = 0; nIndex < ARRAYSIZE(g_UpgradeMapping); nIndex++)
  26. {
  27. LoadString(HINST_THISDLL, IDS_LEGACYSCHEME_NAME + nIndex, g_UpgradeMapping[nIndex].szLegacyName, ARRAYSIZE(g_UpgradeMapping[nIndex].szLegacyName));
  28. LoadString(HINST_THISDLL, IDS_LOCALIZATIONPOINTER + nIndex, g_UpgradeMapping[nIndex].szNewColorSchemeName, ARRAYSIZE(g_UpgradeMapping[nIndex].szNewColorSchemeName));
  29. LoadString(HINST_THISDLL, IDS_NEWSIZE_NAME + nIndex, g_UpgradeMapping[nIndex].szNewSizeName, ARRAYSIZE(g_UpgradeMapping[nIndex].szNewSizeName));
  30. LoadString(HINST_THISDLL, IDS_NEWCONTRASTFLAGS + nIndex, szTempState, ARRAYSIZE(szTempState));
  31. g_UpgradeMapping[nIndex].ContrastLevel = (enumThemeContrastLevels) StrToInt(szTempState);
  32. }
  33. }
  34. return S_OK;
  35. }
  36. HRESULT MapLegacyAppearanceSchemeToIndex(LPCTSTR pszOldSchemeName, int * pnIndex)
  37. {
  38. HRESULT hr = E_FAIL; // Failure means, FALSE, we didn't convert.
  39. *pnIndex = 0;
  40. for (int nIndex = 0; nIndex < ARRAYSIZE(g_UpgradeMapping); nIndex++)
  41. {
  42. // Did we find that pszSchemeName is one of the legacy settings?
  43. if (!StrCmpI(pszOldSchemeName, g_UpgradeMapping[nIndex].szLegacyName))
  44. {
  45. hr = S_OK;
  46. *pnIndex = nIndex;
  47. break;
  48. }
  49. }
  50. return hr;
  51. }
  52. HRESULT CAppearanceScheme::_IsLegacyUpgradeConvert(LPCTSTR pszSchemeName, SYSTEMMETRICSALL * pState, IN BOOL fSetAsDefault)
  53. {
  54. int nIndex = 0;
  55. HRESULT hr = MapLegacyAppearanceSchemeToIndex(pszSchemeName, &nIndex);
  56. if (SUCCEEDED(hr))
  57. {
  58. hr = _ConvertScheme(pszSchemeName, g_UpgradeMapping[nIndex].szNewColorSchemeName, g_UpgradeMapping[nIndex].szNewSizeName, pState, g_UpgradeMapping[nIndex].ContrastLevel, fSetAsDefault, FALSE);
  59. }
  60. return hr;
  61. }
  62. HRESULT CAppearanceScheme::_CustomConvert(LPCTSTR pszSchemeName, SYSTEMMETRICSALL * pState, IN BOOL fSetAsDefault, IN BOOL fSetRegKeyTitle)
  63. {
  64. // This is custom user created scheme.
  65. TCHAR szSizeName[MAX_PATH];
  66. LoadString(HINST_THISDLL, IDS_SIZE_NORMAL, szSizeName, ARRAYSIZE(szSizeName));
  67. return _ConvertScheme(pszSchemeName, pszSchemeName, szSizeName, pState, CONTRAST_NORMAL, fSetAsDefault, fSetRegKeyTitle);
  68. }
  69. HRESULT CAppearanceScheme::_getSizeIndex(IN IThemeStyle * pThemeStyle, IN IThemeSize * pThemeSize, IN BSTR bstrSizeDisplayName, IN long * pnSizeIndex)
  70. {
  71. // This is horrible from a perf perspective, but we only do it once on upgrade.
  72. long nCount;
  73. HRESULT hr = E_FAIL;
  74. *pnSizeIndex = 0;
  75. if (SUCCEEDED(pThemeStyle->get_length(&nCount)))
  76. {
  77. IThemeSize * pThemeSize2;
  78. for (long nIndex = 0; nIndex < nCount; nIndex++)
  79. {
  80. VARIANT var;
  81. var.vt = VT_I4;
  82. var.lVal = nIndex;
  83. if (SUCCEEDED(pThemeStyle->get_item(var, &pThemeSize2)))
  84. {
  85. CComBSTR bstrSize2;
  86. if (SUCCEEDED(pThemeSize2->get_DisplayName(&bstrSize2)))
  87. {
  88. CComBSTR bstrName;
  89. if (!StrCmpIW(bstrSizeDisplayName, bstrSize2) ||
  90. (SUCCEEDED(pThemeSize2->get_Name(&bstrName)) &&
  91. !StrCmpIW(bstrSizeDisplayName, bstrName)))
  92. {
  93. hr = S_OK;
  94. *pnSizeIndex = nIndex;
  95. nIndex = nCount; // End looping now.
  96. }
  97. }
  98. pThemeSize2->Release();
  99. }
  100. }
  101. }
  102. return hr;
  103. }
  104. HRESULT CAppearanceScheme::_getIndex(IN IThemeStyle * pThemeStyle, IN BSTR bstrStyleDisplayName, IN long * pnStyleIndex, IN IThemeSize * pThemeSize, IN BSTR bstrSizeDisplayName, IN long * pnSizeIndex)
  105. {
  106. // This is horrible from a perf perspective, but we only do it once on upgrade.
  107. long nCount;
  108. HRESULT hr = E_FAIL;
  109. *pnStyleIndex = 0;
  110. *pnSizeIndex = 0;
  111. if (SUCCEEDED(get_length(&nCount)))
  112. {
  113. IThemeStyle * pThemeStyle2;
  114. for (long nIndex = 0; nIndex < nCount; nIndex++)
  115. {
  116. VARIANT var;
  117. var.vt = VT_I4;
  118. var.lVal = nIndex;
  119. if (SUCCEEDED(get_item(var, &pThemeStyle2)))
  120. {
  121. CComBSTR bstrStyle2;
  122. if (SUCCEEDED(pThemeStyle2->get_DisplayName(&bstrStyle2)))
  123. {
  124. CComBSTR bstrName;
  125. if (!StrCmpIW(bstrStyleDisplayName, bstrStyle2) ||
  126. (SUCCEEDED(pThemeStyle2->get_Name(&bstrName)) &&
  127. !StrCmpIW(bstrStyleDisplayName, bstrName)))
  128. {
  129. *pnStyleIndex = nIndex;
  130. hr = _getSizeIndex(pThemeStyle, pThemeSize, bstrSizeDisplayName, pnSizeIndex);
  131. nIndex = nCount; // End the search.
  132. }
  133. }
  134. pThemeStyle2->Release();
  135. }
  136. }
  137. }
  138. return hr;
  139. }
  140. HRESULT CAppearanceScheme::_ConvertScheme(LPCTSTR pszLegacyName, // This is the Legacy Name
  141. LPCTSTR pszStyleName, LPCTSTR pszSizeName, SYSTEMMETRICSALL * pState,
  142. IN enumThemeContrastLevels ContrastLevel, IN BOOL fSetAsDefault, IN BOOL fSetRegKeyTitle)
  143. {
  144. // This is custom user created scheme.
  145. IThemeStyle * pThemeStyle;
  146. CComVariant varDisplayNameBSTR(pszStyleName);
  147. HRESULT hr = get_item(varDisplayNameBSTR, &pThemeStyle);
  148. if (FAILED(hr))
  149. {
  150. // If it doesn't exist, create one.
  151. hr = _AddStyle((fSetRegKeyTitle ? pszStyleName : NULL), &pThemeStyle);
  152. }
  153. if (SUCCEEDED(hr))
  154. {
  155. CComBSTR bstrStyleDisplayName(pszStyleName);
  156. hr = pThemeStyle->put_DisplayName(bstrStyleDisplayName);
  157. if (SUCCEEDED(hr))
  158. {
  159. IThemeSize * pThemeSize;
  160. hr = pThemeStyle->AddSize(&pThemeSize);
  161. if (SUCCEEDED(hr))
  162. {
  163. CComBSTR bstrSizeDisplayName(pszSizeName);
  164. hr = pThemeSize->put_DisplayName(bstrSizeDisplayName);
  165. if (SUCCEEDED(hr))
  166. {
  167. hr = SystemMetricsAll_Save(pState, pThemeSize, FALSE);
  168. if (SUCCEEDED(hr))
  169. {
  170. // Set the contrast level.
  171. hr = pThemeSize->put_ContrastLevel(ContrastLevel);
  172. if (SUCCEEDED(hr))
  173. {
  174. IPropertyBag * pPropertyBag;
  175. hr = pThemeSize->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  176. if (SUCCEEDED(hr))
  177. {
  178. hr = SHPropertyBag_WriteStr(pPropertyBag, SZ_PBPROP_COLORSCHEME_LEGACYNAME, pszLegacyName);
  179. pPropertyBag->Release();
  180. }
  181. }
  182. }
  183. }
  184. if (fSetAsDefault && SUCCEEDED(hr))
  185. {
  186. long nStyleIndex;
  187. long nSizeIndex;
  188. hr = _getIndex(pThemeStyle, bstrStyleDisplayName, &nStyleIndex, pThemeSize, bstrSizeDisplayName, &nSizeIndex);
  189. if (SUCCEEDED(hr))
  190. {
  191. TCHAR szData[10];
  192. wnsprintf(szData, ARRAYSIZE(szData), TEXT("%d"), nStyleIndex);
  193. DWORD cbSize = ((lstrlen(szData) + 1) * sizeof(szData[0]));
  194. hr = HrSHSetValue(m_hKeyScheme, NULL, SZ_REGVALUE_SELECTEDSTYLE, REG_SZ, (LPVOID) szData, cbSize);
  195. if (SUCCEEDED(hr))
  196. {
  197. TCHAR szData2[10];
  198. wnsprintf(szData2, ARRAYSIZE(szData2), TEXT("%d"), nSizeIndex);
  199. DWORD cbSize = ((lstrlen(szData2) + 1) * sizeof(szData2[0]));
  200. hr = HrSHSetValue(m_hKeyScheme, szData, SZ_REGVALUE_SELECTEDSIZE, REG_SZ, (LPVOID) szData2, cbSize);
  201. }
  202. }
  203. }
  204. pThemeSize->Release();
  205. }
  206. }
  207. pThemeStyle->Release();
  208. }
  209. return hr;
  210. }
  211. HRESULT LoadCurrentStyle(LPTSTR pszCurrentStyle, int cchSize)
  212. {
  213. HKEY hkey;
  214. HRESULT hr = HrRegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_APPEARANCE, 0, KEY_READ, &hkey);
  215. if (SUCCEEDED(hr))
  216. {
  217. DWORD dwSize = (DWORD)(cchSize * sizeof(pszCurrentStyle[0]));
  218. hr = HrRegQueryValueEx(hkey, REGSTR_KEY_CURRENT, NULL, NULL, (LPBYTE)pszCurrentStyle, &dwSize);
  219. RegCloseKey(hkey);
  220. }
  221. return hr;
  222. }
  223. // This function will do nothing if an upgrade isn't needed.
  224. HRESULT CAppearanceScheme::_InitReg(void)
  225. {
  226. HRESULT hr = S_OK;
  227. if (!m_hKeyScheme)
  228. {
  229. hr = HrRegOpenKeyEx(HKEY_CURRENT_USER, SZ_APPEARANCE_NEWSCHEMES, 0, (KEY_WRITE | KEY_READ), &m_hKeyScheme);
  230. if (SUCCEEDED(hr))
  231. {
  232. // We don't need to upgrade.
  233. }
  234. else
  235. {
  236. // Here is where we need to do the upgrade.
  237. hr = HrRegCreateKeyEx(HKEY_CURRENT_USER, SZ_APPEARANCE_NEWSCHEMES, 0, NULL, REG_OPTION_NON_VOLATILE,
  238. (KEY_WRITE | KEY_READ), NULL, &m_hKeyScheme, 0);
  239. if (SUCCEEDED(hr))
  240. {
  241. HKEY hKeyOld;
  242. hr = HrRegCreateKeyEx(HKEY_CURRENT_USER, SZ_APPEARANCE_SCHEMES, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hKeyOld, 0);
  243. if (SUCCEEDED(hr))
  244. {
  245. TCHAR szCurrentStyle[MAX_PATH];
  246. TCHAR szSchemeName[MAX_PATH];
  247. TCHAR szDefaultScheme[MAX_PATH];
  248. DWORD dwIndex = 0;
  249. // Load in the upgrade mappings.
  250. hr = LoadConversionMappings();
  251. LoadString(HINST_THISDLL, IDS_DEFAULT_APPEARANCES_SCHEME, szDefaultScheme, ARRAYSIZE(szDefaultScheme));
  252. hr = LoadCurrentStyle(szCurrentStyle, ARRAYSIZE(szCurrentStyle));
  253. if (FAILED(hr))
  254. {
  255. // This will fail if the user never changed the legacy "Appearance Scheme".
  256. LoadString(HINST_THISDLL, IDS_DEFAULT_APPEARANCES_SCHEME, szCurrentStyle, ARRAYSIZE(szCurrentStyle));
  257. hr = S_OK;
  258. }
  259. // Now let's walk thru each one and convert it.
  260. while (SUCCEEDED(hr))
  261. {
  262. DWORD dwType;
  263. DWORD cbSize = sizeof(szSchemeName);
  264. hr = HrRegEnumValue(hKeyOld, dwIndex, szSchemeName, &cbSize, NULL, &dwType, NULL, NULL);
  265. if (SUCCEEDED(hr) && (REG_BINARY == dwType))
  266. {
  267. BOOL fSetAsDefault = !StrCmpI(szCurrentStyle, szSchemeName);
  268. SYSTEMMETRICSALL state = {0};
  269. hr = Look_GetSchemeData(hKeyOld, szSchemeName, &state.schemeData);
  270. if (SUCCEEDED(hr))
  271. {
  272. state.schemeData.rgb[COLOR_MENUBAR] = state.schemeData.rgb[COLOR_MENU];
  273. state.schemeData.rgb[COLOR_MENUHILIGHT] = state.schemeData.rgb[COLOR_MENUTEXT];
  274. // See if this is one of the shipping Appearance Schemes, so we want to create it
  275. // special.
  276. hr = _IsLegacyUpgradeConvert(szSchemeName, &state, fSetAsDefault);
  277. if (FAILED(hr))
  278. {
  279. // No, so we will upgrade it as a custom item.
  280. hr = _CustomConvert(szSchemeName, &state, fSetAsDefault, FALSE);
  281. }
  282. // On Upgrade, we need to copy "Windows Standard" to "Current Settings SaveNoVisualStyle".
  283. // That way, when the user toggles from "Professional VS" to "Windows Classic VS", we
  284. // load those colors as the first alternative to visual styles off. Win #151831
  285. if (!StrCmpI(szDefaultScheme, szSchemeName))
  286. {
  287. hr = _CustomConvert(SZ_SAVEGROUP_NOSKIN_TITLE, &state, FALSE, TRUE);
  288. }
  289. }
  290. }
  291. dwIndex++;
  292. }
  293. hr = S_OK;
  294. RegCloseKey(hKeyOld);
  295. }
  296. }
  297. }
  298. }
  299. return hr;
  300. }
  301. HRESULT CAppearanceScheme::_getStyleByIndex(IN long nIndex, OUT IThemeStyle ** ppThemeStyle)
  302. {
  303. HRESULT hr = _InitReg();
  304. if (SUCCEEDED(hr))
  305. {
  306. HKEY hKeyStyle;
  307. TCHAR szKeyName[MAXIMUM_SUB_KEY_LENGTH];
  308. wnsprintf(szKeyName, ARRAYSIZE(szKeyName), TEXT("%d"), nIndex);
  309. hr = HrRegOpenKeyEx(m_hKeyScheme, szKeyName, 0, (KEY_WRITE | KEY_READ), &hKeyStyle);
  310. if (SUCCEEDED(hr))
  311. {
  312. hr = CAppearanceStyle_CreateInstance(hKeyStyle, ppThemeStyle); // This function takes ownership of hKey
  313. if (FAILED(hr))
  314. {
  315. RegCloseKey(hKeyStyle);
  316. }
  317. }
  318. }
  319. return hr;
  320. }
  321. HRESULT CAppearanceScheme::_getCurrentSettings(IN LPCWSTR pszSettings, OUT IThemeStyle ** ppThemeStyle)
  322. {
  323. HRESULT hr = _InitReg();
  324. if (SUCCEEDED(hr))
  325. {
  326. WCHAR szRegValue[MAXIMUM_VALUE_NAME_LENGTH];
  327. HKEY hKeyStyle;
  328. StrCpyNW(szRegValue, SZ_REGVALUE_CURRENT_SETTINGS, ARRAYSIZE(szRegValue));
  329. StrCatBuffW(szRegValue, &pszSettings[2], ARRAYSIZE(szRegValue));
  330. hr = HrRegCreateKeyEx(m_hKeyScheme, szRegValue, 0, NULL, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_READ), NULL, &hKeyStyle, NULL);
  331. if (SUCCEEDED(hr))
  332. {
  333. hr = CAppearanceStyle_CreateInstance(hKeyStyle, ppThemeStyle); // This function takes ownership of hKey
  334. if (FAILED(hr))
  335. {
  336. RegCloseKey(hKeyStyle);
  337. }
  338. }
  339. }
  340. return hr;
  341. }
  342. //===========================
  343. // *** ITheme Interface ***
  344. //===========================
  345. HRESULT CAppearanceScheme::get_DisplayName(OUT BSTR * pbstrDisplayName)
  346. {
  347. WCHAR szDisplayName[MAX_PATH];
  348. LoadString(HINST_THISDLL, IDS_NO_SKIN_DISPLAYNAME, szDisplayName, ARRAYSIZE(szDisplayName));
  349. return HrSysAllocStringW(szDisplayName, pbstrDisplayName);
  350. }
  351. HRESULT CAppearanceScheme::get_length(OUT long * pnLength)
  352. {
  353. HRESULT hr = E_INVALIDARG;
  354. if (pnLength)
  355. {
  356. *pnLength = 0;
  357. hr = _InitReg();
  358. if (SUCCEEDED(hr))
  359. {
  360. DWORD dwValues = 0;
  361. hr = HrRegQueryInfoKey(m_hKeyScheme, NULL, NULL, NULL, &dwValues, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  362. if (SUCCEEDED(hr))
  363. {
  364. HKEY hKeyTemp;
  365. if (SUCCEEDED(HrRegOpenKeyEx(m_hKeyScheme, SZ_REGVALUE_CURRENT_SETTINGS, 0, KEY_READ, &hKeyTemp)))
  366. {
  367. dwValues--; // We want to subtract one for the "Current Settings" key.
  368. RegCloseKey(hKeyTemp);
  369. }
  370. }
  371. *pnLength = (long) dwValues;
  372. }
  373. }
  374. return hr;
  375. }
  376. HRESULT CAppearanceScheme::get_item(IN VARIANT varIndex, OUT IThemeStyle ** ppThemeStyle)
  377. {
  378. HRESULT hr = E_INVALIDARG;
  379. if (ppThemeStyle)
  380. {
  381. long nCount = 0;
  382. get_length(&nCount);
  383. *ppThemeStyle = NULL;
  384. // This is sortof gross, but if we are passed a pointer to another variant, simply
  385. // update our copy here...
  386. if (varIndex.vt == (VT_BYREF | VT_VARIANT) && varIndex.pvarVal)
  387. varIndex = *(varIndex.pvarVal);
  388. switch (varIndex.vt)
  389. {
  390. case VT_I2:
  391. varIndex.lVal = (long)varIndex.iVal;
  392. // And fall through...
  393. case VT_I4:
  394. if ((varIndex.lVal >= 0) && (varIndex.lVal < nCount))
  395. {
  396. hr = _getStyleByIndex(varIndex.lVal, ppThemeStyle);
  397. }
  398. break;
  399. case VT_BSTR:
  400. if (varIndex.bstrVal)
  401. {
  402. if ((L':' == varIndex.bstrVal[0]) && (L':' == varIndex.bstrVal[1]))
  403. {
  404. // This is a "Custom" settings so look in that key.
  405. hr = _getCurrentSettings(varIndex.bstrVal, ppThemeStyle);
  406. }
  407. else
  408. {
  409. for (int nIndex = 0; FAILED(hr) && (nIndex < nCount); nIndex++)
  410. {
  411. IThemeStyle * pThemeStyle;
  412. if (SUCCEEDED(_getStyleByIndex(nIndex, &pThemeStyle)))
  413. {
  414. CComBSTR bstrDisplayName;
  415. if (SUCCEEDED(pThemeStyle->get_DisplayName(&bstrDisplayName)))
  416. {
  417. if (!StrCmpIW(bstrDisplayName, varIndex.bstrVal))
  418. {
  419. // They match, so this is the one.
  420. *ppThemeStyle = pThemeStyle;
  421. pThemeStyle = NULL;
  422. hr = S_OK;
  423. }
  424. }
  425. if (FAILED(hr))
  426. {
  427. if (bstrDisplayName)
  428. {
  429. bstrDisplayName.Empty();
  430. }
  431. if (SUCCEEDED(pThemeStyle->get_Name(&bstrDisplayName)))
  432. {
  433. if (!StrCmpIW(bstrDisplayName, varIndex.bstrVal))
  434. {
  435. // They match, so this is the one.
  436. *ppThemeStyle = pThemeStyle;
  437. pThemeStyle = NULL;
  438. hr = S_OK;
  439. }
  440. }
  441. }
  442. ATOMICRELEASE(pThemeStyle);
  443. }
  444. }
  445. }
  446. }
  447. break;
  448. default:
  449. hr = E_NOTIMPL;
  450. }
  451. }
  452. return hr;
  453. }
  454. HRESULT CAppearanceScheme::get_SelectedStyle(OUT IThemeStyle ** ppThemeStyle)
  455. {
  456. HRESULT hr = E_INVALIDARG;
  457. if (ppThemeStyle)
  458. {
  459. hr = _InitReg();
  460. if (SUCCEEDED(hr))
  461. {
  462. TCHAR szKeyName[MAXIMUM_SUB_KEY_LENGTH];
  463. DWORD cbSize = sizeof(szKeyName);
  464. *ppThemeStyle = NULL;
  465. hr = HrSHGetValue(m_hKeyScheme, NULL, SZ_REGVALUE_SELECTEDSTYLE, NULL, szKeyName, &cbSize);
  466. if (FAILED(hr))
  467. {
  468. // "21" is the Appearance Scheme of "Windows Classic".
  469. StrCpyN(szKeyName, TEXT("21"), ARRAYSIZE(szKeyName));
  470. hr = S_OK;
  471. }
  472. if (SUCCEEDED(hr))
  473. {
  474. HKEY hKeyStyle;
  475. // Let's find the next empty slot
  476. hr = HrRegOpenKeyEx(m_hKeyScheme, szKeyName, 0, (KEY_WRITE | KEY_READ), &hKeyStyle);
  477. if (SUCCEEDED(hr))
  478. {
  479. hr = CAppearanceStyle_CreateInstance(hKeyStyle, ppThemeStyle); // This function takes ownership of hKeyStyle
  480. if (FAILED(hr))
  481. {
  482. RegCloseKey(hKeyStyle);
  483. }
  484. }
  485. }
  486. }
  487. }
  488. return hr;
  489. }
  490. HRESULT CAppearanceScheme::put_SelectedStyle(IN IThemeStyle * pThemeStyle)
  491. {
  492. HRESULT hr = E_INVALIDARG;
  493. if (pThemeStyle)
  494. {
  495. hr = _InitReg();
  496. if (SUCCEEDED(hr))
  497. {
  498. TCHAR szKeyName[MAXIMUM_SUB_KEY_LENGTH];
  499. CComBSTR bstrDisplayNameSource;
  500. hr = pThemeStyle->get_DisplayName(&bstrDisplayNameSource);
  501. if (SUCCEEDED(hr))
  502. {
  503. for (int nIndex = 0; SUCCEEDED(hr); nIndex++)
  504. {
  505. IThemeStyle * pThemeStyleInList;
  506. hr = _getStyleByIndex(nIndex, &pThemeStyleInList);
  507. if (SUCCEEDED(hr))
  508. {
  509. CComBSTR bstrDisplayName;
  510. hr = pThemeStyleInList->get_DisplayName(&bstrDisplayName);
  511. ATOMICRELEASE(pThemeStyleInList);
  512. if (SUCCEEDED(hr))
  513. {
  514. if (!StrCmpIW(bstrDisplayName, bstrDisplayNameSource))
  515. {
  516. // They match, so this is the one.
  517. wnsprintf(szKeyName, ARRAYSIZE(szKeyName), TEXT("%d"), nIndex);
  518. break;
  519. }
  520. }
  521. }
  522. }
  523. }
  524. if (SUCCEEDED(hr))
  525. {
  526. DWORD cbSize = ((lstrlen(szKeyName) + 1) * sizeof(szKeyName[0]));
  527. hr = HrSHSetValue(m_hKeyScheme, NULL, SZ_REGVALUE_SELECTEDSTYLE, REG_SZ, szKeyName, cbSize);
  528. }
  529. }
  530. }
  531. return hr;
  532. }
  533. HRESULT CAppearanceScheme::_AddStyle(IN LPCWSTR pszTitle, OUT IThemeStyle ** ppThemeStyle)
  534. {
  535. HRESULT hr = E_INVALIDARG;
  536. if (ppThemeStyle)
  537. {
  538. *ppThemeStyle = NULL;
  539. hr = _InitReg();
  540. if (SUCCEEDED(hr))
  541. {
  542. if (pszTitle)
  543. {
  544. HKEY hKeyStyle;
  545. hr = HrRegCreateKeyEx(m_hKeyScheme, pszTitle, 0, NULL, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_READ), NULL, &hKeyStyle, NULL);
  546. if (SUCCEEDED(hr))
  547. {
  548. hr = CAppearanceStyle_CreateInstance(hKeyStyle, ppThemeStyle); // This function takes ownership of hKey
  549. if (FAILED(hr))
  550. {
  551. RegCloseKey(hKeyStyle);
  552. }
  553. }
  554. }
  555. else
  556. {
  557. // Find an empty Scheme Name.
  558. for (int nIndex = 0; nIndex < 10000; nIndex++)
  559. {
  560. HKEY hKeyStyle;
  561. TCHAR szKeyName[MAXIMUM_SUB_KEY_LENGTH];
  562. wnsprintf(szKeyName, ARRAYSIZE(szKeyName), TEXT("%d"), nIndex);
  563. // Let's find the next empty spot
  564. hr = HrRegOpenKeyEx(m_hKeyScheme, szKeyName, 0, KEY_READ, &hKeyStyle);
  565. if (SUCCEEDED(hr))
  566. {
  567. RegCloseKey(hKeyStyle);
  568. }
  569. else
  570. {
  571. hr = HrRegCreateKeyEx(m_hKeyScheme, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_READ), NULL, &hKeyStyle, NULL);
  572. if (SUCCEEDED(hr))
  573. {
  574. hr = CAppearanceStyle_CreateInstance(hKeyStyle, ppThemeStyle); // This function takes ownership of hKey
  575. if (FAILED(hr))
  576. {
  577. RegCloseKey(hKeyStyle);
  578. }
  579. }
  580. break;
  581. }
  582. }
  583. }
  584. }
  585. }
  586. return hr;
  587. }
  588. //===========================
  589. // *** IUnknown Interface ***
  590. //===========================
  591. ULONG CAppearanceScheme::AddRef()
  592. {
  593. return InterlockedIncrement(&m_cRef);
  594. }
  595. ULONG CAppearanceScheme::Release()
  596. {
  597. if (InterlockedDecrement(&m_cRef))
  598. return m_cRef;
  599. delete this;
  600. return 0;
  601. }
  602. //===========================
  603. // *** Class Methods ***
  604. //===========================
  605. HRESULT CAppearanceScheme::QueryInterface(REFIID riid, void **ppvObj)
  606. {
  607. static const QITAB qit[] = {
  608. QITABENT(CAppearanceScheme, IPersist),
  609. QITABENT(CAppearanceScheme, IThemeScheme),
  610. QITABENT(CAppearanceScheme, IDispatch),
  611. { 0 },
  612. };
  613. return QISearch(this, qit, riid, ppvObj);
  614. }
  615. CAppearanceScheme::CAppearanceScheme(void) : CImpIDispatch(LIBID_Theme, 1, 0, IID_IThemeScheme), CObjectCLSID(&CLSID_LegacyAppearanceScheme), m_cRef(1)
  616. {
  617. DllAddRef();
  618. // This needs to be allocated in Zero Inited Memory.
  619. // Assert that all Member Variables are inited to Zero.
  620. ASSERT(!m_hKeyScheme);
  621. }
  622. CAppearanceScheme::~CAppearanceScheme()
  623. {
  624. if (m_hKeyScheme)
  625. {
  626. RegCloseKey(m_hKeyScheme);
  627. }
  628. DllRelease();
  629. }
  630. HRESULT CAppearanceScheme_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT LPVOID * ppvObj)
  631. {
  632. HRESULT hr = E_INVALIDARG;
  633. if (punkOuter)
  634. {
  635. return CLASS_E_NOAGGREGATION;
  636. }
  637. if (ppvObj)
  638. {
  639. CAppearanceScheme * pObject = new CAppearanceScheme();
  640. *ppvObj = NULL;
  641. if (pObject)
  642. {
  643. hr = pObject->QueryInterface(riid, ppvObj);
  644. pObject->Release();
  645. }
  646. else
  647. {
  648. hr = E_OUTOFMEMORY;
  649. }
  650. }
  651. return hr;
  652. }