/*****************************************************************************\ FILE: stgTheme.cpp DESCRIPTION: This is the Autmation Object to theme manager object. BryanSt 4/3/2000 (Bryan Starbuck) Copyright (C) Microsoft Corp 2000-2000. All rights reserved. \*****************************************************************************/ #include "priv.h" extern BOOL IsUserHighContrastUser(void); //=========================== // *** Class Internals & Helpers *** //=========================== // lParam can be: 0 == do a case sensitive search. 1 == do a case insensitive search. int DPA_StringCompareCB(LPVOID pvString1, LPVOID pvString2, LPARAM lParam) { // return < 0 for pvPidl1 before pvPidl2. // return == 0 for pvPidl1 equals pvPidl2. // return > 0 for pvPidl1 after pvPidl2. int nSort = 0; // Default to equal LPCTSTR pszToInsert = (LPCTSTR)pvString1; LPCTSTR pszToComparePath = (LPCTSTR)pvString2; if (pszToInsert && pszToComparePath) { LPCTSTR pszToCompareFileName = PathFindFileName(pszToComparePath); if (pszToCompareFileName) { nSort = StrCmp(pszToInsert, pszToCompareFileName); } } return nSort; } #define SZ_THEMES_FILTER TEXT("*.theme") #define SZ_ALL_FILTER TEXT("*.*") HRESULT CThemeManager::_AddThemesFromDir(LPCTSTR pszPath, BOOL fFirstLevel, int nInsertLoc) { HRESULT hr = S_OK; WIN32_FIND_DATA findFileData; TCHAR szSearch[MAX_PATH]; AssertMsg((nInsertLoc >= 0), TEXT("nInsertLoc should never be negative")); StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch)); PathAppend(szSearch, SZ_THEMES_FILTER); HANDLE hFindFiles = FindFirstFile(szSearch, &findFileData); if (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles)) { while (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles)) { if (!(FILE_ATTRIBUTE_DIRECTORY & findFileData.dwFileAttributes)) { StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch)); PathAppend(szSearch, findFileData.cFileName); LPWSTR pszPath = StrDup(szSearch); if (pszPath) { if (nInsertLoc) { if (-1 == DPA_InsertPtr(m_hdpaThemeDirs, nInsertLoc - 1, pszPath)) { // We failed so free the memory LocalFree(pszPath); hr = E_OUTOFMEMORY; } else { nInsertLoc++; } } else { if (-1 == DPA_SortedInsertPtr(m_hdpaThemeDirs, PathFindFileName(pszPath), 0, DPA_StringCompareCB, NULL, DPAS_INSERTBEFORE, pszPath)) { // We failed so free the memory LocalFree(pszPath); hr = E_OUTOFMEMORY; } } } } if (!FindNextFile(hFindFiles, &findFileData)) { break; } } FindClose(hFindFiles); } // We only want to recurse one directory. if (fFirstLevel) { StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch)); PathAppend(szSearch, SZ_ALL_FILTER); HANDLE hFindFiles = FindFirstFile(szSearch, &findFileData); if (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles)) { while (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles)) { // We are looking for any directories. Of course we exclude "." and "..". if ((FILE_ATTRIBUTE_DIRECTORY & findFileData.dwFileAttributes) && StrCmpI(findFileData.cFileName, TEXT(".")) && StrCmpI(findFileData.cFileName, TEXT(".."))) { StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch)); PathAppend(szSearch, findFileData.cFileName); _AddThemesFromDir(szSearch, FALSE, nInsertLoc); } if (!FindNextFile(hFindFiles, &findFileData)) { break; } } FindClose(hFindFiles); } } // We will want to repeat this process recursively for directories. At least // one level of recursively. return hr; } HRESULT CThemeManager::_InitThemeDirs(void) { HRESULT hr = S_OK; if (!m_hdpaThemeDirs) { if (SHRegGetBoolUSValue(SZ_THEMES, SZ_REGVALUE_ENABLEPLUSTHEMES, FALSE, TRUE)) { m_hdpaThemeDirs = DPA_Create(2); if (m_hdpaThemeDirs) { TCHAR szPath[MAX_PATH]; // The follwoing directories can contain themes: // Plus!98 Install Path\Themes // Plus!95 Install Path\Themes // Kids for Plus! Install Path\Themes // Program Files\Plus!\Themes if (SUCCEEDED(GetPlusThemeDir(szPath, ARRAYSIZE(szPath)))) { _AddThemesFromDir(szPath, TRUE, 0); } hr = SHGetResourcePath(TRUE, szPath, ARRAYSIZE(szPath)); if (SUCCEEDED(hr)) { _AddThemesFromDir(szPath, TRUE, 1); } if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_APPDATA, TRUE)) { PathAppend(szPath, TEXT("Microsoft\\Windows\\Themes")); _AddThemesFromDir(szPath, TRUE, 1); } if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_PERSONAL, TRUE)) { _AddThemesFromDir(szPath, TRUE, 1); } // Enum any paths 3rd parties add to the registry HKEY hKey; if (SUCCEEDED(HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_THEMES_THEMEDIRS, 0, KEY_READ, &hKey))) { for (int nDirIndex = 0; SUCCEEDED(hr); nDirIndex++) { TCHAR szValueName[MAXIMUM_VALUE_NAME_LENGTH]; DWORD cchSize = ARRAYSIZE(szValueName); DWORD dwType; DWORD cbSize = sizeof(szPath); hr = HrRegEnumValue(hKey, nDirIndex, szValueName, &cchSize, 0, &dwType, (LPBYTE)szPath, &cbSize); if (SUCCEEDED(hr)) { TCHAR szFinalPath[MAX_PATH]; if (0 == SHExpandEnvironmentStringsForUserW(NULL, szPath, szFinalPath, ARRAYSIZE(szFinalPath))) { StrCpyN(szFinalPath, szPath, ARRAYSIZE(szFinalPath)); } _AddThemesFromDir(szFinalPath, TRUE, 1); } } hr = S_OK; RegCloseKey(hKey); } } else { hr = E_OUTOFMEMORY; } } } return hr; } #define SZ_THEMES TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Themes") #define SZ_REGVALUE_REQUIRESIGNING TEXT("Require VisualStyle Signing") HRESULT CThemeManager::_EnumSkinCB(THEMECALLBACK tcbType, LPCWSTR pszFileName, OPTIONAL LPCWSTR pszDisplayName, OPTIONAL LPCWSTR pszToolTip, OPTIONAL int iIndex) { HRESULT hr = S_OK; // only signed theme files will be enumerated and passed to this function if (pszFileName) { LPWSTR pszPath = StrDup(pszFileName); AssertMsg((NULL != m_hdpaSkinDirs), TEXT("We should never hit this. We will leak. -BryanSt")); if (pszPath) { if (-1 == DPA_AppendPtr(m_hdpaSkinDirs, pszPath)) { // We failed so free the memory LocalFree(pszPath); } } } return hr; } BOOL CThemeManager::EnumSkinCB(THEMECALLBACK tcbType, LPCWSTR pszFileName, OPTIONAL LPCWSTR pszDisplayName, OPTIONAL LPCWSTR pszToolTip, OPTIONAL int iIndex, LPARAM lParam) { CThemeManager * pThis = (CThemeManager *) lParam; HRESULT hr = E_FAIL; if (pThis) { hr = pThis->_EnumSkinCB(tcbType, pszFileName, pszDisplayName, pszToolTip, iIndex); } return SUCCEEDED(hr); } HRESULT CThemeManager::_EnumSkinsFromKey(HKEY hKey) { HRESULT hr = S_OK; TCHAR szPath[MAX_PATH]; for (int nDirIndex = 0; SUCCEEDED(hr); nDirIndex++) { TCHAR szValueName[MAXIMUM_VALUE_NAME_LENGTH]; DWORD cchSize = ARRAYSIZE(szValueName); DWORD dwType; DWORD cbSize = sizeof(szPath); hr = HrRegEnumValue(hKey, nDirIndex, szValueName, &cchSize, 0, &dwType, (LPBYTE)szPath, &cbSize); if (SUCCEEDED(hr)) { hr = ExpandResourceDir(szPath, ARRAYSIZE(szPath)); if (SUCCEEDED(hr)) { hr = EnumThemes(szPath, CThemeManager::EnumSkinCB, (LPARAM) this); LogStatus("EnumThemes(path=\"%ls\") returned %#08lx in CThemeManager::_EnumSkinsFromKey.\r\n", szPath, hr); } } } return S_OK; } HRESULT CThemeManager::_InitSkinDirs(void) { HRESULT hr = S_OK; if (!m_hdpaSkinDirs) { m_hdpaSkinDirs = DPA_Create(2); if (m_hdpaSkinDirs) { // We only want to add skins if they are supported. They are only supported if the VisualStyle manager // can run. We will know that if QueryThemeServices() returns QTS_GLOBALAVAILABLE. BOOL fVisualStylesSupported = (QueryThemeServicesWrap() & QTS_AVAILABLE); LogStatus("QueryThemeServices() returned %hs in CThemeManager::_InitSkinDirs\r\n", (fVisualStylesSupported ? "TRUE" : "FALSE")); // Note that the VisualStyle's Manager API only works when explorer is running. This means we will // lack functionality, but it is their limitation, not ours. if (fVisualStylesSupported) { HKEY hNewKey; if (SUCCEEDED(HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_THEMES_MSTHEMEDIRS, 0, KEY_READ, &hNewKey))) { hr = _EnumSkinsFromKey(hNewKey); RegCloseKey(hNewKey); } if (SUCCEEDED(HrRegOpenKeyEx(HKEY_CURRENT_USER, SZ_THEMES_MSTHEMEDIRS, 0, KEY_READ, &hNewKey))) { hr = _EnumSkinsFromKey(hNewKey); RegCloseKey(hNewKey); } } } else { hr = E_OUTOFMEMORY; } } return hr; } HRESULT CThemeManager::_InitSelectedThemeFile(void) { HRESULT hr = E_INVALIDARG; if (!_pszSelectTheme) { WCHAR szPath[MAX_PATH]; DWORD dwError = SHRegGetPathW(HKEY_CURRENT_USER, SZ_REGKEY_CURRENT_THEME, NULL, szPath, 0); hr = HRESULT_FROM_WIN32(dwError); // Is this the "'s Custom Theme" item? // Or did it fail? If it failed, then no theme is selected. if (SUCCEEDED(hr)) { Str_SetPtr(&_pszSelectTheme, szPath); hr = S_OK; } } return hr; } HRESULT CThemeManager::_SetSelectedThemeEntree(LPCWSTR pszPath) { HRESULT hr = E_INVALIDARG; Str_SetPtr(&_pszSelectTheme, pszPath); if (pszPath) { hr = HrRegSetPath(HKEY_CURRENT_USER, SZ_REGKEY_CURRENT_THEME, NULL, TRUE, pszPath); } else { hr = HrRegDeleteValue(HKEY_CURRENT_USER, SZ_REGKEY_CURRENT_THEME, NULL); } return hr; } //=========================== // *** IThemeManager Interface *** //=========================== HRESULT CThemeManager::get_SelectedTheme(OUT ITheme ** ppTheme) { HRESULT hr = E_INVALIDARG; if (ppTheme) { *ppTheme = NULL; if (IsSafeHost(&hr)) { // In the future, we may want to call into PPID_Theme's IPropertyBag // to find the current visual style. This will factor in "(Modified)" // themes. hr = _InitSelectedThemeFile(); if (SUCCEEDED(hr)) { hr = CThemeFile_CreateInstance(_pszSelectTheme, ppTheme); } } } return hr; } /*****************************************************************************\ DESCRIPTION: Don't forget that this change is not applied until ::ApplyNow() is called. \*****************************************************************************/ HRESULT CThemeManager::put_SelectedTheme(IN ITheme * pTheme) { HRESULT hr = E_INVALIDARG; if (IsSafeHost(&hr)) { CComBSTR bstrPath; if (pTheme) { // Persist the filename to the registry. hr = pTheme->GetPath(VARIANT_TRUE, &bstrPath); } if (SUCCEEDED(hr)) { IPropertyBag * pPropertyBag; hr = _GetPropertyBagByCLSID(&PPID_Theme, &pPropertyBag); if (SUCCEEDED(hr)) { hr = SHPropertyBag_WriteStr(pPropertyBag, SZ_PBPROP_THEME_LOADTHEME, bstrPath); pPropertyBag->Release(); } } } return hr; } HRESULT CThemeManager::get_WebviewCSS(OUT BSTR * pbstrPath) { HRESULT hr = E_INVALIDARG; if (pbstrPath) { *pbstrPath = NULL; if (IsHostLocalZone(CAS_REG_VALIDATION, &hr)) { IThemeScheme * pThemeScheme; hr = _saveGetSelectedScheme(&pThemeScheme); if (SUCCEEDED(hr)) { IThemeStyle * pThemeStyle; hr = pThemeScheme->get_SelectedStyle(&pThemeStyle); if (SUCCEEDED(hr)) { IThemeSize * pThemeSize; hr = pThemeStyle->get_SelectedSize(&pThemeSize); if (SUCCEEDED(hr)) { hr = pThemeSize->get_WebviewCSS(pbstrPath); pThemeSize->Release(); } pThemeStyle->Release(); } pThemeScheme->Release(); } } } return hr; } HRESULT CThemeManager::get_length(OUT long * pnLength) { HRESULT hr = E_INVALIDARG; if (pnLength) { *pnLength = 0; if (IsSafeHost(&hr)) { hr = _InitThemeDirs(); if (SUCCEEDED(hr)) { if (m_hdpaThemeDirs) { *pnLength += DPA_GetPtrCount(m_hdpaThemeDirs); } } } } return hr; } HRESULT CThemeManager::get_item(IN VARIANT varIndex, OUT ITheme ** ppTheme) { HRESULT hr = E_INVALIDARG; if (ppTheme) { *ppTheme = NULL; if (IsSafeHost(&hr)) { long nCount = 0; hr = E_INVALIDARG; get_length(&nCount); // This is sortof gross, but if we are passed a pointer to another variant, simply // update our copy here... if (varIndex.vt == (VT_BYREF | VT_VARIANT) && varIndex.pvarVal) varIndex = *(varIndex.pvarVal); switch (varIndex.vt) { case VT_I2: varIndex.lVal = (long)varIndex.iVal; // And fall through... case VT_I4: if ((varIndex.lVal >= 0) && (varIndex.lVal < nCount)) { if (m_hdpaThemeDirs) { LPWSTR pszFilename = (LPWSTR) DPA_GetPtr(m_hdpaThemeDirs, varIndex.lVal); if (pszFilename) { hr = CThemeFile_CreateInstance(pszFilename, ppTheme); } else { hr = E_FAIL; } } else { AssertMsg(0, TEXT("This should have been initiailized by get_Length(). -BryanSt")); hr = E_FAIL; } } break; case VT_BSTR: if (varIndex.bstrVal) { hr = CThemeFile_CreateInstance(varIndex.bstrVal, ppTheme); } else { hr = E_INVALIDARG; } break; default: hr = E_NOTIMPL; } } } return hr; } HRESULT CThemeManager::get_SelectedScheme(OUT IThemeScheme ** ppThemeScheme) { HRESULT hr = E_INVALIDARG; if (ppThemeScheme) { *ppThemeScheme = NULL; if (IsSafeHost(&hr)) { if (!_pThemeSchemeSelected) { hr = _saveGetSelectedScheme(&_pThemeSchemeSelected); } if (_pThemeSchemeSelected) { IUnknown_Set((IUnknown **) ppThemeScheme, _pThemeSchemeSelected); hr = S_OK; } } } return hr; } HRESULT CThemeManager::_saveGetSelectedScheme(OUT IThemeScheme ** ppThemeScheme) { HRESULT hr = E_INVALIDARG; if (ppThemeScheme) { *ppThemeScheme = NULL; BOOL fIsThemeActive = IsThemeActive(); LogStatus("IsThemeActive() returned %hs in CThemeManager::_saveGetSelectedScheme.\r\n", (fIsThemeActive ? "TRUE" : "FALSE")); // The selected Scheme can either be a legacy "Appearance Scheme" or // a selected ".msstyles" (skin) file. if (fIsThemeActive) { WCHAR szPath[MAX_PATH]; hr = GetCurrentThemeName(szPath, ARRAYSIZE(szPath), NULL, 0, NULL, 0); LogStatus("GetCurrentThemeName(path=\"%ls\", color=\"%ls\", size=\"%ls\") returned %#08lx in CThemeManager::_saveGetSelectedScheme.\r\n", szPath, TEXT("NULL"), TEXT("NULL"), hr); if (SUCCEEDED(hr)) { hr = CSkinScheme_CreateInstance(szPath, ppThemeScheme); } // Currently, we create this object and get the size // in order to force an upgrade in case it's neccessary. IThemeScheme * pThemeSchemeTemp; if (SUCCEEDED(CAppearanceScheme_CreateInstance(NULL, IID_PPV_ARG(IThemeScheme, &pThemeSchemeTemp)))) { long nLength; pThemeSchemeTemp->get_length(&nLength); pThemeSchemeTemp->Release(); } } // We want to get the Appearance scheme if no visual style is selected (i.e. IsThemeActive() returns FALSE). // However, if uxtheme gets confused, IsThemeActive() will return TRUE but GetCurrentThemeName() will fail. // in that case, we want to also fallback to the classic visual style so the UI is usable. if (FAILED(hr)) { // The "Control Panel\\Appearance","Current" key will indicate the selected // Appearance Scheme. hr = CAppearanceScheme_CreateInstance(NULL, IID_PPV_ARG(IThemeScheme, ppThemeScheme)); } } return hr; } /*****************************************************************************\ DESCRIPTION: Don't forget that this change is not applied until ::ApplyNow() is called. \*****************************************************************************/ HRESULT CThemeManager::put_SelectedScheme(IN IThemeScheme * pThemeScheme) { HRESULT hr; if (IsSafeHost(&hr)) { if (pThemeScheme) { CComBSTR bstrPath; IThemeStyle * pThemeStyle; IUnknown_Set((IUnknown **) &_pThemeSchemeSelected, pThemeScheme); pThemeScheme->get_Path(&bstrPath); // It's fine if it returns NULL or empty str. hr = pThemeScheme->get_SelectedStyle(&pThemeStyle); if (SUCCEEDED(hr)) { CComBSTR bstrStyle; hr = pThemeStyle->get_Name(&bstrStyle); if (SUCCEEDED(hr)) { IThemeSize * pThemeSize; hr = pThemeStyle->get_SelectedSize(&pThemeSize); if (SUCCEEDED(hr)) { CComBSTR bstrSize; hr = pThemeSize->get_Name(&bstrSize); if (SUCCEEDED(hr)) { VARIANT variant; variant.vt = VT_BSTR; variant.bstrVal = bstrPath; hr = Write(SZ_PBPROP_VISUALSTYLE_PATH, &variant); if (SUCCEEDED(hr)) { variant.bstrVal = bstrStyle; hr = Write(SZ_PBPROP_VISUALSTYLE_COLOR, &variant); if (SUCCEEDED(hr)) { variant.bstrVal = bstrSize; hr = Write(SZ_PBPROP_VISUALSTYLE_SIZE, &variant); } } } pThemeSize->Release(); } } pThemeStyle->Release(); } } else { hr = E_INVALIDARG; } } return hr; } HRESULT CThemeManager::get_schemeLength(OUT long * pnLength) { HRESULT hr = E_INVALIDARG; if (pnLength) { *pnLength = 1; if (IsSafeHost(&hr)) { hr = _InitSkinDirs(); if (SUCCEEDED(hr)) { if (m_hdpaSkinDirs) { *pnLength += DPA_GetPtrCount(m_hdpaSkinDirs); } } } } return hr; } HRESULT CThemeManager::get_schemeItem(IN VARIANT varIndex, OUT IThemeScheme ** ppThemeScheme) { HRESULT hr = E_INVALIDARG; if (ppThemeScheme) { if (IsSafeHost(&hr)) { long nCount = 0; hr = E_INVALIDARG; get_schemeLength(&nCount); *ppThemeScheme = NULL; // This is sortof gross, but if we are passed a pointer to another variant, simply // update our copy here... if (varIndex.vt == (VT_BYREF | VT_VARIANT) && varIndex.pvarVal) varIndex = *(varIndex.pvarVal); switch (varIndex.vt) { case VT_I2: varIndex.lVal = (long)varIndex.iVal; // And fall through... case VT_I4: if ((varIndex.lVal >= 0) && (varIndex.lVal < nCount)) { if (0 == varIndex.lVal) { // 0 is the Appearance scheme, which means there isn't a skin. // This is the same as the legacy Appeanance tab. hr = CAppearanceScheme_CreateInstance(NULL, IID_PPV_ARG(IThemeScheme, ppThemeScheme)); } else { if (m_hdpaSkinDirs) { LPWSTR pszFilename = (LPWSTR) DPA_GetPtr(m_hdpaSkinDirs, varIndex.lVal-1); if (pszFilename) { hr = CSkinScheme_CreateInstance(pszFilename, ppThemeScheme); } else { hr = E_FAIL; } } else { AssertMsg(0, TEXT("This should have been initiailized by get_schemeLength(). -BryanSt")); hr = E_FAIL; } } } break; case VT_BSTR: if (varIndex.bstrVal && varIndex.bstrVal[0] && !StrCmpI(PathFindExtension(varIndex.bstrVal), TEXT(".msstyles"))) { hr = CSkinScheme_CreateInstance(varIndex.bstrVal, ppThemeScheme); } else { hr = CAppearanceScheme_CreateInstance(NULL, IID_PPV_ARG(IThemeScheme, ppThemeScheme)); } break; default: hr = E_NOTIMPL; } } } return hr; } HRESULT CThemeManager::GetSelectedSchemeProperty(IN BSTR bstrName, OUT BSTR * pbstrValue) { HRESULT hr = E_INVALIDARG; if (bstrName && pbstrValue) { *pbstrValue = NULL; if (IsSafeHost(&hr)) { TCHAR szPath[MAX_PATH]; TCHAR szColor[MAX_PATH]; TCHAR szSize[MAX_PATH]; BOOL fIsThemeActive = IsThemeActive(); LogStatus("IsThemeActive() returned %hs in CThemeManager::GetSelectedSchemeProperty.\r\n", (fIsThemeActive ? "TRUE" : "FALSE")); szPath[0] = 0; szColor[0] = 0; szSize[0] = 0; if (fIsThemeActive) { hr = GetCurrentThemeName(szPath, ARRAYSIZE(szPath), szColor, ARRAYSIZE(szColor), szSize, ARRAYSIZE(szSize)); LogStatus("GetCurrentThemeName() returned %#08lx in CThemeManager::GetSelectedSchemeProperty.\r\n", hr); } if (SUCCEEDED(hr)) { if (!StrCmpI(bstrName, SZ_CSP_PATH)) { PathRemoveFileSpec(szPath); hr = HrSysAllocString(szPath, pbstrValue); } else if (!StrCmpI(bstrName, SZ_CSP_FILE)) { hr = HrSysAllocString(szPath, pbstrValue); } else if (!StrCmpI(bstrName, SZ_CSP_DISPLAYNAME)) { if (szPath[0]) { hr = GetThemeDocumentationProperty(szPath, SZ_THDOCPROP_DISPLAYNAME, szPath, ARRAYSIZE(szPath)); LogStatus("GetThemeDocumentationProperty() returned %#08lx in CThemeManager::GetSelectedSchemeProperty.\r\n", hr); } if (SUCCEEDED(hr)) { hr = HrSysAllocString(szPath, pbstrValue); } } else if (!StrCmpI(bstrName, SZ_CSP_CANONICALNAME)) { if (szPath[0]) { hr = GetThemeDocumentationProperty(szPath, SZ_THDOCPROP_CANONICALNAME, szPath, ARRAYSIZE(szPath)); LogStatus("GetThemeDocumentationProperty() returned %#08lx in CThemeManager::GetSelectedSchemeProperty.\r\n", hr); } if (SUCCEEDED(hr)) { hr = HrSysAllocString(szPath, pbstrValue); } } else if (!StrCmpI(bstrName, SZ_CSP_COLOR)) { hr = HrSysAllocString(szColor, pbstrValue); } else if (!StrCmpI(bstrName, SZ_CSP_SIZE)) { hr = HrSysAllocString(szSize, pbstrValue); } } } } return hr; } HRESULT CThemeManager::GetSpecialTheme(IN BSTR bstrName, OUT ITheme ** ppTheme) { HRESULT hr = E_INVALIDARG; if (bstrName && ppTheme) { *ppTheme = NULL; if (IsSafeHost(&hr)) { if (!StrCmpI(SZ_STDEFAULTTHEME, bstrName)) { TCHAR szPath[MAX_PATH]; hr = HrRegGetPath(HKEY_CURRENT_USER, SZ_THEMES, SZ_REGVALUE_INSTALL_THEME, szPath, ARRAYSIZE(szPath)); if (SUCCEEDED(hr)) { ExpandResourceDir(szPath, ARRAYSIZE(szPath)); hr = CThemeFile_CreateInstance(szPath, ppTheme); } } } } return hr; } HRESULT CThemeManager::SetSpecialTheme(IN BSTR bstrName, IN ITheme * pTheme) { HRESULT hr = E_INVALIDARG; if (bstrName) { if (IsSafeHost(&hr)) { if (!StrCmpI(SZ_STDEFAULTTHEME, bstrName)) { CComBSTR bstrPath; if (pTheme) { hr = pTheme->GetPath(VARIANT_TRUE, &bstrPath); } else { bstrPath = L""; // This means use "Windows Classic". } if (bstrPath) { hr = HrRegSetPath(HKEY_CURRENT_USER, SZ_THEMES, SZ_REGVALUE_INSTALL_THEME, TRUE, bstrPath); } } } } return hr; } HRESULT CThemeManager::GetSpecialScheme(IN BSTR bstrName, OUT IThemeScheme ** ppThemeScheme, OUT IThemeStyle ** ppThemeStyle, OUT IThemeSize ** ppThemeSize) { HRESULT hr = E_INVALIDARG; if (bstrName && ppThemeScheme && ppThemeStyle && ppThemeSize) { *ppThemeScheme = NULL; *ppThemeStyle = NULL; *ppThemeSize = NULL; TCHAR szVisualStylePath[MAX_PATH]; DWORD dwType; DWORD cbSize = sizeof(szVisualStylePath); // Is a SetVisualStyle policy is set, don't honor this call if (ERROR_SUCCESS == SHRegGetUSValue(SZ_REGKEY_POLICIES_SYSTEM, SZ_REGVALUE_POLICY_SETVISUALSTYLE, &dwType, (void *) szVisualStylePath, &cbSize, FALSE, NULL, 0) || IsUserHighContrastUser()) { hr = E_ACCESSDENIED; // Don't mess with visual styles when SetVisualStyle is enforced or high contrast is on } else if(IsSafeHost(&hr)) { if (!StrCmpI(SZ_SSDEFAULVISUALSTYLEON, bstrName) || !StrCmpI(SZ_SSDEFAULVISUALSTYLEOFF, bstrName)) { TCHAR szRegKey[MAX_PATH]; TCHAR szVisualStyle[MAX_PATH]; wnsprintf(szRegKey, ARRAYSIZE(szRegKey), TEXT("%s\\%s"), SZ_THEMES, bstrName); hr = HrRegGetPath(HKEY_CURRENT_USER, szRegKey, SZ_REGVALUE_INSTALL_VISUALSTYLE, szVisualStyle, ARRAYSIZE(szVisualStyle)); if (SUCCEEDED(hr)) { TCHAR szColorStyle[MAX_PATH]; ExpandResourceDir(szVisualStyle, ARRAYSIZE(szVisualStyle)); hr = HrRegGetValueString(HKEY_CURRENT_USER, szRegKey, SZ_REGVALUE_INSTALL_VSCOLOR, szColorStyle, ARRAYSIZE(szColorStyle)); if (SUCCEEDED(hr)) { TCHAR szSize[MAX_PATH]; hr = HrRegGetValueString(HKEY_CURRENT_USER, szRegKey, SZ_REGVALUE_INSTALL_VSSIZE, szSize, ARRAYSIZE(szSize)); if (SUCCEEDED(hr)) { CComVariant varIndex(szVisualStyle); hr = get_schemeItem(varIndex, ppThemeScheme); if (SUCCEEDED(hr)) { CComVariant varColorIndex(szColorStyle); hr = (*ppThemeScheme)->get_item(varColorIndex, ppThemeStyle); if (SUCCEEDED(hr)) { CComVariant varSizeIndex(szSize); hr = (*ppThemeStyle)->get_item(varSizeIndex, ppThemeSize); } } } } } if (FAILED(hr)) { // Return consistent results. ATOMICRELEASE(*ppThemeScheme); ATOMICRELEASE(*ppThemeStyle); ATOMICRELEASE(*ppThemeSize); } } } } return hr; } HRESULT CThemeManager::SetSpecialScheme(IN BSTR bstrName, IN IThemeScheme * pThemeScheme, IThemeStyle * pThemeStyle, IThemeSize * pThemeSize) { HRESULT hr = E_NOTIMPL; if (IsSafeHost(&hr)) { } return hr; } HRESULT CThemeManager::ApplyNow(void) { HRESULT hr = E_INVALIDARG; if (IsSafeHost(&hr)) { hr = ApplyPressed(TUIAP_NONE | TUIAP_WAITFORAPPLY); } return hr; }