1409 lines
48 KiB
C++
1409 lines
48 KiB
C++
/*****************************************************************************\
|
|
FILE: ThemeFile.cpp
|
|
|
|
DESCRIPTION:
|
|
This is the Autmation Object to theme scheme object.
|
|
|
|
BryanSt 4/3/2000 (Bryan Starbuck)
|
|
Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
|
|
\*****************************************************************************/
|
|
|
|
#include "priv.h"
|
|
#include <atlbase.h>
|
|
#include <mmsystem.h>
|
|
#include "ThSettingsPg.h"
|
|
#include "ThemeFile.h"
|
|
|
|
|
|
|
|
LPCTSTR s_pszCursorArray[SIZE_CURSOR_ARRAY] =
|
|
{ // different cursors
|
|
TEXT("Arrow"),
|
|
TEXT("Help"),
|
|
TEXT("AppStarting"),
|
|
TEXT("Wait"),
|
|
TEXT("NWPen"),
|
|
TEXT("No"),
|
|
TEXT("SizeNS"),
|
|
TEXT("SizeWE"),
|
|
TEXT("Crosshair"),
|
|
TEXT("IBeam"),
|
|
TEXT("SizeNWSE"),
|
|
TEXT("SizeNESW"),
|
|
TEXT("SizeAll"),
|
|
TEXT("UpArrow"),
|
|
TEXT("Link"),
|
|
};
|
|
|
|
|
|
// This is a list of string pairs. The first string in the pair is the RegKey and the second is the default sound.
|
|
// NULL means to delete the key. If you use an environment string other than "%SystemRoot%", you need to
|
|
// update _ApplySounds();
|
|
#define SOUND_DEFAULT (UINT)-1
|
|
|
|
THEME_FALLBACK_VALUES s_ThemeSoundsValues[SIZE_SOUNDS_ARRAY] =
|
|
{
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\.Default\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\AppGPFault\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\Close\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\DeviceConnect\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\DeviceDisconnect\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\DeviceFail\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\LowBatteryAlarm\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\MailBeep\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\Maximize\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\MenuCommand\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\MenuPopup\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\Minimize\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\Open\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\PrintComplete\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\RestoreDown\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\RestoreUp\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\RingIn\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\Ringout\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\SystemAsterisk\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\SystemExclamation\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\SystemExit\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\SystemHand\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\SystemNotification\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\SystemQuestion\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\SystemStart\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\SystemStartMenu\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\WindowsLogoff\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\.Default\\WindowsLogon\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\Explorer\\EmptyRecycleBin\\.Current"), SOUND_DEFAULT},
|
|
{TEXT("AppEvents\\Schemes\\Apps\\Explorer\\Navigating\\.Current"), SOUND_DEFAULT},
|
|
};
|
|
|
|
|
|
|
|
//===========================
|
|
// *** Class Internals & Helpers ***
|
|
//===========================
|
|
BOOL CThemeFile::_IsCached(IN BOOL fLoading)
|
|
{
|
|
DWORD dwCache = 0;
|
|
|
|
dwCache |= _IsFiltered(THEMEFILTER_COLORS);
|
|
dwCache |= _IsFiltered(THEMEFILTER_SMSTYLES) << 1;
|
|
dwCache |= _IsFiltered(THEMEFILTER_SMSIZES) << 2;
|
|
|
|
BOOL fIsCached = (dwCache == m_dwCachedState);
|
|
if (fLoading)
|
|
{
|
|
m_dwCachedState = dwCache;
|
|
}
|
|
|
|
return fIsCached;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_GetCustomFont(LPCTSTR pszFontName, LOGFONT * pLogFont)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR szFont[MAX_PATH];
|
|
|
|
if (GetPrivateProfileString(SZ_INISECTION_METRICS, pszFontName, SZ_EMPTY, szFont, ARRAYSIZE(szFont), m_pszThemeFile) &&
|
|
szFont[0])
|
|
{
|
|
if (TEXT('@') == szFont[0]) // Is the string indirect for MUI?
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
if (SUCCEEDED(SHLoadIndirectString(szFont, szTemp, ARRAYSIZE(szTemp), NULL)))
|
|
{
|
|
StrCpyN(szFont, szTemp, ARRAYSIZE(szFont));
|
|
}
|
|
}
|
|
|
|
if (TEXT('{') == szFont[0])
|
|
{
|
|
LPTSTR pszStart = &szFont[1];
|
|
BOOL fHasMore = TRUE;
|
|
|
|
LPTSTR pszEnd = StrChr(pszStart, TEXT(','));
|
|
if (!pszEnd)
|
|
{
|
|
pszEnd = StrChr(pszStart, TEXT('}'));
|
|
fHasMore = FALSE;
|
|
}
|
|
|
|
if (pszEnd)
|
|
{
|
|
pszEnd[0] = 0; // Terminate Name.
|
|
|
|
StrCpyN(pLogFont->lfFaceName, pszStart, ARRAYSIZE(pLogFont->lfFaceName));
|
|
if (fHasMore)
|
|
{
|
|
pszStart = &pszEnd[1];
|
|
pszEnd = StrStr(pszStart, TEXT("pt"));
|
|
if (pszEnd)
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
pszEnd[0] = 0; // Terminate Name.
|
|
pszEnd += 2; // Skip past the "pt"
|
|
|
|
StrCpyN(szTemp, pszStart, ARRAYSIZE(szTemp));
|
|
PathRemoveBlanks(szTemp);
|
|
|
|
pLogFont->lfHeight = -MulDiv(StrToInt(szTemp), DPI_PERSISTED, 72); // Map pt size to lfHeight
|
|
pLogFont->lfHeight = min(-3, pLogFont->lfHeight); // Make sure the font doesn't get too small
|
|
pLogFont->lfHeight = max(-100, pLogFont->lfHeight); // Make sure the font doesn't get too large
|
|
if (TEXT(',') == pszEnd[0])
|
|
{
|
|
pszStart = &pszEnd[1];
|
|
pszEnd = StrChr(pszStart, TEXT('}'));
|
|
if (pszEnd)
|
|
{
|
|
pszEnd[0] = 0; // Terminate Name.
|
|
|
|
pLogFont->lfCharSet = (BYTE) StrToInt(pszStart);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_LoadCustomFonts(void)
|
|
{
|
|
_GetCustomFont(TEXT("CaptionFont"), &(m_systemMetrics.schemeData.ncm.lfCaptionFont));
|
|
_GetCustomFont(TEXT("SmCaptionFont"), &(m_systemMetrics.schemeData.ncm.lfSmCaptionFont));
|
|
_GetCustomFont(TEXT("MenuFont"), &(m_systemMetrics.schemeData.ncm.lfMenuFont));
|
|
_GetCustomFont(TEXT("StatusFont"), &(m_systemMetrics.schemeData.ncm.lfStatusFont));
|
|
_GetCustomFont(TEXT("MessageFont"), &(m_systemMetrics.schemeData.ncm.lfMessageFont));
|
|
_GetCustomFont(TEXT("IconFont"), &(m_systemMetrics.schemeData.lfIconTitle));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// Load the settings in memory
|
|
HRESULT CThemeFile::_LoadLiveSettings(int * pnDPI)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pszThemeFile)
|
|
{
|
|
if (pnDPI)
|
|
{
|
|
*pnDPI = DPI_PERSISTED;
|
|
}
|
|
|
|
// Get property bag with default settings.
|
|
if (_punkSite)
|
|
{
|
|
IPropertyBag * pPropertyBag;
|
|
|
|
hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHPropertyBag_ReadByRef(pPropertyBag, SZ_PBPROP_SYSTEM_METRICS, (void *)&m_systemMetrics, sizeof(m_systemMetrics));
|
|
|
|
if (pnDPI && FAILED(SHPropertyBag_ReadInt(pPropertyBag, SZ_PBPROP_DPI_MODIFIED_VALUE, pnDPI)))
|
|
{
|
|
*pnDPI = DPI_PERSISTED; // Default to the default DPI.
|
|
}
|
|
pPropertyBag->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Load the settings in the .theme file.
|
|
HRESULT CThemeFile::_LoadSettings(void)
|
|
{
|
|
int nCurrentDPI = DPI_PERSISTED;
|
|
HRESULT hr = _LoadLiveSettings(&nCurrentDPI);
|
|
|
|
if (m_pszThemeFile)
|
|
{
|
|
BOOL fFontsFilter = _IsFiltered(THEMEFILTER_SMSTYLES);
|
|
TCHAR szIconMetrics[2048];
|
|
|
|
if (m_systemMetrics.nIcon && m_systemMetrics.nSmallIcon)
|
|
{
|
|
////////////////////////////////////////////
|
|
// Get the icon Metrics
|
|
DWORD cchSize = GetPrivateProfileString(SZ_INISECTION_METRICS, SZ_INIKEY_ICONMETRICS, SZ_EMPTY, szIconMetrics, ARRAYSIZE(szIconMetrics), m_pszThemeFile);
|
|
// if we somehow come up with no icon metrics in the theme, just
|
|
// PUNT and leave cur settings
|
|
if (szIconMetrics[0])
|
|
{ // if something there to set
|
|
ICONMETRICSA iconMetricsA;
|
|
|
|
// translate stored data string to ICONMETRICS bytes
|
|
if ((sizeof(iconMetricsA) == WriteBytesToBuffer(szIconMetrics, (void *)&iconMetricsA, sizeof(iconMetricsA))) && // char str read from and binary bytes
|
|
(sizeof(iconMetricsA) == iconMetricsA.cbSize))
|
|
{
|
|
// ICONMETRICS are stored in ANSI format in the Theme file so if
|
|
// we're living in a UNICODE world we need to convert from ANSI
|
|
// to UNICODE
|
|
ICONMETRICSW iconMetricsW;
|
|
|
|
if (!fFontsFilter)
|
|
{
|
|
ConvertIconMetricsToWIDE(&iconMetricsA, &iconMetricsW);
|
|
m_systemMetrics.schemeData.lfIconTitle = iconMetricsW.lfFont;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////
|
|
// Get Non-Client Metrics
|
|
cchSize = GetPrivateProfileString(SZ_INISECTION_METRICS, SZ_INIKEY_NONCLIENTMETRICS, SZ_EMPTY, szIconMetrics, ARRAYSIZE(szIconMetrics), m_pszThemeFile);
|
|
// if we somehow come up with no icon metrics in the theme, just
|
|
// PUNT and leave cur settings
|
|
if (szIconMetrics[0])
|
|
{
|
|
BOOL fBordersFilter = _IsFiltered(THEMEFILTER_SMSIZES);
|
|
NONCLIENTMETRICSA nonClientMetrics;
|
|
|
|
// if something there to set
|
|
// translate stored data string to ICONMETRICS bytes
|
|
if ((sizeof(nonClientMetrics) == WriteBytesToBuffer(szIconMetrics, (void *)&nonClientMetrics, sizeof(nonClientMetrics))) && // char str read from and binary bytes
|
|
(sizeof(nonClientMetrics) == nonClientMetrics.cbSize))
|
|
{
|
|
// ICONMETRICS are stored in ANSI format in the Theme file so if
|
|
// we're living in a UNICODE world we need to convert from ANSI
|
|
// to UNICODE
|
|
NONCLIENTMETRICSW nonClientMetricsW = {0};
|
|
|
|
ConvertNCMetricsToWIDE(&nonClientMetrics, &nonClientMetricsW);
|
|
nonClientMetricsW.cbSize = sizeof(nonClientMetricsW); // paranoid
|
|
|
|
// what we reset if the user checks Font names and styles
|
|
if (!fFontsFilter)
|
|
{
|
|
// only (some) font information
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfCaptionFont), &(nonClientMetricsW.lfCaptionFont), TFC_STYLE);
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfSmCaptionFont), &(nonClientMetricsW.lfSmCaptionFont), TFC_STYLE);
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfMenuFont), &(nonClientMetricsW.lfMenuFont), TFC_STYLE);
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfStatusFont), &(nonClientMetricsW.lfStatusFont), TFC_STYLE);
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfMessageFont), &(nonClientMetricsW.lfMessageFont), TFC_STYLE);
|
|
}
|
|
|
|
// what we reset if the user checks Font and window si&zes
|
|
if (!fBordersFilter)
|
|
{
|
|
// fonts
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfCaptionFont), &(nonClientMetricsW.lfCaptionFont), TFC_SIZE);
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfSmCaptionFont), &(nonClientMetricsW.lfSmCaptionFont), TFC_SIZE);
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfMenuFont), &(nonClientMetricsW.lfMenuFont), TFC_SIZE);
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfStatusFont), &(nonClientMetricsW.lfStatusFont), TFC_SIZE);
|
|
TransmitFontCharacteristics(&(m_systemMetrics.schemeData.ncm.lfMessageFont), &(nonClientMetricsW.lfMessageFont), TFC_SIZE);
|
|
|
|
// Since we are copying the font sizes, scale them to the current DPI.
|
|
// window elements sizes
|
|
m_systemMetrics.schemeData.ncm.iBorderWidth = nonClientMetricsW.iBorderWidth;
|
|
m_systemMetrics.schemeData.ncm.iScrollWidth = nonClientMetricsW.iScrollWidth;
|
|
m_systemMetrics.schemeData.ncm.iScrollHeight = nonClientMetricsW.iScrollHeight;
|
|
m_systemMetrics.schemeData.ncm.iCaptionWidth = nonClientMetricsW.iCaptionWidth;
|
|
m_systemMetrics.schemeData.ncm.iCaptionHeight = nonClientMetricsW.iCaptionHeight;
|
|
m_systemMetrics.schemeData.ncm.iSmCaptionWidth = nonClientMetricsW.iSmCaptionWidth;
|
|
m_systemMetrics.schemeData.ncm.iSmCaptionHeight = nonClientMetricsW.iSmCaptionHeight;
|
|
m_systemMetrics.schemeData.ncm.iMenuWidth = nonClientMetricsW.iMenuWidth;
|
|
m_systemMetrics.schemeData.ncm.iMenuHeight = nonClientMetricsW.iMenuHeight;
|
|
|
|
// Local custom fonts
|
|
_LoadCustomFonts();
|
|
|
|
if (nCurrentDPI != DPI_PERSISTED)
|
|
{
|
|
LogSystemMetrics("CThemeFile::_LoadSettings() BEFORE Loading from .theme", &m_systemMetrics);
|
|
DPIConvert_SystemMetricsAll(TRUE, &m_systemMetrics, DPI_PERSISTED, nCurrentDPI);
|
|
LogSystemMetrics("CThemeFile::_LoadSettings() AFTER Loading from .theme", &m_systemMetrics);
|
|
}
|
|
|
|
// CHARSET: In Win2k, fontfix.cpp was used as a hack to change the CHARSET from one language to another.
|
|
// That doesn't work for many reasons: a) not called on roaming, b) not called for OS lang changes,
|
|
// c) won't fix the problem for strings with multiple languages, d) etc.
|
|
// Therefore, the SHELL team (BryanSt) had the NTUSER team (MSadek) agree to use DEFAULT_CHARSET all the time.
|
|
// If some app has bad logic testing the charset parameter, then the NTUSER team will shim that app to fix it.
|
|
// The shim would be really simple, on the return from a SystemParametersInfo(SPI_GETNONCLIENTMETRICS or ICONFONTS)
|
|
// just patch the lfCharSet param to the current charset.
|
|
|
|
// For all CHARSETs to DEFAULT_CHARSET
|
|
m_systemMetrics.schemeData.ncm.lfCaptionFont.lfCharSet = DEFAULT_CHARSET;
|
|
m_systemMetrics.schemeData.ncm.lfSmCaptionFont.lfCharSet = DEFAULT_CHARSET;
|
|
m_systemMetrics.schemeData.ncm.lfMenuFont.lfCharSet = DEFAULT_CHARSET;
|
|
m_systemMetrics.schemeData.ncm.lfStatusFont.lfCharSet = DEFAULT_CHARSET;
|
|
m_systemMetrics.schemeData.ncm.lfMessageFont.lfCharSet = DEFAULT_CHARSET;
|
|
m_systemMetrics.schemeData.lfIconTitle.lfCharSet = DEFAULT_CHARSET;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////
|
|
// Get Colors
|
|
BOOL fGrad = FALSE; // Are gradient captions enabled?
|
|
int nIndex;
|
|
BOOL fColorFilter = _IsFiltered(THEMEFILTER_COLORS);
|
|
|
|
ClassicSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, (LPVOID)&fGrad, 0); // Init fGrad
|
|
if (!fColorFilter)
|
|
{
|
|
for (nIndex = 0; nIndex < ARRAYSIZE(s_pszColorNames); nIndex++)
|
|
{
|
|
TCHAR szColor[MAX_PATH];
|
|
|
|
// get string from theme
|
|
DWORD ccbSize = GetPrivateProfileString(SZ_INISECTION_COLORS, s_pszColorNames[nIndex], SZ_EMPTY, szColor, ARRAYSIZE(szColor), m_pszThemeFile);
|
|
if (!ccbSize || !szColor[0])
|
|
{
|
|
if ((nIndex == COLOR_GRADIENTACTIVECAPTION) && !szColor[0])
|
|
{
|
|
// They didn't specify the COLOR_GRADIENTACTIVECAPTION color, so use COLOR_ACTIVECAPTION
|
|
ccbSize = GetPrivateProfileString(SZ_INISECTION_COLORS, s_pszColorNames[COLOR_ACTIVECAPTION], SZ_EMPTY, szColor, ARRAYSIZE(szColor), m_pszThemeFile);
|
|
}
|
|
if ((nIndex == COLOR_GRADIENTINACTIVECAPTION) && !szColor[0])
|
|
{
|
|
// They didn't specify the COLOR_GRADIENTINACTIVECAPTION color, so use COLOR_INACTIVECAPTION
|
|
ccbSize = GetPrivateProfileString(SZ_INISECTION_COLORS, s_pszColorNames[COLOR_INACTIVECAPTION], SZ_EMPTY, szColor, ARRAYSIZE(szColor), m_pszThemeFile);
|
|
}
|
|
}
|
|
|
|
if (ccbSize && szColor[0])
|
|
{
|
|
m_systemMetrics.schemeData.rgb[nIndex] = RGBStringToColor(szColor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AssertMsg((NULL != _punkSite), TEXT("The caller needs to set our site or we can't succeed because we can't find out the icon size."));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_SaveSystemMetrics(SYSTEMMETRICSALL * pSystemMetrics)
|
|
{
|
|
HRESULT hr = _LoadSettings();
|
|
|
|
AssertMsg((NULL != m_pszThemeFile), TEXT("We don't have a file specified yet."));
|
|
if (SUCCEEDED(hr) && m_pszThemeFile)
|
|
{
|
|
int nCurrentDPI = DPI_PERSISTED;
|
|
|
|
_LoadLiveSettings(&nCurrentDPI);
|
|
hr = SystemMetricsAll_Copy(pSystemMetrics, &m_systemMetrics);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Write the following:
|
|
LPWSTR pszStringOut;
|
|
NONCLIENTMETRICSA nonClientMetricsA = {0};
|
|
SYSTEMMETRICSALL systemMetricsPDPI; // SYSMETS in persist DPI
|
|
|
|
SystemMetricsAll_Copy(pSystemMetrics, &systemMetricsPDPI);
|
|
// Scale the values so they are persisted in a DPI independent way. (A.k.a., in 96 DPI)
|
|
LogSystemMetrics("CThemeFile::_SaveSystemMetrics() BEFORE scale to P-DPI for .theme file", &systemMetricsPDPI);
|
|
DPIConvert_SystemMetricsAll(TRUE, &systemMetricsPDPI, nCurrentDPI, DPI_PERSISTED);
|
|
LogSystemMetrics("CThemeFile::_SaveSystemMetrics() AFTER scale to P-DPI for .theme file", &systemMetricsPDPI);
|
|
|
|
ConvertNCMetricsToANSI(&(systemMetricsPDPI.schemeData.ncm), &nonClientMetricsA);
|
|
|
|
// #1 "NonclientMetrics"
|
|
hr = ConvertBinaryToINIByteString((BYTE *)&nonClientMetricsA, sizeof(nonClientMetricsA), &pszStringOut);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _putThemeSetting(SZ_INISECTION_METRICS, SZ_INIKEY_NONCLIENTMETRICS, FALSE, pszStringOut);
|
|
LocalFree(pszStringOut);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// #2 "IconMetrics"
|
|
ICONMETRICSA iconMetricsA;
|
|
|
|
iconMetricsA.cbSize = sizeof(iconMetricsA);
|
|
GetIconMetricsFromSysMetricsAll(&systemMetricsPDPI, &iconMetricsA, sizeof(iconMetricsA));
|
|
hr = ConvertBinaryToINIByteString((BYTE *)&iconMetricsA, sizeof(iconMetricsA), &pszStringOut);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _putThemeSetting(SZ_INISECTION_METRICS, SZ_INIKEY_ICONMETRICS, FALSE, pszStringOut);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int nIndex;
|
|
|
|
for (nIndex = 0; nIndex < ARRAYSIZE(s_pszColorNames); nIndex++)
|
|
{
|
|
LPWSTR pszColor;
|
|
DWORD dwColor = systemMetricsPDPI.schemeData.rgb[nIndex];
|
|
|
|
hr = ConvertBinaryToINIByteString((BYTE *)&dwColor, 3, &pszColor);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD cchSize = lstrlen(pszColor);
|
|
|
|
if (L' ' == pszColor[cchSize - 1])
|
|
{
|
|
pszColor[cchSize - 1] = 0;
|
|
}
|
|
|
|
hr = HrWritePrivateProfileStringW(SZ_INISECTION_COLORS, s_pszColorNames[nIndex], pszColor, m_pszThemeFile);
|
|
LocalFree(pszColor);
|
|
}
|
|
}
|
|
|
|
// Delete the MUI version of the fonts because we just got new NONCLIENTMETRICs
|
|
_putThemeSetting(SZ_INISECTION_METRICS, TEXT("CaptionFont"), FALSE, NULL);
|
|
_putThemeSetting(SZ_INISECTION_METRICS, TEXT("SmCaptionFont"), FALSE, NULL);
|
|
_putThemeSetting(SZ_INISECTION_METRICS, TEXT("MenuFont"), FALSE, NULL);
|
|
_putThemeSetting(SZ_INISECTION_METRICS, TEXT("StatusFont"), FALSE, NULL);
|
|
_putThemeSetting(SZ_INISECTION_METRICS, TEXT("MessageFont"), FALSE, NULL);
|
|
_putThemeSetting(SZ_INISECTION_METRICS, TEXT("IconFont"), FALSE, NULL);
|
|
}
|
|
LocalFree(pszStringOut);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL CThemeFile::_IsFiltered(IN DWORD dwFilter)
|
|
{
|
|
BOOL fFiltered = FALSE;
|
|
|
|
// Get property bag with default settings.
|
|
if (_punkSite)
|
|
{
|
|
IPropertyBag * pPropertyBag;
|
|
|
|
HRESULT hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fFiltered = !SHPropertyBag_ReadBOOLDefRet(pPropertyBag, g_szCBNames[dwFilter], FALSE);
|
|
pPropertyBag->Release();
|
|
}
|
|
}
|
|
|
|
return fFiltered;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_ApplySounds(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!_IsFiltered(THEMEFILTER_SOUNDS))
|
|
{
|
|
int nIndex;
|
|
|
|
for (nIndex = 0; nIndex < ARRAYSIZE(s_ThemeSoundsValues); nIndex++)
|
|
{
|
|
CComBSTR bstrPath;
|
|
|
|
hr = _GetSound(s_ThemeSoundsValues[nIndex].pszRegKey, &bstrPath);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD dwError = SHRegSetPathW(HKEY_CURRENT_USER, s_ThemeSoundsValues[nIndex].pszRegKey, NULL, bstrPath, 0);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
else
|
|
{
|
|
|
|
// First delete the value because we many need to switch from REG_SZ to REG_EXPAND_SZ
|
|
// Ignore if this fails
|
|
HrRegDeleteValue(HKEY_CURRENT_USER, s_ThemeSoundsValues[nIndex].pszRegKey, NULL);
|
|
hr = E_FAIL;
|
|
|
|
// The file didn't specify what to use, so reset to the default values.
|
|
if (s_ThemeSoundsValues[nIndex].nResourceID)
|
|
{
|
|
// Use the specified value.
|
|
TCHAR szReplacement[MAX_PATH];
|
|
DWORD dwType;
|
|
DWORD cbSize;
|
|
|
|
if (s_ThemeSoundsValues[nIndex].nResourceID == SOUND_DEFAULT)
|
|
{
|
|
TCHAR szDefaultKey[MAX_PATH];
|
|
StrCpy(szDefaultKey, s_ThemeSoundsValues[nIndex].pszRegKey);
|
|
|
|
LPTSTR p = szDefaultKey + lstrlen(szDefaultKey) - ARRAYSIZE(L".Current") + 1;
|
|
|
|
// Replace ".Current" with ".default"
|
|
if (*p == L'.')
|
|
{
|
|
StrCpy(p, L".Default");
|
|
cbSize = sizeof szReplacement;
|
|
hr = HrSHGetValue(HKEY_CURRENT_USER, szDefaultKey, NULL, &dwType, (LPVOID) szReplacement, &cbSize);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
PathUnExpandEnvStringsWrap(szReplacement, ARRAYSIZE(szReplacement));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (0 != LoadString(HINST_THISDLL, s_ThemeSoundsValues[nIndex].nResourceID, szReplacement, ARRAYSIZE(szReplacement)))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
dwType = (StrStrW(szReplacement, L"%SystemRoot%")) ? REG_EXPAND_SZ : REG_SZ;
|
|
cbSize = ((lstrlen(szReplacement) + 1) * sizeof(szReplacement[0]));
|
|
|
|
hr = HrSHSetValue(HKEY_CURRENT_USER, s_ThemeSoundsValues[nIndex].pszRegKey, NULL, dwType, (LPVOID) szReplacement, cbSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We leave the value deleted because the default was empty.
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = S_OK; // We don't care if it fails.
|
|
|
|
// Need to flush buffer and ensure new sounds used for next events
|
|
sndPlaySoundW(NULL, SND_ASYNC | SND_NODEFAULT);
|
|
|
|
// Clear the current pointer scheme string from the registry so that Mouse
|
|
// cpl doesn't display a bogus name. Don't care if this fails.
|
|
RegSetValue(HKEY_CURRENT_USER, SZ_REGKEY_SOUNDS, REG_SZ, TEXT(".current"), 0);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_ApplyCursors(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!_IsFiltered(THEMEFILTER_CURSORS))
|
|
{
|
|
int nIndex;
|
|
|
|
for (nIndex = 0; nIndex < ARRAYSIZE(s_pszCursorArray); nIndex++)
|
|
{
|
|
BSTR bstrPath;
|
|
hr = _getThemeSetting(SZ_INISECTION_CURSORS, s_pszCursorArray[nIndex], THEMESETTING_LOADINDIRECT, &bstrPath);
|
|
if (FAILED(hr) || !bstrPath[0])
|
|
{
|
|
// The caller didn't specify a value so delete the key so we use default values.
|
|
hr = HrRegDeleteValue(HKEY_CURRENT_USER, SZ_INISECTION_CURSORS, s_pszCursorArray[nIndex]);
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
hr = S_OK; // it may already not exist, which is fine.
|
|
}
|
|
}
|
|
else if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrRegSetValueString(HKEY_CURRENT_USER, SZ_INISECTION_CURSORS, s_pszCursorArray[nIndex], bstrPath);
|
|
}
|
|
}
|
|
|
|
BSTR bstrCursor;
|
|
if (SUCCEEDED(_getThemeSetting(SZ_INISECTION_CURSORS, SZ_INIKEY_CURSORSCHEME, THEMESETTING_LOADINDIRECT, &bstrCursor)) && bstrCursor && bstrCursor[0])
|
|
{
|
|
// Set the cursor scheme
|
|
HrRegSetValueString(HKEY_CURRENT_USER, SZ_REGKEY_CP_CURSORS, NULL, bstrCursor);
|
|
|
|
// GPease wants me to mark this regkey -1 so he knows it was changed from the display CPL. See
|
|
// him with questions.
|
|
HrRegSetDWORD(HKEY_CURRENT_USER, SZ_REGKEY_CP_CURSORS, SZ_REGVALUE_CURSOR_CURRENTSCHEME, 2);
|
|
}
|
|
else
|
|
{
|
|
HrRegDeleteValue(HKEY_CURRENT_USER, SZ_REGKEY_CP_CURSORS, NULL);
|
|
HrRegDeleteValue(HKEY_CURRENT_USER, SZ_REGKEY_CP_CURSORS, SZ_REGVALUE_CURSOR_CURRENTSCHEME);
|
|
}
|
|
|
|
// For the system to start using the new cursors.
|
|
SystemParametersInfoAsync(SPI_SETCURSORS, 0, 0, 0, SPIF_SENDCHANGE, NULL);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_ApplyWebview(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// We aren't going to support this.
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_ApplyThemeSettings(void)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (m_pszThemeFile)
|
|
{
|
|
HCURSOR hCursorOld = ::SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
hr = S_OK;
|
|
if (!((METRIC_CHANGE | COLOR_CHANGE | SCHEME_CHANGE) & m_systemMetrics.dwChanged))
|
|
{
|
|
// Only load settings if we haven't loaded the settings yet.
|
|
hr = _LoadSettings();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ApplySounds();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ApplyCursors();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ApplyWebview();
|
|
}
|
|
}
|
|
}
|
|
|
|
// OTHERS:
|
|
// 1. Save Icon: SPI_SETICONMETRICS w/iconMetricsW.iHorzSpacing, iVertSpacing, (Policy bIconSpacing).
|
|
// 2. Save Icon: SPI_SETICONMETRICS w/iconMetricsW.lfFont (Policy bIconFont).
|
|
// 2. Save Icon: from Theme:"Control Panel\\Desktop\\WindowMetrics","Shell Icon Size" to reg same. (Policy bIconSpacing). Repeate for "Shell Small Icon Size"
|
|
::SetCursor(hCursorOld);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_getThemeSetting(IN LPCWSTR pszIniSection, IN LPCWSTR pszIniKey, DWORD dwFlags, OUT BSTR * pbstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pbstrPath)
|
|
{
|
|
*pbstrPath = 0;
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
if (m_pszThemeFile)
|
|
{
|
|
WCHAR szPath[MAX_PATH];
|
|
DWORD cbRead = 0;
|
|
|
|
szPath[0] = 0;
|
|
if (THEMESETTING_LOADINDIRECT & dwFlags)
|
|
{
|
|
TCHAR szMUIIniKey[MAX_PATH];
|
|
|
|
wnsprintf(szMUIIniKey, ARRAYSIZE(szMUIIniKey), TEXT("%s.MUI"), pszIniKey);
|
|
cbRead = SHGetIniStringW(pszIniSection, szMUIIniKey, szPath, ARRAYSIZE(szPath), m_pszThemeFile);
|
|
}
|
|
|
|
if (0 == cbRead)
|
|
{
|
|
cbRead = SHGetIniStringW(pszIniSection, pszIniKey, szPath, ARRAYSIZE(szPath), m_pszThemeFile);
|
|
}
|
|
|
|
if (cbRead)
|
|
{
|
|
if (L'@' == szPath[0])
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
if (SUCCEEDED(SHLoadIndirectString(szPath, szTemp, ARRAYSIZE(szTemp), NULL)))
|
|
{
|
|
StrCpyN(szPath, szTemp, ARRAYSIZE(szPath));
|
|
}
|
|
}
|
|
|
|
hr = ExpandResourceDir(szPath, ARRAYSIZE(szPath));
|
|
hr = ExpandThemeTokens(m_pszThemeFile, szPath, ARRAYSIZE(szPath)); // Expand %ThemeDir% or %WinDir%
|
|
|
|
// Sometimes szPath won't be a path.
|
|
if (SUCCEEDED(hr) && !PathIsFileSpec(szPath))
|
|
{
|
|
hr = ((CF_NOTFOUND == ConfirmFile(szPath, TRUE)) ? HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) : S_OK);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrSysAllocString(szPath, pbstrPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// pszPath - NULL means delete value
|
|
HRESULT CThemeFile::_putThemeSetting(IN LPCWSTR pszIniSection, IN LPCWSTR pszIniKey, BOOL fUTF7, IN OPTIONAL LPWSTR pszPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (m_pszThemeFile)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
LPCWSTR pszValue = pszPath;
|
|
|
|
szPath[0] = 0;
|
|
if (pszValue && !PathIsRelative(pszValue) & PathFileExists(pszValue))
|
|
{
|
|
if (PathUnExpandEnvStringsForUser(NULL, pszValue, szPath, ARRAYSIZE(szPath)))
|
|
{
|
|
pszValue = szPath;
|
|
}
|
|
}
|
|
|
|
StrReplaceToken(TEXT("%WinDir%\\"), TEXT("%WinDir%"), szPath, ARRAYSIZE(szPath));
|
|
StrReplaceToken(TEXT("%SystemRoot%\\"), TEXT("%WinDir%"), szPath, ARRAYSIZE(szPath));
|
|
if (fUTF7)
|
|
{
|
|
if (SHSetIniStringW(pszIniSection, pszIniKey, pszValue, m_pszThemeFile))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HrWritePrivateProfileStringW(pszIniSection, pszIniKey, pszValue, m_pszThemeFile);
|
|
}
|
|
|
|
TCHAR szMUIIniKey[MAX_PATH];
|
|
|
|
// Delete any ".MUI" copies because they are out of date.
|
|
wnsprintf(szMUIIniKey, ARRAYSIZE(szMUIIniKey), TEXT("%s.MUI"), pszIniKey);
|
|
HrWritePrivateProfileStringW(pszIniSection, szMUIIniKey, NULL, m_pszThemeFile);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_getIntSetting(IN LPCWSTR pszIniSection, IN LPCWSTR pszIniKey, int nDefault, OUT int * pnValue)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pnValue)
|
|
{
|
|
*pnValue = 0;
|
|
hr = E_FAIL;
|
|
if (m_pszThemeFile)
|
|
{
|
|
*pnValue = GetPrivateProfileInt(pszIniSection, pszIniKey, nDefault, m_pszThemeFile);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_putIntSetting(IN LPCWSTR pszIniSection, IN LPCWSTR pszIniKey, IN int nValue)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (m_pszThemeFile)
|
|
{
|
|
if (WritePrivateProfileInt(pszIniSection, pszIniKey, nValue, m_pszThemeFile))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================
|
|
// *** ITheme Interface ***
|
|
//===========================
|
|
HRESULT CThemeFile::get_DisplayName(OUT BSTR * pbstrDisplayName)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pbstrDisplayName)
|
|
{
|
|
WCHAR szDisplayName[MAX_PATH];
|
|
|
|
*pbstrDisplayName = NULL;
|
|
hr = _getThemeSetting(SZ_INISECTION_THEME, SZ_INIKEY_DISPLAYNAME, THEMESETTING_NORMAL, pbstrDisplayName);
|
|
if (FAILED(hr))
|
|
{
|
|
LPCTSTR pszFileName = PathFindFileName(m_pszThemeFile);
|
|
|
|
hr = E_FAIL;
|
|
if (pszFileName)
|
|
{
|
|
SHTCharToUnicode(pszFileName, szDisplayName, ARRAYSIZE(szDisplayName));
|
|
PathRemoveExtensionW(szDisplayName);
|
|
|
|
hr = HrSysAllocStringW(szDisplayName, pbstrDisplayName);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::put_DisplayName(IN BSTR bstrDisplayName)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
// NULL bstrDisplayName is allowed, it means to delete the name in the file
|
|
// so the filename will be used in the future.
|
|
if (bstrDisplayName)
|
|
{
|
|
hr = _putThemeSetting(SZ_INISECTION_THEME, SZ_INIKEY_DISPLAYNAME, TRUE, bstrDisplayName);
|
|
}
|
|
else
|
|
{
|
|
SHSetIniStringW(SZ_INISECTION_THEME, SZ_INIKEY_DISPLAYNAME, NULL, m_pszThemeFile);
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::get_ScreenSaver(OUT BSTR * pbstrPath)
|
|
{
|
|
return _getThemeSetting(SZ_INISECTION_SCREENSAVER, SZ_INIKEY_SCREENSAVER, THEMESETTING_NORMAL, pbstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::put_ScreenSaver(IN BSTR bstrPath)
|
|
{
|
|
return _putThemeSetting(SZ_INISECTION_SCREENSAVER, SZ_INIKEY_SCREENSAVER, TRUE, bstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::get_Background(OUT BSTR * pbstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pbstrPath)
|
|
{
|
|
hr = _getThemeSetting(SZ_INISECTION_BACKGROUND, SZ_INIKEY_BACKGROUND, THEMESETTING_LOADINDIRECT, pbstrPath);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szNone[MAX_PATH];
|
|
|
|
LoadString(HINST_THISDLL, IDS_NONE, szNone, ARRAYSIZE(szNone));
|
|
if (!StrCmpI(szNone, *pbstrPath))
|
|
{
|
|
(*pbstrPath)[0] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::put_Background(IN BSTR bstrPath)
|
|
{
|
|
return _putThemeSetting(SZ_INISECTION_BACKGROUND, SZ_INIKEY_BACKGROUND, TRUE, bstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::get_BackgroundTile(OUT enumBkgdTile * pnTile)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pnTile)
|
|
{
|
|
TCHAR szSize[10];
|
|
int tile = 0; // Zero is the default value to use if the registry is empty.
|
|
int stretch = 0;
|
|
|
|
if (SUCCEEDED(HrRegGetValueString(HKEY_CURRENT_USER, SZ_INISECTION_BACKGROUND, SZ_REGVALUE_TILEWALLPAPER, szSize, ARRAYSIZE(szSize))))
|
|
{
|
|
tile = StrToInt(szSize);
|
|
}
|
|
|
|
if (SUCCEEDED(HrRegGetValueString(HKEY_CURRENT_USER, SZ_INISECTION_BACKGROUND, SZ_REGVALUE_WALLPAPERSTYLE, szSize, ARRAYSIZE(szSize))))
|
|
{
|
|
tile = (2 & StrToInt(szSize));
|
|
}
|
|
|
|
// If a theme is selected, and we are using a plus wall paper then
|
|
// find out if tiling is on, and what style to use from the ini file.
|
|
// Otherwise, we already got the information from the registry.
|
|
_getIntSetting(SZ_INISECTION_BACKGROUND, SZ_REGVALUE_TILEWALLPAPER, tile, &tile);
|
|
_getIntSetting(SZ_INISECTION_BACKGROUND, SZ_REGVALUE_WALLPAPERSTYLE, stretch, &stretch);
|
|
|
|
stretch &= 2;
|
|
_getIntSetting(SZ_INISECTION_MASTERSELECTOR, SZ_REGVALUE_STRETCH, stretch, &stretch);
|
|
|
|
if (tile)
|
|
{
|
|
*pnTile = BKDGT_TILE;
|
|
}
|
|
else if (stretch)
|
|
{
|
|
*pnTile = BKDGT_STRECH;
|
|
}
|
|
else
|
|
{
|
|
*pnTile = BKDGT_CENTER;
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::put_BackgroundTile(IN enumBkgdTile nTile)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
switch (nTile)
|
|
{
|
|
case BKDGT_STRECH:
|
|
hr = _putThemeSetting(SZ_INISECTION_BACKGROUND, SZ_REGVALUE_TILEWALLPAPER, FALSE, TEXT("0"));
|
|
hr = _putThemeSetting(SZ_INISECTION_BACKGROUND, SZ_REGVALUE_WALLPAPERSTYLE, FALSE, TEXT("2"));
|
|
break;
|
|
case BKDGT_CENTER:
|
|
hr = _putThemeSetting(SZ_INISECTION_BACKGROUND, SZ_REGVALUE_TILEWALLPAPER, FALSE, TEXT("0"));
|
|
hr = _putThemeSetting(SZ_INISECTION_BACKGROUND, SZ_REGVALUE_WALLPAPERSTYLE, FALSE, TEXT("0"));
|
|
break;
|
|
case BKDGT_TILE:
|
|
hr = _putThemeSetting(SZ_INISECTION_BACKGROUND, SZ_REGVALUE_TILEWALLPAPER, FALSE, TEXT("1"));
|
|
hr = _putThemeSetting(SZ_INISECTION_BACKGROUND, SZ_REGVALUE_WALLPAPERSTYLE, FALSE, TEXT("0"));
|
|
break;
|
|
};
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::get_VisualStyle(OUT BSTR * pbstrPath)
|
|
{
|
|
return _getThemeSetting(SZ_INISECTION_VISUALSTYLES, SZ_INIKEY_VISUALSTYLE, THEMESETTING_NORMAL, pbstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::put_VisualStyle(IN BSTR bstrPath)
|
|
{
|
|
return _putThemeSetting(SZ_INISECTION_VISUALSTYLES, SZ_INIKEY_VISUALSTYLE, TRUE, bstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::get_VisualStyleColor(OUT BSTR * pbstrPath)
|
|
{
|
|
return _getThemeSetting(SZ_INISECTION_VISUALSTYLES, SZ_INIKEY_VISUALSTYLECOLOR, THEMESETTING_NORMAL, pbstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::put_VisualStyleColor(IN BSTR bstrPath)
|
|
{
|
|
return _putThemeSetting(SZ_INISECTION_VISUALSTYLES, SZ_INIKEY_VISUALSTYLECOLOR, TRUE, bstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::get_VisualStyleSize(OUT BSTR * pbstrPath)
|
|
{
|
|
return _getThemeSetting(SZ_INISECTION_VISUALSTYLES, SZ_INIKEY_VISUALSTYLESIZE, THEMESETTING_NORMAL, pbstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::put_VisualStyleSize(IN BSTR bstrPath)
|
|
{
|
|
return _putThemeSetting(SZ_INISECTION_VISUALSTYLES, SZ_INIKEY_VISUALSTYLESIZE, TRUE, bstrPath);
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::GetPath(IN VARIANT_BOOL fExpand, OUT BSTR * pbstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pbstrPath && m_pszThemeFile)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
StrCpyN(szPath, m_pszThemeFile, ARRAYSIZE(szPath));
|
|
if (VARIANT_TRUE == fExpand)
|
|
{
|
|
TCHAR szPathTemp[MAX_PATH];
|
|
|
|
if (SHExpandEnvironmentStrings(szPath, szPathTemp, ARRAYSIZE(szPathTemp)))
|
|
{
|
|
StrCpyN(szPath, szPathTemp, ARRAYSIZE(szPath));
|
|
}
|
|
}
|
|
|
|
hr = HrSysAllocString(szPath, pbstrPath);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::SetPath(IN BSTR bstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (bstrPath)
|
|
{
|
|
Str_SetPtr(&m_pszThemeFile, bstrPath);
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::GetCursor(IN BSTR bstrCursor, OUT BSTR * pbstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pbstrPath)
|
|
{
|
|
*pbstrPath = NULL;
|
|
|
|
if (bstrCursor)
|
|
{
|
|
hr = _getThemeSetting(SZ_INISECTION_CURSORS, bstrCursor, THEMESETTING_LOADINDIRECT, pbstrPath);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::SetCursor(IN BSTR bstrCursor, IN BSTR bstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (bstrCursor)
|
|
{
|
|
hr = _putThemeSetting(SZ_INISECTION_CURSORS, bstrCursor, TRUE, bstrPath);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::_GetSound(LPCWSTR pszSoundName, OUT BSTR * pbstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pszSoundName && pbstrPath)
|
|
{
|
|
*pbstrPath = NULL;
|
|
hr = _getThemeSetting(pszSoundName, SZ_INIKEY_DEFAULTVALUE, THEMESETTING_LOADINDIRECT, pbstrPath);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::GetSound(IN BSTR bstrSoundName, OUT BSTR * pbstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pbstrPath)
|
|
{
|
|
*pbstrPath = NULL;
|
|
|
|
if (bstrSoundName)
|
|
{
|
|
hr = _GetSound(bstrSoundName, pbstrPath);
|
|
if (FAILED(hr))
|
|
{
|
|
int nIndex;
|
|
|
|
for (nIndex = 0; nIndex < ARRAYSIZE(s_ThemeSoundsValues); nIndex++)
|
|
{
|
|
if (!StrCmpI(bstrSoundName, s_ThemeSoundsValues[nIndex].pszRegKey))
|
|
{
|
|
// First delete the value because we many need to switch from REG_SZ to REG_EXPAND_SZ
|
|
TCHAR szReplacement[MAX_PATH];
|
|
|
|
LoadString(HINST_THISDLL, s_ThemeSoundsValues[nIndex].nResourceID, szReplacement, ARRAYSIZE(szReplacement));
|
|
hr = HrSysAllocStringW(szReplacement, pbstrPath);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::SetSound(IN BSTR bstrSoundName, IN BSTR bstrPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (bstrSoundName && bstrPath)
|
|
{
|
|
hr = _putThemeSetting(bstrSoundName, SZ_INIKEY_DEFAULTVALUE, TRUE, bstrPath);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::GetIcon(IN BSTR bstrIconName, OUT BSTR * pbstrIconPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pbstrIconPath)
|
|
{
|
|
*pbstrIconPath = NULL;
|
|
|
|
if (bstrIconName)
|
|
{
|
|
WCHAR szPath[MAX_URL_STRING];
|
|
WCHAR szIconType[MAX_PATH];
|
|
|
|
StrCpyNW(szPath, bstrIconName, ARRAYSIZE(szPath));
|
|
LPWSTR pszSeparator = StrChrW(szPath, L':');
|
|
if (pszSeparator)
|
|
{
|
|
StrCpyNW(szIconType, CharNext(pszSeparator), ARRAYSIZE(szIconType));
|
|
pszSeparator[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
// The caller should specify this but this is a safe fallback.
|
|
StrCpyNW(szIconType, L"DefaultValue", ARRAYSIZE(szIconType));
|
|
}
|
|
|
|
hr = _getThemeSetting(szPath, szIconType, THEMESETTING_NORMAL, pbstrIconPath);
|
|
if (FAILED(hr))
|
|
{
|
|
// The Plus! 98 format started adding "Software\Classes" to the path.
|
|
// So try that now.
|
|
// Plus!95 format: "[CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon]"
|
|
// Plus!98 format: "[Software\Classes\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon]"
|
|
WCHAR szPath98[MAX_URL_STRING];
|
|
|
|
wnsprintfW(szPath98, ARRAYSIZE(szPath98), L"Software\\Classes\\%ls", szPath);
|
|
hr = _getThemeSetting(szPath98, szIconType, THEMESETTING_NORMAL, pbstrIconPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::SetIcon(IN BSTR bstrIconName, IN BSTR bstrIconPath)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (bstrIconName && bstrIconPath)
|
|
{
|
|
WCHAR szPath[MAX_URL_STRING];
|
|
WCHAR szIconType[MAX_PATH];
|
|
|
|
StrCpyNW(szPath, bstrIconName, ARRAYSIZE(szPath));
|
|
LPWSTR pszSeparator = StrChrW(szPath, L':');
|
|
if (pszSeparator)
|
|
{
|
|
StrCpyNW(szIconType, CharNext(pszSeparator), ARRAYSIZE(szIconType));
|
|
pszSeparator[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
// The caller should specify this but this is a safe fallback.
|
|
StrCpyNW(szIconType, L"DefaultValue", ARRAYSIZE(szIconType));
|
|
}
|
|
|
|
hr = _putThemeSetting(szPath, szIconType, TRUE, bstrIconPath);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//===========================
|
|
// *** IPropertyBag Interface ***
|
|
//===========================
|
|
HRESULT CThemeFile::Read(IN LPCOLESTR pszPropName, IN VARIANT * pVar, IN IErrorLog *pErrorLog)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pszPropName && pVar)
|
|
{
|
|
if (!StrCmpW(pszPropName, SZ_PBPROP_SYSTEM_METRICS))
|
|
{
|
|
hr = _LoadSettings();
|
|
|
|
// This is pretty ugly.
|
|
pVar->vt = VT_BYREF;
|
|
pVar->byref = &m_systemMetrics;
|
|
}
|
|
else if (!StrCmpW(pszPropName, SZ_PBPROP_HASSYSMETRICS))
|
|
{
|
|
hr = _LoadSettings();
|
|
|
|
pVar->vt = VT_BOOL;
|
|
pVar->boolVal = VARIANT_FALSE;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szIconMetrics[2048];
|
|
|
|
DWORD cchSize = GetPrivateProfileString(SZ_INISECTION_METRICS, SZ_INIKEY_ICONMETRICS, SZ_EMPTY, szIconMetrics, ARRAYSIZE(szIconMetrics), m_pszThemeFile);
|
|
if (szIconMetrics[0])
|
|
{
|
|
cchSize = GetPrivateProfileString(SZ_INISECTION_METRICS, SZ_INIKEY_NONCLIENTMETRICS, SZ_EMPTY, szIconMetrics, ARRAYSIZE(szIconMetrics), m_pszThemeFile);
|
|
if (szIconMetrics[0])
|
|
{
|
|
cchSize = GetPrivateProfileString(SZ_INISECTION_COLORS, s_pszColorNames[COLOR_ACTIVECAPTION], SZ_EMPTY, szIconMetrics, ARRAYSIZE(szIconMetrics), m_pszThemeFile);
|
|
pVar->boolVal = (szIconMetrics[0] ? VARIANT_TRUE : VARIANT_FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::Write(IN LPCOLESTR pszPropName, IN VARIANT *pVar)
|
|
{
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
if (pszPropName && pVar)
|
|
{
|
|
if (!StrCmpW(pszPropName, SZ_PBPROP_APPLY_THEMEFILE))
|
|
{
|
|
VariantInit(pVar);
|
|
hr = _ApplyThemeSettings(); // This will do nothing if already loaded.
|
|
}
|
|
else if (!StrCmpW(pszPropName, SZ_PBPROP_SYSTEM_METRICS) && (VT_BYREF == pVar->vt) && pVar->byref)
|
|
{
|
|
SYSTEMMETRICSALL * pCurrent = (SYSTEMMETRICSALL *) pVar->byref;
|
|
|
|
// The caller will pass SYSTEMMETRICS in the live system DPI.
|
|
hr = _SaveSystemMetrics(pCurrent);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================
|
|
// *** IUnknown Interface ***
|
|
//===========================
|
|
ULONG CThemeFile::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
|
|
ULONG CThemeFile::Release()
|
|
{
|
|
if (InterlockedDecrement(&m_cRef))
|
|
return m_cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CThemeFile, IObjectWithSite),
|
|
QITABENT(CThemeFile, IPropertyBag),
|
|
QITABENT(CThemeFile, ITheme),
|
|
QITABENT(CThemeFile, IDispatch),
|
|
{ 0 },
|
|
};
|
|
|
|
return QISearch(this, qit, riid, ppvObj);
|
|
}
|
|
|
|
|
|
//===========================
|
|
// *** Class Methods ***
|
|
//===========================
|
|
CThemeFile::CThemeFile(LPCTSTR pszThemeFile) : CImpIDispatch(LIBID_Theme, 1, 0, IID_ITheme), m_cRef(1)
|
|
{
|
|
DllAddRef();
|
|
|
|
// This needs to be allocated in Zero Inited Memory.
|
|
// Assert that all Member Variables are inited to Zero.
|
|
|
|
m_dwCachedState = 0xFFFFFFFF;
|
|
|
|
InitFrost();
|
|
}
|
|
|
|
|
|
CThemeFile::~CThemeFile()
|
|
{
|
|
Str_SetPtr(&m_pszThemeFile, NULL);
|
|
|
|
DllRelease();
|
|
}
|
|
|
|
|
|
HRESULT CThemeFile_CreateInstance(IN LPCWSTR pszThemeFile, OUT ITheme ** ppTheme)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (ppTheme)
|
|
{
|
|
CThemeFile * pObject = new CThemeFile(pszThemeFile);
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
*ppTheme = NULL;
|
|
if (pObject)
|
|
{
|
|
hr = pObject->SetPath((BSTR)pszThemeFile);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pObject->QueryInterface(IID_PPV_ARG(ITheme, ppTheme));
|
|
}
|
|
|
|
pObject->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|