windows-nt/Source/XPSP1/NT/shell/themes/themeui/stgtheme.cpp

1068 lines
32 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*****************************************************************************\
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 "<UserName>'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;
}