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.
 
 
 
 
 
 

2894 lines
90 KiB

#include "stdafx.h"
#include "utils.h"
#include "..\\deskfldr.h"
#include <cfgmgr32.h> // MAX_GUID_STRING_LEN
#pragma hdrstop
const TCHAR c_szSetup[] = REGSTR_PATH_SETUP TEXT("\\Setup");
const TCHAR c_szSharedDir[] = TEXT("SharedDir");
BOOL g_fDirtyAdvanced;
BOOL g_fLaunchGallery; // If true, we launched the gallery, so close the dialog.
DWORD g_dwApplyFlags = (AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH);
// used to indicate if desktop cleanup settings have changes
extern int g_iRunDesktopCleanup = BST_INDETERMINATE; // indicates uninitilized value.
STDAPI ApplyDesktopCleanupSettings();
BOOL _IsNonEnumPolicySet(const CLSID *pclsid);
static const LPCTSTR c_rgpszWallpaperExt[] = {
TEXT("BMP"), TEXT("GIF"),
TEXT("JPG"), TEXT("JPE"),
TEXT("JPEG"),TEXT("DIB"),
TEXT("PNG"), TEXT("HTM"),
TEXT("HTML")
};
const static DWORD aBackHelpIDs[] = {
IDC_BACK_SELECT, IDH_DISPLAY_BACKGROUND_WALLPAPERLIST,
IDC_BACK_WPLIST, IDH_DISPLAY_BACKGROUND_WALLPAPERLIST,
IDC_BACK_BROWSE, IDH_DISPLAY_BACKGROUND_BROWSE_BUTTON,
IDC_BACK_WEB, IDH_DISPLAY_BACKGROUND_DESKTOP_ITEMS,
IDC_BACK_DISPLAY, IDH_DISPLAY_BACKGROUND_PICTUREDISPLAY,
IDC_BACK_WPSTYLE, IDH_DISPLAY_BACKGROUND_PICTUREDISPLAY,
IDC_BACK_PREVIEW, IDH_DISPLAY_BACKGROUND_MONITOR,
IDC_BACK_COLORPICKERLABEL, IDH_DISPLAY_BACKGROUND_BACKGROUND_COLOR,
IDC_BACK_COLORPICKER, IDH_DISPLAY_BACKGROUND_BACKGROUND_COLOR,
0, 0
};
#define SZ_HELPFILE_DESKTOPTAB TEXT("display.hlp")
#define SZ_REGKEY_PROGRAMFILES TEXT("Software\\Microsoft\\Windows\\CurrentVersion")
#define SZ_REGKEY_PLUS95DIR TEXT("Software\\Microsoft\\Plus!\\Setup") // PLUS95_KEY
#define SZ_REGKEY_PLUS98DIR TEXT("Software\\Microsoft\\Plus!98") // PLUS98_KEY
#define SZ_REGKEY_KIDSDIR TEXT("Software\\Microsoft\\Microsoft Kids\\Kids Plus!") // KIDS_KEY
#define SZ_REGKEY_WALLPAPER TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Wallpaper")
#define SZ_REGKEY_WALLPAPERMRU TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Wallpaper\\MRU")
#define SZ_REGKEY_LASTTHEME TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\LastTheme")
#define SZ_REGVALUE_PLUS95DIR TEXT("DestPath") // PLUS95_PATH
#define SZ_REGVALUE_PLUS98DIR TEXT("Path") // PLUS98_PATH
#define SZ_REGVALUE_KIDSDIR TEXT("InstallDir") // KIDS_PATH
#define SZ_REGVALUE_PROGRAMFILESDIR TEXT("ProgramFilesDir")
#define SZ_REGVALUE_PROGRAMFILESDIR TEXT("ProgramFilesDir")
#define SZ_REGVALUE_USETILE TEXT("UseTile") // If it's not a watermark background, does the user want to default to "Center" or "Stretch". Different users like different settings.
#define SZ_REGVALUE_LASTSCAN TEXT("LastScan") // When was the last time we scanned the file sizes?
#ifndef RECTHEIGHT
#define RECTHEIGHT(rc) ((rc).bottom - (rc).top)
#define RECTWIDTH(rc) ((rc).right - (rc).left)
#endif
//===========================
// *** Class Internals & Helpers ***
//===========================
#ifdef NEVER
BOOL IsWallpaperDesktopV2(LPCTSTR lpszWallpaper)
{
TCHAR szBuf[MAX_PATH];
TCHAR szDesktopV2path[MAX_PATH];
TCHAR szDesktopV2[100];
LoadString(HINST_THISDLL, IDS_MILLEN_DESKTOP, szDesktopV2, ARRAYSIZE(szDesktopV2));
LoadString(HINST_THISDLL, IDS_MILLEN_DESKTOP_PATH, szDesktopV2path, ARRAYSIZE(szDesktopV2path));
//Get the windows directory.
if (!GetWindowsDirectory(szBuf, ARRAYSIZE(szBuf)))
{
szBuf[0] = 0;
}
//Append the path to Desktop V2.
if(PathAppend(szBuf, szDesktopV2path))
{
//Append the wallpaper name.
if(PathAppend(szBuf, szDesktopV2))
{
//Check the given wallpaper name against the DesktopV2 wallpaper name we just built.
if(StrCmpIC(szBuf, lpszWallpaper) == 0)
return(TRUE); //Yup! the wallpaper we have is indeed the DesktopV2 wallpaper.
}
}
return FALSE; //Nope this is someother wallpaper.
}
#endif //NEVER
HRESULT CBackPropSheetPage::_LoadState(void)
{
HRESULT hr = S_OK;
if (!_fStateLoaded)
{
hr = _LoadIconState();
if (SUCCEEDED(hr))
{
hr = _LoadDesktopOptionsState();
if (SUCCEEDED(hr))
{
_fStateLoaded = TRUE;
}
}
}
return hr;
}
#define SZ_ICON_DEFAULTICON L"DefaultValue"
HRESULT CBackPropSheetPage::_GetIconPath(IN CLSID clsid, IN LPCWSTR pszName, IN BOOL fOldIcon, IN LPWSTR pszPath, IN DWORD cchSize)
{
HRESULT hr = E_FAIL;
int nIndex;
if (!StrCmpIW(SZ_ICON_DEFAULTICON, pszName))
{
pszName = L"";
}
for (nIndex = 0; nIndex < ARRAYSIZE(_IconData); nIndex++)
{
if (IsEqualCLSID(*(c_aIconRegKeys[nIndex].pclsid), clsid) &&
!StrCmpIW(pszName, c_aIconRegKeys[nIndex].szIconValue))
{
// We found it.
if (fOldIcon)
{
wnsprintfW(pszPath, cchSize, L"%s,%d", _IconData[nIndex].szOldFile, _IconData[nIndex].iOldIndex);
}
else
{
wnsprintfW(pszPath, cchSize, L"%s,%d", _IconData[nIndex].szNewFile, _IconData[nIndex].iNewIndex);
}
hr = S_OK;
break;
}
}
return hr;
}
HRESULT CBackPropSheetPage::_SetIconPath(IN CLSID clsid, IN LPCWSTR pszName, IN LPCWSTR pszPath, IN int nResourceID)
{
HRESULT hr = E_FAIL;
int nIndex;
if (!StrCmpIW(SZ_ICON_DEFAULTICON, pszName))
{
pszName = L"";
}
for (nIndex = 0; nIndex < ARRAYSIZE(_IconData); nIndex++)
{
if (IsEqualCLSID(*(c_aIconRegKeys[nIndex].pclsid), clsid) &&
!StrCmpIW(pszName, c_aIconRegKeys[nIndex].szIconValue))
{
TCHAR szTemp[MAX_PATH];
if (!pszPath || !pszPath[0])
{
// The caller didn't specify an icon so use the default values.
if (!SHExpandEnvironmentStrings(c_aIconRegKeys[nIndex].pszDefault, szTemp, ARRAYSIZE(szTemp)))
{
StrCpyN(szTemp, c_aIconRegKeys[nIndex].pszDefault, ARRAYSIZE(szTemp));
}
pszPath = szTemp;
nResourceID = c_aIconRegKeys[nIndex].nDefaultIndex;
}
// We found it.
StrCpyNW(_IconData[nIndex].szNewFile, pszPath, ARRAYSIZE(_IconData[nIndex].szNewFile));
_IconData[nIndex].iNewIndex = nResourceID;
hr = S_OK;
break;
}
}
return hr;
}
HRESULT CBackPropSheetPage::_LoadIconState(void)
{
HRESULT hr = S_OK;
// load the icons and add them to the image lists
// get the icon files and indexes from the registry, including for the Default recycle bin
for (int nIndex = 0; nIndex < ARRAYSIZE(_IconData); nIndex++)
{
TCHAR szTemp[MAX_PATH];
szTemp[0] = 0;
IconGetRegValueString(c_aIconRegKeys[nIndex].pclsid, TEXT("DefaultIcon"), c_aIconRegKeys[nIndex].szIconValue, szTemp, ARRAYSIZE(szTemp));
int iIndex = PathParseIconLocation(szTemp);
// store the icon information
StrCpyNW(_IconData[nIndex].szOldFile, szTemp, ARRAYSIZE(_IconData[nIndex].szOldFile));
StrCpyNW(_IconData[nIndex].szNewFile, szTemp, ARRAYSIZE(_IconData[nIndex].szNewFile));
_IconData[nIndex].iOldIndex = iIndex;
_IconData[nIndex].iNewIndex = iIndex;
}
return hr;
}
HRESULT CBackPropSheetPage::_LoadDesktopOptionsState(void)
{
HRESULT hr = S_OK;
int iStartPanel;
TCHAR szRegPath[MAX_PATH];
// i = 0 is for StartPanel off and i = 1 is for StartPanel ON!
for(iStartPanel = 0; iStartPanel <= 1; iStartPanel++)
{
int iIndex;
//Get the proper registry path based on if StartPanel is ON/OFF
wsprintf(szRegPath, REGSTR_PATH_HIDDEN_DESKTOP_ICONS, c_apstrRegLocation[iStartPanel]);
//Load the settings for all icons we are interested in.
for(iIndex = 0; iIndex < NUM_DESKICONS; iIndex++)
{
TCHAR szValueName[MAX_GUID_STRING_LEN];
SHUnicodeToTChar(c_aDeskIconId[iIndex].pwszCLSID, szValueName, ARRAYSIZE(szValueName));
//Read the setting from the registry!
_aHideDesktopIcon[iStartPanel][iIndex].fHideIcon = SHRegGetBoolUSValue(szRegPath, szValueName, FALSE, /* default */FALSE);
_aHideDesktopIcon[iStartPanel][iIndex].fDirty = FALSE;
//Update the NonEnum attribute data.
if((c_aDeskIconId[iIndex].fCheckNonEnumAttrib) && (iStartPanel == 1))
{
TCHAR szAttriRegPath[MAX_PATH];
DWORD dwSize = sizeof(_aDeskIconNonEnumData[iIndex].rgfAttributes);
ULONG rgfDefault = 0; //By default the SFGAO_NONENUMERATED bit if off!
wsprintf(szAttriRegPath, REGSTR_PATH_EXP_SHELLFOLDER, szValueName);
//Read the attributes.
SHRegGetUSValue(szAttriRegPath, REGVAL_ATTRIBUTES,
NULL,
&(_aDeskIconNonEnumData[iIndex].rgfAttributes),
&dwSize,
FALSE,
&rgfDefault,
sizeof(rgfDefault));
//If SHGAO_NONENUMERATED bit is ON, then we need to hide the checkboxes in both modes.
if(_aDeskIconNonEnumData[iIndex].rgfAttributes & SFGAO_NONENUMERATED)
{
//Overwrite what we read earlier! These icons are hidden in both modes!
_aHideDesktopIcon[0][iIndex].fHideIcon = TRUE;
_aHideDesktopIcon[1][iIndex].fHideIcon = TRUE;
}
}
//Check the policy if needed!
if((c_aDeskIconId[iIndex].fCheckNonEnumPolicy) && (iStartPanel == 1))
{
if(_IsNonEnumPolicySet(c_aDeskIconId[iIndex].pclsid))
{
//Remember that this policy is set. So that we can disable these controls in UI.
_aDeskIconNonEnumData[iIndex].fNonEnumPolicySet = TRUE;
//Remember to hide these icons in both modes!
_aHideDesktopIcon[0][iIndex].fHideIcon = TRUE;
_aHideDesktopIcon[1][iIndex].fHideIcon = TRUE;
}
}
} //for (all desktop items)
} //for both the modes (StartPanel off and On)
return hr;
}
HRESULT CBackPropSheetPage::_SaveIconState(void)
{
HRESULT hr = S_OK;
BOOL fDorked = FALSE;
if (_fStateLoaded)
{
int nIndex;
// Change the system icons
for(nIndex = 0; nIndex < ARRAYSIZE(_IconData); nIndex++)
{
if ((lstrcmpi(_IconData[nIndex].szNewFile, _IconData[nIndex].szOldFile) != 0) ||
(_IconData[nIndex].iNewIndex != _IconData[nIndex].iOldIndex))
{
TCHAR szTemp[MAX_PATH];
wnsprintf(szTemp, ARRAYSIZE(szTemp), TEXT("%s,%d"), _IconData[nIndex].szNewFile, _IconData[nIndex].iNewIndex);
IconSetRegValueString(c_aIconRegKeys[nIndex].pclsid, TEXT("DefaultIcon"), c_aIconRegKeys[nIndex].szIconValue, szTemp);
// Next two lines necessary if the user does an Apply as opposed to OK
StrCpyNW(_IconData[nIndex].szOldFile, _IconData[nIndex].szNewFile, ARRAYSIZE(_IconData[nIndex].szOldFile));
_IconData[nIndex].iOldIndex = _IconData[nIndex].iNewIndex;
fDorked = TRUE;
}
}
}
// Make the system notice we changed the system icons
if (fDorked)
{
SHChangeNotify(SHCNE_ASSOCCHANGED, 0, NULL, NULL); // should do the trick!
SHUpdateRecycleBinIcon();
}
return hr;
}
HRESULT CBackPropSheetPage::_SaveDesktopOptionsState(void)
{
HRESULT hr = S_OK;
int iStartPanel;
TCHAR szRegPath[MAX_PATH];
BOOL fUpdateDesktop = FALSE;
// i = 0 is for StartPanel off and i = 1 is for StartPanel ON!
for(iStartPanel = 0; iStartPanel <= 1; iStartPanel++)
{
int iIndex;
//Get the proper registry path based on if StartPanel is ON/OFF
wsprintf(szRegPath, REGSTR_PATH_HIDDEN_DESKTOP_ICONS, c_apstrRegLocation[iStartPanel]);
//Load the settings for all icons we are interested in.
for(iIndex = 0; iIndex < NUM_DESKICONS; iIndex++)
{
//Update the registry only if the particular icon entry is dirty.
if(_aHideDesktopIcon[iStartPanel][iIndex].fDirty)
{
TCHAR szValueName[MAX_GUID_STRING_LEN];
SHUnicodeToTChar(c_aDeskIconId[iIndex].pwszCLSID, szValueName, ARRAYSIZE(szValueName));
//Write the setting to the registry!
SHRegSetUSValue(szRegPath, szValueName, REG_DWORD,
&(_aHideDesktopIcon[iStartPanel][iIndex].fHideIcon),
sizeof(_aHideDesktopIcon[iStartPanel][iIndex].fHideIcon),
SHREGSET_FORCE_HKCU);
_aHideDesktopIcon[iStartPanel][iIndex].fDirty = FALSE;
fUpdateDesktop = TRUE; //Desktop window needs to be refreshed.
// Note this will be done only once per index because SFGAO_NONENUMERATED bit is
// reset in rgfAttributes.
if((c_aDeskIconId[iIndex].fCheckNonEnumAttrib) &&
(_aDeskIconNonEnumData[iIndex].rgfAttributes & SFGAO_NONENUMERATED) &&
(_aHideDesktopIcon[iStartPanel][iIndex].fHideIcon == FALSE))
{
TCHAR szAttriRegPath[MAX_PATH];
wsprintf(szAttriRegPath, REGSTR_PATH_EXP_SHELLFOLDER, szValueName);
//We need to remove the SFGAO_NONENUMERATED attribute bit!
//We assume here is that when we save to registry, we save the same value
//for both the modes.
ASSERT(_aHideDesktopIcon[0][iIndex].fHideIcon == _aHideDesktopIcon[1][iIndex].fHideIcon);
//Strip out the NonEnum attribute!
_aDeskIconNonEnumData[iIndex].rgfAttributes &= ~SFGAO_NONENUMERATED;
//And save it in the registry!
SHRegSetUSValue(szAttriRegPath, REGVAL_ATTRIBUTES,
REG_DWORD,
&(_aDeskIconNonEnumData[iIndex].rgfAttributes),
sizeof(_aDeskIconNonEnumData[iIndex].rgfAttributes),
SHREGSET_FORCE_HKCU);
}
}
}
}
if(fUpdateDesktop)
PostMessage(GetShellWindow(), WM_COMMAND, FCIDM_REFRESH, 0L); //Refresh desktop!
_fHideDesktopIconDirty = FALSE; //We just saved. So, reset the dirty bit!
return hr;
}
int CBackPropSheetPage::_AddAFileToLV(LPCTSTR pszDir, LPTSTR pszFile, UINT nBitmap)
{
int index = -1;
TCHAR szTemp[MAX_PATH];
if (pszDir)
{
lstrcpyn(szTemp, pszDir, ARRAYSIZE(szTemp));
PathAppend(szTemp, pszFile);
}
else if (pszFile && *pszFile && (lstrcmpi(pszFile, g_szNone) != 0))
{
lstrcpyn(szTemp, pszFile, ARRAYSIZE(szTemp));
}
else
{
*szTemp = TEXT('\0');
}
TCHAR szLVIText[MAX_PATH];
StrCpyN(szLVIText, PathFindFileName(pszFile), ARRAYSIZE(szLVIText));
PathRemoveExtension(szLVIText);
PathMakePretty(szLVIText);
LV_ITEM lvi = {0};
lvi.mask = LVIF_TEXT | LVIF_PARAM | (nBitmap != -1 ? LVIF_IMAGE : 0);
lvi.iItem = 0x7FFFFFFF;
lvi.pszText = szLVIText;
lvi.iImage = nBitmap;
lvi.lParam = (LPARAM)StrDup(szTemp);
if (lvi.lParam)
{
index = ListView_InsertItem(_hwndLV, &lvi);
if (index == -1)
{
LocalFree((HLOCAL)lvi.lParam);
}
else
{
ListView_SetColumnWidth(_hwndLV, 0, LVSCW_AUTOSIZE);
}
}
return index;
}
void CBackPropSheetPage::_AddFilesToLV(LPCTSTR pszDir, LPCTSTR pszSpec, UINT nBitmap, BOOL fCount)
{
WIN32_FIND_DATA fd;
HANDLE h;
TCHAR szBuf[MAX_PATH];
StrCpyN(szBuf, pszDir, ARRAYSIZE(szBuf));
StrCatBuff(szBuf, TEXT("\\*."), SIZECHARS(szBuf));
StrCatBuff(szBuf, pszSpec, SIZECHARS(szBuf));
h = FindFirstFile(szBuf, &fd);
if (h != INVALID_HANDLE_VALUE)
{
do
{
// Skip files that are "Super-hidden" like "Winnt.bmp" and "Winnt256.bmp"
if ((fd.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)) != (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))
{
if (!fCount)
{
_AddAFileToLV(pszDir, fd.cFileName, nBitmap);
}
else
{
_nFileCount++;
}
}
}
while (FindNextFile(h, &fd));
FindClose(h);
}
}
int CBackPropSheetPage::_FindWallpaper(LPCTSTR pszFile)
{
int nItems = ListView_GetItemCount(_hwndLV);
int i;
for (i=0; i<nItems; i++)
{
LV_ITEM lvi = {0};
lvi.iItem = i;
lvi.mask = LVIF_PARAM;
ListView_GetItem(_hwndLV, &lvi);
if (StrCmpIC(pszFile, (LPCTSTR)lvi.lParam) == 0)
{
return i;
}
}
return -1;
}
void CBackPropSheetPage::_UpdatePreview(IN WPARAM flags, IN BOOL fUpdateThemePage)
{
WALLPAPEROPT wpo;
wpo.dwSize = sizeof(WALLPAPEROPT);
g_pActiveDesk->GetWallpaperOptions(&wpo, 0);
if (wpo.dwStyle & WPSTYLE_TILE)
{
flags |= BP_TILE;
}
else if(wpo.dwStyle & WPSTYLE_STRETCH)
{
flags |= BP_STRETCH;
}
WCHAR wszWallpaper[INTERNET_MAX_URL_LENGTH];
g_pActiveDesk->GetWallpaper(wszWallpaper, ARRAYSIZE(wszWallpaper), 0);
HRESULT hr = S_OK;
if (!_pThemePreview)
{
hr = CoCreateInstance(CLSID_ThemePreview, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemePreview, &_pThemePreview));
if (SUCCEEDED(hr) && _punkSite)
{
IPropertyBag * pPropertyBag;
hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
ASSERT(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
HWND hwndPlaceHolder = GetDlgItem(_hwnd, IDC_BACK_PREVIEW);
if (hwndPlaceHolder)
{
RECT rcPreview;
GetClientRect(hwndPlaceHolder, &rcPreview);
MapWindowPoints(hwndPlaceHolder, _hwnd, (LPPOINT)&rcPreview, 2);
hr = _pThemePreview->CreatePreview(_hwnd, TMPREV_SHOWMONITOR | TMPREV_SHOWBKGND, WS_VISIBLE | WS_CHILDWINDOW | WS_OVERLAPPED, 0, rcPreview.left, rcPreview.top, rcPreview.right - rcPreview.left, rcPreview.bottom - rcPreview.top, pPropertyBag, IDC_BACK_PREVIEW);
if (SUCCEEDED(hr))
{
// If we succeeded, remove the dummy window.
DestroyWindow(hwndPlaceHolder);
hr = SHPropertyBag_WritePunk(pPropertyBag, SZ_PBPROP_PREVIEW2, _pThemePreview);
_fThemePreviewCreated = TRUE;
}
}
pPropertyBag->Release();
}
}
}
if (_punkSite)
{
IThemeUIPages * pThemeUIPages;
HRESULT hr = _punkSite->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUIPages));
if (SUCCEEDED(hr))
{
hr = pThemeUIPages->UpdatePreview(0);
pThemeUIPages->Release();
}
if (fUpdateThemePage)
{
IPropertyBag * pPropertyBag;
hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
if (SUCCEEDED(hr))
{
// Tell the theme that we have customized the values.
hr = SHPropertyBag_WriteInt(pPropertyBag, SZ_PBPROP_CUSTOMIZE_THEME, 0);
pPropertyBag->Release();
}
}
}
if (!_fThemePreviewCreated)
{
HWND hwndOldPreview = GetDlgItem(_hwnd, IDC_BACK_PREVIEW);
if (hwndOldPreview)
{
SendDlgItemMessage(_hwnd, IDC_BACK_PREVIEW, WM_SETBACKINFO, flags, 0);
}
}
}
void CBackPropSheetPage::_EnableControls(void)
{
BOOL fEnable;
WCHAR wszWallpaper[INTERNET_MAX_URL_LENGTH];
LPTSTR pszWallpaper;
g_pActiveDesk->GetWallpaper(wszWallpaper, ARRAYSIZE(wszWallpaper), 0);
pszWallpaper = (LPTSTR)wszWallpaper;
BOOL fIsPicture = IsWallpaperPicture(pszWallpaper);
// Style combo only enabled if a non-null picture
// is being viewed.
fEnable = fIsPicture && (*pszWallpaper) && (!_fPolicyForStyle);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_WPSTYLE), fEnable);
// 98/09/10 vtan #209753: Also remember to disable the corresponding
// text item with the keyboard shortcut. Not disabling this will
// allow the shortcut to be invoked but will cause the incorrect
// dialog item to be "clicked".
(BOOL)EnableWindow(GetDlgItem(_hwnd, IDC_BACK_DISPLAY), fEnable);
}
int CBackPropSheetPage::_GetImageIndex(LPCTSTR pszFile)
{
int iRet = 0;
if (pszFile && *pszFile)
{
LPCTSTR pszExt = PathFindExtension(pszFile);
if (*pszExt == TEXT('.'))
{
pszExt++;
for (iRet=0; iRet<ARRAYSIZE(c_rgpszWallpaperExt); iRet++)
{
if (StrCmpIC(pszExt, c_rgpszWallpaperExt[iRet]) == 0)
{
//
// Add one because 'none' took the 0th slot.
//
iRet++;
return(iRet);
}
}
//
// If we fell off the end of the for loop here,
// this is a file with unknown extension. So, we assume that
// it is a normal wallpaper and it gets the Bitmap's icon
//
iRet = 1;
}
else
{
//
// Unknown files get Bitmap's icon.
//
iRet = 1;
}
}
return iRet;
}
// This function is called when another tab is trying to change our
// Tile mode. This means that our tab may not have been activated yet
// and may not activate until later.
HRESULT CBackPropSheetPage::_SetNewWallpaperTile(IN DWORD dwMode, IN BOOL fUpdateThemePage)
{
HRESULT hr = E_UNEXPECTED;
AssertMsg((NULL != g_pActiveDesk), TEXT("We need g_pActiveDesk or we can't change the background"));
if (g_pActiveDesk)
{
WALLPAPEROPT wpo;
wpo.dwSize = sizeof(wpo);
g_pActiveDesk->GetWallpaperOptions(&wpo, 0);
wpo.dwStyle = dwMode;
hr = g_pActiveDesk->SetWallpaperOptions(&wpo, 0);
}
if (_hwndWPStyle)
{
ComboBox_SetCurSel(_hwndWPStyle, dwMode);
_UpdatePreview(0, fUpdateThemePage);
}
return hr;
}
HRESULT CBackPropSheetPage::_SetNewWallpaper(LPCTSTR pszFileIn, IN BOOL fUpdateThemePageIn)
{
HRESULT hr = S_OK;
WCHAR szFile[MAX_PATH];
WCHAR szTemp[MAX_PATH];
LPWSTR pszFile = szFile;
DWORD cchFile = ARRAYSIZE(szFile);
LPWSTR pszTemp = szTemp;
DWORD cchTemp = ARRAYSIZE(szTemp);
//
// Make a copy of the file name.
//
DWORD cchFileIn = lstrlen(pszFileIn) + 1;
if ( cchFileIn > cchFile )
{
cchFile = cchFileIn;
pszFile = (LPWSTR) LocalAlloc(LPTR, cchFile * sizeof(WCHAR));
if (NULL == pszFile)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
StrCpyN(pszFile, pszFileIn, cchFile);
//
// Replace all "(none)" with empty strings.
//
if (lstrcmpi(pszFile, g_szNone) == 0)
{
pszFile[0] = TEXT('\0');
}
//
// Replace net drives with UNC names.
//
if( pszFile[1] == TEXT(':') )
{
DWORD dwErr;
TCHAR szDrive[3];
//
// Copy just the drive letter and see if it maps to a network drive.
//
lstrcpyn(szDrive, pszFile, ARRAYSIZE(szDrive));
dwErr = SHWNetGetConnection(szDrive, pszTemp, &cchTemp );
//
// See if our buffer was too small. If so, make it bigger and try
// again.
//
if ( ERROR_MORE_DATA == dwErr )
{
// Add the size of the rest of the filepath to the UNC path.
cchTemp += cchFile;
pszTemp = (LPWSTR) LocalAlloc( LPTR, cchTemp * sizeof(WCHAR) );
if ( NULL == pszTemp )
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
dwErr = SHWNetGetConnection(szDrive, pszTemp, &cchTemp );
}
//
// If it maps to a network location, replace the network drive letter
// with the UNC path.
//
if ( NO_ERROR == dwErr )
{
if (pszTemp[0] == TEXT('\\') && pszTemp[1] == TEXT('\\'))
{
DWORD cchLen;
wcscat(pszTemp, pszFile + 2);
//
// See if the new string will fit into our file buffer.
//
cchLen = wcslen(pszTemp) + 1;
if ( cchLen > cchFile )
{
if ( szFile != pszFile )
{
LocalFree( pszFile );
}
cchFile = cchLen;
pszFile = (LPWSTR) LocalAlloc(LPTR, cchFile * sizeof(WCHAR) );
if ( NULL == pszFile )
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
wcscpy(pszFile, pszTemp);
}
}
}
//
// If necessary, update the desk state object.
//
hr = g_pActiveDesk->GetWallpaper(pszTemp, cchTemp, 0);
if (FAILED(hr))
goto Cleanup;
//
// If we need more room, allocate it on the heap and try again.
//
if ( MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_MORE_DATA ) == hr )
{
if ( szTemp != pszTemp )
{
LocalFree( pszTemp );
}
cchTemp = INTERNET_MAX_URL_LENGTH;
pszTemp = (LPWSTR) LocalAlloc( LPTR, cchTemp * sizeof(WCHAR) );
if ( NULL == pszTemp )
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
hr = g_pActiveDesk->GetWallpaper(pszTemp, cchTemp, 0);
if (S_OK != hr)
goto Cleanup;
}
//
// Make sure the old background doesn't equal the new background.
//
if (StrCmpIC(pszTemp, pszFile) != 0)
{
//
// Did they choose something other than a .bmp?
// And is ActiveDesktop off?
//
if (!IsNormalWallpaper(pszFileIn))
{
Str_SetPtr(&_pszOriginalFile, pszFileIn);
}
else
{
// We may not need to have a temp file.
Str_SetPtr(&_pszOriginalFile, NULL);
}
Str_SetPtr(&_pszLastSourcePath, pszFile);
hr = g_pActiveDesk->SetWallpaper(pszFile, 0);
if (SUCCEEDED(hr))
{
if (fUpdateThemePageIn)
{
_SetNewWallpaperTile(_GetStretchMode(pszFile), fUpdateThemePageIn);
}
}
}
//
// Update the preview picture of the new wallpaper.
//
_UpdatePreview(0, fUpdateThemePageIn);
//
// If the wallpaper does not have a directory specified, (this may happen if other apps. change this value),
// we have to figure it out.
//
//
// REVIEW: gpease 17-MAY-2001
// GetWallpaperWithPath() probably should return a value if it
// fails or the buffer is too small. We might need to grow the
// buffer to append strings to the pszFile. Currently, it looks
// like this function takes "foobar.bmp"and prepends "c:\windows\"
// to it so MAX_PATH is probably sufficent.
//
GetWallpaperWithPath(pszFile, pszTemp, cchTemp);
LPTSTR pszFileForList = (_pszOriginalFile ? _pszOriginalFile : pszTemp);
int iSelectionNew = (pszFileForList[0] ? _FindWallpaper(pszFileForList) : 0);
if (iSelectionNew == -1)
{
iSelectionNew = _AddAFileToLV(NULL, pszFileForList, _GetImageIndex(pszFileForList));
}
_fSelectionFromUser = FALSE; // disable
//
// If necessary, select the item in the listview.
//
int iSelected = ListView_GetNextItem(_hwndLV, -1, LVNI_SELECTED);
if (iSelected != iSelectionNew)
{
ListView_SetItemState(_hwndLV, iSelectionNew, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
}
//
// Put all controls in correct enabled state.
//
_EnableControls();
//
// Make sure the selected item is visible.
//
ListView_EnsureVisible(_hwndLV, iSelectionNew, FALSE);
_fSelectionFromUser = TRUE; // re-enable
Cleanup:
if ( szFile != pszFile && NULL != pszFile )
{
LocalFree( pszFile );
}
if ( szTemp != pszTemp && NULL != pszTemp )
{
LocalFree( pszTemp );
}
return hr;
}
int CALLBACK CBackPropSheetPage::_SortBackgrounds(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
TCHAR szFile1[MAX_PATH], szFile2[MAX_PATH];
LPTSTR lpszFile1, lpszFile2;
StrCpyN(szFile1, (LPTSTR)lParam1, ARRAYSIZE(szFile1));
lpszFile1 = PathFindFileName(szFile1);
PathRemoveExtension(lpszFile1);
PathMakePretty(lpszFile1);
StrCpyN(szFile2, (LPTSTR)lParam2, ARRAYSIZE(szFile2));
lpszFile2 = PathFindFileName(szFile2);
PathRemoveExtension(lpszFile2);
PathMakePretty(lpszFile2);
return StrCmpIC(lpszFile1, lpszFile2);
}
HRESULT CBackPropSheetPage::_GetPlus95ThemesDir(LPTSTR pszPath, DWORD cchSize)
{
DWORD dwType;
DWORD cbSize = (sizeof(pszPath[0]) * cchSize);
HRESULT hr = HrSHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_PLUS95DIR, SZ_REGVALUE_PLUS95DIR, &dwType, pszPath, &cbSize);
if (SUCCEEDED(hr))
{
TCHAR szSubDir[MAX_PATH];
LPTSTR pszFile = PathFindFileName(pszPath);
if (pszFile)
{
// Plus!95 DestPath has "Plus!.dll" on the end so get rid of that.
pszFile[0] = 0;
}
// Tack on a "Themes" onto the path
LoadString(HINST_THISDLL, IDS_THEMES_SUBDIR, szSubDir, ARRAYSIZE(szSubDir));
PathAppend(pszPath, szSubDir);
}
return hr;
}
HRESULT CBackPropSheetPage::_GetPlus98ThemesDir(LPTSTR pszPath, DWORD cchSize)
{
DWORD dwType;
DWORD cbSize = (sizeof(pszPath[0]) * cchSize);
HRESULT hr = HrSHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_PLUS98DIR, SZ_REGVALUE_PLUS98DIR, &dwType, pszPath, &cbSize);
if (SUCCEEDED(hr))
{
TCHAR szSubDir[MAX_PATH];
LoadString(HINST_THISDLL, IDS_THEMES_SUBDIR, szSubDir, ARRAYSIZE(szSubDir));
PathAppend(pszPath, szSubDir);
}
return hr;
}
HRESULT CBackPropSheetPage::_GetKidsThemesDir(LPTSTR pszPath, DWORD cchSize)
{
DWORD dwType;
DWORD cbSize = (sizeof(pszPath[0]) * cchSize);
HRESULT hr = HrSHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_KIDSDIR, SZ_REGVALUE_KIDSDIR, &dwType, pszPath, &cbSize);
if (SUCCEEDED(hr))
{
TCHAR szSubDir[MAX_PATH];
// Tack a "\Plus! for Kids\Themes" onto the path
PathAppend(pszPath, TEXT("Plus! for Kids"));
LoadString(HINST_THISDLL, IDS_THEMES_SUBDIR, szSubDir, ARRAYSIZE(szSubDir));
PathAppend(pszPath, szSubDir);
}
return hr;
}
HRESULT CBackPropSheetPage::_GetHardDirThemesDir(LPTSTR pszPath, DWORD cchSize)
{
DWORD dwType;
DWORD cbSize = (sizeof(pszPath[0]) * cchSize);
HRESULT hr = HrSHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_PROGRAMFILES, SZ_REGVALUE_PROGRAMFILESDIR, &dwType, pszPath, &cbSize);
if (SUCCEEDED(hr))
{
TCHAR szSubDir[MAX_PATH];
// Tack a "\Plus! for Kids\Themes" onto the path
PathAppend(pszPath, TEXT("Plus!"));
LoadString(HINST_THISDLL, IDS_THEMES_SUBDIR, szSubDir, ARRAYSIZE(szSubDir));
PathAppend(pszPath, szSubDir);
}
return hr;
}
BOOL CBackPropSheetPage::_DoesDirHaveMoreThanMax(LPCTSTR pszPath, int nMax)
{
_nFileCount = 0;
_nFileMax = nMax;
_AddPicturesFromDirRecursively(pszPath, TRUE);
return (nMax < _nFileCount);
}
#define MAX_PICTURES_TOSTOPRECURSION 100 // PERF: If the directory (My Pictures) has more than this many pictures, only add the pictures in the top level.
HRESULT CBackPropSheetPage::_AddFilesToList(void)
{
HRESULT hr = S_OK;
TCHAR szPath[MAX_PATH];
// Get the directory with the wallpaper files.
if (!GetStringFromReg(HKEY_LOCAL_MACHINE, c_szSetup, c_szSharedDir, NULL, szPath, ARRAYSIZE(szPath)))
{
if (!GetWindowsDirectory(szPath, ARRAYSIZE(szPath)))
{
szPath[0] = 0;
}
}
// Add only the *.BMP files in the windows directory.
_AddFilesToLV(szPath, c_rgpszWallpaperExt[0], 1, FALSE);
// Get the wallpaper Directory name
GetWallpaperDirName(szPath, ARRAYSIZE(szPath));
// Add all pictures from Wallpaper directory to the list!
_AddPicturesFromDir(szPath, FALSE);
// Get the path to the "My Pictures" folder
// NOTE: don't create the My Pictures directory -- if it doesn't exist, we won't find anything there anyway!
if (S_OK == SHGetFolderPath(NULL, CSIDL_MYPICTURES, NULL, 0, szPath))
{
// Add all pictures in "My Pictures" directory to the list!
if (!_DoesDirHaveMoreThanMax(szPath, MAX_PICTURES_TOSTOPRECURSION))
{
hr = _AddPicturesFromDirRecursively(szPath, FALSE);
}
}
//Get the path to the common "%UserProfile%\Application Data\" folder
if (S_OK == SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szPath))
{
// Add all pictures in common "%UserProfile%\Application Data\Microsoft Internet Explorer\" so we get the user's
// "Internet Explorer Wallpaper.bmp" file.
PathAppend(szPath, TEXT("Microsoft\\Internet Explorer"));
_AddPicturesFromDir(szPath, FALSE);
}
// Add pictures from Theme Directories
// 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(_GetPlus98ThemesDir(szPath, ARRAYSIZE(szPath))))
{
_AddPicturesFromDirRecursively(szPath, FALSE);
}
else if (SUCCEEDED(_GetPlus95ThemesDir(szPath, ARRAYSIZE(szPath))))
{
_AddPicturesFromDirRecursively(szPath, FALSE);
}
else if (SUCCEEDED(_GetKidsThemesDir(szPath, ARRAYSIZE(szPath))))
{
_AddPicturesFromDirRecursively(szPath, FALSE);
}
else if (SUCCEEDED(_GetHardDirThemesDir(szPath, ARRAYSIZE(szPath))))
{
_AddPicturesFromDirRecursively(szPath, FALSE);
}
return hr;
}
#define SZ_ALL_FILTER TEXT("*.*")
HRESULT CBackPropSheetPage::_AddPicturesFromDirRecursively(IN LPCTSTR pszDirName, BOOL fCount)
{
HRESULT hr = S_OK;
WIN32_FIND_DATA findFileData;
TCHAR szSearchPath[MAX_PATH];
_AddPicturesFromDir(pszDirName, fCount);
StrCpyN(szSearchPath, pszDirName, ARRAYSIZE(szSearchPath));
PathAppend(szSearchPath, SZ_ALL_FILTER);
HANDLE hFindFiles = FindFirstFile(szSearchPath, &findFileData);
if (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles))
{
while (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles) &&
!(fCount && (_nFileMax < _nFileCount)))
{
if ((FILE_ATTRIBUTE_DIRECTORY & findFileData.dwFileAttributes) &&
!PathIsDotOrDotDot(findFileData.cFileName))
{
TCHAR szSubDir[MAX_PATH];
StrCpyN(szSubDir, pszDirName, ARRAYSIZE(szSubDir));
PathAppend(szSubDir, findFileData.cFileName);
hr = _AddPicturesFromDirRecursively(szSubDir, fCount);
}
if (!FindNextFile(hFindFiles, &findFileData))
{
break;
}
}
FindClose(hFindFiles);
}
return hr;
}
void CBackPropSheetPage::_AddPicturesFromDir(LPCTSTR pszDirName, BOOL fCount)
{
int i;
// Add only the *.BMP files first (They can be shown even when Active Desktop is OFF)
_AddFilesToLV(pszDirName, c_rgpszWallpaperExt[0], 1, fCount);
if(_fAllowHtml)
{
// BMPs have already been added; So, start from the next.
for (i=1; i<ARRAYSIZE(c_rgpszWallpaperExt); i++)
{
// The .htm extension includes the .html files. Hence the .html extension is skipped.
// The .jpe extension includes the .jpeg files too. So, it .jpeg is skipped too!
if((lstrcmpi(c_rgpszWallpaperExt[i],TEXT("HTML")) == 0) ||
(lstrcmpi(c_rgpszWallpaperExt[i],TEXT("JPEG")) == 0))
continue;
_AddFilesToLV(pszDirName, c_rgpszWallpaperExt[i], i+1, fCount);
}
}
}
HRESULT GetActiveDesktop(IActiveDesktop ** ppActiveDesktop)
{
HRESULT hr = S_OK;
if (!*ppActiveDesktop)
{
IActiveDesktopP * piadp;
if (SUCCEEDED(hr = CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&piadp, IID_IActiveDesktopP)))
{
WCHAR wszScheme[MAX_PATH];
DWORD dwcch = ARRAYSIZE(wszScheme);
// Get the global "edit" scheme and set ourselves us to read from and edit that scheme
if (SUCCEEDED(piadp->GetScheme(wszScheme, &dwcch, SCHEME_GLOBAL | SCHEME_EDIT)))
{
piadp->SetScheme(wszScheme, SCHEME_LOCAL);
}
hr = piadp->QueryInterface(IID_PPV_ARG(IActiveDesktop, ppActiveDesktop));
piadp->Release();
}
}
else
{
(*ppActiveDesktop)->AddRef();
}
return hr;
}
HRESULT ReleaseActiveDesktop(IActiveDesktop ** ppActiveDesktop)
{
HRESULT hr = S_OK;
if (*ppActiveDesktop)
{
if((*ppActiveDesktop)->Release() == 0)
*ppActiveDesktop = NULL;
}
return hr;
}
#define SZ_REGKEY_CONTROLPANEL_DESKTOP TEXT("Control Panel\\Desktop")
#define SZ_REGVALUE_CP_PATTERN TEXT("pattern")
#define SZ_REGVALUE_CP_PATTERNUPGRADE TEXT("Pattern Upgrade")
#define SZ_REGVALUE_CONVERTED_WALLPAPER TEXT("ConvertedWallpaper")
#define SZ_REGVALUE_ORIGINAL_WALLPAPER TEXT("OriginalWallpaper") // We store this to find when someone changed the wallpaper around us
#define SZ_REGVALUE_CONVERTED_WP_LASTWRITE TEXT("ConvertedWallpaper Last WriteTime")
HRESULT CBackPropSheetPage::_LoadTempWallpaperSettings(IN LPCWSTR pszWallpaperFile)
{
// When we converted a non-.BMP wallpaper to a .bmp temp file,
// we keep the name of the original wallpaper path stored in _pszOriginalFile.
// We need to load that in now.
TCHAR szTempWallPaper[MAX_PATH];
DWORD dwType;
DWORD cbSize = sizeof(szTempWallPaper);
// ISSUE: CONVERTED and ORIGINAL are backwards, but we shipped beta1 like this so we can't change it... blech
DWORD dwError = SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CONVERTED_WALLPAPER, &dwType, (void *) szTempWallPaper, &cbSize);
HRESULT hr = HRESULT_FROM_WIN32(dwError);
if (SUCCEEDED(hr) && szTempWallPaper[0] && !_fWallpaperChanged)
{
TCHAR szOriginalWallPaper[MAX_PATH];
cbSize = sizeof(szOriginalWallPaper);
DWORD dwError = SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_ORIGINAL_WALLPAPER, &dwType, (void *) szOriginalWallPaper, &cbSize);
// It's possible that someone changed the wallpaper externally (IE's "Set as Wallpaper").
// We need to detect this and ignore the converted wallpaper regkey (SZ_REGVALUE_CONVERTED_WALLPAPER).
if ((ERROR_SUCCESS == dwError) && !StrCmpI(szOriginalWallPaper, pszWallpaperFile))
{
Str_SetPtr(&_pszOriginalFile, szTempWallPaper);
Str_SetPtr(&_pszOrigLastApplied, szTempWallPaper);
}
}
Str_SetPtrW(&_pszWallpaperInUse, pszWallpaperFile);
cbSize = sizeof(_ftLastWrite);
dwError = SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CONVERTED_WP_LASTWRITE, &dwType, (void *) &_ftLastWrite, &cbSize);
return S_OK; // Ignore the hr because it's fine if the value wasn't found.
}
#define POLICY_DISABLECOLORCUSTOMIZATION_ON 0x00000001
HRESULT CBackPropSheetPage::_LoadBackgroundColor(IN BOOL fInit)
{
HRESULT hr = E_INVALIDARG;
if (_punkSite)
{
IPropertyBag * pPropertyBag;
hr = _punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
if (SUCCEEDED(hr))
{
_rgbBkgdColor = 0x00000000;
hr = SHPropertyBag_ReadDWORD(pPropertyBag, SZ_PBPROP_BACKGROUND_COLOR, &_rgbBkgdColor);
if (fInit)
{
// Check the policy.
if (POLICY_DISABLECOLORCUSTOMIZATION_ON == SHRestricted(REST_NODISPLAYAPPEARANCEPAGE))
{
// We need to disable and hide the windows. We need to disable them so they can't get
// focus or accessibility.
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_COLORPICKER), FALSE);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_COLORPICKERLABEL), FALSE);
ShowWindow(GetDlgItem(_hwnd, IDC_BACK_COLORPICKER), SW_HIDE);
ShowWindow(GetDlgItem(_hwnd, IDC_BACK_COLORPICKERLABEL), SW_HIDE);
}
else
{
_colorControl.Initialize(GetDlgItem(_hwnd, IDC_BACK_COLORPICKER), _rgbBkgdColor);
}
}
else
{
_colorControl.SetColor(_rgbBkgdColor);
}
pPropertyBag->Release();
}
}
return hr;
}
HRESULT CBackPropSheetPage::_Initialize(void)
{
HRESULT hr = S_OK;
if (!_fInitialized && g_pActiveDesk)
{
WCHAR szPath[MAX_PATH];
// Add & select the current setting.
hr = g_pActiveDesk->GetWallpaper(szPath, ARRAYSIZE(szPath), 0);
if (SUCCEEDED(hr))
{
hr = _LoadTempWallpaperSettings(szPath);
_fInitialized = TRUE;
}
}
return hr;
}
void CBackPropSheetPage::_OnInitDialog(HWND hwnd)
{
int i;
TCHAR szBuf[MAX_PATH];
_Initialize();
_colorControl.ChangeTheme(hwnd);
// Upgrade the pattern setting. Since we got rid of the UI, we want to
// get rid of the setting on upgrade. We only want to do this once since
// if the user added it back, we don't want to redelete it.
if (FALSE == SHRegGetBoolUSValue(SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CP_PATTERNUPGRADE, FALSE, FALSE))
{
SHDeleteValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CP_PATTERN);
SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CP_PATTERNUPGRADE, REG_SZ, TEXT("TRUE"), ((lstrlen(TEXT("TRUE")) + 1) * sizeof(TCHAR)));
}
//
// Set some member variables.
//
_hwnd = hwnd;
_hwndLV = GetDlgItem(hwnd, IDC_BACK_WPLIST);
_hwndWPStyle = GetDlgItem(hwnd, IDC_BACK_WPSTYLE);
HWND hWndPrev = GetDlgItem(hwnd, IDC_BACK_PREVIEW);
if (hWndPrev)
{
SetWindowBits(hWndPrev, GWL_EXSTYLE, RTL_MIRRORED_WINDOW, 0);
}
_UpdatePreview(0, FALSE);
InitDeskHtmlGlobals();
if (!g_pActiveDesk)
{
return;
}
//
// Read in the restrictions.
//
_fForceAD = SHRestricted(REST_FORCEACTIVEDESKTOPON);
_fAllowAD = _fForceAD || !PolicyNoActiveDesktop();
if (_fAllowAD == FALSE)
{
_fAllowHtml = FALSE;
}
else
{
_fAllowHtml = !SHRestricted(REST_NOHTMLWALLPAPER);
}
//
// Check to see if there is a policy for Wallpaper name and wallpaper style.
//
_fPolicyForWallpaper = ReadPolicyForWallpaper(NULL, 0);
_fPolicyForStyle = ReadPolicyForWPStyle(NULL);
//
// Get the images into the listview.
//
HIMAGELIST himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON), ILC_MASK | ILC_COLOR32, ARRAYSIZE(c_rgpszWallpaperExt),
ARRAYSIZE(c_rgpszWallpaperExt));
if (himl)
{
SHFILEINFO sfi;
// Add the 'None' icon.
HICON hIconNone = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDI_BACK_NONE),
IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON), 0);
ImageList_AddIcon(himl, hIconNone);
int iPrefixLen = lstrlen(TEXT("foo."));
StrCpyN(szBuf, TEXT("foo."), ARRAYSIZE(szBuf)); //Pass "foo.bmp" etc., to SHGetFileInfo instead of ".bmp"
for (i=0; i<ARRAYSIZE(c_rgpszWallpaperExt); i++)
{
StrCpyN(szBuf+iPrefixLen, c_rgpszWallpaperExt[i], ARRAYSIZE(szBuf) - iPrefixLen);
if (SHGetFileInfo(szBuf, 0, &sfi, SIZEOF(sfi), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES))
{
ImageList_AddIcon(himl, sfi.hIcon);
DestroyIcon(sfi.hIcon);
}
}
ListView_SetImageList(_hwndLV, himl, LVSIL_SMALL);
}
// Add the single column that we want.
LV_COLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.iSubItem = 0;
ListView_InsertColumn(_hwndLV, 0, &lvc);
// Add 'none' option.
_AddAFileToLV(NULL, g_szNone, 0);
// Add the rest of the files.
_AddFilesToList();
// Sort the standard items.
ListView_SortItems(_hwndLV, _SortBackgrounds, 0);
WCHAR wszBuf[MAX_PATH];
LPTSTR pszBuf;
// Add & select the current setting.
g_pActiveDesk->GetWallpaper(wszBuf, ARRAYSIZE(wszBuf), 0);
//Convert wszBuf to szBuf.
pszBuf = (LPTSTR)wszBuf;
if (!_fAllowHtml && !IsNormalWallpaper(pszBuf))
{
*pszBuf = TEXT('\0');
}
_SetNewWallpaper(pszBuf, FALSE);
int iEndStyle = WPSTYLE_STRETCH;
for (i=0; i<= iEndStyle; i++)
{
LoadString(HINST_THISDLL, IDS_WPSTYLE+i, szBuf, ARRAYSIZE(szBuf));
ComboBox_AddString(_hwndWPStyle, szBuf);
}
WALLPAPEROPT wpo;
wpo.dwSize = sizeof(wpo);
g_pActiveDesk->GetWallpaperOptions(&wpo, 0);
ComboBox_SetCurSel(_hwndWPStyle, wpo.dwStyle);
// Adjust various UI components.
if (!_fAllowChanges)
{
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_DISPLAY), FALSE);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_WPSTYLE), FALSE);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_BROWSE), FALSE);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_WPLIST), FALSE);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_SELECT), FALSE);
}
// Disable controls based on the policies
if(_fPolicyForWallpaper)
{
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_BROWSE), FALSE);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_WPLIST), FALSE);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_SELECT), FALSE);
}
if(_fPolicyForStyle)
{
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_WPSTYLE), FALSE);
EnableWindow(GetDlgItem(_hwnd, IDC_BACK_DISPLAY), FALSE);
}
COMPONENTSOPT co;
co.dwSize = sizeof(COMPONENTSOPT);
g_pActiveDesk->GetDesktopItemOptions(&co, 0);
//if activedesktop is forced to be on, this overrides the NOACTIVEDESKTOP restriction
if (_fForceAD)
{
if(!co.fActiveDesktop)
{
co.fActiveDesktop = TRUE;
g_pActiveDesk->SetDesktopItemOptions(&co, 0);
}
}
else
{
//See if Active Desktop is to be turned off by restriction.
if (!_fAllowAD)
{
if (co.fActiveDesktop)
{
co.fActiveDesktop = FALSE;
g_pActiveDesk->SetDesktopItemOptions(&co, 0);
}
}
}
_EnableControls();
_LoadBackgroundColor(TRUE);
if (_fOpenAdvOnInit)
{
// Tell the Advanced dialog to open.
PostMessage(_hwnd, WM_COMMAND, (WPARAM)IDC_BACK_WEB, (LPARAM)GetDlgItem(_hwnd, IDC_BACK_WEB));
}
_StartSizeChecker();
}
// This function checks to see if the currently selected wallpaper is a HTML wallpaper
// and if so, it makes sure that the active desktop is enabled. If it is disabled
// then it prompts the user asking a question to see if the user wants to enable it.
//
void EnableADifHtmlWallpaper(HWND hwnd)
{
if(!g_pActiveDesk)
{
return;
}
// turn active desktop on or off, depending on background
ActiveDesktop_ApplyChanges();
}
void CBackPropSheetPage::_OnNotify(LPNMHDR lpnm)
{
//
// Start with a small stack allocation.
//
WCHAR wszBuf[MAX_PATH];
LPWSTR pszBuf = wszBuf;
DWORD cchBuf = ARRAYSIZE(wszBuf);
switch (lpnm->code)
{
case PSN_SETACTIVE:
{
HRESULT hr;
//
// Make sure the correct wallpaper is selected.
//
hr = g_pActiveDesk->GetWallpaper(pszBuf, cchBuf, 0);
if (FAILED(hr))
break;
//
// If we need more room, allocate it on the heap and try again.
//
if ( MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_MORE_DATA ) == hr )
{
cchBuf = INTERNET_MAX_URL_LENGTH;
pszBuf = (LPWSTR) LocalAlloc( LPTR, cchBuf * sizeof(WCHAR) );
if ( NULL == pszBuf )
break;
hr = g_pActiveDesk->GetWallpaper(pszBuf, cchBuf, 0);
if (S_OK != hr)
break;
}
_LoadBackgroundColor(FALSE);
_SetNewWallpaper(pszBuf, FALSE);
if (g_pActiveDesk)
{
WALLPAPEROPT wpo;
wpo.dwSize = sizeof(wpo);
g_pActiveDesk->GetWallpaperOptions(&wpo, 0);
ComboBox_SetCurSel(_hwndWPStyle, wpo.dwStyle);
}
}
break;
case PSN_APPLY:
_OnApply();
break;
case LVN_ITEMCHANGED:
NM_LISTVIEW *pnmlv = (NM_LISTVIEW *)lpnm;
if ((pnmlv->uChanged & LVIF_STATE) &&
(pnmlv->uNewState & LVIS_SELECTED))
{
LV_ITEM lvi = {0};
lvi.iItem = pnmlv->iItem;
lvi.mask = LVIF_PARAM;
ListView_GetItem(_hwndLV, &lvi);
LPCTSTR pszSelectedNew = (LPCTSTR)lvi.lParam;
//
// Make sure the correct wallpaper is selected.
//
HRESULT hr = g_pActiveDesk->GetWallpaper(pszBuf, cchBuf, 0);
if (FAILED(hr))
break;
//
// If we need more room, allocate it on the heap and try again.
//
if ( MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_MORE_DATA ) == hr )
{
cchBuf = INTERNET_MAX_URL_LENGTH;
pszBuf = (LPWSTR) LocalAlloc( LPTR, cchBuf * sizeof(WCHAR) );
if ( NULL == pszBuf )
break;
hr = g_pActiveDesk->GetWallpaper(pszBuf, cchBuf, 0);
if (S_OK != hr)
break;
}
if (lstrcmp(pszSelectedNew, pszBuf) != 0)
{
_SetNewWallpaper(pszSelectedNew, _fSelectionFromUser);
EnableApplyButton(_hwnd);
}
}
break;
}
//
// Free heap allocation (if any)
//
if ( wszBuf != pszBuf && NULL != pszBuf )
{
LocalFree( pszBuf );
}
}
#define MAX_PAGES 12
// Parameters:
// hwnd: We parent our UI on this hwnd.
// dwPage: Which page does the caller want to come up as default?
// Use ADP_DEFAULT if they don't care
// Return: S_OK if the user closed the dialog with OK.
// HRESULT_FROM_WIN32(ERROR_CANCELLED) will be returned
// if the user clicked the cancel button.
HRESULT CBackPropSheetPage::_LaunchAdvancedDisplayProperties(HWND hwnd)
{
HRESULT hr = E_OUTOFMEMORY;
CCompPropSheetPage * pWebDialog = new CCompPropSheetPage();
if (pWebDialog)
{
BOOL fEnableApply = FALSE;
IUnknown_SetSite(SAFECAST(pWebDialog, IObjectWithSite *), SAFECAST(this, IObjectWithSite *));
hr = pWebDialog->DisplayAdvancedDialog(_hwnd, SAFECAST(this, IPropertyBag *), &fEnableApply);
if (SUCCEEDED(hr) && (fEnableApply || _fHideDesktopIconDirty))
{
EnableApplyButton(_hwnd);
}
IUnknown_SetSite(SAFECAST(pWebDialog, IObjectWithSite *), NULL);
pWebDialog->Release();
}
return hr;
}
void CBackPropSheetPage::_OnCommand(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WORD wNotifyCode = HIWORD(wParam);
WORD wID = LOWORD(wParam);
HWND hwndCtl = (HWND)lParam;
switch (wID)
{
case IDC_BACK_WPSTYLE:
switch (wNotifyCode)
{
case CBN_SELCHANGE:
WALLPAPEROPT wpo;
wpo.dwSize = sizeof(WALLPAPEROPT);
g_pActiveDesk->GetWallpaperOptions(&wpo, 0);
wpo.dwStyle = ComboBox_GetCurSel(_hwndWPStyle);
g_pActiveDesk->SetWallpaperOptions(&wpo, 0);
_EnableControls();
_UpdatePreview(0, TRUE);
EnableApplyButton(_hwnd);
break;
}
break;
case IDC_BACK_BROWSE:
_BrowseForBackground();
break;
case IDC_BACK_WEB:
_LaunchAdvancedDisplayProperties(_hwnd);
break;
case IDC_BACK_COLORPICKER:
{
COLORREF rbgColorNew;
if (SUCCEEDED(_colorControl.OnCommand(hdlg, uMsg, wParam, lParam)) &&
SUCCEEDED(_colorControl.GetColor(&rbgColorNew)) &&
(rbgColorNew != _rgbBkgdColor))
{
_rgbBkgdColor = rbgColorNew;
if (_punkSite)
{
IPropertyBag * pPropertyBag;
if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag))))
{
SHPropertyBag_WriteDWORD(pPropertyBag, SZ_PBPROP_BACKGROUND_COLOR, _rgbBkgdColor);
pPropertyBag->Release();
}
}
EnableApplyButton(_hwnd);
_UpdatePreview(0, TRUE);
}
}
break;
}
}
HRESULT CBackPropSheetPage::_BrowseForBackground(void)
{
HRESULT hr;
WCHAR wszFileName[INTERNET_MAX_URL_LENGTH];
hr = g_pActiveDesk->GetWallpaper(wszFileName, ARRAYSIZE(wszFileName), 0);
if (SUCCEEDED(hr))
{
WCHAR szTestPath[MAX_PATH];
WCHAR szPath[MAX_PATH];
StrCpyNW(szPath, wszFileName, ARRAYSIZE(szPath));
PathRemoveFileSpec(szPath);
if (GetWindowsDirectory(szTestPath, ARRAYSIZE(szTestPath)) &&
!StrCmpIW(szTestPath, szPath))
{
// If the directory is equal to the boring %windir%, then use "My Pictures" instead.
hr = (SHGetSpecialFolderPath(NULL, wszFileName, CSIDL_MYPICTURES, FALSE) ? S_OK : E_FAIL);
lstrcat(wszFileName, TEXT("\\"));
}
else if (GetSystemDirectory(szTestPath, ARRAYSIZE(szTestPath)) &&
!StrCmpIW(szTestPath, szPath))
{
// If the directory is equal to the boring %windir%\system32, then use "My Pictures" instead.
hr = (SHGetSpecialFolderPath(NULL, wszFileName, CSIDL_MYPICTURES, FALSE) ? S_OK : E_FAIL);
lstrcat(wszFileName, TEXT("\\"));
}
else if (GetWindowsDirectory(szTestPath, ARRAYSIZE(szTestPath)))
{
PathAppendW(szTestPath, L"Web\\Wallpaper");
if (!StrCmpIW(szTestPath, szPath))
{
// If the directory is equal to the boring %windir%\web\wallpaper, then use "My Pictures" instead.
hr = (SHGetSpecialFolderPath(NULL, wszFileName, CSIDL_MYPICTURES, FALSE) ? S_OK : E_FAIL);
lstrcat(wszFileName, TEXT("\\"));
}
}
}
else
{
hr = (SHGetSpecialFolderPath(NULL, wszFileName, CSIDL_MYPICTURES, TRUE) ? S_OK : E_FAIL);
lstrcat(wszFileName, TEXT("\\"));
}
if (SUCCEEDED(hr))
{
DWORD adwFlags[] = { GFN_PICTURE, GFN_PICTURE, 0, 0};
int aiTypes[] = { IDS_BACK_FILETYPES, IDS_ALL_PICTURES, 0, 0};
if (_fAllowHtml)
{
SetFlag(adwFlags[0], GFN_LOCALHTM);
SetFlag(adwFlags[2], GFN_LOCALHTM);
aiTypes[2] = IDS_HTMLDOC;
}
if (wszFileName[0] == TEXT('\0'))
{
if (!GetWindowsDirectory(wszFileName, ARRAYSIZE(wszFileName)))
{
wszFileName[0] = 0;
}
// GetFileName breaks up the string into a directory and file
// component, so we append a slash to make sure everything
// is considered part of the directory.
lstrcat(wszFileName, TEXT("\\"));
}
if (GetFileName(_hwnd, wszFileName, ARRAYSIZE(wszFileName), aiTypes, adwFlags) &&
ValidateFileName(_hwnd, wszFileName, IDS_BACK_TYPE1))
{
if (_fAllowHtml || IsNormalWallpaper(wszFileName))
{
_SetNewWallpaper(wszFileName, TRUE);
EnableApplyButton(_hwnd);
}
}
}
return hr;
}
void CBackPropSheetPage::_OnDestroy()
{
}
INT_PTR CALLBACK CBackPropSheetPage::BackgroundDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
CBackPropSheetPage * pThis = (CBackPropSheetPage *)GetWindowLongPtr(hDlg, DWLP_USER);
if (WM_INITDIALOG == wMsg)
{
PROPSHEETPAGE * pPropSheetPage = (PROPSHEETPAGE *) lParam;
if (pPropSheetPage)
{
SetWindowLongPtr(hDlg, DWLP_USER, pPropSheetPage->lParam);
pThis = (CBackPropSheetPage *)pPropSheetPage->lParam;
}
}
if (pThis)
return pThis->_BackgroundDlgProc(hDlg, wMsg, wParam, lParam);
return DefWindowProc(hDlg, wMsg, wParam, lParam);
}
BOOL_PTR CBackPropSheetPage::_BackgroundDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
_OnInitDialog(hdlg);
break;
case WM_NOTIFY:
_OnNotify((LPNMHDR)lParam);
break;
case WM_COMMAND:
_OnCommand(hdlg, uMsg, wParam, lParam);
break;
case WM_SYSCOLORCHANGE:
case WM_SETTINGCHANGE:
case WM_DISPLAYCHANGE:
case WM_QUERYNEWPALETTE:
case WM_PALETTECHANGED:
SHPropagateMessage(hdlg, uMsg, wParam, lParam, TRUE);
break;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, SZ_HELPFILE_DESKTOPTAB, HELP_WM_HELP, (ULONG_PTR)aBackHelpIDs);
break;
case WM_CONTEXTMENU:
WinHelp((HWND) wParam, SZ_HELPFILE_DESKTOPTAB, HELP_CONTEXTMENU, (ULONG_PTR)(LPVOID) aBackHelpIDs);
break;
case WM_DESTROY:
{
TCHAR szFileName[MAX_PATH];
//Delete the tempoaray HTX file created for non-HTML wallpaper preview.
GetTempPath(ARRAYSIZE(szFileName), szFileName);
lstrcatn(szFileName, PREVIEW_PICTURE_FILENAME, ARRAYSIZE(szFileName));
DeleteFile(szFileName);
_OnDestroy();
}
break;
case WM_DRAWITEM:
switch (wParam)
{
case IDC_BACK_COLORPICKER:
_colorControl.OnDrawItem(hdlg, uMsg, wParam, lParam);
return TRUE;
}
break;
case WM_THEMECHANGED:
_colorControl.ChangeTheme(hdlg);
break;
}
return FALSE;
}
HRESULT CBackPropSheetPage::_OnApply(void)
{
// Our parent dialog will be notified of the Apply event and will call our
// IBasePropPage::OnApply() to do the real work.
return S_OK;
}
/*****************************************************************************\
DESCRIPTION:
This function will start a background thread which will make sure our
MRU of pictures in the Wallpaper list have been checked. They will be checked
to verify that we know their width & height. This way, when we choose a wallpaper, we can quickly
see if it should use "Stretch" or "Tile". We want to tile if they are very
small, indicating that they are probably watermark in nature.
\*****************************************************************************/
#define TIME_SCANFREQUENCY (8 * 60 /*Secs*/) // We don't want to rescan the files more than once per 8 minutes
HRESULT CBackPropSheetPage::_StartSizeChecker(void)
{
HRESULT hr = S_OK;
BOOL fSkipCheck = FALSE;
DWORD dwType;
FILETIME ftLastScan;
FILETIME ftCurrentTime;
SYSTEMTIME stCurrentTime;
DWORD cbSize = sizeof(ftLastScan);
GetSystemTime(&stCurrentTime);
SystemTimeToFileTime(&stCurrentTime, &ftCurrentTime);
// If we have recently scanned, skip the scan.
if ((ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_WALLPAPER, SZ_REGVALUE_LASTSCAN, &dwType, (LPBYTE) &ftLastScan, &cbSize)) &&
(REG_BINARY == dwType) &&
(sizeof(ftLastScan) == cbSize))
{
ULARGE_INTEGER * pulLastScan = (ULARGE_INTEGER *)&ftLastScan;
ULARGE_INTEGER * pulCurrent = (ULARGE_INTEGER *)&ftCurrentTime;
ULARGE_INTEGER ulDelta;
ulDelta.QuadPart = (pulCurrent->QuadPart - pulLastScan->QuadPart);
ulDelta.QuadPart /= 10000000; // units in a second
if (ulDelta.QuadPart < TIME_SCANFREQUENCY)
{
fSkipCheck = TRUE;
}
}
if (!fSkipCheck)
{
AddRef();
if (!SHCreateThread(CBackPropSheetPage::SizeCheckerThreadProc, this, (CTF_COINIT | CTF_FREELIBANDEXIT | CTF_PROCESS_REF), NULL))
{
hr = E_FAIL;
Release();
}
SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_WALLPAPER, SZ_REGVALUE_LASTSCAN, REG_BINARY, (LPCBYTE) &ftCurrentTime, sizeof(ftLastScan));
}
return hr;
}
typedef struct
{
TCHAR szPath[MAX_PATH];
DWORD dwSizeX;
DWORD dwSizeY;
FILETIME ftLastModified;
} WALLPAPERSIZE_STRUCT;
#define MAX_WALLPAPERSIZEMRU 500
HRESULT CBackPropSheetPage::_GetMRUObject(IMruDataList ** ppSizeMRU)
{
HRESULT hr = CoCreateInstance(CLSID_MruLongList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IMruDataList, ppSizeMRU));
if (SUCCEEDED(hr))
{
hr = (*ppSizeMRU)->InitData(MAX_WALLPAPERSIZEMRU, MRULISTF_USE_STRCMPIW, HKEY_CURRENT_USER, SZ_REGKEY_WALLPAPERMRU, NULL);
if (FAILED(hr))
{
ATOMICRELEASE(*ppSizeMRU);
}
}
return hr;
}
BOOL IsGraphicsFile(LPCTSTR pszFile)
{
BOOL fIsGraphicsFile = FALSE;
if (pszFile && *pszFile)
{
LPCTSTR pszExt = PathFindExtension(pszFile);
if (*pszExt == TEXT('.'))
{
pszExt++;
for (int iRet = 0; iRet < ARRAYSIZE(c_rgpszWallpaperExt); iRet++)
{
if (StrCmpIC(pszExt, c_rgpszWallpaperExt[iRet]) == 0)
{
fIsGraphicsFile = TRUE;
}
}
}
}
return fIsGraphicsFile;
}
HRESULT CBackPropSheetPage::_CalcSizeForFile(IN LPCTSTR pszPath, IN WIN32_FIND_DATA * pfdFile, IN OUT DWORD * pdwAdded)
{
HRESULT hr = S_OK;
if (!_pSizeMRUBk)
{
hr = _GetMRUObject(&_pSizeMRUBk);
}
if (SUCCEEDED(hr))
{
WALLPAPERSIZE_STRUCT wallpaperSize;
int nIndex;
StrCpyNW(wallpaperSize.szPath, pszPath, ARRAYSIZE(wallpaperSize.szPath));
// Let's see if it's already in the MRU.
hr = _pSizeMRUBk->FindData((LPCBYTE) &wallpaperSize, sizeof(wallpaperSize), &nIndex);
if (SUCCEEDED(hr))
{
// If so, let's see if it's been modified since.
hr = _pSizeMRUBk->GetData(nIndex, (LPBYTE) &wallpaperSize, sizeof(wallpaperSize));
if (SUCCEEDED(hr))
{
if (CompareFileTime(&wallpaperSize.ftLastModified, &pfdFile->ftLastWriteTime))
{
// We want to delete this index because it would colide with the name of
// the new entry we are going to add below.
_pSizeMRUBk->Delete(nIndex);
hr = E_FAIL; // We need to rescan.
}
else
{
(*pdwAdded)++; // We are only going to check the first 500 files. We don't want to waste too much time on this heuristical feature.
}
}
}
if (FAILED(hr))
{
(*pdwAdded)++; // We are only going to check the first 500 files. We don't want to waste too much time on this heuristical feature.
hr = S_OK;
// We didn't find it so we need to add it.
if (!_pImgFactBk)
{
hr = CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellImageDataFactory, &_pImgFactBk));
}
if (SUCCEEDED(hr))
{
IShellImageData* pImage;
hr = _pImgFactBk->CreateImageFromFile(pszPath, &pImage);
if (SUCCEEDED(hr))
{
hr = pImage->Decode(SHIMGDEC_DEFAULT, 0, 0);
if (SUCCEEDED(hr))
{
SIZE size;
hr = pImage->GetSize(&size);
if (SUCCEEDED(hr) && size.cx && size.cy)
{
DWORD dwSlot = 0;
StrCpyNW(wallpaperSize.szPath, pszPath, ARRAYSIZE(wallpaperSize.szPath));
wallpaperSize.dwSizeX = size.cx;
wallpaperSize.dwSizeY = size.cy;
wallpaperSize.ftLastModified = pfdFile->ftLastWriteTime;
hr = _pSizeMRUBk->AddData((LPCBYTE) &wallpaperSize, sizeof(wallpaperSize), &dwSlot);
}
}
pImage->Release();
}
}
}
}
return hr;
}
HRESULT CBackPropSheetPage::_CalcSizeFromDir(IN LPCTSTR pszPath, IN OUT DWORD * pdwAdded, IN BOOL fRecursive)
{
HRESULT hr = S_OK;
if (MAX_WALLPAPERSIZEMRU > *pdwAdded)
{
WIN32_FIND_DATA findFileData;
TCHAR szSearchPath[MAX_PATH];
StrCpyN(szSearchPath, pszPath, ARRAYSIZE(szSearchPath));
PathAppend(szSearchPath, SZ_ALL_FILTER);
HANDLE hFindFiles = FindFirstFile(szSearchPath, &findFileData);
if (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles))
{
while (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles) &&
(MAX_WALLPAPERSIZEMRU > *pdwAdded))
{
if (!PathIsDotOrDotDot(findFileData.cFileName))
{
if (FILE_ATTRIBUTE_DIRECTORY & findFileData.dwFileAttributes)
{
if (fRecursive)
{
TCHAR szSubDir[MAX_PATH];
StrCpyN(szSubDir, pszPath, ARRAYSIZE(szSubDir));
PathAppend(szSubDir, findFileData.cFileName);
hr = _CalcSizeFromDir(szSubDir, pdwAdded, fRecursive);
}
}
else
{
if (IsGraphicsFile(findFileData.cFileName))
{
TCHAR szPath[MAX_PATH];
StrCpyN(szPath, pszPath, ARRAYSIZE(szPath));
PathAppend(szPath, findFileData.cFileName);
hr = _CalcSizeForFile(szPath, &findFileData, pdwAdded);
}
}
}
if (!FindNextFile(hFindFiles, &findFileData))
{
break;
}
}
FindClose(hFindFiles);
}
}
return hr;
}
/*****************************************************************************\
DESCRIPTION:
This function will create or update the sizes of the files we have in the
wallpaper list. We can later use this to decide if we want to select "Tile"
vs. "Stretch".
PERF:
We don't track more than 500 files because we want to keep the MRU from
growing too much. Users shouldn't have more than that many files normally.
And if so, they won't get this feature.
Max 500 Files: First scan will take ~35 seconds on a 300MHz 128MB machine.
Max 500 Files: Update scan will take ~3 seconds on a 300MHz 128MB machine.
\*****************************************************************************/
DWORD CBackPropSheetPage::_SizeCheckerThreadProc(void)
{
HRESULT hr;
DWORD dwAdded = 0;
TCHAR szPath[MAX_PATH];
// We want to make our priority low so we don't slow down the UI.
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
// Get the directory with the wallpaper files.
if (!GetStringFromReg(HKEY_LOCAL_MACHINE, c_szSetup, c_szSharedDir, NULL, szPath, ARRAYSIZE(szPath)))
{
if (!GetWindowsDirectory(szPath, ARRAYSIZE(szPath)))
{
szPath[0] = 0;
}
}
// Add only the *.BMP files in the windows directory.
_CalcSizeFromDir(szPath, &dwAdded, FALSE);
// Get the wallpaper Directory name
szPath[0] = 0;
GetWallpaperDirName(szPath, ARRAYSIZE(szPath));
if (szPath[0])
{
// Add all pictures from Wallpaper directory to the list!
_CalcSizeFromDir(szPath, &dwAdded, TRUE);
}
//Get the path to the "My Pictures" folder
if (S_OK == SHGetFolderPath(NULL, CSIDL_MYPICTURES | CSIDL_FLAG_CREATE, NULL, 0, szPath))
{
// Add all pictures in "My Pictures" directory to the list!
hr = _CalcSizeFromDir(szPath, &dwAdded, TRUE);
}
//Get the path to the common "My Pictures" folder
if (S_OK == SHGetFolderPath(NULL, CSIDL_COMMON_PICTURES | CSIDL_FLAG_CREATE, NULL, 0, szPath))
{
// Add all pictures in common "My Pictures" directory to the list!
hr = _CalcSizeFromDir(szPath, &dwAdded, TRUE);
}
// Add pictures from Theme Directories
// 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(_GetPlus98ThemesDir(szPath, ARRAYSIZE(szPath))))
{
_CalcSizeFromDir(szPath, &dwAdded, TRUE);
}
else if (SUCCEEDED(_GetPlus95ThemesDir(szPath, ARRAYSIZE(szPath))))
{
_CalcSizeFromDir(szPath, &dwAdded, TRUE);
}
else if (SUCCEEDED(_GetKidsThemesDir(szPath, ARRAYSIZE(szPath))))
{
_CalcSizeFromDir(szPath, &dwAdded, TRUE);
}
else if (SUCCEEDED(_GetHardDirThemesDir(szPath, ARRAYSIZE(szPath))))
{
_CalcSizeFromDir(szPath, &dwAdded, TRUE);
}
ATOMICRELEASE(_pSizeMRUBk);
ATOMICRELEASE(_pImgFactBk);
_fScanFinished = TRUE;
Release();
return 0;
}
// We decide to use tile mode if the width and height of the
// picture are 256x256 or smaller. Anything this small is most
// likely a watermark. Besides, it will always look bad stretched
// or centered.
// We make exceptions for the following wallpaper that we ship
// that is watermark:
// "Boiling Point.jpg", which is 163x293.
// "Fall Memories.jpg", which is 210x185.
// "Fly Away.jpg", which is 210x185.
// "Prairie Wind.jpg", which is 255x255.
// "Santa Fe Stucco.jpg", which is 256x256.
// "Soap Bubbles.jpg", which is 256x256.
// "Water Color.jpg", which is 218x162.
#define SHOULD_USE_TILE(xPicture, yPicture, xMonitor, yMonitor) ((((((LONG)(xPicture) * 6) < (xMonitor)) && (((LONG)(yPicture) * 6) < (yMonitor)))) || \
(((xPicture) <= 256) && ((yPicture) <= 256)) || \
(((xPicture) == 163) && ((yPicture) == 293)))
DWORD CBackPropSheetPage::_GetStretchMode(IN LPCTSTR pszPath)
{
HRESULT hr = S_OK;
DWORD dwStretchMode = WPSTYLE_STRETCH; // Default to Stretch.
if (_fScanFinished)
{
// If we just finished the Scan, we want to release _pSizeMRU and get a new one.
// The object will cache the registry state so it may have none or very few of the results
// because it was obtained before the background thread did all it's work.
ATOMICRELEASE(_pSizeMRU);
_fScanFinished = FALSE;
}
if (!_pSizeMRU)
{
hr = _GetMRUObject(&_pSizeMRU);
}
if (SUCCEEDED(hr))
{
WALLPAPERSIZE_STRUCT wallpaperSize;
int nIndex;
StrCpyNW(wallpaperSize.szPath, pszPath, ARRAYSIZE(wallpaperSize.szPath));
// Let's see if it's already in the MRU.
hr = _pSizeMRU->FindData((LPCBYTE) &wallpaperSize, sizeof(wallpaperSize), &nIndex);
if (SUCCEEDED(hr))
{
// If so, let's see if it's been modified since.
hr = _pSizeMRU->GetData(nIndex, (LPBYTE) &wallpaperSize, sizeof(wallpaperSize));
if (SUCCEEDED(hr))
{
WIN32_FIND_DATA findFileData;
HANDLE hFindFiles = FindFirstFile(pszPath, &findFileData);
if (hFindFiles && (INVALID_HANDLE_VALUE != hFindFiles))
{
// Yes, the value exists and is up to date.
if (!CompareFileTime(&wallpaperSize.ftLastModified, &findFileData.ftLastWriteTime))
{
RECT rc;
GetMonitorRects(GetPrimaryMonitor(), &rc, 0);
// We decide to use tile mode if the width and height of the
// picture are 1/6th the size of the default monitor.
if (SHOULD_USE_TILE(wallpaperSize.dwSizeX, wallpaperSize.dwSizeY, RECTWIDTH(rc), RECTHEIGHT(rc)))
{
dwStretchMode = WPSTYLE_TILE;
}
else
{
double dWidth = ((double)wallpaperSize.dwSizeX * ((double)RECTHEIGHT(rc) / ((double)RECTWIDTH(rc))));
// We want to use WPSTYLE_CENTER if it's more than 7% off of a 4x3 aspect ratio.
// We do this to prevent it from looking bad because it's stretched too much in
// one direction. The reason we use 7% is because some common screen solutions
// (1280 x 1024) aren't 4x3, but they are under 7% of that.
if (dWidth <= (wallpaperSize.dwSizeY * 1.07) && (dWidth >= (wallpaperSize.dwSizeY * 0.92)))
{
dwStretchMode = WPSTYLE_STRETCH; // This is within 4x3
}
else
{
dwStretchMode = WPSTYLE_CENTER;
}
}
}
FindClose(hFindFiles);
}
}
}
}
return dwStretchMode;
}
//===========================
// *** IBasePropPage Interface ***
//===========================
HRESULT CBackPropSheetPage::GetAdvancedDialog(OUT IAdvancedDialog ** ppAdvDialog)
{
HRESULT hr = E_INVALIDARG;
if (ppAdvDialog)
{
*ppAdvDialog = NULL;
hr = _LoadState();
if (SUCCEEDED(hr))
{
CCompPropSheetPage * pThis = new CCompPropSheetPage();
if (pThis)
{
hr = pThis->QueryInterface(IID_PPV_ARG(IAdvancedDialog, ppAdvDialog));
pThis->Release();
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
return hr;
}
HRESULT CBackPropSheetPage::OnApply(IN PROPPAGEONAPPLY oaAction)
{
HRESULT hr = S_OK;
if (PPOAACTION_CANCEL != oaAction)
{
if (_fAllowChanges)
{
// The user clicked Okay in the dialog so merge the dirty state from the
// advanced dialog into the base dialog.
EnableADifHtmlWallpaper(_hwnd);
SetSafeMode(SSM_CLEAR);
g_pActiveDesk->SetWallpaper(_pszOriginalFile, 0);
SetSafeMode(SSM_CLEAR);
EnableADifHtmlWallpaper(_hwnd);
if (g_pActiveDesk)
{
g_pActiveDesk->ApplyChanges(g_dwApplyFlags);
}
}
if (SUCCEEDED(hr))
{
hr = _SaveIconState();
if (SUCCEEDED(hr))
{
hr = _SaveDesktopOptionsState();
}
}
if (g_iRunDesktopCleanup != BST_INDETERMINATE)
{
ApplyDesktopCleanupSettings(); // ignore return value, as nobody cares about it
}
SetWindowLongPtr(_hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
}
return hr;
}
BOOL IsIconHeaderProperty(IN LPCOLESTR pszPropName)
{
return (!StrCmpNIW(SZ_ICONHEADER, pszPropName, ARRAYSIZE(SZ_ICONHEADER) - 1) &&
((ARRAYSIZE(SZ_ICONHEADER) + MAX_GUID_STRING_LEN - 1) < lstrlenW(pszPropName)));
}
BOOL IsShowDeskIconProperty(IN LPCOLESTR pszPropName)
{
return ((!StrCmpNIW(STARTPAGE_ON_PREFIX, pszPropName, LEN_PROP_PREFIX) ||
!StrCmpNIW(STARTPAGE_OFF_PREFIX, pszPropName, LEN_PROP_PREFIX) ||
!StrCmpNIW(POLICY_PREFIX, pszPropName, LEN_PROP_PREFIX)) &&
((LEN_PROP_PREFIX + MAX_GUID_STRING_LEN - 1) <= lstrlenW(pszPropName)));
}
//===========================
// *** IPropertyBag Interface ***
//===========================
HRESULT CBackPropSheetPage::Read(IN LPCOLESTR pszPropName, IN VARIANT * pVar, IN IErrorLog *pErrorLog)
{
HRESULT hr = E_INVALIDARG;
if (pszPropName && pVar)
{
VARTYPE vtDesired = pVar->vt;
if (!StrCmpW(pszPropName, SZ_PBPROP_BACKGROUND_PATH)) // Get the real current wallpaper (after conversion to .bmp)
{
WCHAR szPath[MAX_PATH];
hr = g_pActiveDesk->GetWallpaper(szPath, ARRAYSIZE(szPath), 0);
if (SUCCEEDED(hr))
{
WCHAR szFullPath[MAX_PATH];
// The string may come back with environment variables.
if (0 == SHExpandEnvironmentStrings(szPath, szFullPath, ARRAYSIZE(szFullPath)))
{
StrCpyN(szFullPath, szPath, ARRAYSIZE(szFullPath)); // We failed so use the original.
}
hr = InitVariantFromStr(pVar, szFullPath);
}
}
else if (!StrCmpW(pszPropName, SZ_PBPROP_BACKGROUNDSRC_PATH)) // Get the original wallpaper (before convertion to .bmp)
{
WCHAR szPath[MAX_PATH];
hr = _Initialize();
if (SUCCEEDED(hr))
{
if (_pszLastSourcePath)
{
hr = InitVariantFromStr(pVar, _pszLastSourcePath);
}
else if (_pszOrigLastApplied)
{
hr = InitVariantFromStr(pVar, _pszOrigLastApplied);
}
else
{
hr = g_pActiveDesk->GetWallpaper(szPath, ARRAYSIZE(szPath), 0);
if (SUCCEEDED(hr))
{
hr = InitVariantFromStr(pVar, szPath);
}
}
}
}
else if (!StrCmpW(pszPropName, SZ_PBPROP_BACKGROUND_TILE))
{
if (g_pActiveDesk)
{
WALLPAPEROPT wpo;
wpo.dwSize = sizeof(wpo);
hr = g_pActiveDesk->GetWallpaperOptions(&wpo, 0);
if (SUCCEEDED(hr))
{
pVar->ulVal = wpo.dwStyle;
pVar->vt = VT_UI4;
}
}
}
else if (!StrCmpW(pszPropName, SZ_PBPROP_WEBCOMPONENTS))
{
if (g_pActiveDesk)
{
g_pActiveDesk->AddRef();
pVar->punkVal = g_pActiveDesk;
pVar->vt = VT_UNKNOWN;
hr = S_OK;
}
}
else if (IsIconHeaderProperty(pszPropName))
{
// The caller can pass us the string in the following format:
// pszPropName="CLSID\{<CLSID>}\DefaultIcon:<Item>" = "<FilePath>,<ResourceIndex>"
// For example:
// pszPropName="CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon:DefaultValue" = "%WinDir%SYSTEM\COOL.DLL,16"
hr = _LoadState();
if (SUCCEEDED(hr))
{
CLSID clsid;
WCHAR szTemp[MAX_PATH];
// Get the CLSID
StrCpyNW(szTemp, &(pszPropName[ARRAYSIZE(SZ_ICONHEADER) - 2]), ARRAYSIZE(szTemp));
hr = SHCLSIDFromString(szTemp, &clsid);
if (SUCCEEDED(hr))
{
// Get the name of the icon type. Normally this is "DefaultIcon", but it can be several states, like
// "full" and "empty" for the recycle bin.
LPCWSTR pszToken = StrChrW((pszPropName + ARRAYSIZE(SZ_ICONHEADER)), L':');
BOOL fOldIcon = FALSE;
// If they use a ";" instead of a ":" then they want the old icon.
if (!pszToken)
{
pszToken = StrChrW((pszPropName + ARRAYSIZE(SZ_ICONHEADER)), L';');
fOldIcon = TRUE;
}
hr = E_FAIL;
if (pszToken)
{
TCHAR szIconPath[MAX_PATH];
pszToken++;
hr = _GetIconPath(clsid, pszToken, FALSE, szIconPath, ARRAYSIZE(szIconPath));
if (SUCCEEDED(hr))
{
hr = InitVariantFromStr(pVar, szIconPath);
}
}
}
}
}
else if(IsShowDeskIconProperty(pszPropName))
{
int iStartPaneOn = (int)(StrCmpNIW(pszPropName, STARTPAGE_ON_PREFIX, LEN_PROP_PREFIX) == 0);
for(int iIndex = 0; iIndex < NUM_DESKICONS; iIndex++)
{
if(lstrcmpiW(pszPropName+LEN_PROP_PREFIX, c_aDeskIconId[iIndex].pwszCLSID) == 0)
{
BOOL fBoolValue = FALSE;
pVar->vt = VT_BOOL;
//Check if we are looking for the POLICY or for Show/Hide
if(!StrCmpNIW(POLICY_PREFIX, pszPropName, LEN_PROP_PREFIX))
{
//We are reading "whether-the-POLICY-is-set" property!
fBoolValue = _aDeskIconNonEnumData[iIndex].fNonEnumPolicySet;
}
else
{
//We are reading the fHideIcon property.
fBoolValue = _aHideDesktopIcon[iStartPaneOn][iIndex].fHideIcon;
}
pVar ->boolVal = fBoolValue ? VARIANT_TRUE : VARIANT_FALSE;
hr = S_OK;
break; //break out of the loop!
}
}
}
if (SUCCEEDED(hr))
hr = VariantChangeTypeForRead(pVar, vtDesired);
}
return hr;
}
HRESULT CBackPropSheetPage::Write(IN LPCOLESTR pszPropName, IN VARIANT *pVar)
{
HRESULT hr = E_INVALIDARG;
if (pszPropName && pVar)
{
if ((VT_UI4 == pVar->vt) &&
_fAllowChanges &&
!StrCmpW(pszPropName, SZ_PBPROP_BACKGROUND_TILE))
{
hr = _SetNewWallpaperTile(pVar->ulVal, FALSE);
}
if (!StrCmpW(pszPropName, SZ_PBPROP_OPENADVANCEDDLG) &&
(VT_BOOL == pVar->vt))
{
_fOpenAdvOnInit = (VARIANT_TRUE == pVar->boolVal);
hr = S_OK;
}
else if (!StrCmpW(pszPropName, SZ_PBPROP_WEBCOMPONENTS) &&
(VT_UNKNOWN == pVar->vt))
{
IUnknown_Set((IUnknown **) &g_pActiveDesk, pVar->punkVal);
hr = S_OK;
}
else if (VT_BSTR == pVar->vt)
{
if (_fAllowChanges && !StrCmpW(pszPropName, SZ_PBPROP_BACKGROUND_PATH))
{
_fWallpaperChanged = TRUE;
hr = _SetNewWallpaper(pVar->bstrVal, FALSE);
}
else if (IsIconHeaderProperty(pszPropName))
{
// The caller can pass us the string in the following format:
// pszPropName="CLSID\{<CLSID>}\DefaultIcon:<Item>" = "<FilePath>,<ResourceIndex>"
// For example:
// pszPropName="CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon:DefaultValue" = "%WinDir%SYSTEM\COOL.DLL,16"
hr = _LoadState();
if (SUCCEEDED(hr))
{
CLSID clsid;
WCHAR szTemp[MAX_PATH];
// Get the CLSID
StrCpyNW(szTemp, &(pszPropName[ARRAYSIZE(SZ_ICONHEADER) - 2]), ARRAYSIZE(szTemp));
hr = SHCLSIDFromString(szTemp, &clsid);
if (SUCCEEDED(hr))
{
// Get the name of the icon type. Normally this is "DefaultIcon", but it can be several states, like
// "full" and "empty" for the recycle bin.
LPCWSTR pszToken = StrChrW((pszPropName + ARRAYSIZE(SZ_ICONHEADER)), L':');
hr = E_FAIL;
if (pszToken)
{
pszToken++;
StrCpyNW(szTemp, pszToken, ARRAYSIZE(szTemp));
// Now the pVar->bstrVal is the icon path + "," + resourceID. Separate those two.
WCHAR szPath[MAX_PATH];
StrCpyNW(szPath, pVar->bstrVal, ARRAYSIZE(szPath));
int nResourceID = PathParseIconLocationW(szPath);
hr = _SetIconPath(clsid, szTemp, szPath, nResourceID);
}
}
}
}
}
else if((VT_BOOL == pVar->vt) && (IsShowDeskIconProperty(pszPropName)))
{
int iStartPaneOn = (int)(StrCmpNIW(pszPropName, STARTPAGE_ON_PREFIX, LEN_PROP_PREFIX) == 0);
for(int iIndex = 0; iIndex < NUM_DESKICONS; iIndex++)
{
if(lstrcmpiW(pszPropName+LEN_PROP_PREFIX, c_aDeskIconId[iIndex].pwszCLSID) == 0)
{
BOOL fNewHideIconStatus = (VARIANT_TRUE == pVar->boolVal);
//check if the new hide icon status is different from the old one.
if(_aHideDesktopIcon[iStartPaneOn][iIndex].fHideIcon != fNewHideIconStatus)
{
_aHideDesktopIcon[iStartPaneOn][iIndex].fHideIcon = fNewHideIconStatus;
_aHideDesktopIcon[iStartPaneOn][iIndex].fDirty = TRUE;
_fHideDesktopIconDirty = TRUE;
}
hr = S_OK;
break; //break out of the loop!
}
}
}
}
return hr;
}
//===========================
// *** IShellPropSheetExt Interface ***
//===========================
HRESULT CBackPropSheetPage::AddPages(IN LPFNSVADDPROPSHEETPAGE pfnAddPage, IN LPARAM lParam)
{
HRESULT hr = E_NOTIMPL;
PROPSHEETPAGE psp = {0};
// If classic shell is forced, then we desk.cpl will put-up the old background page
// So, we should not replace that with this new background page.
// (Note: All other ActiveDesktop restrictions are checked in dcomp.cpp to prevent
// the web tab from appearing there).
if (SHRestricted(REST_CLASSICSHELL))
{
// It's restricted, so don't add this page.
hr = E_ACCESSDENIED;
}
else
{
// Initialize a bunch of propsheetpage variables.
psp.dwSize = sizeof(psp);
psp.hInstance = HINST_THISDLL;
psp.dwFlags = PSP_DEFAULT | PSP_USECALLBACK;
psp.lParam = (LPARAM) this;
// psp.hIcon = NULL; // unused (PSP_USEICON is not set)
// psp.pszTitle = NULL; // unused (PSP_USETITLE is not set)
// psp.lParam = 0; // unused
// psp.pcRefParent = NULL;
psp.pszTemplate = MAKEINTRESOURCE(IDD_BACKGROUND);
psp.pfnDlgProc = CBackPropSheetPage::BackgroundDlgProc;
HPROPSHEETPAGE hpsp = CreatePropertySheetPage(&psp);
if (hpsp)
{
if (pfnAddPage(hpsp, lParam))
{
hr = S_OK;
}
else
{
DestroyPropertySheetPage(hpsp);
hr = E_FAIL;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
//===========================
// *** IUnknown Interface ***
//===========================
ULONG CBackPropSheetPage::AddRef()
{
_cRef++;
return _cRef;
}
ULONG CBackPropSheetPage::Release()
{
ASSERT(_cRef > 0);
_cRef--;
if (_cRef > 0)
return _cRef;
delete this;
return 0;
}
HRESULT CBackPropSheetPage::QueryInterface(REFIID riid, void **ppvObj)
{
HRESULT hr = E_NOINTERFACE;
static const QITAB qit[] = {
QITABENT(CBackPropSheetPage, IObjectWithSite),
QITABENT(CBackPropSheetPage, IBasePropPage),
QITABENT(CBackPropSheetPage, IPersist),
QITABENT(CBackPropSheetPage, IPropertyBag),
QITABENTMULTI(CBackPropSheetPage, IShellPropSheetExt, IBasePropPage),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
//===========================
// *** Class Methods ***
//===========================
CBackPropSheetPage::CBackPropSheetPage(void) : CObjectCLSID(&PPID_Background)
{
_cRef = 1;
_punkSite = NULL;
_pszOriginalFile = NULL;
_pszLastSourcePath = NULL;
_pszOrigLastApplied = NULL;
_pszWallpaperInUse = NULL;
_pImgFactBk = NULL;
_pSizeMRU = NULL;
_pSizeMRUBk = NULL;
_fThemePreviewCreated = FALSE;
_pThemePreview = NULL;
_fWallpaperChanged = FALSE;
_fSelectionFromUser = TRUE;
_fStateLoaded = FALSE;
_fOpenAdvOnInit = FALSE;
_fScanFinished = FALSE;
_fInitialized = FALSE;
_fAllowChanges = (!SHRestricted(REST_NOCHANGINGWALLPAPER) && !IsTSPerfFlagEnabled(TSPerFlag_NoADWallpaper) && !IsTSPerfFlagEnabled(TSPerFlag_NoWallpaper));
g_dwApplyFlags = (AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH);
GetActiveDesktop(&g_pActiveDesk);
}
CBackPropSheetPage::~CBackPropSheetPage(void)
{
ASSERT(!_pSizeMRUBk); // Should have been released by the background thread.
ASSERT(!_pImgFactBk); // Should have been released by the background thread.
Str_SetPtr(&_pszOriginalFile, NULL);
Str_SetPtrW(&_pszOrigLastApplied, NULL);
Str_SetPtrW(&_pszWallpaperInUse, NULL);
Str_SetPtrW(&_pszLastSourcePath, NULL);
if (_pSizeMRU)
{
_pSizeMRU->Release();
_pSizeMRU = NULL;
}
if (_pThemePreview)
{
_pThemePreview->Release();
_pThemePreview = NULL;
}
ReleaseActiveDesktop(&g_pActiveDesk);
}