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.
5855 lines
203 KiB
5855 lines
203 KiB
#include "stdafx.h"
|
|
#pragma hdrstop
|
|
|
|
#include "..\deskfldr.h"
|
|
#include "dutil.h"
|
|
|
|
extern "C" char * __cdecl StrTokEx(char ** pstring, const char * control);
|
|
|
|
#define DXA_GROWTH_CONST 10
|
|
#define ZINDEX_START 1000
|
|
|
|
#define MAXID_LENGTH 10 //Maximum number of digits in ID string plus 1.
|
|
|
|
#define TF_DESKSTAT 0
|
|
#define TF_DYNAMICHTML 0
|
|
|
|
IActiveDesktop *g_pActiveDesk = NULL;
|
|
|
|
#define c_szRegStrDesktop REGSTR_PATH_DESKTOP
|
|
#define c_szWallpaper REG_VAL_GENERAL_WALLPAPER
|
|
#define c_szBackupWallpaper REG_VAL_GENERAL_BACKUPWALLPAPER
|
|
#define c_szPattern TEXT("Pattern")
|
|
#define c_szTileWall REG_VAL_GENERAL_TILEWALLPAPER
|
|
#define c_szWallpaperStyle REG_VAL_GENERAL_WALLPAPERSTYLE
|
|
#define c_szWallpaperTime REG_VAL_GENERAL_WALLPAPERTIME
|
|
#define c_szWallpaperLocalTime REG_VAL_GENERAL_WALLPAPERLOCALTIME
|
|
#define c_szRefreshDesktop TEXT("RefreshDesktop")
|
|
#define c_szBufferedRefresh TEXT("BufferedRefresh")
|
|
|
|
#define COMP_TYPE 0x00000003
|
|
#define COMP_SELECTED 0x00002000
|
|
#define COMP_NOSCROLL 0x00004000
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define ENTERPROC EnterProcDS
|
|
#define EXITPROC ExitProcDS
|
|
|
|
void EnterProcDS(DWORD dwTraceLevel, LPSTR szFmt, ...);
|
|
void ExitProcDS(DWORD dwTraceLevel, LPSTR szFmt, ...);
|
|
|
|
extern DWORD g_dwDeskStatTrace;
|
|
|
|
#else
|
|
#ifndef CCOVER
|
|
#pragma warning(disable:4002)
|
|
#define ENTERPROC()
|
|
#define EXITPROC()
|
|
#else // ccover buildi
|
|
// these are needed because of a bug in cl.exe that results in improper processing
|
|
// of #pragma when run with cl -P, and then compiling
|
|
#define ENTERPROC 1 ? (void) 0 : (void)
|
|
#define EXITPROC 1 ? (void) 0 : (void)
|
|
#endif //end of ccover
|
|
#endif
|
|
|
|
MAKE_CONST_BSTR(s_sstrBeforeEnd, L"BeforeEnd");
|
|
MAKE_CONST_BSTR(s_sstrDeskMovr, L"DeskMovr");
|
|
MAKE_CONST_BSTR(s_sstrDeskMovrW, L"DeskMovrW");
|
|
MAKE_CONST_BSTR(s_sstrclassid, L"classid");
|
|
MAKE_CONST_BSTR(s_sstrEmpty, L"");
|
|
|
|
|
|
STDAPI ParseDesktopComponent(HWND hwndOwner, LPWSTR wszURL, COMPONENT *pInfo);
|
|
|
|
WCHAR wUnicodeBOM = 0xfeff; // Little endian unicode Byte Order Mark.First byte:0xff, Second byte: 0xfe.
|
|
|
|
//extern BOOL IsWallpaperDesktopV2(LPCTSTR lpszWallpaper);
|
|
|
|
CReadFileObj::CReadFileObj(LPCTSTR lpszFileName)
|
|
{
|
|
//Open the file
|
|
if ((_hFile = CreateFile(lpszFileName, GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
WCHAR wBOM;
|
|
DWORD dwBytesRead = 0;
|
|
|
|
if ((ReadFile(_hFile, (LPVOID)&wBOM, sizeof(WCHAR), &dwBytesRead, NULL)) &&
|
|
(dwBytesRead == sizeof(WCHAR)))
|
|
{
|
|
if (wBOM == wUnicodeBOM)
|
|
_iCharset = UNICODE_HTML_CHARSET;
|
|
else
|
|
{
|
|
//Note: Anything other than the little endian unicode file is treated as ansi.
|
|
_iCharset = ANSI_HTML_CHARSET;
|
|
SetFilePointer(_hFile, 0L, NULL, FILE_BEGIN); //Seek to the begining of the file
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CReadFileObj::~CReadFileObj()
|
|
{
|
|
if (_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(_hFile);
|
|
_hFile = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This will read and if necessary convert between ANSI and UNICODE
|
|
//
|
|
HRESULT CReadFileObj::FileReadAndConvertChars(int iDestCharset, LPWSTR lpwszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead, UINT *puiCharsConverted)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
DWORD dwCharsRead = 0;
|
|
DWORD dwTotalCharsConverted = 0;
|
|
if (_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (_iCharset == UNICODE_HTML_CHARSET)
|
|
{
|
|
if (iDestCharset == UNICODE_HTML_CHARSET)
|
|
{
|
|
hres = FileReadCharsW(lpwszBuff, uiCharsToRead, (UINT *)&dwCharsRead);
|
|
dwTotalCharsConverted = dwCharsRead;
|
|
}
|
|
else
|
|
{
|
|
//Destination is ansi; Read the UNICODE source and convert to ANSI.
|
|
WCHAR wszBuf[INTERNET_MAX_URL_LENGTH + 1]; //Temp buffer to read the UNICODE chars into.
|
|
LPSTR lpszBuff = (LPSTR)lpwszBuff;
|
|
|
|
DWORD dwTotalCharsToRead = (DWORD)uiCharsToRead;
|
|
|
|
while(dwTotalCharsToRead)
|
|
{
|
|
DWORD dwCount;
|
|
DWORD dwActuallyRead;
|
|
|
|
// - 1 to give room for a null character at the end.
|
|
dwCount = (DWORD)min(dwTotalCharsToRead, (ARRAYSIZE(wszBuf) - 1));
|
|
if (ReadFile(_hFile, (LPSTR)wszBuf, dwCount*sizeof(WCHAR), &dwActuallyRead, NULL))
|
|
{
|
|
DWORD dwConverted;
|
|
dwActuallyRead = dwActuallyRead/sizeof(WCHAR);
|
|
|
|
//Null terminate the source buffer.
|
|
wszBuf[dwActuallyRead] = L'\0'; //UNICODE null terminate the source.
|
|
//Convert what we just read.
|
|
dwConverted = SHUnicodeToAnsi(wszBuf, lpszBuff, dwActuallyRead+1); //+1 for null termination
|
|
|
|
//Update the count & stuff.
|
|
lpszBuff += dwConverted - 1; //Subtract the null.
|
|
dwTotalCharsToRead -= dwActuallyRead;
|
|
dwCharsRead += dwActuallyRead;
|
|
dwTotalCharsConverted += dwConverted - 1; //Subtract the null.
|
|
|
|
if (dwActuallyRead < dwCount)
|
|
break; //We have reached the end of file.
|
|
}
|
|
else
|
|
{
|
|
hres = E_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Source file is ANSI. Check the Destination.
|
|
if (iDestCharset == ANSI_HTML_CHARSET)
|
|
{
|
|
//Destination is ANSI too! Cool! No need for conversion!
|
|
hres = FileReadCharsA((LPSTR)lpwszBuff, uiCharsToRead, (UINT *)&dwCharsRead);
|
|
dwTotalCharsConverted = dwCharsRead;
|
|
}
|
|
else
|
|
{
|
|
//Destination is UNICODE! Read the ansi and convert it to UNICODE!
|
|
char szBuf[INTERNET_MAX_URL_LENGTH + 1]; //Temp buffer to read the ansi chars into.
|
|
DWORD dwTotalCharsToRead = (DWORD)uiCharsToRead;
|
|
|
|
while(dwTotalCharsToRead)
|
|
{
|
|
DWORD dwCount;
|
|
DWORD dwActuallyRead;
|
|
|
|
// - 1 to give room for a null character at the end.
|
|
dwCount = (DWORD)min(dwTotalCharsToRead, (ARRAYSIZE(szBuf) - 1));
|
|
|
|
if (ReadFile(_hFile, (LPSTR)szBuf, dwCount, &dwActuallyRead, NULL))
|
|
{
|
|
DWORD dwConverted;
|
|
//Null terminate the source buffer.
|
|
szBuf[dwActuallyRead] = '\0'; //ANSI null terminate the source.
|
|
//Convert what we just read.
|
|
dwConverted = SHAnsiToUnicode(szBuf, lpwszBuff, dwActuallyRead+1); //+1 for null termination
|
|
|
|
//Update the count & stuff.
|
|
lpwszBuff += dwConverted - 1; //Subtract the null.
|
|
dwTotalCharsToRead -= dwActuallyRead;
|
|
dwCharsRead += dwActuallyRead;
|
|
dwTotalCharsConverted += dwConverted - 1; //Subtract the null.
|
|
|
|
if (dwActuallyRead < dwCount)
|
|
break; //We have reached the end of file.
|
|
}
|
|
else
|
|
{
|
|
hres = E_FAIL;
|
|
break;
|
|
}
|
|
} //while
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hres = E_FAIL; //The file handle is bad.
|
|
|
|
*puiCharsActuallyRead = (UINT)dwCharsRead;
|
|
*puiCharsConverted = (UINT)dwTotalCharsConverted;
|
|
return hres;
|
|
}
|
|
|
|
|
|
HRESULT CReadFileObj::FileReadCharsA(LPSTR lpszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
DWORD dwCharsRead = 0;
|
|
|
|
if ((_hFile != INVALID_HANDLE_VALUE) &&
|
|
(_iCharset == ANSI_HTML_CHARSET) &&
|
|
ReadFile(_hFile, (LPVOID)lpszBuff, (DWORD)(uiCharsToRead), &dwCharsRead, NULL))
|
|
{
|
|
dwCharsRead = dwCharsRead; //get the number of wchars read.
|
|
hres = S_OK;
|
|
}
|
|
*puiCharsActuallyRead = (UINT)dwCharsRead;
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// NOTE: The uiCharsToRead must be atleast one less than the size of the buffer (lpwszBuff)
|
|
// because one null may be written at the end of the buffer by SHAnsiToUnicode().
|
|
//
|
|
HRESULT CReadFileObj::FileReadCharsW(LPWSTR lpwszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
DWORD dwCharsRead = 0;
|
|
|
|
if ((_hFile != INVALID_HANDLE_VALUE) &&
|
|
(_iCharset == UNICODE_HTML_CHARSET) &&
|
|
ReadFile(_hFile, (LPVOID)lpwszBuff, (DWORD)(uiCharsToRead*sizeof(WCHAR)), &dwCharsRead, NULL))
|
|
{
|
|
dwCharsRead = dwCharsRead/sizeof(WCHAR); //get the number of wchars read.
|
|
hres = S_OK;
|
|
}
|
|
*puiCharsActuallyRead = (UINT)dwCharsRead;
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CReadFileObj::FileSeekChars(LONG lCharOffset, DWORD dwOrigin)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
if (_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (SetFilePointer(_hFile,
|
|
lCharOffset*((_iCharset == UNICODE_HTML_CHARSET) ? sizeof(WCHAR) : sizeof(char)),
|
|
NULL,
|
|
dwOrigin) != INVALID_SET_FILE_POINTER)
|
|
hres = S_OK;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CReadFileObj::FileGetCurCharOffset(LONG *plCharOffset)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
DWORD dwByteOffset = 0;
|
|
|
|
*plCharOffset = 0;
|
|
if (_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
if ((dwByteOffset = SetFilePointer(_hFile,
|
|
0L,
|
|
NULL,
|
|
FILE_CURRENT)) != INVALID_SET_FILE_POINTER)
|
|
{
|
|
*plCharOffset = dwByteOffset/((_iCharset == UNICODE_HTML_CHARSET) ? sizeof(WCHAR) : sizeof(char));
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
BOOL GetStringFromReg(HKEY hkey,
|
|
LPCTSTR lpszSubkey,
|
|
LPCTSTR lpszValueName,
|
|
LPTSTR lpszValue,
|
|
DWORD cchSizeofValueBuff)
|
|
{
|
|
DWORD cb = cchSizeofValueBuff * sizeof(lpszValue[0]);
|
|
return (ERROR_SUCCESS == SHGetValue(hkey, lpszSubkey, lpszValueName, NULL, lpszValue, &cb));
|
|
}
|
|
|
|
void GetWallpaperFileTime(LPCTSTR pszWallpaper, LPFILETIME lpftFileTime)
|
|
{
|
|
HANDLE hFile;
|
|
BOOL fRet = FALSE;
|
|
|
|
if ((hFile = CreateFile(pszWallpaper, GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
fRet = GetFileTime(hFile, NULL, NULL, lpftFileTime);
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (!fRet)
|
|
{
|
|
ZeroMemory(lpftFileTime, sizeof(FILETIME));
|
|
}
|
|
|
|
// no return value
|
|
}
|
|
|
|
BOOL HasWallpaperReallyChanged(LPCTSTR pszRegKey, LPTSTR pszOldWallpaper, LPTSTR pszBackupWallpaper, DWORD dwOldWallpaperStyle, DWORD dwNewWallpaperStyle)
|
|
{
|
|
// we default to TRUE here.
|
|
|
|
if ((dwOldWallpaperStyle == dwNewWallpaperStyle)
|
|
&& (0 == lstrcmpi(pszOldWallpaper, pszBackupWallpaper)))
|
|
{
|
|
// The wallpaper filename and style hasn't changed.
|
|
// But, the content of this file could have changed.
|
|
// See if the content has changed by looking at the
|
|
// last-written date and time stamp on this file.
|
|
FILETIME ftOld, ftBack;
|
|
DWORD cbBack = sizeof(ftBack);
|
|
|
|
// if either of these fail, then they will
|
|
// remain Zero so the compare will
|
|
// be successful.
|
|
GetWallpaperFileTime(pszOldWallpaper, &ftOld);
|
|
if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, pszRegKey, c_szWallpaperTime, NULL, &ftBack, &cbBack))
|
|
{
|
|
ZeroMemory(&ftBack, sizeof(ftBack));
|
|
}
|
|
|
|
//Get the last written time of the backup wallpaper from registry
|
|
if (0 == CompareFileTime(&ftOld, &ftBack))
|
|
return FALSE; // everything is the same!
|
|
|
|
// Win2K QFE bug 10689 (AndrewGr)
|
|
// same check, but instead of checking UTC time, check local time converted to UTC time
|
|
// this is because FAT disks store local time, not UTC time
|
|
FILETIME ftLocalBack, ftLocalBackUtc;
|
|
|
|
cbBack = sizeof(ftLocalBack);
|
|
|
|
if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, pszRegKey, c_szWallpaperLocalTime, NULL, &ftLocalBack, &cbBack))
|
|
{
|
|
ZeroMemory(&ftLocalBack, sizeof(ftLocalBack));
|
|
}
|
|
|
|
LocalFileTimeToFileTime(&ftLocalBack, &ftLocalBackUtc);
|
|
|
|
if (ftOld.dwLowDateTime == ftLocalBackUtc.dwLowDateTime
|
|
&& (ftOld.dwHighDateTime == ftLocalBackUtc.dwHighDateTime))
|
|
// everything is the same!
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------//
|
|
// Function: ReadWallpaperStyleFromReg()
|
|
//
|
|
// This function reads the "TileWallpaper" and the "WallpaperStyle" from the given location
|
|
// in the registry.
|
|
//
|
|
//-------------------------------------------------------------------------------------------------------------//
|
|
|
|
int GetIntFromReg(HKEY hKey,
|
|
LPCTSTR lpszSubkey,
|
|
LPCTSTR lpszNameValue,
|
|
int iDefault)
|
|
{
|
|
TCHAR szValue[20];
|
|
DWORD dwSizeofValueBuff = sizeof(szValue);
|
|
int iRetValue = iDefault;
|
|
DWORD dwType;
|
|
|
|
if ((SHGetValue(hKey, lpszSubkey, lpszNameValue, &dwType, szValue,
|
|
&dwSizeofValueBuff) == ERROR_SUCCESS) && dwSizeofValueBuff)
|
|
{
|
|
if (dwType == REG_SZ)
|
|
{
|
|
iRetValue = (int)StrToInt(szValue);
|
|
}
|
|
}
|
|
|
|
return iRetValue;
|
|
}
|
|
|
|
void ReadWallpaperStyleFromReg(LPCTSTR pszRegKey, DWORD *pdwWallpaperStyle, BOOL fIgnorePlatforms)
|
|
{
|
|
if (GetIntFromReg(HKEY_CURRENT_USER, pszRegKey, c_szTileWall, WPSTYLE_TILE))
|
|
{
|
|
// "Tile" overrides the "Stretch" style.
|
|
*pdwWallpaperStyle = WPSTYLE_TILE;
|
|
}
|
|
else
|
|
{
|
|
// else, STRETCH or CENTER.
|
|
*pdwWallpaperStyle = GetIntFromReg(HKEY_CURRENT_USER, pszRegKey, c_szWallpaperStyle, WPSTYLE_CENTER);
|
|
}
|
|
}
|
|
|
|
BOOL CActiveDesktop::_IsDisplayInSafeMode(void)
|
|
{
|
|
WCHAR wszDisplay[MAX_PATH];
|
|
DWORD dwcch = MAX_PATH;
|
|
|
|
return (SUCCEEDED(GetScheme(wszDisplay, &dwcch, SCHEME_GLOBAL | SCHEME_DISPLAY))
|
|
&& (0 == StrCmpW(wszDisplay, REG_DESKCOMP_SAFEMODE_SUFFIX_L)));
|
|
}
|
|
|
|
|
|
BOOL ReadPolicyForWallpaper(LPTSTR pszPolicy, DWORD cchPolicy)
|
|
{
|
|
BOOL fPolicySet = FALSE;
|
|
DWORD cb = cchPolicy * sizeof(pszPolicy[0]);
|
|
if ((SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_WP_POLICY, c_szWallpaper, NULL, pszPolicy, &cb) == ERROR_SUCCESS) && cb)
|
|
{
|
|
// even if this value was originally REG_SZ it may still
|
|
// have environment vars in it for legacy reasons!
|
|
if (SUCCEEDED(PathExpandEnvStringsWrap(pszPolicy, cchPolicy)))
|
|
{
|
|
fPolicySet = TRUE; //Policy is there!
|
|
}
|
|
else
|
|
{
|
|
pszPolicy[0] = 0; // if we couldn't expand correctly, null it out to be safe
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// See if the TS Perf policy is set to turn it off for perf.
|
|
fPolicySet = (IsTSPerfFlagEnabled(TSPerFlag_NoADWallpaper) || IsTSPerfFlagEnabled(TSPerFlag_NoWallpaper)); //No policy is set!
|
|
}
|
|
|
|
return fPolicySet;
|
|
}
|
|
|
|
HRESULT GetWallpaperPath(HKEY hKey, LPCTSTR pszKey, LPCTSTR pszValue, LPCTSTR pszFallback, LPTSTR pszPath, DWORD cchSize)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (GetStringFromReg(hKey, pszKey, pszValue, pszPath, cchSize))
|
|
{
|
|
hr = PathExpandEnvStringsWrap(pszPath, cchSize);
|
|
}
|
|
else if (pszFallback)
|
|
{
|
|
hr = StringCchCopy(pszPath, cchSize, pszFallback);
|
|
}
|
|
else
|
|
{
|
|
pszPath[0] = 0;
|
|
hr = S_FALSE; // couldn't get it from registry, we null the output buffer, but this is not catastrophic
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL ReadPolicyForWPStyle(LPDWORD lpdwStyle)
|
|
{
|
|
DWORD dwStyle;
|
|
DWORD dwType;
|
|
TCHAR szValue[20];
|
|
DWORD dwSizeofValueBuff = sizeof(szValue);
|
|
BOOL fRet = FALSE;
|
|
|
|
// The caller can passin a NULL, if they are not interested in the actual value and they just
|
|
// want to know if this policy is set or not.
|
|
if (!lpdwStyle)
|
|
lpdwStyle = &dwStyle;
|
|
|
|
if ((SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_WP_POLICY, c_szWallpaperStyle, &dwType, szValue,
|
|
&dwSizeofValueBuff) == ERROR_SUCCESS) && dwSizeofValueBuff)
|
|
{
|
|
if (dwType == REG_SZ)
|
|
{
|
|
*lpdwStyle = (DWORD)StrToInt(szValue);
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
BOOL CActiveDesktop::_ReadWallpaper(BOOL fActiveDesktop)
|
|
{
|
|
ENTERPROC(2, "DS ReadWallpaper()");
|
|
|
|
TCHAR szDeskcomp[MAX_PATH];
|
|
GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
|
|
|
|
_fPolicyForWPName = ReadPolicyForWallpaper(_szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper));
|
|
_fPolicyForWPStyle = ReadPolicyForWPStyle(&_wpo.dwStyle);
|
|
|
|
//
|
|
// Read in the wallpaper and style from the appropriate registry location.
|
|
//
|
|
LPCTSTR pszRegKey;
|
|
if (fActiveDesktop)
|
|
{
|
|
pszRegKey = szDeskcomp;
|
|
TCHAR szOldWallpaper[MAX_PATH];
|
|
DWORD dwOldWallpaperStyle;
|
|
|
|
// Read the Wallpaper from the Old location.
|
|
if (S_OK != GetWallpaperPath(HKEY_CURRENT_USER, c_szRegStrDesktop, c_szWallpaper, NULL, szOldWallpaper, ARRAYSIZE(szOldWallpaper)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Read wallpaper style from the old location.
|
|
ReadWallpaperStyleFromReg((LPCTSTR)c_szRegStrDesktop, &dwOldWallpaperStyle, FALSE);
|
|
|
|
// Read the wallpaper from the new location too!
|
|
if ((!_fPolicyForWPName) || (_IsDisplayInSafeMode()))
|
|
{
|
|
HRESULT hrPath = GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szWallpaper, szOldWallpaper, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper));
|
|
if (S_FALSE == hrPath)
|
|
{
|
|
pszRegKey = c_szRegStrDesktop;
|
|
}
|
|
else if (FAILED(hrPath))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//Read wallpaper style from the new location too!
|
|
if (!_fPolicyForWPStyle)
|
|
{
|
|
ReadWallpaperStyleFromReg(pszRegKey, &_wpo.dwStyle, FALSE);
|
|
}
|
|
|
|
//If there is a Safe mode scheme here do NOT attempt to change wallpaper
|
|
if ((!_IsDisplayInSafeMode()) && (!_fPolicyForWPName))
|
|
{
|
|
//Read what is stored as "Backup" wallpaper.
|
|
if (S_OK != GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szBackupWallpaper, szOldWallpaper, _szBackupWallpaper, ARRAYSIZE(_szBackupWallpaper)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
//See if the Old wallpaper is differnet from the backed up wallpaper
|
|
if (HasWallpaperReallyChanged(pszRegKey, szOldWallpaper, _szBackupWallpaper, dwOldWallpaperStyle, _wpo.dwStyle))
|
|
{
|
|
//They are different. This means that some other app has changed the "Old" wallpaper
|
|
//after the last time we backed it up in the registry.
|
|
// Make this wallpaper as the Selected wallpaper!
|
|
|
|
if (FAILED(StringCchCopy(_szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper), szOldWallpaper)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
_wpo.dwStyle = dwOldWallpaperStyle;
|
|
|
|
_fWallpaperDirty = TRUE;
|
|
_fWallpaperChangedDuringInit = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//Make a backup of the "Old" wallpaper from szOldWallpaper
|
|
if (FAILED(StringCchCopy(_szBackupWallpaper, ARRAYSIZE(_szBackupWallpaper), szOldWallpaper)))
|
|
{
|
|
_szBackupWallpaper[0] = 0; // on failure null it out, this value is just an optimization
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszRegKey = c_szRegStrDesktop; //Get it from the old location!
|
|
|
|
//Since active desktop is not available, read wallpaper from old location.
|
|
if (!_fPolicyForWPName)
|
|
{
|
|
if (S_OK != GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szWallpaper, NULL, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//Read the wallpaper style
|
|
if (!_fPolicyForWPStyle)
|
|
ReadWallpaperStyleFromReg(pszRegKey, &_wpo.dwStyle, TRUE);
|
|
|
|
//Make a backup of the "Old" wallpaper from _szSelectedWallpaper
|
|
if (FAILED(StringCchCopy(_szBackupWallpaper, ARRAYSIZE(_szBackupWallpaper), _szSelectedWallpaper)))
|
|
{
|
|
_szBackupWallpaper[0] = 0; // on failure null it out, this value is just an optimization
|
|
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS ReadWallpaper! (_szSelectedWP=>%s<)", _szSelectedWallpaper);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CActiveDesktop::_ReadPattern(void)
|
|
{
|
|
ENTERPROC(2, "DS ReadPattern()");
|
|
|
|
GetStringFromReg(HKEY_CURRENT_USER, c_szRegStrDesktop, c_szPattern, _szSelectedPattern, ARRAYSIZE(_szSelectedPattern));
|
|
|
|
EXITPROC(2, "DS ReadPattern! (_szSelectedPattern=>%s<)", _szSelectedPattern);
|
|
}
|
|
|
|
void CActiveDesktop::_ReadComponent(HKEY hkey, LPCTSTR pszComp)
|
|
{
|
|
ENTERPROC(2, "DS ReadComponent(hk=%08X,pszComp=>%s<)", hkey, pszComp);
|
|
|
|
HKEY hkeyComp;
|
|
|
|
if (RegOpenKeyEx(hkey, pszComp, 0, KEY_READ, &hkeyComp) == ERROR_SUCCESS)
|
|
{
|
|
DWORD cbSize;
|
|
COMPONENTA comp;
|
|
comp.dwSize = sizeof(COMPONENTA);
|
|
|
|
//
|
|
// Read in the source string.
|
|
//
|
|
cbSize = sizeof(comp.szSource);
|
|
if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_SOURCE, NULL, NULL, (LPBYTE)&comp.szSource, &cbSize) != ERROR_SUCCESS)
|
|
{
|
|
comp.szSource[0] = TEXT('\0');
|
|
}
|
|
|
|
//
|
|
// Read in the SubscribedURL string.
|
|
//
|
|
cbSize = sizeof(comp.szSubscribedURL);
|
|
if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_SUBSCRIBED_URL, NULL, NULL, (LPBYTE)&comp.szSubscribedURL, &cbSize) != ERROR_SUCCESS)
|
|
{
|
|
comp.szSubscribedURL[0] = TEXT('\0');
|
|
}
|
|
|
|
//
|
|
// Read in the Friendly name string.
|
|
//
|
|
cbSize = sizeof(comp.szFriendlyName);
|
|
if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_NAME, NULL, NULL, (LPBYTE)&comp.szFriendlyName, &cbSize) != ERROR_SUCCESS)
|
|
{
|
|
comp.szFriendlyName[0] = TEXT('\0');
|
|
}
|
|
|
|
//
|
|
// Read in and parse the flags.
|
|
//
|
|
DWORD dwFlags;
|
|
cbSize = sizeof(dwFlags);
|
|
if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_FLAGS, NULL, NULL, (LPBYTE)&dwFlags, &cbSize) != ERROR_SUCCESS)
|
|
{
|
|
dwFlags = 0;
|
|
}
|
|
comp.iComponentType = dwFlags & COMP_TYPE;
|
|
comp.fChecked = (dwFlags & COMP_SELECTED) != 0;
|
|
comp.fNoScroll = (dwFlags & COMP_NOSCROLL) != 0;
|
|
comp.fDirty = FALSE; //Reading it fresh from registry; Can't be dirty!
|
|
|
|
//
|
|
// Read in the location.
|
|
//
|
|
cbSize = sizeof(comp.cpPos);
|
|
if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_POSITION, NULL, NULL, (LPBYTE)&comp.cpPos, &cbSize) != ERROR_SUCCESS)
|
|
{
|
|
ZeroMemory(&comp.cpPos, sizeof(comp.cpPos));
|
|
}
|
|
|
|
//
|
|
// In IE4.x, we have a very huge positive number (0x7fffffff) as the COMPONENT_TOP;
|
|
// As a result some component's z-index overflowed into the negative range (0x80000003)
|
|
// To fix this, we halved the COMPONENT_TOP (0x3fffffff) and also check for negative z-index
|
|
// values and covert them to postive values.
|
|
if (comp.cpPos.izIndex < 0)
|
|
comp.cpPos.izIndex = COMPONENT_TOP;
|
|
|
|
//
|
|
// Make sure the cpPos.dwSize is set to correct value
|
|
//
|
|
comp.cpPos.dwSize = sizeof(COMPPOS);
|
|
|
|
//
|
|
// Read in the current ItemState
|
|
//
|
|
cbSize = sizeof(comp.dwCurItemState);
|
|
if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_CURSTATE, NULL, NULL, (LPBYTE)&comp.dwCurItemState, &cbSize) != ERROR_SUCCESS)
|
|
{
|
|
//If the item state is missing, we must be reading from IE4 machine.
|
|
comp.dwCurItemState = IS_NORMAL;
|
|
}
|
|
|
|
//
|
|
// Read in the Original state info.
|
|
//
|
|
cbSize = sizeof(comp.csiOriginal);
|
|
if ((SHQueryValueEx(hkeyComp, REG_VAL_COMP_ORIGINALSTATEINFO, NULL, NULL, (LPBYTE)&comp.csiOriginal, &cbSize) != ERROR_SUCCESS) ||
|
|
(comp.csiOriginal.dwSize != sizeof(comp.csiOriginal)))
|
|
{
|
|
//If the item state is missing, we must be reading from IE4 machine.
|
|
// Set the OriginalState to the default info.
|
|
SetStateInfo(&comp.csiOriginal, &comp.cpPos, IS_NORMAL);
|
|
comp.csiOriginal.dwHeight = comp.csiOriginal.dwWidth = COMPONENT_DEFAULT_WIDTH;
|
|
}
|
|
|
|
//
|
|
// Read in the Restored state info.
|
|
//
|
|
cbSize = sizeof(comp.csiRestored);
|
|
if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_RESTOREDSTATEINFO, NULL, NULL, (LPBYTE)&comp.csiRestored, &cbSize) != ERROR_SUCCESS)
|
|
{
|
|
//If the item state is missing, we must be reading from IE4 machine.
|
|
// Set the restored State to the default info.
|
|
SetStateInfo(&comp.csiRestored, &comp.cpPos, IS_NORMAL);
|
|
}
|
|
|
|
//
|
|
// Add the component to the component list.
|
|
//
|
|
AddComponentPrivate(&comp, StrToInt(pszComp));
|
|
|
|
//
|
|
// Increment our counter so we know where to add any new
|
|
// components after we're done.
|
|
//
|
|
_dwNextID++;
|
|
|
|
RegCloseKey(hkeyComp);
|
|
}
|
|
|
|
EXITPROC(2, "DS ReadComponent!");
|
|
}
|
|
|
|
typedef struct _tagSortStruct {
|
|
int ihdsaIndex;
|
|
int izIndex;
|
|
} SORTSTRUCT;
|
|
|
|
int CALLBACK pfnComponentSort(LPVOID p1, LPVOID p2, LPARAM lParam)
|
|
{
|
|
SORTSTRUCT * pss1 = (SORTSTRUCT *)p1;
|
|
SORTSTRUCT * pss2 = (SORTSTRUCT *)p2;
|
|
|
|
if (pss1->izIndex > pss2->izIndex)
|
|
return 1;
|
|
|
|
if (pss1->izIndex < pss2->izIndex)
|
|
return -1;
|
|
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// ModifyZIndex
|
|
//
|
|
// Little helper function to put the zindex of the windowed and windowless components
|
|
// into correct buckets so that zorting will produce a correct order by zindex.
|
|
//
|
|
// If we don't do this then windowless components may end up zordering above windowed ones.
|
|
//
|
|
void ModifyZIndex(COMPONENTA * pcomp)
|
|
{
|
|
if (pcomp->cpPos.izIndex != COMPONENT_TOP) {
|
|
if (!IsWindowLessComponent(pcomp))
|
|
pcomp->cpPos.izIndex += COMPONENT_TOP_WINDOWLESS;
|
|
}
|
|
else
|
|
{
|
|
if (IsWindowLessComponent(pcomp))
|
|
pcomp->cpPos.izIndex = COMPONENT_TOP_WINDOWLESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// SortAndRationalize
|
|
//
|
|
// SortAndRationalize will take an unsorted component list and sort it such that the components
|
|
// come out in the correct z-index indicated order. It will also rebase the z-index values at
|
|
// a known constant so that the z-index values will not grow endlessly. SortAndRationalize also
|
|
// imposes windowed vs. windowless criteria to the zindex values such that windowless components
|
|
// always zorder under windowed ones.
|
|
//
|
|
void CActiveDesktop::_SortAndRationalize(void)
|
|
{
|
|
int icComponents;
|
|
HDPA hdpa;
|
|
|
|
if (_hdsaComponent && ((icComponents = DSA_GetItemCount(_hdsaComponent)) > 1) && (hdpa = DPA_Create(0))) {
|
|
COMPONENTA * pcomp;
|
|
SORTSTRUCT * pss;
|
|
int i, iCur = ZINDEX_START;
|
|
BOOL fInsertFailed = FALSE;
|
|
HDSA hdsaOld;
|
|
|
|
// Go through each component and insert it's hdsa-index and zindex into the hdpa
|
|
for (i = 0; i < icComponents; i++)
|
|
{
|
|
if (!(pss = (SORTSTRUCT *)LocalAlloc(LPTR, sizeof(SORTSTRUCT))))
|
|
break;
|
|
|
|
pcomp = (COMPONENTA *)DSA_GetItemPtr(_hdsaComponent, i);
|
|
ModifyZIndex(pcomp);
|
|
pss->ihdsaIndex = i;
|
|
pss->izIndex = pcomp->cpPos.izIndex;
|
|
if (DPA_AppendPtr(hdpa, (void FAR *)pss) == -1) {
|
|
LocalFree((HANDLE)pss);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Sort the hdpa by zindex
|
|
DPA_Sort(hdpa, pfnComponentSort, 0);
|
|
|
|
// Save old values
|
|
hdsaOld = _hdsaComponent;
|
|
|
|
// Null out the old hdsa, so AddComponentPrivate will create a new one
|
|
_hdsaComponent = NULL;
|
|
|
|
// Now go through the sorted hdpa and update the component zindex with a ZINDEX_START based zindex, then
|
|
// add the component to the new hdsa in sorted order.
|
|
for (i = 0; i < icComponents; i++) {
|
|
if (!(pss = (SORTSTRUCT *)DPA_GetPtr(hdpa, i)))
|
|
break;
|
|
// Get component and update it's zIndex and id
|
|
pcomp = (COMPONENTA *)DSA_GetItemPtr(hdsaOld, pss->ihdsaIndex);
|
|
pcomp->cpPos.izIndex = iCur;
|
|
iCur += 2;
|
|
|
|
// Free ptr
|
|
LocalFree((HANDLE)pss);
|
|
|
|
// Add to new hdsa in sorted order
|
|
if (!fInsertFailed) {
|
|
fInsertFailed = !AddComponentPrivate(pcomp, pcomp->dwID);
|
|
}
|
|
}
|
|
|
|
// If we're completely successfull then destroy the old hdsa. Otherwise we need
|
|
// to destroy the new one and restore the old one.
|
|
if ((i == icComponents) && !fInsertFailed) {
|
|
DSA_Destroy(hdsaOld);
|
|
} else {
|
|
if (_hdsaComponent)
|
|
DSA_Destroy(_hdsaComponent);
|
|
_hdsaComponent = hdsaOld;
|
|
}
|
|
|
|
DPA_Destroy(hdpa);
|
|
}
|
|
}
|
|
|
|
void CActiveDesktop::_ReadComponents(BOOL fActiveDesktop)
|
|
{
|
|
ENTERPROC(2, "DS ReadComponents()");
|
|
|
|
HKEY hkey;
|
|
TCHAR szDeskcomp[MAX_PATH];
|
|
|
|
GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_COMPONENTS, _pszScheme);
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, szDeskcomp, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD cbSize;
|
|
int i = 0;
|
|
TCHAR lpszSubkey[MAX_PATH];
|
|
|
|
//
|
|
// Read in the general settings.
|
|
//
|
|
DWORD dwSettings;
|
|
cbSize = sizeof(dwSettings);
|
|
if (SHQueryValueEx(hkey, REG_VAL_COMP_SETTINGS, NULL, NULL, (LPBYTE)&dwSettings, &cbSize) == ERROR_SUCCESS)
|
|
{
|
|
_co.fEnableComponents = (dwSettings & COMPSETTING_ENABLE) != 0;
|
|
}
|
|
_co.fActiveDesktop = fActiveDesktop;
|
|
|
|
//
|
|
// Read in all the desktop components
|
|
//
|
|
while (RegEnumKey(hkey, i, lpszSubkey, ARRAYSIZE(lpszSubkey)) == ERROR_SUCCESS)
|
|
{
|
|
_ReadComponent(hkey, lpszSubkey);
|
|
i++;
|
|
}
|
|
|
|
_SortAndRationalize();
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
EXITPROC(2, "DS ReadComponents!");
|
|
}
|
|
|
|
void CActiveDesktop::_Initialize(void)
|
|
{
|
|
ENTERPROC(2, "DS Initialize()");
|
|
|
|
if (!_fInitialized)
|
|
{
|
|
_fInitialized = TRUE;
|
|
InitDeskHtmlGlobals();
|
|
|
|
SHELLSTATE ss = {0};
|
|
SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
|
|
|
|
BOOL fActiveDesktop = BOOLIFY(ss.fDesktopHTML);
|
|
|
|
_co.dwSize = sizeof(_co);
|
|
_wpo.dwSize = sizeof(_wpo);
|
|
|
|
//
|
|
// This per-user registry branch may not exist for this user. Or, even if
|
|
// it does exist, it may have some stale info. So ensure that atlreast the
|
|
// default components are there and that the html version is current for this
|
|
// branch of the registry!
|
|
// If everything is current, the following function does nothing!
|
|
//
|
|
CDeskHtmlProp_RegUnReg(TRUE); //TRUE => install.
|
|
|
|
_ReadWallpaper(fActiveDesktop);
|
|
_ReadPattern();
|
|
_ReadComponents(fActiveDesktop);
|
|
|
|
// If we are in safemode, the we can not use Dynamic Html to make updates because
|
|
// updates involve complete change of background Html.
|
|
if (_IsDisplayInSafeMode())
|
|
_fUseDynamicHtml = FALSE;
|
|
else
|
|
_fUseDynamicHtml = TRUE; //Any component added after the initialization must go through dynamic html.
|
|
|
|
_fDirty = FALSE;
|
|
_fNeedBodyEnd = FALSE;
|
|
}
|
|
|
|
EXITPROC(2, "DS Initialize!");
|
|
}
|
|
|
|
|
|
void CActiveDesktop::_SaveWallpaper(void)
|
|
{
|
|
ENTERPROC(2, "DS SaveWallpaper");
|
|
TCHAR szDeskcomp[MAX_PATH];
|
|
BOOL fNormalWallpaper;
|
|
|
|
GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
|
|
|
|
//
|
|
// Compute tiling string.
|
|
//
|
|
TCHAR szTiled[2];
|
|
szTiled[0] = TEXT('0') + (TCHAR)(_wpo.dwStyle & WPSTYLE_TILE);
|
|
szTiled[1] = NULL;
|
|
|
|
//
|
|
// Compute the Wallpaper styling string
|
|
//
|
|
TCHAR szWPStyle[2];
|
|
//
|
|
// NOTE: If WPSTYLE_TILE is set, we still want to say WallpaperStyle="0"; This won't hurt
|
|
// because TileWallpaper="1" will over-ride this anyway.
|
|
// The reason for this hack is that during memphis setup, they put a tiled wallpaper. Then we
|
|
// write WallpaperStyle=1 and TileWallpaper=1 in new and old locations. Then, then change
|
|
// the wallpaper and set TileWallpaper=0. Since the WallpaperStyle continues to be 1, they
|
|
// get a tiled wallpaper finally. The following is to avoid this problem!
|
|
//
|
|
szWPStyle[0] = TEXT('0') + (TCHAR)(_wpo.dwStyle & WPSTYLE_STRETCH);
|
|
szWPStyle[1] = NULL;
|
|
|
|
|
|
//
|
|
// Write out wallpaper settings in new active desktop area.
|
|
//
|
|
if (_fWallpaperDirty || _fWallpaperChangedDuringInit)
|
|
{
|
|
if (!_fPolicyForWPStyle)
|
|
{
|
|
SHSetValue(HKEY_CURRENT_USER, szDeskcomp,
|
|
c_szTileWall, REG_SZ, szTiled, CbFromCch(lstrlen(szTiled)+1));
|
|
}
|
|
|
|
//
|
|
// Note: We do not write the Wallpaper Style string for older systems because we do not
|
|
// want to over-write what PlusPack writes. However, for newer Operating systems, we
|
|
// want to write the WallpaperStyle also.
|
|
//
|
|
if (!_fPolicyForWPStyle)
|
|
{
|
|
SHSetValue(HKEY_CURRENT_USER, szDeskcomp,
|
|
c_szWallpaperStyle, REG_SZ, szWPStyle, CbFromCch(lstrlen(szWPStyle)+1));
|
|
}
|
|
|
|
if (!_fPolicyForWPName)
|
|
{
|
|
SHRegSetPath(HKEY_CURRENT_USER, szDeskcomp, c_szWallpaper, _szSelectedWallpaper, 0);
|
|
}
|
|
}
|
|
|
|
if (fNormalWallpaper = IsNormalWallpaper(_szSelectedWallpaper))
|
|
{
|
|
if (FAILED(StringCchCopy(_szBackupWallpaper, ARRAYSIZE(_szBackupWallpaper), _szSelectedWallpaper)))
|
|
{
|
|
_szBackupWallpaper[0] = 0;
|
|
}
|
|
}
|
|
|
|
if (!_fPolicyForWPName)
|
|
{
|
|
FILETIME ft, ftLocal;
|
|
GetWallpaperFileTime(_szBackupWallpaper, &ft);
|
|
FileTimeToLocalFileTime(&ft, &ftLocal); // for FAT systems to track across DST changes
|
|
|
|
// Backup the "Old type" wallpaper's name here in the new location
|
|
// sothat we can detect when this gets changed by some other app.
|
|
SHRegSetPath(HKEY_CURRENT_USER, szDeskcomp, c_szBackupWallpaper, _szBackupWallpaper, 0);
|
|
|
|
SHSetValue(HKEY_CURRENT_USER, szDeskcomp,
|
|
c_szWallpaperTime, REG_BINARY, &ft,
|
|
sizeof(ft));
|
|
|
|
SHSetValue(HKEY_CURRENT_USER, szDeskcomp,
|
|
c_szWallpaperLocalTime, REG_BINARY, &ftLocal,
|
|
sizeof(ftLocal)); // AndrewGr save local time not UTC time
|
|
}
|
|
|
|
//
|
|
// Even if this wallpaper is not valid in normal desktop (i.e., even if it is not a .BMP),
|
|
// write it out in normal desktop registry area.
|
|
//
|
|
if (_fWallpaperDirty)
|
|
{
|
|
if (!_fPolicyForWPStyle)
|
|
{
|
|
SHSetValue(HKEY_CURRENT_USER, c_szRegStrDesktop,
|
|
c_szTileWall, REG_SZ, szTiled, CbFromCch(lstrlen(szTiled)+1));
|
|
}
|
|
//
|
|
// Note: We do not write the Wallpaper Style string for older systems because we do not
|
|
// want to over-write what PlusPack writes. However, for newer Operating systems, we
|
|
// want to write the WallpaperStyle also.
|
|
//
|
|
if (!_fPolicyForWPStyle)
|
|
{
|
|
SHSetValue(HKEY_CURRENT_USER, c_szRegStrDesktop,
|
|
c_szWallpaperStyle, REG_SZ, szWPStyle, CbFromCch(lstrlen(szWPStyle)+1));
|
|
}
|
|
|
|
if (!_fPolicyForWPName)
|
|
{
|
|
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
|
|
(fNormalWallpaper ? _szSelectedWallpaper : _szBackupWallpaper),
|
|
SPIF_UPDATEINIFILE);
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS SaveWallpaper");
|
|
}
|
|
|
|
void CActiveDesktop::_SaveComponent(HKEY hkey, int iIndex, COMPONENTA *pcomp)
|
|
{
|
|
ENTERPROC(2, "DS SaveComponent(hkey=%08X,iIndex=%d,pcomp=%08X)", hkey, iIndex, pcomp);
|
|
|
|
TCHAR szSubKey[8];
|
|
HKEY hkeySub;
|
|
|
|
if (SUCCEEDED(StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%d"), iIndex)))
|
|
{
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(hkey, szSubKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkeySub, 0))
|
|
{
|
|
pcomp->fDirty = FALSE; //Since we are saving in the registry, reset this!
|
|
//
|
|
// Write out the source string and Friendly name string.
|
|
//
|
|
RegSetValueEx(hkeySub, REG_VAL_COMP_SOURCE, 0, REG_SZ, (LPBYTE)pcomp->szSource, (lstrlen(pcomp->szSource)+1)*sizeof(TCHAR));
|
|
RegSetValueEx(hkeySub, REG_VAL_COMP_SUBSCRIBED_URL, 0, REG_SZ, (LPBYTE)pcomp->szSubscribedURL, (lstrlen(pcomp->szSubscribedURL)+1)*sizeof(TCHAR));
|
|
RegSetValueEx(hkeySub, REG_VAL_COMP_NAME, 0, REG_SZ, (LPBYTE)pcomp->szFriendlyName, (lstrlen(pcomp->szFriendlyName)+1)*sizeof(TCHAR));
|
|
|
|
//
|
|
// Compute and write out flags.
|
|
//
|
|
DWORD dwFlags = 0;
|
|
dwFlags |= pcomp->iComponentType;
|
|
if (pcomp->fChecked)
|
|
{
|
|
dwFlags |= COMP_SELECTED;
|
|
}
|
|
if (pcomp->fNoScroll)
|
|
{
|
|
dwFlags |= COMP_NOSCROLL;
|
|
}
|
|
RegSetValueEx(hkeySub, REG_VAL_COMP_FLAGS, 0, REG_DWORD, (LPBYTE)&dwFlags, sizeof(dwFlags));
|
|
|
|
//
|
|
// Write out the position.
|
|
//
|
|
RegSetValueEx(hkeySub, REG_VAL_COMP_POSITION, 0, REG_BINARY, (LPBYTE)&pcomp->cpPos, sizeof(pcomp->cpPos));
|
|
|
|
// Write out the Current state
|
|
RegSetValueEx(hkeySub, REG_VAL_COMP_CURSTATE, 0, REG_DWORD, (LPBYTE)&pcomp->dwCurItemState, sizeof(pcomp->dwCurItemState));
|
|
|
|
// Write out the Original State Info
|
|
RegSetValueEx(hkeySub, REG_VAL_COMP_ORIGINALSTATEINFO, 0, REG_BINARY, (LPBYTE)&pcomp->csiOriginal, sizeof(pcomp->csiOriginal));
|
|
|
|
// Write out the Restored State Info
|
|
RegSetValueEx(hkeySub, REG_VAL_COMP_RESTOREDSTATEINFO, 0, REG_BINARY, (LPBYTE)&pcomp->csiRestored, sizeof(pcomp->csiRestored));
|
|
|
|
RegCloseKey(hkeySub);
|
|
}
|
|
}
|
|
EXITPROC(2, "DS SaveComponent!");
|
|
}
|
|
|
|
|
|
void CActiveDesktop::_SaveComponents(void)
|
|
{
|
|
ENTERPROC(2, "DS SaveComponents");
|
|
DWORD dwFlags = 0, dwDataLength = sizeof(dwFlags);
|
|
int i;
|
|
TCHAR szDeskcomp[MAX_PATH];
|
|
|
|
GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_COMPONENTS, _pszScheme);
|
|
|
|
//
|
|
// We need to preserve the old GENFLAGS, so read them now before we roach them.
|
|
//
|
|
SHGetValue(HKEY_CURRENT_USER, szDeskcomp, REG_VAL_COMP_GENFLAGS, NULL,
|
|
&dwFlags, &dwDataLength);
|
|
|
|
//
|
|
// Delete the entire registry key.
|
|
//
|
|
SHDeleteKey(HKEY_CURRENT_USER, szDeskcomp);
|
|
|
|
//
|
|
// Recreate the registry key.
|
|
//
|
|
HKEY hkey;
|
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, szDeskcomp, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, 0))
|
|
{
|
|
//
|
|
// Write out the version number.
|
|
//
|
|
DWORD dw = CUR_DESKHTML_VERSION;
|
|
RegSetValueEx(hkey, REG_VAL_COMP_VERSION, 0, REG_DWORD, (LPBYTE)(&dw), sizeof(dw));
|
|
|
|
dw = CUR_DESKHTML_MINOR_VERSION;
|
|
RegSetValueEx(hkey, REG_VAL_COMP_MINOR_VERSION, 0, REG_DWORD, (LPBYTE)(&dw), sizeof(dw));
|
|
|
|
//
|
|
// Write out the general settings.
|
|
//
|
|
DWORD dwSettings = 0;
|
|
if (_co.fEnableComponents)
|
|
{
|
|
dwSettings |= COMPSETTING_ENABLE;
|
|
}
|
|
RegSetValueEx(hkey, REG_VAL_COMP_SETTINGS, 0, REG_DWORD, (LPBYTE)&dwSettings, sizeof(dwSettings));
|
|
|
|
//
|
|
// Write out the general flags
|
|
//
|
|
RegSetValueEx(hkey, REG_VAL_COMP_GENFLAGS, 0, REG_DWORD, (LPBYTE)&dwFlags, sizeof(dwFlags));
|
|
|
|
if (_hdsaComponent)
|
|
{
|
|
//
|
|
// Write out the settings for each component
|
|
//
|
|
for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
|
|
{
|
|
COMPONENTA * pcomp;
|
|
|
|
if (pcomp = (COMPONENTA *)DSA_GetItemPtr(_hdsaComponent, i))
|
|
{
|
|
pcomp->dwID = i;
|
|
_SaveComponent(hkey, i, pcomp);
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
EXITPROC(2, "DS SaveComponents");
|
|
}
|
|
|
|
void CActiveDesktop::_SavePattern(DWORD dwFlags)
|
|
{
|
|
ENTERPROC(2, "DS SavePattern()");
|
|
|
|
if (_fPatternDirty && (dwFlags & SAVE_PATTERN_NAME))
|
|
{
|
|
//
|
|
// Write out the pattern to the registry and INI files.
|
|
//
|
|
SystemParametersInfo(SPI_SETDESKPATTERN, 0, _szSelectedPattern, SPIF_UPDATEINIFILE);
|
|
}
|
|
|
|
if (IsValidPattern(_szSelectedPattern) && (dwFlags & GENERATE_PATTERN_FILE))
|
|
{
|
|
//
|
|
// Write out the pattern as a BMP file for use in HTML.
|
|
//
|
|
TCHAR szBitmapFile[MAX_PATH];
|
|
HANDLE hFileBitmap = INVALID_HANDLE_VALUE;
|
|
|
|
if (SUCCEEDED(GetPerUserFileName(szBitmapFile, ARRAYSIZE(szBitmapFile), PATTERN_FILENAME)))
|
|
{
|
|
hFileBitmap = CreateFile(szBitmapFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, NULL);
|
|
}
|
|
|
|
if (hFileBitmap != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD cbWritten;
|
|
|
|
BITMAPFILEHEADER bmfh = {0};
|
|
bmfh.bfType = 0x4D42; // 'BM'
|
|
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD) + 8*sizeof(DWORD);
|
|
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD);
|
|
WriteFile(hFileBitmap, &bmfh, sizeof(bmfh), &cbWritten, NULL);
|
|
|
|
BITMAPINFOHEADER bmih = {0};
|
|
bmih.biSize = sizeof(BITMAPINFOHEADER);
|
|
bmih.biWidth = 8;
|
|
bmih.biHeight = 8;
|
|
bmih.biPlanes = 1;
|
|
bmih.biBitCount = 1;
|
|
bmih.biCompression = BI_RGB;
|
|
WriteFile(hFileBitmap, &bmih, sizeof(bmih), &cbWritten, NULL);
|
|
|
|
RGBQUAD argbTable[2] = {0};
|
|
DWORD rgb;
|
|
rgb = GetSysColor(COLOR_BACKGROUND);
|
|
argbTable[0].rgbBlue = GetBValue(rgb);
|
|
argbTable[0].rgbGreen = GetGValue(rgb);
|
|
argbTable[0].rgbRed = GetRValue(rgb);
|
|
rgb = GetSysColor(COLOR_WINDOWTEXT);
|
|
argbTable[1].rgbBlue = GetBValue(rgb);
|
|
argbTable[1].rgbGreen = GetGValue(rgb);
|
|
argbTable[1].rgbRed = GetRValue(rgb);
|
|
WriteFile(hFileBitmap, argbTable, sizeof(argbTable), &cbWritten, NULL);
|
|
|
|
DWORD adwBits[8];
|
|
PatternToDwords(_szSelectedPattern, adwBits);
|
|
WriteFile(hFileBitmap, adwBits, sizeof(adwBits), &cbWritten, NULL);
|
|
|
|
CloseHandle(hFileBitmap);
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS SavePattern!");
|
|
}
|
|
|
|
void CActiveDesktop::_WriteHtmlFromString(LPCTSTR psz)
|
|
{
|
|
ENTERPROC(3, "DS WriteHtmlFromString(psz=>%s<)", psz);
|
|
LPCWSTR pwsz;
|
|
WCHAR szBuf[INTERNET_MAX_URL_LENGTH];
|
|
UINT uiLen;
|
|
int cch;
|
|
|
|
if ((_pStream == NULL) && (_iDestFileCharset == ANSI_HTML_CHARSET))
|
|
{
|
|
cch = SHUnicodeToAnsi(psz, (LPSTR)szBuf, ARRAYSIZE(szBuf));
|
|
ASSERT(cch == lstrlenW((LPWSTR)psz)+1);
|
|
pwsz = (LPCWSTR)szBuf;
|
|
uiLen = lstrlenA((LPSTR)szBuf);
|
|
}
|
|
else
|
|
{
|
|
pwsz = psz;
|
|
uiLen = lstrlenW(pwsz);
|
|
}
|
|
|
|
UINT cbWritten;
|
|
|
|
_WriteHtmlW(pwsz, uiLen, &cbWritten);
|
|
|
|
EXITPROC(3, "DS WriteHtmlFromString!");
|
|
}
|
|
|
|
void CActiveDesktop::_WriteHtmlFromId(UINT uid)
|
|
{
|
|
ENTERPROC(3, "DS WriteHtmlFromId(uid=%d)", uid);
|
|
|
|
TCHAR szBuf[INTERNET_MAX_URL_LENGTH];
|
|
LoadString(HINST_THISDLL, uid, szBuf, ARRAYSIZE(szBuf));
|
|
_WriteHtmlFromString(szBuf);
|
|
|
|
EXITPROC(3, "DS WriteHtmlFromId!");
|
|
}
|
|
|
|
void CActiveDesktop::_WriteHtmlFromIdF(UINT uid, ...)
|
|
{
|
|
ENTERPROC(3, "DS WriteHtmlFromIdF(uid=%d,...)", uid);
|
|
|
|
TCHAR szBufFmt[INTERNET_MAX_URL_LENGTH];
|
|
TCHAR szBuf[INTERNET_MAX_URL_LENGTH];
|
|
|
|
LoadString(HINST_THISDLL, uid, szBufFmt, ARRAYSIZE(szBufFmt));
|
|
|
|
va_list arglist;
|
|
va_start(arglist, uid);
|
|
HRESULT hr = StringCchVPrintf(szBuf, ARRAYSIZE(szBuf), szBufFmt, arglist);
|
|
va_end(arglist);
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_WriteHtmlFromString(szBuf);
|
|
}
|
|
|
|
EXITPROC(3, "DS WriteHtmlFromIdF!");
|
|
}
|
|
|
|
void CActiveDesktop::_WriteHtmlFromFile(LPCTSTR pszContents)
|
|
{
|
|
ENTERPROC(3, "DS WriteHtmlFromFile(pszContents=>%s<)", pszContents);
|
|
|
|
CReadFileObj *pReadFileObj = new CReadFileObj(pszContents);
|
|
|
|
if (pReadFileObj)
|
|
{
|
|
if (pReadFileObj->_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
WCHAR wcBuf[INTERNET_MAX_URL_LENGTH + 1];
|
|
UINT uiCharCount = ARRAYSIZE(wcBuf) -1; //Leave room for null termination.
|
|
UINT uiCharsRead;
|
|
UINT uiCharsConverted;
|
|
int iDestCharset = (_pStream ? UNICODE_HTML_CHARSET : _iDestFileCharset);
|
|
while (SUCCEEDED(pReadFileObj->FileReadAndConvertChars(iDestCharset, wcBuf, uiCharCount, &uiCharsRead, &uiCharsConverted)) && uiCharsRead)
|
|
{
|
|
UINT cbWritten;
|
|
|
|
_WriteHtmlW(wcBuf, uiCharsConverted, &cbWritten);
|
|
|
|
if (uiCharsRead < uiCharCount)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
delete pReadFileObj;
|
|
}
|
|
|
|
EXITPROC(3, "DS WriteHtmlFromFile!");
|
|
}
|
|
|
|
void CActiveDesktop::_WriteHtmlFromReadFileObj(CReadFileObj *pFileObj, int iOffsetStart, int iOffsetEnd)
|
|
{
|
|
ENTERPROC(3, "DS WriteHtmlFromReadFileObj(pFileObj=%08X,iOffsetStart=%d,iOffsetEnd=%d)", pFileObj, iOffsetStart, iOffsetEnd);
|
|
|
|
if (iOffsetStart != -1)
|
|
{
|
|
pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(iOffsetEnd == -1);
|
|
iOffsetEnd = -1;
|
|
}
|
|
|
|
//Get the number of WIDECHARs to be written
|
|
UINT cchWrite = (iOffsetEnd == -1) ? 0xFFFFFFFF : (iOffsetEnd - iOffsetStart);
|
|
|
|
while (cchWrite)
|
|
{
|
|
WCHAR wcBuf[INTERNET_MAX_URL_LENGTH+1];
|
|
|
|
//
|
|
// Read a chunk.
|
|
//
|
|
UINT cchTryRead = (UINT)min(cchWrite, (ARRAYSIZE(wcBuf) - 1));
|
|
UINT cchActualRead;
|
|
HRESULT hres;
|
|
|
|
//Note: if we are reading ANSI, we still use the unicode buff; but cast it!
|
|
if (_iDestFileCharset == ANSI_HTML_CHARSET)
|
|
hres = pFileObj->FileReadCharsA((LPSTR)wcBuf, cchTryRead, &cchActualRead);
|
|
else
|
|
hres = pFileObj->FileReadCharsW(wcBuf, cchTryRead, &cchActualRead);
|
|
|
|
if (SUCCEEDED(hres) && cchActualRead)
|
|
{
|
|
//
|
|
// Write a chunk.
|
|
//
|
|
UINT cchWritten;
|
|
|
|
_WriteHtmlW(wcBuf, cchActualRead, &cchWritten);
|
|
|
|
if (cchActualRead < cchTryRead)
|
|
{
|
|
//
|
|
// End of file, all done.
|
|
//
|
|
break;
|
|
}
|
|
|
|
cchWrite -= cchActualRead;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Error reading from file, all done.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXITPROC(3, "DS WriteHtmlFromHfile!");
|
|
}
|
|
|
|
int CActiveDesktop::_ScanForTagA(CReadFileObj *pFileObj, int iOffsetStart, LPCSTR pszTag)
|
|
{
|
|
ENTERPROC(2, "DS ScanForTagA(pFileObj=%08X,iOffsetStart=%d,pszTagA=>%s<)",
|
|
pFileObj, iOffsetStart, pszTag);
|
|
|
|
int iRet = -1;
|
|
BOOL fDoneReading = FALSE;
|
|
int iOffset;
|
|
DWORD cchTag = lstrlenA(pszTag);
|
|
|
|
pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
|
|
iOffset = iOffsetStart;
|
|
|
|
DWORD cchBuf = 0;
|
|
while (!fDoneReading)
|
|
{
|
|
char szBuf[INTERNET_MAX_URL_LENGTH+1];
|
|
|
|
//
|
|
// Fill in the buffer.
|
|
//
|
|
UINT cchTryRead = ARRAYSIZE(szBuf) - cchBuf - 1;
|
|
UINT cchRead;
|
|
if (SUCCEEDED(pFileObj->FileReadCharsA(&szBuf[cchBuf], cchTryRead, &cchRead)) && cchRead)
|
|
{
|
|
cchBuf += cchRead;
|
|
|
|
//
|
|
// Terminate the string.
|
|
//
|
|
szBuf[cchBuf] = '\0';
|
|
|
|
//
|
|
// Scan for the tag.
|
|
//
|
|
LPSTR pszTagInBuf = StrStrIA(szBuf, pszTag);
|
|
|
|
if (pszTagInBuf)
|
|
{
|
|
//
|
|
// Found the tag, compute the offset.
|
|
//
|
|
iRet = (int) (iOffset + pszTagInBuf - szBuf);
|
|
fDoneReading = TRUE;
|
|
}
|
|
else if (cchRead < cchTryRead)
|
|
{
|
|
//
|
|
// Ran out of file without finding tag.
|
|
//
|
|
fDoneReading = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Compute how many bytes we want to throw away
|
|
// from this buffer so we can read in more data.
|
|
// We don't want to throw away all the bytes because
|
|
// the tag we want may span two buffers.
|
|
//
|
|
DWORD cchSkip = cchBuf - cchTag;
|
|
|
|
//
|
|
// Advance the file offset.
|
|
//
|
|
iOffset += cchSkip;
|
|
|
|
//
|
|
// Reduce the buffer size.
|
|
//
|
|
cchBuf -= cchSkip;
|
|
|
|
//
|
|
// Move the kept bytes to the beginning of the buffer.
|
|
//
|
|
MoveMemory(szBuf, szBuf + cchSkip, cchBuf * sizeof(szBuf[0]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fDoneReading = TRUE;
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS ScanForTagA=%d", iRet);
|
|
return iRet;
|
|
}
|
|
|
|
int CActiveDesktop::_ScanForTagW(CReadFileObj *pFileObj, int iOffsetStart, LPCWSTR pwszTag)
|
|
{
|
|
ENTERPROC(2, "DS ScanForTag(pFileObj=%08X,iOffsetStart=%d,pszTagA=>%s<)",
|
|
pFileObj, iOffsetStart, pwszTag);
|
|
|
|
int iRet = -1;
|
|
BOOL fDoneReading = FALSE;
|
|
int iOffset;
|
|
DWORD cchTag = lstrlenW(pwszTag);
|
|
|
|
pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
|
|
iOffset = iOffsetStart;
|
|
|
|
DWORD cchBuf = 0;
|
|
while (!fDoneReading)
|
|
{
|
|
WCHAR wszBuf[INTERNET_MAX_URL_LENGTH+1];
|
|
|
|
//
|
|
// Fill in the buffer.
|
|
//
|
|
UINT cchTryRead = ARRAYSIZE(wszBuf) - cchBuf - 1;
|
|
UINT cchRead;
|
|
if (SUCCEEDED(pFileObj->FileReadCharsW(&wszBuf[cchBuf], cchTryRead, &cchRead)) && cchRead)
|
|
{
|
|
cchBuf += cchRead;
|
|
|
|
//
|
|
// Terminate the string.
|
|
//
|
|
wszBuf[cchBuf] = L'\0';
|
|
|
|
//
|
|
// Scan for the tag.
|
|
//
|
|
LPWSTR pwszTagInBuf = StrStrIW(wszBuf, pwszTag);
|
|
|
|
if (pwszTagInBuf)
|
|
{
|
|
//
|
|
// Found the tag, compute the offset.
|
|
//
|
|
iRet = (int) (iOffset + pwszTagInBuf - wszBuf);
|
|
fDoneReading = TRUE;
|
|
}
|
|
else if (cchRead < cchTryRead)
|
|
{
|
|
//
|
|
// Ran out of file without finding tag.
|
|
//
|
|
fDoneReading = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Compute how many bytes we want to throw away
|
|
// from this buffer so we can read in more data.
|
|
// We don't want to throw away all the bytes because
|
|
// the tag we want may span two buffers.
|
|
//
|
|
DWORD cchSkip = cchBuf - cchTag;
|
|
|
|
//
|
|
// Advance the file offset.
|
|
//
|
|
iOffset += cchSkip;
|
|
|
|
//
|
|
// Reduce the buffer size.
|
|
//
|
|
cchBuf -= cchSkip;
|
|
|
|
//
|
|
// Move the kept bytes to the beginning of the buffer.
|
|
//
|
|
MoveMemory(wszBuf, wszBuf + cchSkip, cchBuf*sizeof(wszBuf[0]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fDoneReading = TRUE;
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS ScanForTag=%d", iRet);
|
|
return iRet;
|
|
}
|
|
|
|
int CActiveDesktop::_ScanTagEntriesA(CReadFileObj *pReadFileObj, int iOffsetStart, TAGENTRYA *pte, int cte)
|
|
{
|
|
ENTERPROC(2, "DS ScanTagEntriesA(pReadFileObj=%08X,iOffsetStart=%d,pte=%08X,cte=%d)",
|
|
pReadFileObj, iOffsetStart, pte, cte);
|
|
|
|
int iRet = -1;
|
|
int i;
|
|
|
|
for (i=0; i<cte; i++,pte++)
|
|
{
|
|
iRet = _ScanForTagA(pReadFileObj, iOffsetStart, pte->pszTag);
|
|
if (iRet != -1)
|
|
{
|
|
if (pte->fSkipPast)
|
|
{
|
|
iRet += lstrlenA(pte->pszTag);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS ScanTagEntriesA=%d", iRet);
|
|
return iRet;
|
|
}
|
|
|
|
int CActiveDesktop::_ScanTagEntriesW(CReadFileObj *pReadFileObj, int iOffsetStart, TAGENTRYW *pte, int cte)
|
|
{
|
|
ENTERPROC(2, "DS ScanTagEntriesW(pReadFileObj=%08X,iOffsetStart=%d,pte=%08X,cte=%d)",
|
|
pReadFileObj, iOffsetStart, pte, cte);
|
|
|
|
int iRet = -1;
|
|
int i;
|
|
|
|
for (i=0; i<cte; i++,pte++)
|
|
{
|
|
iRet = _ScanForTagW(pReadFileObj, iOffsetStart, pte->pwszTag);
|
|
if (iRet != -1)
|
|
{
|
|
if (pte->fSkipPast)
|
|
{
|
|
iRet += lstrlenW(pte->pwszTag);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS ScanTagEntriesW=%d", iRet);
|
|
return iRet;
|
|
}
|
|
|
|
void CActiveDesktop::_ParseAnsiInputHtmlFile( LPTSTR szSelectedWallpaper, int *piOffsetBase, int *piOffsetComp)
|
|
{
|
|
//
|
|
// Figure out where to insert the base href tag.
|
|
//
|
|
int iOffsetBase = 0, iBaseTagStart;
|
|
BOOL fUseBaseHref;
|
|
LONG lOffsetDueToBOM = 0; //Character Offset due to the Byte Order Mark.
|
|
//1 for UNICODE and 0 for ANSI files.
|
|
|
|
// 98/11/11 #248047 vtan: This code looks for a <BASE HREF=...> tag.
|
|
// It used to use a scan for "<BASE" and assume that this was the
|
|
// desired tag. HTML allows a "<BASEFONT>" tag which was being
|
|
// mistaken for a "<BASE HREF=...>" tag. The code now looks for the
|
|
// same string but looks at the character following the "<BASE" to
|
|
// see if it's a white-space character.
|
|
|
|
fUseBaseHref = TRUE;
|
|
_pReadFileObjHtmlBkgd->FileGetCurCharOffset(&lOffsetDueToBOM);
|
|
iOffsetBase = (int)lOffsetDueToBOM;
|
|
iBaseTagStart = _ScanForTagA(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, "<BASE");
|
|
|
|
if (iBaseTagStart != -1)
|
|
{
|
|
UINT uiCountChars, uiTryToRead;
|
|
char szBaseTagBuffer[6+1]; // allow for "<BASEx" plus a NULL.
|
|
|
|
_pReadFileObjHtmlBkgd->FileSeekChars(iBaseTagStart, FILE_BEGIN);
|
|
uiTryToRead = ARRAYSIZE(szBaseTagBuffer) - 1;
|
|
if (SUCCEEDED(_pReadFileObjHtmlBkgd->FileReadCharsA(szBaseTagBuffer, uiTryToRead, &uiCountChars)) && uiCountChars)
|
|
{
|
|
char ch;
|
|
|
|
ch = szBaseTagBuffer[5];
|
|
fUseBaseHref = ((ch != ' ') &&
|
|
(ch != '\r') &&
|
|
(ch != '\n') && // this covers the UNIX line break scheme
|
|
(ch != '\t'));
|
|
}
|
|
}
|
|
if (fUseBaseHref)
|
|
{
|
|
TAGENTRYA rgteBase[] = {
|
|
{ "<HEAD>", TRUE, },
|
|
{ "<BODY", FALSE, },
|
|
{ "<HTML>", TRUE, },
|
|
};
|
|
iOffsetBase = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, rgteBase, ARRAYSIZE(rgteBase));
|
|
if (iOffsetBase == -1)
|
|
{
|
|
iOffsetBase = (int)lOffsetDueToBOM;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Figure out where to insert the components.
|
|
//
|
|
TAGENTRYA rgteComponents[] = {
|
|
{ "</BODY>", FALSE, },
|
|
{ "</HTML>", FALSE, },
|
|
};
|
|
int iOffsetComponents = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteComponents, ARRAYSIZE(rgteComponents));
|
|
|
|
//
|
|
// Write out the initial HTML up to the <HEAD> tag.
|
|
//
|
|
_WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, iOffsetBase);
|
|
|
|
//
|
|
// Write out the base tag.
|
|
//
|
|
if (fUseBaseHref)
|
|
{
|
|
//BASE tag must point to the base "URL". So, don't strip out the filename.
|
|
_WriteHtmlFromIdF(IDS_BASE_TAG, szSelectedWallpaper);
|
|
}
|
|
|
|
// Figure out where to insert the DIV clause
|
|
TAGENTRYA rgteBodyStart[] = {
|
|
{ "<BODY", FALSE, },
|
|
};
|
|
int iOffsetBodyStart = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteBodyStart, ARRAYSIZE(rgteBodyStart));
|
|
// Write out HTML until after the <BODY ......>
|
|
if (iOffsetBodyStart == -1)
|
|
{ // the <BODY> tag is not found, so we need to insert it.
|
|
// Copy over stuff until </HEAD>
|
|
TAGENTRYA rgteHeadEnd[] = {
|
|
{ "</HEAD>", TRUE, },
|
|
};
|
|
int iOffsetHeadEnd = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteHeadEnd, ARRAYSIZE(rgteHeadEnd));
|
|
if (iOffsetHeadEnd != -1)
|
|
{
|
|
_WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetHeadEnd);
|
|
iOffsetBase = iOffsetHeadEnd;
|
|
}
|
|
_WriteHtmlFromIdF(IDS_BODY_CENTER_WP2); // "<BODY>"
|
|
_fNeedBodyEnd = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TAGENTRYA rgteBodyEnd[] = {
|
|
{ ">", TRUE, },
|
|
};
|
|
int iOffsetBodyEnd = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBodyStart, rgteBodyEnd, ARRAYSIZE(rgteBodyEnd));
|
|
if (iOffsetBodyEnd == -1)
|
|
{ // An error in the HTML.
|
|
iOffsetBodyEnd = iOffsetBodyStart; // FEATURE: We need a better recovery idea.
|
|
}
|
|
_WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetBodyEnd);
|
|
iOffsetBase = iOffsetBodyEnd;
|
|
}
|
|
|
|
*piOffsetBase = iOffsetBase;
|
|
*piOffsetComp = iOffsetComponents;
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtmlHeader(void)
|
|
{
|
|
ENTERPROC(2, "DS GenerateHtmlHeader()");
|
|
|
|
EnumMonitorsArea ema;
|
|
GetMonitorSettings(&ema);
|
|
|
|
RECT rcViewAreas[LV_MAX_WORKAREAS]; // WorkArea minus toolbar/tray areas
|
|
int nViewAreas = ARRAYSIZE(rcViewAreas);
|
|
// Get the ViewAreas
|
|
if (!GetViewAreas(rcViewAreas, &nViewAreas))
|
|
{
|
|
nViewAreas = 0;
|
|
}
|
|
|
|
//Assume that the final Deskstat.htt that we generate is going to be in UNICODE.
|
|
//This will change to ANSI only if the background html wallpaper is ANSI (determined later)
|
|
_iDestFileCharset = UNICODE_HTML_CHARSET;
|
|
//
|
|
// Write out the background and color.
|
|
//
|
|
TCHAR szSelectedWallpaper[INTERNET_MAX_URL_LENGTH];
|
|
// If the wallpaper does not have a directory specified (this may happen if other apps. change this value),
|
|
// we have to figure it out.
|
|
if (!GetWallpaperWithPath(_szSelectedWallpaper, szSelectedWallpaper, ARRAYSIZE(szSelectedWallpaper)))
|
|
{
|
|
return; // gross, but probably cleanest way
|
|
}
|
|
|
|
BOOL fValidWallpaper = GetFileAttributes(szSelectedWallpaper) != 0xFFFFFFFF;
|
|
if (_fSingleItem || IsWallpaperPicture(szSelectedWallpaper) || !fValidWallpaper)
|
|
{
|
|
//
|
|
// Write the BOM for UNICODE
|
|
//
|
|
if (_hFileHtml)
|
|
{
|
|
DWORD cbWritten;
|
|
|
|
WriteFile(_hFileHtml, (LPCSTR)&wUnicodeBOM, sizeof(wUnicodeBOM), &cbWritten, NULL);
|
|
}
|
|
|
|
// To account for the vagaries of the desktop browser (it's TopLeft starts from the TopLeft
|
|
// of the Desktop ViewArea instead of the TopLeft of the monitor, as might be expected)
|
|
// which happens only in the case of one active monitor systems, we add the width of the
|
|
// tray/toolbars to the co-ordinates of the DIV section of each monitor's wallpaper.
|
|
int iLeft, iTop;
|
|
if (nViewAreas == 1)
|
|
{
|
|
iLeft = rcViewAreas[0].left - ema.rcVirtualMonitor.left;
|
|
iTop = rcViewAreas[0].top - ema.rcVirtualMonitor.top;
|
|
}
|
|
else
|
|
{
|
|
iLeft = 0;
|
|
iTop = 0;
|
|
}
|
|
|
|
//
|
|
// Write out the standard header.
|
|
//
|
|
UINT i;
|
|
for (i=IDS_COMMENT_BEGIN; i<IDS_BODY_BEGIN; i++)
|
|
{
|
|
_WriteHtmlFromIdF(i);
|
|
}
|
|
|
|
//
|
|
// Write out the body tag, with background bitmap.
|
|
//
|
|
DWORD rgbDesk;
|
|
rgbDesk = GetSysColor(COLOR_DESKTOP);
|
|
|
|
TCHAR szBitmapFile[MAX_PATH];
|
|
if (FAILED(GetPerUserFileName(szBitmapFile, ARRAYSIZE(szBitmapFile), PATTERN_FILENAME)))
|
|
{
|
|
szBitmapFile[0] = 0;
|
|
}
|
|
|
|
if (!_fSingleItem && _szSelectedWallpaper[0] && fValidWallpaper)
|
|
{
|
|
TCHAR szWallpaperUrl[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cch = ARRAYSIZE(szWallpaperUrl);
|
|
UrlCreateFromPath(szSelectedWallpaper, szWallpaperUrl, &cch, URL_INTERNAL_PATH);
|
|
|
|
switch (_wpo.dwStyle)
|
|
{
|
|
case WPSTYLE_TILE:
|
|
//
|
|
// Ignore the pattern, tile the wallpaper as background.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_BODY_BEGIN2, szWallpaperUrl, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
|
|
break;
|
|
|
|
case WPSTYLE_CENTER:
|
|
if (IsValidPattern(_szSelectedPattern))
|
|
{
|
|
//
|
|
// Tile the pattern as the main background.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_BODY_BEGIN2, szBitmapFile, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
|
|
if (_fBackgroundHtml) // We are generating the HTML for preview
|
|
{
|
|
_WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP, szWallpaperUrl);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Write out a DIV section for a centered, untiled wallpaper.
|
|
//
|
|
// write it out for each monitor.
|
|
for(int i = 0; i < ema.iMonitors; i++)
|
|
{
|
|
_WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP2,
|
|
ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
|
|
ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
|
|
ema.rcMonitor[i].right - ema.rcMonitor[i].left,
|
|
ema.rcMonitor[i].bottom - ema.rcMonitor[i].top,
|
|
szWallpaperUrl);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Write out a non-tiled, centered wallpaper as background.
|
|
//
|
|
if (_fBackgroundHtml) // We are generating the HTML for preview
|
|
{
|
|
_WriteHtmlFromIdF(IDS_BODY_CENTER_WP, szWallpaperUrl, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
|
|
}
|
|
else
|
|
{
|
|
_WriteHtmlFromIdF(IDS_BODY_CENTER_WP2, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
|
|
// write it out for each monitor.
|
|
for(int i = 0; i < ema.iMonitors; i++)
|
|
{
|
|
_WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP2,
|
|
ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
|
|
ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
|
|
ema.rcMonitor[i].right - ema.rcMonitor[i].left,
|
|
ema.rcMonitor[i].bottom - ema.rcMonitor[i].top,
|
|
szWallpaperUrl);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WPSTYLE_STRETCH:
|
|
//
|
|
// Ignore the pattern, create a DIV section of the wallpaper
|
|
// stretched to 100% of the screen.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_BODY_BEGIN2, c_szNULL, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
|
|
if (_fBackgroundHtml) // We are generating the HTML for preview
|
|
{
|
|
_WriteHtmlFromIdF(IDS_STRETCH_WALLPAPER, szWallpaperUrl);
|
|
}
|
|
else
|
|
{
|
|
// stretch it for each monitor.
|
|
for(int i = 0; i < ema.iMonitors; i++)
|
|
{
|
|
_WriteHtmlFromIdF(IDS_DIV_START3, ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
|
|
ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
|
|
ema.rcMonitor[i].right - ema.rcMonitor[i].left,
|
|
ema.rcMonitor[i].bottom - ema.rcMonitor[i].top);
|
|
_WriteHtmlFromIdF(IDS_STRETCH_WALLPAPER, szWallpaperUrl);
|
|
_WriteHtmlFromId(IDS_DIV_END);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Ignore the wallpaper, generate either a tiled pattern
|
|
// or solid color background.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_BODY_BEGIN2, !_fSingleItem && IsValidPattern(_szSelectedPattern) ? szBitmapFile : c_szNULL, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((_pReadFileObjHtmlBkgd = new CReadFileObj(szSelectedWallpaper)) &&
|
|
(_pReadFileObjHtmlBkgd->_hFile != INVALID_HANDLE_VALUE))
|
|
{
|
|
//The final Desktop.htt will be in ANSI only if the source html file is also in ansi.
|
|
//So, get the type from the selected wallpaper object.
|
|
_iDestFileCharset = _pReadFileObjHtmlBkgd->_iCharset;
|
|
//
|
|
// Write the BOM for UNICODE
|
|
//
|
|
if (_hFileHtml && (_iDestFileCharset == UNICODE_HTML_CHARSET))
|
|
{
|
|
DWORD cbWritten;
|
|
|
|
WriteFile(_hFileHtml, (LPCSTR)&wUnicodeBOM, sizeof(wUnicodeBOM), &cbWritten, NULL);
|
|
}
|
|
|
|
//
|
|
// Figure out where to insert the base href tag.
|
|
//
|
|
int iOffsetBase = 0;
|
|
int iOffsetComponents;
|
|
// 98/11/11 #248047 vtan: This code looks for a <BASE HREF=...> tag.
|
|
// It used to use a scan for "<BASE" and assume that this was the
|
|
// desired tag. HTML allows a "<BASEFONT>" tag which was being
|
|
// mistaken for a "<BASE HREF=...>" tag. The code now looks for the
|
|
// same string but looks at the character following the "<BASE" to
|
|
// see if it's a white-space character.
|
|
|
|
if (_iDestFileCharset == ANSI_HTML_CHARSET)
|
|
{
|
|
//The following function parses the ANSI input html file and finds various offsets
|
|
_ParseAnsiInputHtmlFile(szSelectedWallpaper, &iOffsetBase, &iOffsetComponents);
|
|
}
|
|
else
|
|
{
|
|
//The following code parses the UNICODE input html wallpaper file.
|
|
int iBaseTagStart;
|
|
BOOL fUseBaseHref;
|
|
LONG lOffsetDueToBOM = 0; //Character Offset due to the Byte Order Mark.
|
|
//1 for UNICODE and 0 for ANSI files.
|
|
fUseBaseHref = TRUE;
|
|
_pReadFileObjHtmlBkgd->FileGetCurCharOffset(&lOffsetDueToBOM);
|
|
iOffsetBase = (int)lOffsetDueToBOM;
|
|
iBaseTagStart = _ScanForTagW(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, L"<BASE");
|
|
|
|
if (iBaseTagStart != -1)
|
|
{
|
|
UINT uiCountChars, uiTryToRead;
|
|
WCHAR wszBaseTagBuffer[6+1]; // allow for "<BASEx" plus a NULL.
|
|
|
|
_pReadFileObjHtmlBkgd->FileSeekChars(iBaseTagStart, FILE_BEGIN);
|
|
uiTryToRead = ARRAYSIZE(wszBaseTagBuffer) - 1;
|
|
if (SUCCEEDED(_pReadFileObjHtmlBkgd->FileReadCharsW(wszBaseTagBuffer, uiTryToRead, &uiCountChars)) && uiCountChars)
|
|
{
|
|
WCHAR wc;
|
|
|
|
wc = wszBaseTagBuffer[5];
|
|
fUseBaseHref = ((wc != L' ') &&
|
|
(wc != L'\r') &&
|
|
(wc != L'\n') && // this covers the UNIX line break scheme
|
|
(wc != L'\t'));
|
|
}
|
|
}
|
|
if (fUseBaseHref)
|
|
{
|
|
TAGENTRYW rgteBase[] = {
|
|
{ L"<HEAD>", TRUE, },
|
|
{ L"<BODY", FALSE, },
|
|
{ L"<HTML>", TRUE, },
|
|
};
|
|
iOffsetBase = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, rgteBase, ARRAYSIZE(rgteBase));
|
|
if (iOffsetBase == -1)
|
|
{
|
|
iOffsetBase = (int)lOffsetDueToBOM;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Figure out where to insert the components.
|
|
//
|
|
TAGENTRYW rgteComponents[] = {
|
|
{ L"</BODY>", FALSE, },
|
|
{ L"</HTML>", FALSE, },
|
|
};
|
|
iOffsetComponents = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteComponents, ARRAYSIZE(rgteComponents));
|
|
|
|
//
|
|
// Write out the initial HTML up to the <HEAD> tag.
|
|
//
|
|
_WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, iOffsetBase);
|
|
|
|
//
|
|
// Write out the base tag.
|
|
//
|
|
if (fUseBaseHref)
|
|
{
|
|
//BASE tag must point to the base "URL". So, don't strip out the filename.
|
|
_WriteHtmlFromIdF(IDS_BASE_TAG, szSelectedWallpaper);
|
|
}
|
|
|
|
// Figure out where to insert the DIV clause
|
|
TAGENTRYW rgteBodyStart[] = {
|
|
{ L"<BODY", FALSE, },
|
|
};
|
|
int iOffsetBodyStart = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteBodyStart, ARRAYSIZE(rgteBodyStart));
|
|
// Write out HTML until after the <BODY ......>
|
|
if (iOffsetBodyStart == -1)
|
|
{ // the <BODY> tag is not found, so we need to insert it.
|
|
// Copy over stuff until </HEAD>
|
|
TAGENTRYW rgteHeadEnd[] = {
|
|
{ L"</HEAD>", TRUE, },
|
|
};
|
|
int iOffsetHeadEnd = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteHeadEnd, ARRAYSIZE(rgteHeadEnd));
|
|
if (iOffsetHeadEnd != -1)
|
|
{
|
|
_WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetHeadEnd);
|
|
iOffsetBase = iOffsetHeadEnd;
|
|
}
|
|
_WriteHtmlFromIdF(IDS_BODY_CENTER_WP2); // "<BODY>"
|
|
_fNeedBodyEnd = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TAGENTRYW rgteBodyEnd[] = {
|
|
{ L">", TRUE, },
|
|
};
|
|
int iOffsetBodyEnd = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBodyStart, rgteBodyEnd, ARRAYSIZE(rgteBodyEnd));
|
|
if (iOffsetBodyEnd == -1)
|
|
{ // An error in the HTML.
|
|
iOffsetBodyEnd = iOffsetBodyStart; // FEATURE: We need a better recovery idea.
|
|
}
|
|
_WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetBodyEnd);
|
|
iOffsetBase = iOffsetBodyEnd;
|
|
}
|
|
|
|
}
|
|
// Insert the DIV clause
|
|
if (ema.iMonitors > 1)
|
|
{
|
|
int iIndexPrimaryMonitor;
|
|
HMONITOR hMonitorPrimary;
|
|
MONITORINFO monitorInfo;
|
|
|
|
// 99/03/23 #275429 vtan: We used GetViewAreas() to fill in rcViewAreas above.
|
|
// The code here used to assume that [0] ALWAYS referred to the primary monitor.
|
|
// This isn't the case if the monitor settings are changed without a restart.
|
|
// In order to compensate for this and always render the wallpaper into the
|
|
// primary monitor, a search is performed to find a (left, top) that matches
|
|
// one of the work areas and this is used as the primary monitor. If none can
|
|
// be found then default to the old algorithm.
|
|
|
|
hMonitorPrimary = GetPrimaryMonitor();
|
|
monitorInfo.cbSize = sizeof(monitorInfo);
|
|
TBOOL(GetMonitorInfo(hMonitorPrimary, &monitorInfo));
|
|
iIndexPrimaryMonitor = -1;
|
|
for (int i = 0; (iIndexPrimaryMonitor < 0) && (i < nViewAreas); ++i)
|
|
{
|
|
if ((monitorInfo.rcWork.left == rcViewAreas[i].left) && (monitorInfo.rcWork.top == rcViewAreas[i].top))
|
|
{
|
|
iIndexPrimaryMonitor = i;
|
|
}
|
|
}
|
|
if (iIndexPrimaryMonitor < 0)
|
|
iIndexPrimaryMonitor = 0;
|
|
if ((nViewAreas <= 0) || (rcViewAreas[iIndexPrimaryMonitor].right == rcViewAreas[iIndexPrimaryMonitor].left))
|
|
// The second case could occur on bootup
|
|
{
|
|
// Some error occured when getting the ViewAreas. Recover from the error by using the workarea.
|
|
// Get the workarea of the primary monitor, since HTML wallpapers are displayed only there.
|
|
GetMonitorWorkArea(hMonitorPrimary, &rcViewAreas[iIndexPrimaryMonitor]);
|
|
}
|
|
_WriteHtmlFromIdF(IDS_DIV_START3,
|
|
rcViewAreas[iIndexPrimaryMonitor].left - ema.rcVirtualMonitor.left,
|
|
rcViewAreas[iIndexPrimaryMonitor].top - ema.rcVirtualMonitor.top,
|
|
rcViewAreas[iIndexPrimaryMonitor].right - rcViewAreas[iIndexPrimaryMonitor].left,
|
|
rcViewAreas[iIndexPrimaryMonitor].bottom - rcViewAreas[iIndexPrimaryMonitor].top);
|
|
}
|
|
|
|
//
|
|
// Write out HTML from after <HEAD> tag to just before </BODY> tag.
|
|
//
|
|
_WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetComponents);
|
|
|
|
if (ema.iMonitors > 1)
|
|
{
|
|
_WriteHtmlFromId(IDS_DIV_END);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_pReadFileObjHtmlBkgd)
|
|
delete _pReadFileObjHtmlBkgd;
|
|
_pReadFileObjHtmlBkgd = NULL;
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS GenerateHtmlHeader!");
|
|
}
|
|
|
|
void CActiveDesktop::_WriteResizeable(COMPONENTA *pcomp)
|
|
{
|
|
TCHAR szResizeable[3];
|
|
|
|
//If Resize is set, then the comp is resizeable in both X and Y directions!
|
|
if (pcomp->cpPos.fCanResize || (pcomp->cpPos.fCanResizeX && pcomp->cpPos.fCanResizeY))
|
|
{
|
|
szResizeable[0] = TEXT('X');
|
|
szResizeable[1] = TEXT('Y');
|
|
szResizeable[2] = TEXT('\0');
|
|
}
|
|
else if (pcomp->cpPos.fCanResizeX)
|
|
{
|
|
szResizeable[0] = TEXT('X');
|
|
szResizeable[1] = TEXT('\0');
|
|
}
|
|
else if (pcomp->cpPos.fCanResizeY)
|
|
{
|
|
szResizeable[0] = TEXT('Y');
|
|
szResizeable[1] = TEXT('\0');
|
|
}
|
|
|
|
_WriteHtmlFromIdF(IDS_RESIZEABLE, szResizeable);
|
|
}
|
|
|
|
void CActiveDesktop::_WriteHtmlW(LPCWSTR wcBuf, UINT cchToWrite, UINT *pcchWritten)
|
|
{
|
|
ULONG cchWritten = 0;
|
|
UINT uiSize;
|
|
|
|
if (_pStream)
|
|
{
|
|
uiSize = sizeof(WCHAR);
|
|
_pStream->Write((LPVOID)wcBuf, cchToWrite * uiSize, &cchWritten);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(_hFileHtml);
|
|
uiSize = (_iDestFileCharset == ANSI_HTML_CHARSET) ? sizeof(char) : sizeof(WCHAR);
|
|
WriteFile(_hFileHtml, (LPCVOID)wcBuf, cchToWrite * uiSize, &cchWritten, NULL);
|
|
}
|
|
*pcchWritten = (UINT)(cchWritten/uiSize); //Convert to number of chars.
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtmlPicture(COMPONENTA *pcomp)
|
|
{
|
|
ENTERPROC(2, "DS GenerateHtmlPicture(pcomp=%08X)");
|
|
|
|
//
|
|
// Write out the image src HTML.
|
|
//
|
|
TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cch = ARRAYSIZE(szUrl);
|
|
HRESULT hr = UrlCreateFromPath(pcomp->szSource, szUrl, &cch, 0);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = StringCchCopy(szUrl, ARRAYSIZE(szUrl), pcomp->szSource);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_WriteHtmlFromIdF(IDS_IMAGE_BEGIN2, pcomp->dwID, szUrl);
|
|
|
|
//
|
|
// Write out whether this image is resizeable or not!
|
|
//
|
|
_WriteResizeable(pcomp);
|
|
|
|
//
|
|
// Write out the URL that must be used for subscription purposes.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_SUBSCRIBEDURL, pcomp->szSubscribedURL);
|
|
|
|
//
|
|
// Write out the image location HTML.
|
|
//
|
|
if ((pcomp->cpPos.dwWidth == COMPONENT_DEFAULT_WIDTH) &&
|
|
(pcomp->cpPos.dwHeight == COMPONENT_DEFAULT_HEIGHT))
|
|
{
|
|
_WriteHtmlFromIdF(IDS_IMAGE_LOCATION, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.izIndex);
|
|
}
|
|
else
|
|
{
|
|
_WriteHtmlFromIdF(IDS_IMAGE_SIZE, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop,
|
|
pcomp->cpPos.dwWidth, pcomp->cpPos.dwHeight, pcomp->cpPos.izIndex);
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS GenerateHtmlPicture!");
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtmlDoc(COMPONENTA *pcomp)
|
|
{
|
|
ENTERPROC(2, "DS GenerateHtmlDoc(pcomp=%08X)");
|
|
|
|
TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
|
|
DWORD dwSize = ARRAYSIZE(szUrl);
|
|
LPTSTR lpszUrl = szUrl;
|
|
|
|
if (FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &dwSize, 0)))
|
|
lpszUrl = pcomp->szSource;
|
|
|
|
//
|
|
// Write out the DIV header HTML.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_DIV_START2, pcomp->dwID, lpszUrl);
|
|
|
|
//
|
|
// Write out whether this component is resizeable or not!
|
|
//
|
|
_WriteResizeable(pcomp);
|
|
|
|
//
|
|
// Write out the DIV location HTML.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_DIV_SIZE, pcomp->cpPos.dwHeight, _fSingleItem ? 0 : pcomp->cpPos.iLeft,
|
|
_fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.dwWidth, pcomp->cpPos.izIndex);
|
|
|
|
//
|
|
// Extract the doc contents directly into the HTML.
|
|
//
|
|
_WriteHtmlFromFile(pcomp->szSource);
|
|
|
|
//
|
|
// Close the DIV section.
|
|
//
|
|
_WriteHtmlFromId(IDS_DIV_END);
|
|
|
|
EXITPROC(2, "DS GenerateHtmlDoc!");
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtmlSite(COMPONENTA *pcomp)
|
|
{
|
|
ENTERPROC(2, "DS GenerateHtmlSite(pcomp=%08X)");
|
|
|
|
//
|
|
// Write out the frame src HTML.
|
|
//
|
|
TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cch=ARRAYSIZE(szUrl);
|
|
if (FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &cch, 0)))
|
|
{
|
|
if (FAILED(StringCchCopy(szUrl, ARRAYSIZE(szUrl), pcomp->szSource)))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
DWORD currentURLLength, maximumURLLength;
|
|
LPTSTR pszURL = NULL;
|
|
TCHAR szFormatBuffer[0x0100];
|
|
|
|
// 98/09/29 #211384 vtan: There is a limitation in wvsprintf.
|
|
// It only allows 2048 bytes in its buffer. If the URL is
|
|
// longer than 1024 characters less the IDS_IFRAME_BEGIN2
|
|
// string length less the component ID less "scrolling=no"
|
|
// if the component cannot be scrolled then the URL string
|
|
// will not be correctly inserted into the IDS_IFRAME_BEGIN2
|
|
// string and there will be a missing end-quote and trident
|
|
// will fail to render desktop.htt correctly.
|
|
|
|
// To correct against this the followING limits the length of
|
|
// the URL to this maximum and truncates any characters
|
|
// beyond the limit so that the IDS_IFRAME_BEGIN2 string
|
|
// contains its end-quote and trident does not barf.
|
|
|
|
// The above condition is a boundary condition and this
|
|
// check is quick so that the calculations that follow do
|
|
// not have to be executed repeatedly.
|
|
|
|
currentURLLength = lstrlen(szUrl);
|
|
if (currentURLLength > 768) // a hard-coded limit
|
|
{
|
|
maximumURLLength = 1024; // wvsprintf limit
|
|
LoadString(HINST_THISDLL, IDS_IFRAME_BEGIN2, szFormatBuffer, ARRAYSIZE(szFormatBuffer));
|
|
maximumURLLength -= lstrlen(szFormatBuffer); // IDS_IFRAME_BEGIN2
|
|
maximumURLLength -= 16; // pcomp->dwID
|
|
maximumURLLength -= lstrlen(TEXT("scrolling=no")); // pcomp->fNoScroll
|
|
if (currentURLLength > maximumURLLength)
|
|
szUrl[maximumURLLength] = static_cast<TCHAR>('\0');
|
|
}
|
|
_WriteHtmlFromIdF(IDS_IFRAME_BEGIN2, pcomp->dwID, szUrl, pcomp->fNoScroll ? TEXT("scrolling=no") : c_szNULL);
|
|
|
|
//
|
|
// Write out whether this Component is resizeable or not!
|
|
//
|
|
_WriteResizeable(pcomp);
|
|
|
|
// 98/09/29 #211384 vtan: See above.
|
|
|
|
currentURLLength = lstrlen(pcomp->szSubscribedURL);
|
|
if (currentURLLength > 768)
|
|
{
|
|
if (SUCCEEDED(StringCchCopy(szUrl, ARRAYSIZE(szUrl), pcomp->szSubscribedURL)))
|
|
{
|
|
maximumURLLength = 1024;
|
|
LoadString(HINST_THISDLL, IDS_SUBSCRIBEDURL, szFormatBuffer, ARRAYSIZE(szFormatBuffer));
|
|
maximumURLLength -= lstrlen(szFormatBuffer); // IDS_SUBSCRIBEDURL
|
|
if (currentURLLength > maximumURLLength)
|
|
szUrl[maximumURLLength] = static_cast<TCHAR>('\0');
|
|
pszURL = szUrl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszURL = pcomp->szSubscribedURL;
|
|
}
|
|
|
|
if (pszURL)
|
|
{
|
|
//
|
|
// Write out the URL that must be used for subscription purposes.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_SUBSCRIBEDURL, pszURL);
|
|
|
|
//
|
|
// Write out the frame location HTML.
|
|
//
|
|
_WriteHtmlFromIdF(IDS_IFRAME_SIZE, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop,
|
|
pcomp->cpPos.dwWidth, pcomp->cpPos.dwHeight, pcomp->cpPos.izIndex);
|
|
}
|
|
|
|
EXITPROC(2, "DS GenerateHtmlSite!");
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtmlControl(COMPONENTA *pcomp)
|
|
{
|
|
ENTERPROC(2, "DS GenerateHtmlControl(pcomp=%08X)");
|
|
ASSERT(pcomp);
|
|
|
|
// Did the Administrator restrict "Channel UI"?
|
|
if (SHRestricted2W(REST_NoChannelUI, NULL, 0))
|
|
{
|
|
TCHAR szChannelOCGUID[GUIDSTR_MAX];
|
|
|
|
SHStringFromGUID(CLSID_ChannelOC, szChannelOCGUID, ARRAYSIZE(szChannelOCGUID));
|
|
if (!StrCmpNI(pcomp->szSource, &(szChannelOCGUID[1]), lstrlen(pcomp->szSource)-3))
|
|
{
|
|
// Yes, so we need to hide the Channel Desktop Component.
|
|
// Return here before we generate it.
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write out the control HTML.
|
|
//
|
|
|
|
// First the control header
|
|
_WriteHtmlFromIdF(IDS_CONTROL_1, pcomp->dwID);
|
|
// then the size
|
|
_WriteHtmlFromIdF(IDS_CONTROL_2, pcomp->cpPos.dwHeight, _fSingleItem ? 0 : pcomp->cpPos.iLeft,
|
|
_fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.dwWidth, pcomp->cpPos.izIndex);
|
|
//
|
|
// Write out whether this Control is resizeable or not!
|
|
//
|
|
_WriteResizeable(pcomp);
|
|
|
|
// Finally the rest of the control
|
|
_WriteHtmlFromIdF(IDS_CONTROL_3, pcomp->szSource);
|
|
|
|
EXITPROC(2, "DS GenerateHtmlControl!");
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtmlComponent(COMPONENTA *pcomp)
|
|
{
|
|
ENTERPROC(2, "DS GenerateHtmlComponent(pcomp=%08X)");
|
|
|
|
switch(pcomp->iComponentType)
|
|
{
|
|
case COMP_TYPE_PICTURE:
|
|
_GenerateHtmlPicture(pcomp);
|
|
break;
|
|
|
|
case COMP_TYPE_HTMLDOC:
|
|
_GenerateHtmlDoc(pcomp);
|
|
break;
|
|
|
|
case COMP_TYPE_WEBSITE:
|
|
_GenerateHtmlSite(pcomp);
|
|
break;
|
|
|
|
case COMP_TYPE_CONTROL:
|
|
_GenerateHtmlControl(pcomp);
|
|
break;
|
|
}
|
|
|
|
EXITPROC(2, "DS GenerateHtmlComponent!");
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtmlFooter(void)
|
|
{
|
|
ENTERPROC(2, "DS GenerateHtmlFooter()");
|
|
|
|
//
|
|
// Write out the deskmovr object.
|
|
//
|
|
if (!_fNoDeskMovr)
|
|
{
|
|
TCHAR szDeskMovrFile[MAX_PATH];
|
|
|
|
if (GetWindowsDirectory(szDeskMovrFile, ARRAYSIZE(szDeskMovrFile)) &&
|
|
PathAppend(szDeskMovrFile, DESKMOVR_FILENAME))
|
|
{
|
|
_WriteHtmlFromFile(szDeskMovrFile);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write out the concluding HTML tags.
|
|
//
|
|
if (_pReadFileObjHtmlBkgd)
|
|
{
|
|
if (_fNeedBodyEnd)
|
|
{ // We had introduced the <BODY> tag by ourselves.
|
|
_WriteHtmlFromId(IDS_BODY_END2);
|
|
_fNeedBodyEnd = FALSE;
|
|
}
|
|
_WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, -1, -1);
|
|
delete _pReadFileObjHtmlBkgd; //Close the file and cleanup!
|
|
_pReadFileObjHtmlBkgd = NULL;
|
|
}
|
|
else
|
|
{
|
|
_WriteHtmlFromId(IDS_BODY_END);
|
|
}
|
|
|
|
EXITPROC(2, "DS GenerateHtmlFooter!");
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtml(void)
|
|
{
|
|
ENTERPROC(2, "DS GenerateHtml()");
|
|
|
|
TCHAR szHtmlFile[MAX_PATH];
|
|
|
|
//
|
|
// Compute the filename.
|
|
//
|
|
szHtmlFile[0] = TEXT('\0');
|
|
|
|
if (SUCCEEDED(GetPerUserFileName(szHtmlFile, ARRAYSIZE(szHtmlFile), DESKTOPHTML_FILENAME)))
|
|
{
|
|
// Recreate the file.
|
|
_hFileHtml = CreateFile(szHtmlFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, NULL);
|
|
if (_hFileHtml != INVALID_HANDLE_VALUE)
|
|
{
|
|
_GenerateHtmlHeader();
|
|
|
|
if (_co.fEnableComponents && _hdsaComponent && DSA_GetItemCount(_hdsaComponent) &&
|
|
!SHRestricted(REST_NODESKCOMP))
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
|
|
{
|
|
COMPONENTA comp;
|
|
comp.dwSize = sizeof(COMPONENTA);
|
|
|
|
if ((DSA_GetItem(_hdsaComponent, i, &comp) != -1) && (comp.fChecked))
|
|
{
|
|
_GenerateHtmlComponent(&comp);
|
|
}
|
|
}
|
|
}
|
|
|
|
_GenerateHtmlFooter();
|
|
CloseHandle(_hFileHtml);
|
|
SetDesktopFlags(COMPONENTS_DIRTY, 0);
|
|
}
|
|
else
|
|
{
|
|
|
|
// 99/05/19 #340772 vtan: If unable to open desktop.htt it's probably
|
|
// in use by another process or task (perhaps trident is trying to
|
|
// render it). In this case mark it dirty so that it will get recreated
|
|
// - yet again but this time with more current data.
|
|
|
|
SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS GenerateHtml!");
|
|
}
|
|
|
|
HRESULT CActiveDesktop::GenerateDesktopItemHtml(LPCWSTR pwszFileName, COMPONENT *pcomp, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
ENTERPROC(2, "DS GenerateComponentHtml(pcomp=%08X)", pcomp);
|
|
|
|
//Check for the input parameters
|
|
if (!pwszFileName || (pcomp && (pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT))))
|
|
return E_INVALIDARG;
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
//
|
|
// Create the file.
|
|
//
|
|
_hFileHtml = CreateFile(pwszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (_hFileHtml != INVALID_HANDLE_VALUE)
|
|
{
|
|
_fNoDeskMovr = TRUE;
|
|
_fBackgroundHtml = TRUE;
|
|
//Check if we need to add a component
|
|
if (pcomp)
|
|
{
|
|
COMPONENTA CompA;
|
|
|
|
CompA.dwSize = sizeof(CompA);
|
|
WideCompToMultiComp(pcomp, &CompA);
|
|
|
|
_fSingleItem = TRUE;
|
|
_GenerateHtmlHeader();
|
|
|
|
_GenerateHtmlComponent(&CompA);
|
|
_GenerateHtmlFooter();
|
|
_fSingleItem = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//generate just the header and the footer with proper
|
|
// wallpaper and pattern info!
|
|
_GenerateHtmlHeader();
|
|
_GenerateHtmlFooter();
|
|
}
|
|
_fBackgroundHtml = FALSE;
|
|
_fNoDeskMovr = FALSE;
|
|
|
|
CloseHandle(_hFileHtml);
|
|
|
|
hres = S_OK;
|
|
}
|
|
_hFileHtml = NULL;
|
|
|
|
EXITPROC(2, "DS GenerateComponentHtml=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// AddUrl
|
|
//
|
|
//
|
|
|
|
HRESULT CActiveDesktop::AddUrl(HWND hwnd, LPCWSTR pszSourceW, LPCOMPONENT pcomp, DWORD dwFlags)
|
|
{
|
|
LPTSTR pszExt;
|
|
HRESULT fOkay = TRUE;
|
|
BOOL fExtIsCdf,fPathIsUrl;
|
|
BOOL fSubscribed = FALSE;
|
|
COMPONENT compLocal;
|
|
COMPONENTA compA;
|
|
TCHAR szSource[INTERNET_MAX_URL_LENGTH];
|
|
|
|
// 98/08/28 vtan #202777: The following if statement sanitizes parameters
|
|
// passed to AddUrl(). The statements following the "||" are executed
|
|
// despite the for pcomp against NULL. This causes an access violation
|
|
// and an exception to be thrown.
|
|
|
|
#if 0
|
|
//Check for the input parameters.
|
|
if (!pszSourceW || (pcomp &&
|
|
((pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT))) ||
|
|
((pcomp->dwSize == sizeof(*pcomp)) && !VALIDATESTATE(pcomp->dwCurItemState))))
|
|
return E_INVALIDARG;
|
|
#else
|
|
|
|
// The following performs the same comparison but is spread into three
|
|
// separate comparisons. As performance is not a critical issue here
|
|
// but correctness is this makes the tests clear and understandable.
|
|
// The invalid conditions are described.
|
|
|
|
// Validate input parameters. Invalid parameters are:
|
|
// 1) NULL pszSourceW
|
|
// 2) pcomp->dwSize for a COMPONENT struct but invalid pcomp->dwCurItemState
|
|
// 3) pcomp->dwSize is not for a COMPONENT struct nor for a IE4COMPONENT struct
|
|
|
|
if (pszSourceW == NULL)
|
|
return(E_INVALIDARG);
|
|
if (pcomp != NULL)
|
|
{
|
|
if ((pcomp->dwSize == sizeof(*pcomp)) && !VALIDATESTATE(pcomp->dwCurItemState))
|
|
return(E_INVALIDARG);
|
|
if ((pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT)))
|
|
return(E_INVALIDARG);
|
|
}
|
|
#endif
|
|
|
|
// Catch folks that call our API's to add components and prevent them from doing
|
|
// so if the restriction is in place.
|
|
if (SHIsRestricted(NULL, REST_NOADDDESKCOMP))
|
|
return E_ACCESSDENIED;
|
|
|
|
if (!pcomp)
|
|
{
|
|
pcomp = &compLocal;
|
|
pcomp->dwSize = sizeof(compLocal);
|
|
pcomp->dwCurItemState = IS_NORMAL;
|
|
}
|
|
|
|
// Attempt to come up with a reasonable window handle if none is passed in. ParseDesktopComponent
|
|
// will fail to attempt to create a subscription if a NULL window handle is passed in.
|
|
if (!hwnd)
|
|
hwnd = GetLastActivePopup(GetActiveWindow());
|
|
|
|
compA.dwSize = sizeof(compA);
|
|
compA.dwCurItemState = (pcomp->dwSize != sizeof(IE4COMPONENT)) ? pcomp->dwCurItemState : IS_NORMAL;
|
|
|
|
SHUnicodeToTChar(pszSourceW, szSource, ARRAYSIZE(szSource));
|
|
pszExt = PathFindExtension(szSource);
|
|
fExtIsCdf = lstrcmpi(pszExt, TEXT(".CDF")) == 0;
|
|
fPathIsUrl = PathIsURL(szSource) && !UrlIsFileUrl(szSource);
|
|
|
|
if (FindComponent(szSource, (g_pActiveDesk ? g_pActiveDesk : this)))
|
|
{
|
|
if (dwFlags & ADDURL_SILENT)
|
|
{
|
|
if (FAILED(StringCchCopy(compA.szSource, ARRAYSIZE(compA.szSource), szSource)))
|
|
{
|
|
compA.szSource[0] = 0;
|
|
}
|
|
|
|
|
|
MultiCompToWideComp(&compA, pcomp);
|
|
RemoveDesktopItem(pcomp, 0);
|
|
}
|
|
else
|
|
{
|
|
// This is a long string. So,...
|
|
TCHAR szMsg[512];
|
|
TCHAR szMsg2[256];
|
|
TCHAR szTitle[128];
|
|
LoadString(HINST_THISDLL, IDS_COMP_EXISTS, szMsg, ARRAYSIZE(szMsg));
|
|
LoadString(HINST_THISDLL, IDS_COMP_EXISTS_2, szMsg2, ARRAYSIZE(szMsg2));
|
|
StringCchCat(szMsg, ARRAYSIZE(szMsg), szMsg2); // display, truncation fine
|
|
LoadString(HINST_THISDLL, IDS_COMP_TITLE, szTitle, ARRAYSIZE(szTitle));
|
|
MessageBox(hwnd, szMsg, szTitle, MB_OK);
|
|
|
|
fOkay = FALSE;
|
|
}
|
|
}
|
|
|
|
if (fOkay && CheckForExistingSubscription(szSource))
|
|
{
|
|
if ((dwFlags & ADDURL_SILENT) ||
|
|
(ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_SUBSCRIBED),
|
|
MAKEINTRESOURCE(IDS_COMP_TITLE), MB_YESNO) == IDYES))
|
|
{
|
|
DeleteFromSubscriptionList(szSource);
|
|
}
|
|
else
|
|
{
|
|
fOkay = FALSE;
|
|
}
|
|
}
|
|
|
|
if (fOkay)
|
|
{
|
|
if (fPathIsUrl || fExtIsCdf)
|
|
{
|
|
HRESULT hr;
|
|
IProgressDialog * pProgressDlg = NULL;
|
|
DECLAREWAITCURSOR;
|
|
|
|
// 98/12/16 vtan #250938: Cannot add new components that are not
|
|
// local with ICW run to completion. Tell the user and launch ICW.
|
|
|
|
if (!IsICWCompleted())
|
|
{
|
|
if ((dwFlags & ADDURL_SILENT) == 0)
|
|
{
|
|
ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_ICW_ADD), MAKEINTRESOURCE(IDS_COMP_ICW_TITLE), MB_OK);
|
|
LaunchICW();
|
|
}
|
|
fOkay = FALSE;
|
|
}
|
|
else
|
|
{
|
|
SetWaitCursor();
|
|
// ParseDesktopComponent can hang for a long time, we need some sort of progress
|
|
// UI up before we call it.
|
|
if (!(dwFlags & ADDURL_SILENT) && !fExtIsCdf)
|
|
{
|
|
if (pProgressDlg = CProgressDialog_CreateInstance(IDS_COMP_TITLE, IDA_ISEARCH, g_hinst))
|
|
{
|
|
TCHAR szConnecting[80];
|
|
LoadString(HINST_THISDLL, IDS_CONNECTING, szConnecting, ARRAYSIZE(szConnecting));
|
|
pProgressDlg->SetLine(1, szConnecting, FALSE, NULL);
|
|
pProgressDlg->SetLine(2, szSource, TRUE, NULL);
|
|
pProgressDlg->StartProgressDialog(hwnd, NULL, PROGDLG_AUTOTIME | PROGDLG_NOPROGRESSBAR, NULL);
|
|
}
|
|
}
|
|
|
|
hr = ParseDesktopComponent(hwnd, szSource, pcomp);
|
|
|
|
if (pProgressDlg)
|
|
{
|
|
pProgressDlg->StopProgressDialog();
|
|
fOkay = !pProgressDlg->HasUserCancelled(); // User may have cancelled the progress dialog
|
|
pProgressDlg->Release();
|
|
}
|
|
ResetWaitCursor();
|
|
|
|
if (hr == S_FALSE) // User cancelled operation via subscription download dialog
|
|
fOkay = FALSE;
|
|
|
|
if (fOkay)
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Convert ed's wide thinggy to multi.
|
|
//
|
|
WideCompToMultiComp(pcomp, &compA);
|
|
|
|
fSubscribed = TRUE;
|
|
}
|
|
else if (!fExtIsCdf)
|
|
{
|
|
//
|
|
// This is some non-CDF url.
|
|
//
|
|
CreateComponent(&compA, szSource);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We barfed on a CDF, bring up an error message.
|
|
//
|
|
if (!(dwFlags & ADDURL_SILENT))
|
|
{
|
|
ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_BADURL),
|
|
MAKEINTRESOURCE(IDS_COMP_TITLE), MB_OK);
|
|
}
|
|
fOkay = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is just some local file.
|
|
//
|
|
CreateComponent(&compA, szSource);
|
|
}
|
|
}
|
|
|
|
if (fOkay && fPathIsUrl && !fSubscribed)
|
|
{
|
|
//
|
|
// Run subscription code on URLs if CDF code hasn't already.
|
|
//
|
|
if (dwFlags & ADDURL_SILENT)
|
|
{
|
|
ISubscriptionMgr *psm;
|
|
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr, NULL,
|
|
CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&psm)))
|
|
{
|
|
//We need to zero init this structure except the cbSize field.
|
|
SUBSCRIPTIONINFO siDefault = {sizeof(SUBSCRIPTIONINFO)};
|
|
//This field is already initialized above.
|
|
//siDefault.cbSize = sizeof(siDefault);
|
|
psm->CreateSubscription(hwnd, szSource, szSource, CREATESUBS_NOUI, SUBSTYPE_DESKTOPURL, &siDefault);
|
|
psm->UpdateSubscription(szSource);
|
|
psm->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HRESULT hres = CreateSubscriptionsWizard(SUBSTYPE_DESKTOPURL, szSource, NULL, hwnd);
|
|
if (!SUCCEEDED(hres)) //Some error, or the user chose Cancel - we should fail.
|
|
{
|
|
ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_BADSUBSCRIBE),
|
|
MAKEINTRESOURCE(IDS_COMP_TITLE), MB_OK);
|
|
}
|
|
fOkay = (hres == S_OK); //could be S_FALSE, which means CreateSubscription was cancelled
|
|
//so we don't display the above error, but we don't create the DTI
|
|
}
|
|
}
|
|
|
|
MultiCompToWideComp(&compA, pcomp);
|
|
|
|
if (fOkay)
|
|
{
|
|
AddDesktopItem(pcomp, 0);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
void CActiveDesktop::_SaveSettings(DWORD dwFlags)
|
|
{
|
|
ENTERPROC(2, "DS SaveSettings()");
|
|
|
|
if (dwFlags & AD_APPLY_SAVE)
|
|
{
|
|
// Don't ever modify the safemode settings
|
|
TCHAR szDeskcomp[MAX_PATH];
|
|
|
|
GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
|
|
if (!StrStr(szDeskcomp, REG_DESKCOMP_SAFEMODE_SUFFIX))
|
|
{
|
|
//
|
|
// Write out registry settings.
|
|
//
|
|
_SaveWallpaper();
|
|
_SaveComponents();
|
|
_SavePattern(SAVE_PATTERN_NAME);
|
|
}
|
|
};
|
|
|
|
if (dwFlags & AD_APPLY_HTMLGEN)
|
|
{
|
|
//We need to generate the Patten.bmp file too!
|
|
_SavePattern(GENERATE_PATTERN_FILE);
|
|
|
|
//
|
|
// Write out HTML file.
|
|
//
|
|
_GenerateHtml();
|
|
}
|
|
|
|
// The 3rd largest hang found by WindowsUpdate crash uploader has been that the Desktop hwnd hangs
|
|
// and the display CPYU
|
|
#define SENDMESSAGE_TIMEOUT (10 * 1000)
|
|
|
|
if (dwFlags & AD_APPLY_REFRESH)
|
|
{
|
|
HWND hwndShell = GetShellWindow();
|
|
SHELLSTATE ss = {0};
|
|
DWORD_PTR pdwTemp = 0;
|
|
|
|
SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
|
|
BOOL fWasActiveDesktop = BOOLIFY(ss.fDesktopHTML);
|
|
BOOL fIsActiveDesktop = BOOLIFY(_co.fActiveDesktop);
|
|
|
|
if (fIsActiveDesktop && !IsICWCompleted())
|
|
TBOOL(DisableUndisplayableComponents(this));
|
|
if (fIsActiveDesktop != fWasActiveDesktop)
|
|
{
|
|
if (hwndShell)
|
|
{
|
|
|
|
SendMessageTimeout(hwndShell, WM_WININICHANGE, SPI_SETDESKWALLPAPER, (LPARAM)TEXT("ToggleDesktop"), SMTO_NORMAL, SENDMESSAGE_TIMEOUT, &pdwTemp);
|
|
}
|
|
|
|
//Force a SHRefresh with this dummy call
|
|
SHGetSetSettings(NULL, 0, TRUE);
|
|
}
|
|
else if (fIsActiveDesktop && hwndShell)
|
|
{
|
|
//See if we can simply make the changes dynamically instead of refreshing the whole page
|
|
|
|
// 98/09/22 #182982 vtan: Use dynamic HTML to refresh only if specifically told by a flag.
|
|
|
|
if (_fUseDynamicHtml && (dwFlags & AD_APPLY_DYNAMICREFRESH))
|
|
{
|
|
SendMessageTimeout(hwndShell, DTM_MAKEHTMLCHANGES, (WPARAM)0, (LPARAM)0L, SMTO_NORMAL, SENDMESSAGE_TIMEOUT, &pdwTemp);
|
|
}
|
|
else
|
|
{
|
|
//Can't use dynamic html. We have to refresh the whole page.
|
|
SendMessageTimeout(hwndShell, WM_WININICHANGE, SPI_SETDESKWALLPAPER,
|
|
(LPARAM)((dwFlags & AD_APPLY_BUFFERED_REFRESH) ? c_szBufferedRefresh : c_szRefreshDesktop), SMTO_NORMAL, SENDMESSAGE_TIMEOUT, &pdwTemp);
|
|
}
|
|
}
|
|
|
|
_fUseDynamicHtml = TRUE;
|
|
}
|
|
|
|
//
|
|
// Data is no longer dirty.
|
|
//
|
|
_fDirty = FALSE;
|
|
_fWallpaperDirty = FALSE;
|
|
_fWallpaperChangedDuringInit = FALSE;
|
|
_fPatternDirty = FALSE;
|
|
|
|
EXITPROC(2, "DS SaveSettings!");
|
|
}
|
|
|
|
ULONG CActiveDesktop::AddRef(void)
|
|
{
|
|
ENTERPROC(1, "DS AddRef()");
|
|
|
|
_cRef++;
|
|
|
|
EXITPROC(1, "DS AddRef=%d", _cRef);
|
|
return _cRef;
|
|
}
|
|
|
|
// pwzPath: The path where the temp files go (%userprofile%/windows)
|
|
// pszFile: The original file name ("Joe's Vacation Picture.jpg")
|
|
// pszInUse: The wallpaper in use.
|
|
HRESULT _DeleteUnusedTempFiles(IN LPCWSTR pwzPath, IN LPCTSTR pszFile)
|
|
{
|
|
TCHAR szTemplate[MAX_PATH];
|
|
WIN32_FIND_DATA findFileData;
|
|
LPCTSTR pszFileName = PathFindFileName(pszFile);
|
|
|
|
HRESULT hr = StringCchPrintf(szTemplate, ARRAYSIZE(szTemplate), TEXT("%ls\\Wallpaper*.bmp"), pwzPath);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HANDLE hFindFile = FindFirstFile(szTemplate, &findFileData);
|
|
|
|
if (INVALID_HANDLE_VALUE != hFindFile)
|
|
{
|
|
do
|
|
{
|
|
// Is this an old template? (Different name than we are currently using?
|
|
// Also, don't delete the wallpaper that is in use.
|
|
if (StrCmpI(findFileData.cFileName, pszFileName))
|
|
{
|
|
DeleteFile(szTemplate); // Yes so delete it.
|
|
}
|
|
}
|
|
while (FindNextFile(hFindFile, &findFileData));
|
|
|
|
FindClose(hFindFile);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// nIndex: The file to try.
|
|
// pszInUse: This is the file we should skip because it's in use.
|
|
// pwzPath: On the way in, this is the selected wallpaper to convert.
|
|
// On the way out, this is is the converted file.
|
|
HRESULT _ConvertToTempFile(IN int nIndex, IN LPCWSTR pwzTempPath, IN LPTSTR pwzPath, IN int cchSize)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR wzNewFile[MAX_PATH];
|
|
LPCWSTR pszFileName = PathFindFileName(pwzPath);
|
|
|
|
if (pszFileName)
|
|
{
|
|
hr = StringCchPrintf(wzNewFile, ARRAYSIZE(wzNewFile), L"%s\\Wallpaper%d.bmp", pwzTempPath, nIndex);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHConvertGraphicsFile(pwzPath, wzNewFile, SHCGF_REPLACEFILE);
|
|
|
|
// This may fail for one of many reasons, and we just fall back to the old behavior if it fails.
|
|
// This may fail if they don't have write permission of the disk, run out of disk space, or
|
|
// this is a file type that we don't support.
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = StringCchCopy(pwzPath, cchSize, wzNewFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// pszFile: On the way in, this will contain the full path to the original file.
|
|
// On the way out, if we succeed, it will be modified to the temp file
|
|
// that is the converted equivalent of the file on the way in.
|
|
HRESULT CActiveDesktop::_ConvertFileToTempBitmap(IN LPWSTR pszFile, IN int cchSize)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR wzPath[MAX_PATH];
|
|
|
|
if (S_OK == SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wzPath) &&
|
|
PathAppend(wzPath, TEXT("Microsoft")))
|
|
{
|
|
CreateDirectoryW(wzPath, NULL);
|
|
|
|
// Let's try the modified names to come up with something we can use.
|
|
for (int nIndex = 1; FAILED(hr) && (nIndex < 100); nIndex++)
|
|
{
|
|
hr = _ConvertToTempFile(nIndex, wzPath, pszFile, cchSize);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_DeleteUnusedTempFiles(wzPath, pszFile);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#define SZ_REGKEY_CONTROLPANEL_DESKTOP TEXT("Control Panel\\Desktop")
|
|
#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_WALLPAPER TEXT("Wallpaper")
|
|
#define SZ_REGVALUE_CONVERTED_WP_LASTWRITE TEXT("ConvertedWallpaper Last WriteTime")
|
|
|
|
HRESULT CActiveDesktop::_SaveTempWallpaperSettings(void)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// When we converted a non-.BMP wallpaper to a .bmp temp file,
|
|
// we keep the name of the original wallpaper path stored in _szSelectedWallpaper.
|
|
// We need to save that.
|
|
if (_szSelectedWallpaper)
|
|
{
|
|
hr = S_OK;
|
|
|
|
DWORD cbSize = sizeof(_szSelectedWallpaper[0]) * (lstrlen(_szSelectedWallpaper) + 1);
|
|
|
|
Str_SetPtr(&_pszOrigLastApplied, _szSelectedWallpaper);
|
|
|
|
// ISSUE: CONVERTED and ORIGINAL are backwards, but we shipped beta1 like this so we can't change it... blech
|
|
DWORD dwError = SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CONVERTED_WALLPAPER, REG_SZ, _szSelectedWallpaper, cbSize);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
Str_SetPtrW(&_pszWallpaperInUse, _szSelectedWallpaper);
|
|
cbSize = sizeof(_szSelectedWallpaperConverted[0]) * (lstrlen(_szSelectedWallpaperConverted) + 1);
|
|
|
|
Str_SetPtr(&_pszOrigLastApplied, _szSelectedWallpaper);
|
|
|
|
dwError = SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_ORIGINAL_WALLPAPER, REG_SZ, (void *) _szSelectedWallpaperConverted, cbSize);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
dwError = SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_WALLPAPER, REG_SZ, (void *) _szSelectedWallpaperConverted, cbSize);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
// Set date/time stamp of the original file (_szSelectedWallpaper) so we can later determine if the user changed the original.
|
|
if (_szSelectedWallpaper[0])
|
|
{
|
|
HANDLE hFile = CreateFile(_szSelectedWallpaper, GENERIC_READ, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
|
|
NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE != hFile)
|
|
{
|
|
if (GetFileTime(hFile, NULL, NULL, &_ftLastWrite))
|
|
{
|
|
dwError = SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CONVERTED_WP_LASTWRITE, REG_BINARY, &_ftLastWrite, sizeof(_ftLastWrite));
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ULARGE_INTEGER * puli = (ULARGE_INTEGER *) &_ftLastWrite;
|
|
puli->QuadPart = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::ApplyChanges(DWORD dwFlags)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
ENTERPROC(1, "DS Apply(dwFlags=%08X)", dwFlags);
|
|
|
|
BOOL fActiveDesktop = FALSE; // default to disable active desktop
|
|
|
|
// determine if we should enable active desktop
|
|
if (SHRestricted(REST_FORCEACTIVEDESKTOPON))
|
|
{
|
|
// if policy requires active desktop, then use that
|
|
fActiveDesktop = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// if desktop components are locked -> active desktop is on
|
|
DWORD dwDesktopFlags = GetDesktopFlags();
|
|
if (dwDesktopFlags & COMPONENTS_LOCKED)
|
|
{
|
|
fActiveDesktop = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// if desktop icons are hidden -> active desktop is on
|
|
SHELLSTATE ss;
|
|
SHGetSetSettings(&ss, SSF_HIDEICONS, FALSE);
|
|
if (ss.fHideIcons)
|
|
{
|
|
fActiveDesktop = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Convert the background if needed.
|
|
// if background is not a .bmp --> active desktop is on if we can't auto-convert
|
|
if (!IsNormalWallpaper(_szSelectedWallpaper))
|
|
{
|
|
BOOL fBitmapWallpaper = FALSE;
|
|
|
|
// create the factory
|
|
|
|
IShellImageDataFactory* pImgFact;
|
|
|
|
hres = CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_PPV_ARG(IShellImageDataFactory, &pImgFact));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IShellImageData * pImage;
|
|
|
|
hres = pImgFact->CreateImageFromFile(_szSelectedWallpaper, &pImage);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
// PERF: cache decoded data
|
|
hres = pImage->Decode(SHIMGDEC_DEFAULT, 0, 0);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (S_FALSE == pImage->IsTransparent() &&
|
|
S_FALSE == pImage->IsAnimated())
|
|
{
|
|
hres = StringCchCopy(_szSelectedWallpaperConverted, ARRAYSIZE(_szSelectedWallpaperConverted), _szSelectedWallpaper);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
HRESULT hrConvert = _ConvertFileToTempBitmap(_szSelectedWallpaperConverted, ARRAYSIZE(_szSelectedWallpaperConverted));
|
|
if (SUCCEEDED(hrConvert))
|
|
{
|
|
if (S_OK == hrConvert) // if we actually had to convert (we may have already done the conversion)
|
|
{
|
|
_fDirty = TRUE; // if we converted, then we have changed the background and must persist it
|
|
_SaveTempWallpaperSettings();
|
|
hres = StringCchCopy(_szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper), _szSelectedWallpaperConverted);
|
|
}
|
|
fBitmapWallpaper = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pImage->Release();
|
|
}
|
|
pImgFact->Release();
|
|
}
|
|
|
|
if (!fBitmapWallpaper)
|
|
{
|
|
fActiveDesktop = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!fActiveDesktop)
|
|
{
|
|
// if any elements are checked --> active desktop is on
|
|
if (_hdsaComponent)
|
|
{
|
|
INT cComponents = DSA_GetItemCount(_hdsaComponent);
|
|
for (INT i = 0; i < cComponents; i++)
|
|
{
|
|
COMPONENTA* pComponent = (COMPONENTA*)DSA_GetItemPtr(_hdsaComponent, i);
|
|
if (pComponent && pComponent->fChecked)
|
|
{
|
|
fActiveDesktop = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_co.fActiveDesktop != fActiveDesktop)
|
|
{
|
|
_co.fActiveDesktop = fActiveDesktop;
|
|
_fDirty = TRUE;
|
|
}
|
|
|
|
if (dwFlags & AD_APPLY_FORCE)
|
|
{
|
|
_fDirty = TRUE;
|
|
_fWallpaperDirty = TRUE;
|
|
_fPatternDirty = TRUE;
|
|
}
|
|
|
|
if (_fDirty || _fWallpaperChangedDuringInit)
|
|
{
|
|
_SaveSettings(dwFlags);
|
|
}
|
|
|
|
EXITPROC(1, "DS ApplyChanges=%d", hres);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG CActiveDesktop::Release(void)
|
|
{
|
|
UINT nRet = --_cRef;
|
|
ENTERPROC(1, "DS Release()");
|
|
|
|
if (_cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
EXITPROC(1, "DS Release=%d", nRet);
|
|
return nRet;
|
|
}
|
|
|
|
CActiveDesktop::CActiveDesktop()
|
|
{
|
|
_cRef = 1;
|
|
_fNoDeskMovr = FALSE;
|
|
_fBackgroundHtml = FALSE;
|
|
_fUseDynamicHtml = TRUE;
|
|
_hdsaComponent = NULL;
|
|
_pszScheme = NULL;
|
|
|
|
DllAddRef();
|
|
}
|
|
|
|
CActiveDesktop::~CActiveDesktop()
|
|
{
|
|
if (_hdsaComponent)
|
|
{
|
|
DSA_Destroy(_hdsaComponent);
|
|
}
|
|
if (_pszScheme)
|
|
{
|
|
LocalFree((HANDLE)_pszScheme);
|
|
}
|
|
|
|
DllRelease();
|
|
}
|
|
|
|
HRESULT CActiveDesktop::GetWallpaper(LPWSTR pwszWallpaper, UINT cchWallpaper, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
ENTERPROC(1, "DS GetWallpaper(pszWallpaper=%08X,cchWallpaper=%d)", pwszWallpaper, cchWallpaper);
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if (pwszWallpaper && cchWallpaper)
|
|
{
|
|
hres = StringCchCopy(pwszWallpaper, cchWallpaper, _szSelectedWallpaper);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if ( cchWallpaper < wcslen(_szSelectedWallpaper) )
|
|
{
|
|
hres = MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_MORE_DATA );
|
|
}
|
|
else
|
|
{
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
TraceMsg(TF_WARNING, "DS GetWallpaper unable to return wallpaper");
|
|
}
|
|
|
|
EXITPROC(1, "DS GetWallpaper=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::SetWallpaper(LPCWSTR pwszWallpaper, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
WCHAR szTemp[MAX_PATH];
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if (_fPolicyForWPName) // If a policy exists, the caller can not change the wallpaper.
|
|
return S_FALSE;
|
|
|
|
if (pwszWallpaper)
|
|
{
|
|
hres = StringCchCopy(szTemp, ARRAYSIZE(szTemp), pwszWallpaper);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = PathExpandEnvStringsWrap(szTemp, ARRAYSIZE(szTemp)); // We unexpand only when we persist.
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (lstrcmp(_szSelectedWallpaper, szTemp) != 0)
|
|
{
|
|
hres = StringCchCopy(_szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper), szTemp);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
_fWallpaperDirty = TRUE;
|
|
_fDirty = TRUE;
|
|
_fUseDynamicHtml = FALSE; //Setting wallpaper causes a lot of change; So, can't use dynamic html
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ENTERPROC(1, "DS SetWallpaper(pszWallpaper=>%s<)", pwszWallpaper ? szTemp : TEXT("(NULL)"));
|
|
|
|
EXITPROC(1, "DS SetWallpaper=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::GetWallpaperOptions(WALLPAPEROPT *pwpo, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
ENTERPROC(1, "DS GetWallpaperOptions(pwpo=%08X)");
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if ((pwpo) && (pwpo->dwSize == sizeof(*pwpo)))
|
|
{
|
|
*pwpo = _wpo;
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS GetWallpaperOptions could not return options");
|
|
}
|
|
|
|
EXITPROC(1, "DS GetWallpaperOptions=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::SetWallpaperOptions(LPCWALLPAPEROPT pwpo, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
ENTERPROC(1, "DS SetWallpaperOptions(pwpo=%08X)", pwpo);
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if (_fPolicyForWPStyle) //If a policy exists for wallpaper style, the caller can not change it.
|
|
return S_FALSE;
|
|
|
|
|
|
if ((pwpo) && (pwpo->dwSize == sizeof(*pwpo)))
|
|
{
|
|
_wpo = *pwpo;
|
|
_fWallpaperDirty = TRUE;
|
|
_fDirty = TRUE;
|
|
_fUseDynamicHtml = FALSE; //Changing wallpaper options causes us to regenerate the whole thing.
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS SetWallpaperOptions could not set options");
|
|
}
|
|
|
|
EXITPROC(1, "DS SetWallpaperOptions=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::GetPattern(LPWSTR pwszPattern, UINT cchPattern, DWORD dwReserved)
|
|
{
|
|
HRESULT hres;
|
|
ENTERPROC(1, "DS GetPattern(psz=%08X,cch=%d)", pwszPattern, cchPattern);
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if (!pwszPattern || (cchPattern == 0))
|
|
{
|
|
hres = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
hres = StringCchCopy(pwszPattern, cchPattern, _szSelectedPattern);
|
|
}
|
|
|
|
EXITPROC(1, "DS GetPattern=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::SetPattern(LPCWSTR pwszPattern, DWORD dwReserved)
|
|
{
|
|
ENTERPROC(1, "DS SetPattern(psz=>%s<)", pwszPattern ? pwszPattern : TEXT("(NULL)"));
|
|
|
|
HRESULT hres = E_INVALIDARG;
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if (pwszPattern)
|
|
{
|
|
if (lstrcmp(_szSelectedPattern, pwszPattern) != 0)
|
|
{
|
|
hres = StringCchCopy(_szSelectedPattern, ARRAYSIZE(_szSelectedPattern), pwszPattern);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
_fPatternDirty = TRUE;
|
|
_fDirty = TRUE;
|
|
_fUseDynamicHtml = FALSE; //Setting pattern causes us to regenerate the whole thing.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = E_FAIL;
|
|
}
|
|
}
|
|
|
|
EXITPROC(1, "DS SetPattern=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::GetDesktopItemOptions(COMPONENTSOPT *pco, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
ENTERPROC(1, "DS GetComponentsOptions(pco=%08X)", pco);
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if (pco && (pco->dwSize == sizeof(*pco)))
|
|
{
|
|
*pco = _co;
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS GetComponentsOptions unable to return options");
|
|
}
|
|
|
|
EXITPROC(1, "DS GetComponentsOptions=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::SetDesktopItemOptions(LPCCOMPONENTSOPT pco, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
ENTERPROC(1, "DS SetComponentsOptions(pco=%08X)", pco);
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if (pco && (pco->dwSize == sizeof(*pco)))
|
|
{
|
|
_co = *pco;
|
|
_fDirty = TRUE;
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS SetComponentsOptions unable to set options");
|
|
}
|
|
|
|
EXITPROC(1, "DS SetComponentsOptions=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// SetStateInfo()
|
|
// This function simply sets up the COMPSTATEINFO structure passed using the current
|
|
// position and size from the COMPPOS structure and the itemState passed.
|
|
//
|
|
void SetStateInfo(COMPSTATEINFO *pCompStateInfo, COMPPOS *pCompPos, DWORD dwItemState)
|
|
{
|
|
pCompStateInfo->dwSize = sizeof(*pCompStateInfo);
|
|
pCompStateInfo->iLeft = pCompPos->iLeft;
|
|
pCompStateInfo->iTop = pCompPos->iTop;
|
|
pCompStateInfo->dwWidth = pCompPos->dwWidth;
|
|
pCompStateInfo->dwHeight = pCompPos->dwHeight;
|
|
pCompStateInfo->dwItemState = dwItemState;
|
|
}
|
|
|
|
void ConvertCompStruct(COMPONENTA *pCompDest, COMPONENTA *pCompSrc, BOOL fPubToPriv)
|
|
{
|
|
pCompDest -> dwID = pCompSrc -> dwID;
|
|
pCompDest -> iComponentType = pCompSrc -> iComponentType;
|
|
pCompDest -> fChecked = pCompSrc -> fChecked;
|
|
pCompDest -> fDirty = pCompSrc -> fDirty;
|
|
pCompDest -> fNoScroll = pCompSrc -> fNoScroll;
|
|
pCompDest -> cpPos = pCompSrc -> cpPos;
|
|
|
|
if (fPubToPriv)
|
|
{
|
|
COMPONENT *pComp = (COMPONENT *)pCompSrc;
|
|
|
|
pCompDest->dwSize = sizeof(COMPONENTA);
|
|
SHUnicodeToTChar(pComp->wszSource, pCompDest->szSource, ARRAYSIZE(pCompDest->szSource));
|
|
SHUnicodeToTChar(pComp->wszFriendlyName, pCompDest->szFriendlyName, ARRAYSIZE(pCompDest->szFriendlyName));
|
|
SHUnicodeToTChar(pComp->wszSubscribedURL, pCompDest->szSubscribedURL, ARRAYSIZE(pCompDest->szSubscribedURL));
|
|
|
|
//Check to see if the public component is from IE4 app (old size)
|
|
if (pCompSrc->dwSize == sizeof(COMPONENT))
|
|
{
|
|
// Since the dest component is the same size as the most current structure, all fields
|
|
// are valid.
|
|
// CAUTION: The following fields are at a different offset in public and private
|
|
// structures. So, you need to use pcomp instead of pCompSrc for example.
|
|
pCompDest->dwCurItemState = pComp->dwCurItemState;
|
|
pCompDest->csiOriginal = pComp->csiOriginal;
|
|
pCompDest->csiRestored = pComp->csiRestored;
|
|
}
|
|
else
|
|
{
|
|
// Since the size did not match, we assume that this is an older structure.
|
|
// Since the older struct does not have any Original and Restored sizes, let's copy
|
|
// the default values.
|
|
IE4COMPONENT *pIE4Comp = (IE4COMPONENT *)pCompSrc;
|
|
pCompDest->dwCurItemState = IS_NORMAL;
|
|
SetStateInfo(&pCompDest->csiOriginal, &pIE4Comp->cpPos, IS_NORMAL);
|
|
SetStateInfo(&pCompDest->csiRestored, &pIE4Comp->cpPos, IS_NORMAL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
COMPONENT *pComp = (COMPONENT *)pCompDest;
|
|
|
|
if (pCompDest->dwSize != sizeof(COMPONENT))
|
|
pCompDest->dwSize = sizeof(IE4COMPONENT);
|
|
SHTCharToUnicode(pCompSrc->szSource, pComp->wszSource, ARRAYSIZE(pComp->wszSource));
|
|
SHTCharToUnicode(pCompSrc->szFriendlyName, pComp->wszFriendlyName, ARRAYSIZE(pComp->wszFriendlyName));
|
|
SHTCharToUnicode(pCompSrc->szSubscribedURL, pComp->wszSubscribedURL, ARRAYSIZE(pComp->wszSubscribedURL));
|
|
|
|
//Check to see if the public component is from IE4 app (old size)
|
|
if (pComp->dwSize == sizeof(COMPONENT))
|
|
{
|
|
// Since the dest component is the same size as the most current structure, all fields
|
|
// are valid.
|
|
// CAUTION: The following fields are at a different offset in public and private
|
|
// structures. So, you need to use pcomp instead of pCompDest for example.
|
|
pComp->dwCurItemState = pCompSrc->dwCurItemState;
|
|
pComp->csiOriginal = pCompSrc->csiOriginal;
|
|
pComp->csiRestored = pCompSrc->csiRestored;
|
|
}
|
|
// else, the dest component is IE4COMPONENT and the additional fields are not there.
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT CActiveDesktop::_AddDTIWithUIPrivateA(HWND hwnd, LPCCOMPONENT pComp, DWORD dwFlags)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
PCWSTR pszUrl = pComp->wszSource;
|
|
int nScheme = GetUrlScheme(pszUrl);
|
|
DWORD dwCurItemState;
|
|
if ((URL_SCHEME_INVALID == nScheme) || (URL_SCHEME_UNKNOWN == nScheme))
|
|
{
|
|
TCHAR szFullyQualified[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cchSize = ARRAYSIZE(szFullyQualified);
|
|
|
|
if (SUCCEEDED(ParseURLFromOutsideSource(pszUrl, szFullyQualified, &cchSize, NULL)))
|
|
nScheme = GetUrlScheme(szFullyQualified);
|
|
}
|
|
|
|
// Is this URL valid to subscribe to? Did the caller specify they want use
|
|
// to try to subscribe to it?
|
|
if ((URL_SCHEME_FILE != nScheme) && (URL_SCHEME_ABOUT != nScheme) &&
|
|
IsFlagSet(dwFlags, DTI_ADDUI_DISPSUBWIZARD) && hwnd)
|
|
{
|
|
//Create a subscription.
|
|
hres = CreateSubscriptionsWizard(SUBSTYPE_DESKTOPURL, pszUrl, NULL, hwnd);
|
|
if (hres != S_OK)
|
|
{
|
|
return hres;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the component to the registry.
|
|
//
|
|
|
|
// PERF: This function creates a second COM objects.
|
|
// We need to Inline the functionality.
|
|
if (pComp->dwSize == sizeof(IE4COMPONENT))
|
|
dwCurItemState = IS_NORMAL;
|
|
else
|
|
dwCurItemState = pComp->dwCurItemState;
|
|
hres = AddRemoveDesktopComponentNoUI(TRUE, AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH, pszUrl, NULL, pComp->iComponentType,
|
|
pComp->cpPos.iLeft, pComp->cpPos.iTop, pComp->cpPos.dwWidth, pComp->cpPos.dwHeight, TRUE, dwCurItemState) ? S_OK : E_FAIL;
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
|
|
#define STC_DESKTOPCOMPONENT 0x00000002
|
|
STDAPI SubscribeToCDF(HWND hwndParent, LPCWSTR pwzUrl, DWORD dwCDFTypes);
|
|
|
|
HRESULT CActiveDesktop::AddDesktopItemWithUI(HWND hwnd, LPCOMPONENT pComp, DWORD dwFlags)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
// We need to support IE4 apps calling with the old component structure too!
|
|
// We use the size field to detect IE4 v/s newer apps!
|
|
if (!pComp ||
|
|
((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))) ||
|
|
((pComp->dwSize == sizeof(*pComp)) && !VALIDATESTATE(pComp->dwCurItemState)) ||
|
|
((pComp->iComponentType < 0) || (pComp->iComponentType > COMP_TYPE_MAX))) //Validate the component type
|
|
return E_INVALIDARG;
|
|
|
|
// Catch folks that call our API's to add components and prevent them from doing
|
|
// so if the restriction is in place.
|
|
if (SHIsRestricted(NULL, REST_NOADDDESKCOMP))
|
|
return E_ACCESSDENIED;
|
|
|
|
// Check if the component already exists.
|
|
BOOL fCompExists = FALSE;
|
|
int cComp;
|
|
GetDesktopItemCount(&cComp, 0);
|
|
int i;
|
|
COMPONENT comp;
|
|
comp.dwSize = sizeof(COMPONENT); //This needs to be initialized for ConvertCompStruc to work!
|
|
COMPONENTA compA;
|
|
TCHAR szSource[INTERNET_MAX_URL_LENGTH];
|
|
SHUnicodeToTChar(pComp->wszSource, szSource, ARRAYSIZE(szSource));
|
|
|
|
for (i=0; i<cComp && !fCompExists; i++)
|
|
{
|
|
compA.dwSize = sizeof(compA);
|
|
if (GetComponentPrivate(i, &compA)
|
|
&& lstrcmpi(szSource, compA.szSource) == 0)
|
|
{
|
|
fCompExists = TRUE;
|
|
ConvertCompStruct((COMPONENTA *)&comp, &compA, FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOL fAskToInstall;
|
|
if (ZoneCheckUrlW(pComp->wszSource, URLACTION_SHELL_INSTALL_DTITEMS, (PUAF_NOUI), NULL) == S_OK)
|
|
{
|
|
fAskToInstall = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fAskToInstall = FALSE;
|
|
}
|
|
|
|
if (S_OK != ZoneCheckUrlW(pComp->wszSource, URLACTION_SHELL_INSTALL_DTITEMS, (hwnd ? (PUAF_FORCEUI_FOREGROUND | PUAF_WARN_IF_DENIED) : PUAF_NOUI), NULL))
|
|
return E_ACCESSDENIED;
|
|
|
|
BOOL fCompSubDeleted = FALSE;
|
|
SUBSCRIPTIONINFO si = {sizeof(SUBSCRIPTIONINFO)};
|
|
// si.bstrUserName = NULL;
|
|
// si.bstrPassword = NULL;
|
|
// si.bstrFriendlyName = NULL;
|
|
//
|
|
// Confirmation dialog.
|
|
//
|
|
if (hwnd)
|
|
{
|
|
if (fCompExists)
|
|
{
|
|
//Prompt the user to delete the existing ADI.
|
|
// This is a long string. So,...
|
|
TCHAR szMsg[512];
|
|
TCHAR szMsg2[256];
|
|
TCHAR szTitle[128];
|
|
LoadString(HINST_THISDLL, IDS_COMP_EXISTS, szMsg, ARRAYSIZE(szMsg));
|
|
LoadString(HINST_THISDLL, IDS_COMP_EXISTS_2, szMsg2, ARRAYSIZE(szMsg2));
|
|
StringCchCat(szMsg, ARRAYSIZE(szMsg), szMsg2); // truncation is fine, this is display text
|
|
LoadString(HINST_THISDLL, IDS_COMP_TITLE, szTitle, ARRAYSIZE(szTitle));
|
|
MessageBox(hwnd, szMsg, szTitle, MB_OK);
|
|
|
|
return E_FAIL;
|
|
}
|
|
else if (fAskToInstall)
|
|
{
|
|
if (ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_CONFIRM_ADD),
|
|
MAKEINTRESOURCE(IDS_INTERNET_EXPLORER), MB_YESNO) != IDYES)
|
|
{
|
|
return E_FAIL; //User choses not to install this desktop component!
|
|
}
|
|
}
|
|
}
|
|
|
|
hres = SubscribeToCDF(hwnd, pComp->wszSubscribedURL, STC_DESKTOPCOMPONENT);
|
|
switch(hres)
|
|
{
|
|
case E_INVALIDARG:
|
|
{
|
|
// E_UNEXPECTED is returned from SubscribeToCDFUrlA() when the URL doesn't point to
|
|
// a CDF file, so we assume it's a web page.
|
|
|
|
hres = _AddDTIWithUIPrivateA(hwnd, pComp, dwFlags);
|
|
if (hres != S_OK && fCompSubDeleted) // Restore the old component
|
|
{
|
|
hres = AddDesktopItem(&comp, 0);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
ISubscriptionMgr *psm;
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr, NULL,
|
|
CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&psm)))
|
|
{
|
|
si.cbSize = sizeof(si);
|
|
psm->CreateSubscription(hwnd, comp.wszSubscribedURL, si.bstrFriendlyName, CREATESUBS_NOUI, SUBSTYPE_DESKTOPURL, &si);
|
|
psm->Release();
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "CActiveDesktop::AddDesktopItemWithUI : CoCreateInstance for CLSID_SubscriptionMgr failed.");
|
|
}
|
|
}
|
|
}
|
|
ApplyChanges(AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH);
|
|
}
|
|
break;
|
|
|
|
case E_ACCESSDENIED:
|
|
// The file was a CDF but didn't contain Desktop Component Information
|
|
if (hwnd)
|
|
{
|
|
TCHAR szMsg[MAX_PATH];
|
|
TCHAR szTitle[MAX_PATH];
|
|
|
|
LoadString(HINST_THISDLL, IDS_ADDCOMP_ERROR_CDFNODTI, szMsg, ARRAYSIZE(szMsg));
|
|
LoadString(HINST_THISDLL, IDS_INTERNET_EXPLORER, szTitle, ARRAYSIZE(szTitle));
|
|
MessageBox(hwnd, szMsg, szTitle, MB_OK);
|
|
}
|
|
break;
|
|
case E_UNEXPECTED:
|
|
// This was a CDF but it was misauthored.
|
|
if (hwnd)
|
|
{
|
|
TCHAR szMsg[MAX_PATH];
|
|
TCHAR szTitle[MAX_PATH];
|
|
|
|
LoadString(HINST_THISDLL, IDS_ADDCOMP_ERROR_CDFINALID, szMsg, ARRAYSIZE(szMsg));
|
|
LoadString(HINST_THISDLL, IDS_INTERNET_EXPLORER, szTitle, ARRAYSIZE(szTitle));
|
|
MessageBox(hwnd, szMsg, szTitle, MB_OK);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (hwnd && SUCCEEDED(hres))
|
|
{
|
|
// If the active desktop is currently OFF, we need to turn it ON
|
|
SHELLSTATE ss = {0};
|
|
SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
|
|
if (!ss.fDesktopHTML)
|
|
{
|
|
COMPONENTSOPT co;
|
|
co.dwSize = sizeof(COMPONENTSOPT);
|
|
GetDesktopItemOptions(&co, 0);
|
|
co.fActiveDesktop = TRUE;
|
|
SetDesktopItemOptions(&co, 0);
|
|
ApplyChanges(AD_APPLY_REFRESH | AD_APPLY_DYNAMICREFRESH);
|
|
}
|
|
}
|
|
|
|
if (fCompSubDeleted)
|
|
{
|
|
if (si.bstrUserName)
|
|
{
|
|
SysFreeString(si.bstrUserName);
|
|
}
|
|
if (si.bstrPassword)
|
|
{
|
|
SysFreeString(si.bstrPassword);
|
|
}
|
|
if (si.bstrFriendlyName)
|
|
{
|
|
SysFreeString(si.bstrFriendlyName);
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
void RestoreComponent(HDSA hdsaComponents, COMPONENTA * pcomp)
|
|
{
|
|
int i;
|
|
|
|
// If we are split then set the bit saying that the listview needs to be adjusted. This is done
|
|
// when we check the state of desktop.htm in EnsureUpdateHtml.
|
|
// Note: Do this only if this component is enabled.
|
|
if ((pcomp->dwCurItemState & IS_SPLIT) && (pcomp->fChecked))
|
|
{
|
|
pcomp->dwCurItemState |= IS_ADJUSTLISTVIEW;
|
|
SetDesktopFlags(COMPONENTS_ZOOMDIRTY, COMPONENTS_ZOOMDIRTY);
|
|
}
|
|
|
|
for (i = 0; i < DSA_GetItemCount(hdsaComponents); i++)
|
|
{
|
|
COMPONENTA * pcompT;
|
|
|
|
if (pcompT = (COMPONENTA *)DSA_GetItemPtr(hdsaComponents, i))
|
|
{
|
|
// If this component is split/fullscreen and is different from the source component
|
|
// but it is at the same location then it must be on this monitor (work area) so restore it.
|
|
if (ISZOOMED(pcompT) &&
|
|
lstrcmpi(pcomp->szSource, pcompT->szSource) &&
|
|
(pcomp->cpPos.iTop == pcompT->cpPos.iTop) &&
|
|
((pcomp->cpPos.iLeft + pcomp->cpPos.dwWidth) == (pcompT->cpPos.iLeft + pcompT->cpPos.dwWidth)))
|
|
{
|
|
pcompT->dwCurItemState = pcompT->csiRestored.dwItemState;
|
|
pcompT->cpPos.iLeft = pcompT->csiRestored.iLeft;
|
|
pcompT->cpPos.iTop = pcompT->csiRestored.iTop;
|
|
pcompT->cpPos.dwWidth = pcompT->csiRestored.dwWidth;
|
|
pcompT->cpPos.dwHeight = pcompT->csiRestored.dwHeight;
|
|
pcompT->cpPos.izIndex = COMPONENT_TOP;
|
|
pcompT->fDirty = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT CActiveDesktop::AddDesktopItem(LPCCOMPONENT pComp, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
COMPONENTA CompA;
|
|
CompA.dwSize = sizeof(CompA);
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
// We need to support IE4 apps calling with the old component structure too!
|
|
// We use the size field to detect IE4 v/s newer apps!
|
|
if (!pComp ||
|
|
((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))) ||
|
|
((pComp->dwSize == sizeof(*pComp)) && !VALIDATESTATE(pComp->dwCurItemState)))
|
|
return E_INVALIDARG;
|
|
|
|
// Catch folks that call our API's to add components and prevent them from doing
|
|
// so if the restriction is in place.
|
|
if ((!_fIgnoreAddRemovePolicies) && (SHIsRestricted(NULL, REST_NOADDDESKCOMP)))
|
|
return E_ACCESSDENIED;
|
|
|
|
// Convert the external structure to the internal format
|
|
ConvertCompStruct(&CompA, (COMPONENTA *)pComp, TRUE);
|
|
|
|
// If the component is already present, then fail the call!
|
|
if (_FindComponentBySource(CompA.szSource, &CompA) > -1)
|
|
return hres;
|
|
|
|
//Make sure that the COMPPOS size field is set before we add it!
|
|
CompA.cpPos.dwSize = sizeof(COMPPOS);
|
|
|
|
PositionComponent(&CompA, &CompA.cpPos, CompA.iComponentType, TRUE);
|
|
|
|
if (_hdsaComponent && ISZOOMED(&CompA))
|
|
RestoreComponent(_hdsaComponent, &CompA);
|
|
|
|
//Make sure the this component's fDirty flag is off.
|
|
CompA.fDirty = FALSE;
|
|
|
|
// Set the dummy bit here - this forces folks to do bitwise testing on the dwCurItemState field
|
|
// instead of testing for equality. This will allow us to expand use of the field down the
|
|
// road without compatibility problems.
|
|
CompA.dwCurItemState |= IS_INTERNALDUMMYBIT;
|
|
|
|
if (AddComponentPrivate(&CompA, _dwNextID++))
|
|
{
|
|
// It might be cheaper to attempt to insert the component in the
|
|
// correct z-order but it's less code to just call _SortAndRationalize
|
|
// after the insertion is done.
|
|
_SortAndRationalize();
|
|
hres = S_OK;
|
|
}
|
|
|
|
return(hres);
|
|
}
|
|
|
|
BOOL CActiveDesktop::AddComponentPrivate(COMPONENTA *pcomp, DWORD dwID)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
ENTERPROC(1, "DS AddComponent(pcomp=%08X)", pcomp);
|
|
|
|
if (pcomp)
|
|
{
|
|
if (_hdsaComponent == NULL)
|
|
{
|
|
_hdsaComponent = DSA_Create(sizeof(COMPONENTA), DXA_GROWTH_CONST);
|
|
}
|
|
|
|
if (_hdsaComponent)
|
|
{
|
|
pcomp->dwID = dwID;
|
|
|
|
if (DSA_AppendItem(_hdsaComponent, pcomp) != -1)
|
|
{
|
|
_fDirty = TRUE;
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS AddComponent unable to append DSA");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS AddComponent unable to create DSA");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS AddComponent unable to add a component");
|
|
}
|
|
|
|
EXITPROC(1, "DS AddComponent=%d", fRet);
|
|
return fRet;
|
|
}
|
|
|
|
//
|
|
// This finds out if a given component already exists by comparing the szSource
|
|
// If so, it fills out the correct dwID and returns the index.
|
|
//
|
|
int CActiveDesktop::_FindComponentBySource(LPTSTR lpszSource, COMPONENTA *pComp)
|
|
{
|
|
int iRet = -1;
|
|
ENTERPROC(2, "DS FindComponentIdBySource(pComp=%8X)", pComp);
|
|
|
|
if (_hdsaComponent)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
|
|
{
|
|
COMPONENTA comp;
|
|
comp.dwSize = sizeof(COMPONENTA);
|
|
|
|
if (DSA_GetItem(_hdsaComponent, i, &comp) != -1)
|
|
{
|
|
if (!lstrcmpi(comp.szSource, lpszSource))
|
|
{
|
|
*pComp = comp;
|
|
iRet = i;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS FindComponentIndexByID unable to get a component");
|
|
}
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS FindComponentIdBySource=%d", iRet);
|
|
return iRet;
|
|
}
|
|
|
|
int CActiveDesktop::_FindComponentIndexByID(DWORD dwID)
|
|
{
|
|
int iRet = -1;
|
|
ENTERPROC(2, "DS FindComponentIndexByID(dwID=%d)", dwID);
|
|
|
|
if (_hdsaComponent)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
|
|
{
|
|
COMPONENTA comp;
|
|
comp.dwSize = sizeof(COMPONENTA);
|
|
|
|
if (DSA_GetItem(_hdsaComponent, i, &comp) != -1)
|
|
{
|
|
if (comp.dwID == dwID)
|
|
{
|
|
iRet = i;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS FindComponentIndexByID unable to get a component");
|
|
}
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS FindComponent=%d", iRet);
|
|
return iRet;
|
|
}
|
|
|
|
|
|
//
|
|
// This function is to be used only in special situations. Given a Url, it finds a component
|
|
// that has the src= pointed to that url. Note that what we have is szSource is something like
|
|
// "c:\foo\bar.bmp"; But, what is passed to this function is "file://c:/foo/bar.htm"
|
|
//
|
|
// Warning: This function does a conversion from Path to Url for every component before
|
|
// comparing with the given Url. This is in-efficient. We do it this way because converting
|
|
// the given Url ,which was converted to url from path, back to Path may not result in the
|
|
// original path. In other words a round-trip from path to Url and back to path may not result
|
|
// in the path that was originally entered by the end-user.
|
|
//
|
|
int CActiveDesktop::_FindComponentBySrcUrl(LPTSTR lpszSrcUrl, COMPONENTA *pComp)
|
|
{
|
|
int iRet = -1;
|
|
ENTERPROC(2, "DS FindComponentBySrcUrl(pComp=%8X)", pComp);
|
|
|
|
if (_hdsaComponent)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
|
|
{
|
|
COMPONENTA comp;
|
|
comp.dwSize = sizeof(COMPONENTA);
|
|
|
|
if (DSA_GetItem(_hdsaComponent, i, &comp) != -1)
|
|
{
|
|
TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
|
|
LPTSTR lpszUrl = szUrl;
|
|
DWORD dwSize;
|
|
|
|
//Convert the szSource to Url
|
|
dwSize = ARRAYSIZE(szUrl);
|
|
|
|
if (FAILED(UrlCreateFromPath(comp.szSource, lpszUrl, &dwSize, 0)))
|
|
lpszUrl = comp.szSource;
|
|
|
|
if (!lstrcmpi(lpszUrl, lpszSrcUrl))
|
|
{
|
|
*pComp = comp;
|
|
iRet = i;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS FindComponentBySrcUrl unable to get a component");
|
|
}
|
|
}
|
|
}
|
|
|
|
EXITPROC(2, "DS FindComponentBySrcUrl=%d", iRet);
|
|
return iRet;
|
|
}
|
|
|
|
HRESULT CActiveDesktop:: GetDesktopItemByID(ULONG_PTR dwID, COMPONENT *pcomp, DWORD dwReserved)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
ENTERPROC(1, "DS GetComponentByID(dwID=%d,pcomp=%08X)", dwID, pcomp);
|
|
COMPONENTA CompA;
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
// We need to support IE4 apps calling with the old component structure too!
|
|
// We use the size field to detect IE4 v/s newer apps!
|
|
if (!pcomp || ((pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT))))
|
|
return E_INVALIDARG;
|
|
|
|
if (pcomp)
|
|
{
|
|
int index = _FindComponentIndexByID((DWORD)dwID);
|
|
if (index != -1)
|
|
{
|
|
if (DSA_GetItem(_hdsaComponent, index, &CompA) != -1)
|
|
{
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS GetComponentByID unable to get component");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS GetComponentByID unable to find component");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS GetComponentByID given NULL pcomp");
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
MultiCompToWideComp(&CompA, pcomp);
|
|
}
|
|
|
|
EXITPROC(1, "DS GetComponentByID=%d", hres);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::RemoveDesktopItem(LPCCOMPONENT pComp, DWORD dwReserved)
|
|
{
|
|
COMPONENTA CompA, CompToDelete;
|
|
int iIndex;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
// We need to support IE4 apps calling with the old component structure too!
|
|
// We use the size field to detect IE4 v/s newer apps!
|
|
if (!pComp || ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))))
|
|
return E_INVALIDARG;
|
|
|
|
CompA.dwSize = sizeof(CompA);
|
|
CompToDelete.dwSize = sizeof(CompToDelete);
|
|
|
|
//Convert the struct to internal struct.
|
|
ConvertCompStruct(&CompA, (COMPONENTA *)pComp, TRUE);
|
|
|
|
// See if the component already exists.
|
|
iIndex = _FindComponentBySource(CompA.szSource, &CompToDelete);
|
|
|
|
if (iIndex > -1)
|
|
{
|
|
if (RemoveComponentPrivate(iIndex, &CompToDelete))
|
|
{
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
|
|
return(hres);
|
|
}
|
|
|
|
BOOL CActiveDesktop::RemoveComponentPrivate(int iIndex, COMPONENTA *pcomp)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
ENTERPROC(1, "DS RemoveComponent(pcomp=%08X)", pcomp);
|
|
|
|
if (_hdsaComponent)
|
|
{
|
|
if (iIndex == -1)
|
|
iIndex = _FindComponentIndexByID(pcomp->dwID);
|
|
if (iIndex != -1)
|
|
{
|
|
if (DSA_DeleteItem(_hdsaComponent, iIndex) != -1)
|
|
{
|
|
_fDirty = TRUE;
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS RemoveComponent could not remove an item");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS RemoveComponent could not find item to remove");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS RemoveComponent has no components to remove");
|
|
}
|
|
|
|
EXITPROC(1, "DS RemoveComponent=%d", fRet);
|
|
return fRet;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::_CopyComponent(COMPONENTA *pCompDest, COMPONENTA *pCompSrc, DWORD dwFlags)
|
|
{
|
|
HRESULT hrTemp, hr = S_OK;
|
|
|
|
//Copy only those elements mentioned in the flag!
|
|
|
|
// if (dwFlags & COMP_ELEM_ID)
|
|
// pCompDest->dwID = pCompSrc->dwID;
|
|
if (dwFlags & COMP_ELEM_TYPE)
|
|
pCompDest-> iComponentType = pCompSrc->iComponentType;
|
|
if (dwFlags & COMP_ELEM_CHECKED)
|
|
pCompDest-> fChecked = pCompSrc->fChecked;
|
|
if (dwFlags & COMP_ELEM_DIRTY)
|
|
pCompDest-> fDirty = pCompSrc-> fDirty;
|
|
if (dwFlags & COMP_ELEM_NOSCROLL)
|
|
pCompDest-> fNoScroll = pCompSrc-> fNoScroll;
|
|
if (dwFlags & COMP_ELEM_POS_LEFT)
|
|
pCompDest-> cpPos.iLeft= pCompSrc->cpPos.iLeft;
|
|
if (dwFlags & COMP_ELEM_POS_TOP)
|
|
pCompDest-> cpPos.iTop= pCompSrc->cpPos.iTop;
|
|
if (dwFlags & COMP_ELEM_SIZE_WIDTH)
|
|
pCompDest-> cpPos.dwWidth= pCompSrc->cpPos.dwWidth;
|
|
if (dwFlags & COMP_ELEM_SIZE_HEIGHT)
|
|
pCompDest-> cpPos.dwHeight= pCompSrc->cpPos.dwHeight;
|
|
if (dwFlags & COMP_ELEM_POS_ZINDEX)
|
|
pCompDest-> cpPos.izIndex= pCompSrc->cpPos.izIndex;
|
|
|
|
if (dwFlags & COMP_ELEM_SOURCE)
|
|
{
|
|
hrTemp = StringCchCopy(pCompDest->szSource, ARRAYSIZE(pCompDest->szSource), pCompSrc->szSource);
|
|
if (FAILED(hrTemp))
|
|
{
|
|
hr = hrTemp;
|
|
}
|
|
}
|
|
|
|
if (dwFlags & COMP_ELEM_FRIENDLYNAME)
|
|
{
|
|
hrTemp = StringCchCopy(pCompDest->szFriendlyName, ARRAYSIZE(pCompDest->szFriendlyName), pCompSrc->szFriendlyName);
|
|
if (FAILED(hrTemp))
|
|
{
|
|
hr = hrTemp;
|
|
}
|
|
}
|
|
|
|
if (dwFlags & COMP_ELEM_SUBSCRIBEDURL)
|
|
{
|
|
hrTemp = StringCchCopy(pCompDest->szSubscribedURL, ARRAYSIZE(pCompDest->szSubscribedURL), pCompSrc->szSubscribedURL);
|
|
if (FAILED(hrTemp))
|
|
{
|
|
hr = hrTemp;
|
|
}
|
|
}
|
|
|
|
if (dwFlags & COMP_ELEM_ORIGINAL_CSI)
|
|
pCompDest->csiOriginal = pCompSrc->csiOriginal;
|
|
|
|
if (dwFlags & COMP_ELEM_RESTORED_CSI)
|
|
{
|
|
pCompDest->csiRestored = pCompSrc->csiRestored;
|
|
|
|
// 98/08/21 vtan #174542: When changing csiRestored using the Active
|
|
// Desktop API and the component is zoomed the csiRestored information
|
|
// needs to be copied to the cpPos field as well as this is where the
|
|
// actual information is stored when the component is restored. This
|
|
// is only applicable to the case when the component is zoomed.
|
|
|
|
if (ISZOOMED(pCompDest))
|
|
{
|
|
pCompDest->cpPos.iLeft = pCompSrc->csiRestored.iLeft;
|
|
pCompDest->cpPos.iTop = pCompSrc->csiRestored.iTop;
|
|
pCompDest->cpPos.dwWidth = pCompSrc->csiRestored.dwWidth;
|
|
pCompDest->cpPos.dwHeight = pCompSrc->csiRestored.dwHeight;
|
|
}
|
|
}
|
|
if (dwFlags & COMP_ELEM_CURITEMSTATE) // Only allow the modification of the public bits - propagate the internal bits unchanged.
|
|
pCompDest->dwCurItemState = (pCompDest->dwCurItemState & IS_VALIDINTERNALBITS) | (pCompSrc->dwCurItemState & ~IS_VALIDINTERNALBITS);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::GetDesktopItemBySource(LPCWSTR lpcwszSource, LPCOMPONENT pComp, DWORD dwFlags)
|
|
{
|
|
COMPONENTA CompNew;
|
|
HRESULT hres = E_FAIL;
|
|
int iIndex;
|
|
|
|
//Passing a NULL to SHUnicodeToTChar causes a fault. So, let's fail it.
|
|
if (lpcwszSource == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
// We need to support IE4 apps calling with the old component structure too!
|
|
// We use the size field to detect IE4 v/s newer apps!
|
|
if (!pComp || ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))))
|
|
return E_INVALIDARG;
|
|
|
|
CompNew.dwSize = sizeof(COMPONENTA);
|
|
|
|
SHUnicodeToTChar(lpcwszSource, CompNew.szSource, ARRAYSIZE(CompNew.szSource));
|
|
|
|
iIndex = _FindComponentBySource(CompNew.szSource, &CompNew);
|
|
|
|
if (iIndex > -1)
|
|
{
|
|
MultiCompToWideComp(&CompNew, pComp);
|
|
hres = S_OK;
|
|
}
|
|
|
|
return(hres);
|
|
}
|
|
|
|
HRESULT CActiveDesktop::ModifyDesktopItem(LPCCOMPONENT pComp, DWORD dwFlags)
|
|
{
|
|
COMPONENTA CompA, CompNew;
|
|
HRESULT hres = E_FAIL;
|
|
int iIndex = -1;
|
|
|
|
// We need to support IE4 apps calling with the old component structure too!
|
|
// We use the size field to detect IE4 v/s newer apps!
|
|
if (!pComp || ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))))
|
|
return E_INVALIDARG;
|
|
|
|
CompA.dwSize = sizeof(COMPONENTA);
|
|
CompNew.dwSize = sizeof(COMPONENTA);
|
|
|
|
//Convert public param structure to private param structure.
|
|
ConvertCompStruct(&CompA, (COMPONENTA *)pComp, TRUE);
|
|
|
|
//See if this component already exists.
|
|
iIndex = _FindComponentBySource(CompA.szSource, &CompNew);
|
|
if (iIndex > -1)
|
|
{
|
|
hres = _CopyComponent(&CompNew, &CompA, dwFlags);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (dwFlags & (COMP_ELEM_POS_LEFT | COMP_ELEM_POS_TOP | COMP_ELEM_SIZE_WIDTH | COMP_ELEM_SIZE_HEIGHT | COMP_ELEM_CHECKED | COMP_ELEM_CURITEMSTATE))
|
|
PositionComponent(&CompNew, &CompNew.cpPos, CompNew.iComponentType, FALSE);
|
|
if (ISZOOMED(&CompNew))
|
|
RestoreComponent(_hdsaComponent, &CompNew);
|
|
|
|
CompNew.fDirty = TRUE; //Since the component is modified, we set the dirty bit!
|
|
if (UpdateComponentPrivate(iIndex, &CompNew))
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
|
|
return(hres);
|
|
}
|
|
|
|
BOOL CActiveDesktop::UpdateComponentPrivate(int iIndex, COMPONENTA *pcomp)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
ENTERPROC(1, "DS UpdateComponentPrivate(pcomp=%08X)", pcomp);
|
|
|
|
if (_hdsaComponent)
|
|
{
|
|
if (iIndex == -1)
|
|
iIndex = _FindComponentIndexByID(pcomp->dwID);
|
|
|
|
if (iIndex != -1)
|
|
{
|
|
if (DSA_SetItem(_hdsaComponent, iIndex, pcomp) != -1)
|
|
{
|
|
_fDirty = TRUE;
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS UpdateComponent could not update an item");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS UpdateComponent could not find item to update");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS UpdateComponent has no components to update");
|
|
}
|
|
|
|
EXITPROC(1, "DS UpdateComponent=%d", fRet);
|
|
return fRet;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::GetDesktopItemCount(LPINT lpiCount, DWORD dwReserved)
|
|
{
|
|
if (!lpiCount)
|
|
return (E_INVALIDARG);
|
|
|
|
*lpiCount = 0;
|
|
|
|
ENTERPROC(1, "DS GetComponentsCount()");
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
if (_hdsaComponent)
|
|
{
|
|
*lpiCount = DSA_GetItemCount(_hdsaComponent);
|
|
}
|
|
|
|
EXITPROC(1, "DS GetComponentsCount=%d", *lpiCount);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::GetDesktopItem(int nComponent, COMPONENT *pComp, DWORD dwReserved)
|
|
{
|
|
COMPONENTA CompA;
|
|
|
|
ASSERT(!dwReserved); // These should be 0
|
|
|
|
// We need to support IE4 apps calling with the old component structure too!
|
|
// We use the size field to detect IE4 v/s newer apps!
|
|
if ((nComponent < 0) || !pComp || ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))))
|
|
return E_INVALIDARG;
|
|
|
|
CompA.dwSize = sizeof(COMPONENTA);
|
|
|
|
if (GetComponentPrivate(nComponent, &CompA))
|
|
{
|
|
//Convert the structure to the Public form.
|
|
ConvertCompStruct((COMPONENTA *)pComp, &CompA, FALSE);
|
|
return(S_OK);
|
|
}
|
|
else
|
|
return(E_FAIL);
|
|
}
|
|
|
|
BOOL CActiveDesktop::GetComponentPrivate(int nComponent, COMPONENTA *pcomp)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
ENTERPROC(1, "DS GetComponent(nComponent=%d,pcomp=%08X)", nComponent, pcomp);
|
|
|
|
if (_hdsaComponent && pcomp && (nComponent < DSA_GetItemCount(_hdsaComponent)))
|
|
{
|
|
if (DSA_GetItem(_hdsaComponent, nComponent, pcomp) != -1)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS GetComponent unable to get a component");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DS GetComponent does not have a DSA");
|
|
}
|
|
|
|
EXITPROC(1, "DS GetComponent=%d", fRet);
|
|
return fRet;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::QueryInterface(REFIID riid, LPVOID *ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IActiveDesktop))
|
|
{
|
|
*ppvObj = (IActiveDesktop *)this;
|
|
_Initialize();
|
|
}
|
|
else if (IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppvObj = (IActiveDesktop *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IActiveDesktopP))
|
|
{
|
|
*ppvObj = (IActiveDesktopP *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IADesktopP2))
|
|
{
|
|
*ppvObj = (IADesktopP2 *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IPropertyBag))
|
|
{
|
|
*ppvObj = (IPropertyBag *)this;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
// Helper function so that it's easy to create one internally
|
|
// Actually, it's not ver much help any more...
|
|
STDAPI CActiveDesktop_InternalCreateInstance(LPUNKNOWN * ppunk, REFIID riid)
|
|
{
|
|
return CActiveDesktop_CreateInstance(NULL, riid, (void **)ppunk);
|
|
}
|
|
|
|
// Our class factory create instance code
|
|
STDAPI CActiveDesktop_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut)
|
|
{
|
|
TraceMsg(TF_DESKSTAT, "CActiveDesktop- CreateInstance");
|
|
|
|
CActiveDesktop *pad = new CActiveDesktop();
|
|
|
|
if (pad)
|
|
{
|
|
HRESULT hres = pad->QueryInterface(riid, ppvOut);
|
|
pad->Release();
|
|
return hres;
|
|
}
|
|
|
|
*ppvOut = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
//
|
|
// FEATURE - Move g_dwDeskStatTrace into ccshell.ini to prevent recompiles.
|
|
//
|
|
DWORD g_dwDeskStatTrace = 2;
|
|
static DWORD g_dwIndent = 0;
|
|
static const TCHAR c_szDotDot[] = TEXT("..");
|
|
|
|
#define MAX_INDENTATION_VALUE 0x20
|
|
|
|
void EnterProcDS(DWORD dwTraceLevel, LPSTR pszFmt, ...)
|
|
{
|
|
TCHAR szFmt[1000];
|
|
va_list arglist;
|
|
|
|
SHAnsiToTChar(pszFmt, szFmt, ARRAYSIZE(szFmt));
|
|
if (dwTraceLevel <= g_dwDeskStatTrace)
|
|
{
|
|
TCHAR szOutput[1000];
|
|
szOutput[0] = TEXT('\0');
|
|
|
|
for (DWORD i=0; i<g_dwIndent; i++)
|
|
{
|
|
StringCchCat(szOutput, ARRAYSIZE(szOutput), c_szDotDot); // truncation fine, this is debug spew
|
|
}
|
|
|
|
int cchOutput = lstrlen(szOutput);
|
|
va_start(arglist, pszFmt);
|
|
StringCchVPrintf(szOutput + cchOutput, ARRAYSIZE(szOutput) - cchOutput, szFmt, arglist); // truncation fine, this is debug spew
|
|
va_end(arglist);
|
|
|
|
TraceMsg(TF_DESKSTAT, "%s", szOutput);
|
|
|
|
// We don't want this value to get out of hand because of
|
|
// unmatched Enter and Exit calls in functions (which will
|
|
// trash the stack).
|
|
if (g_dwIndent < MAX_INDENTATION_VALUE)
|
|
g_dwIndent++;
|
|
}
|
|
}
|
|
|
|
void ExitProcDS(DWORD dwTraceLevel, LPSTR pszFmt, ...)
|
|
{
|
|
TCHAR szFmt[1000];
|
|
TCHAR szOutput[1000];
|
|
va_list arglist;
|
|
|
|
|
|
SHAnsiToTChar(pszFmt, szFmt, ARRAYSIZE(szFmt));
|
|
if (dwTraceLevel <= g_dwDeskStatTrace)
|
|
{
|
|
//This can happen if the Enter and Exit procs are unmatched.
|
|
if (g_dwIndent > 0)
|
|
g_dwIndent--;
|
|
|
|
szOutput[0] = TEXT('\0');
|
|
|
|
for (DWORD i=0; i<g_dwIndent; i++)
|
|
{
|
|
StringCchCat(szOutput, ARRAYSIZE(szOutput), c_szDotDot); // truncation fine, this is debug spew
|
|
}
|
|
|
|
int cchOutput = lstrlen(szOutput);
|
|
va_start(arglist, pszFmt);
|
|
StringCchVPrintf(szOutput + cchOutput, ARRAYSIZE(szOutput) - cchOutput, szFmt, arglist); // truncation fine, this is debug spew
|
|
va_end(arglist);
|
|
|
|
|
|
|
|
TraceMsg(TF_DESKSTAT, "%s", szOutput);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*************************************************************************
|
|
*
|
|
* IActiveDesktopP methods and helper functions
|
|
*
|
|
* IActiveDesktopP is a private interface used to implement helper
|
|
* functionality that is used internally by the various shell binaries.
|
|
*
|
|
* Notes:
|
|
* Getting an interface to IActiveDesktopP does not initialize the state
|
|
* of the object such that member functions are able to call IActiveDesktop
|
|
* member functions. This is so that it is a more lightweight implementation
|
|
* and also simplifies the implementation of SetScheme. If a subsequent QI for
|
|
* IActiveDesktop is performed then it will initialize properly and any member
|
|
* function can then be called.
|
|
*
|
|
*************************************************************************/
|
|
|
|
//
|
|
// SetScheme
|
|
//
|
|
// Used to set the current scheme that the object will read and write to
|
|
// when it is initialized. This method must be called before a subsequent
|
|
// QI to IActiveDesktop is made.
|
|
//
|
|
HRESULT CActiveDesktop::SetScheme(LPCWSTR pwszSchemeName, DWORD dwFlags)
|
|
{
|
|
LPTSTR pszSchemeName, pszAlloc;
|
|
int icch;
|
|
|
|
// Can't set the local scheme after we've been initialized...we can fix this
|
|
// later if necessary but for now it's simplest this way.
|
|
if (_fInitialized && (dwFlags & SCHEME_LOCAL))
|
|
return E_FAIL;
|
|
|
|
// Sanity checks
|
|
if (!pwszSchemeName || ((icch = lstrlenW(pwszSchemeName)) > MAX_PATH - 1))
|
|
return E_INVALIDARG;
|
|
|
|
pszSchemeName = (LPTSTR)pwszSchemeName;
|
|
|
|
if (dwFlags & SCHEME_CREATE)
|
|
{
|
|
LONG lRet;
|
|
HKEY hkey, hkey2;
|
|
|
|
lRet = RegCreateKeyEx(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME_LOCATION, 0, NULL, 0, KEY_CREATE_SUB_KEY, NULL, &hkey, NULL);
|
|
if (ERROR_SUCCESS == lRet)
|
|
{
|
|
lRet = RegCreateKeyEx(hkey, pszSchemeName, 0, NULL, 0, KEY_WRITE, NULL, &hkey2, NULL);
|
|
if (ERROR_SUCCESS == lRet)
|
|
{
|
|
RegCloseKey(hkey2);
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
if (ERROR_SUCCESS != lRet)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (dwFlags & SCHEME_LOCAL)
|
|
{
|
|
// The local case is easy - just copy the string to our local variable,
|
|
// it will be used when IActiveDesktop is initialized.
|
|
if (!(pszAlloc = (LPTSTR)LocalAlloc(LPTR, (icch + 1) * sizeof(TCHAR))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (_pszScheme)
|
|
LocalFree((HANDLE)_pszScheme);
|
|
|
|
_pszScheme = pszAlloc;
|
|
|
|
HRESULT hr = StringCchCopy(_pszScheme, icch + 1, pszSchemeName);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if (dwFlags & SCHEME_GLOBAL)
|
|
{
|
|
// Update the registry with the new global scheme value
|
|
if (dwFlags & SCHEME_DISPLAY)
|
|
SHSetValue(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME, REG_VAL_SCHEME_DISPLAY,
|
|
REG_SZ, pszSchemeName, CbFromCch(lstrlen(pszSchemeName) + 1));
|
|
if (dwFlags & SCHEME_EDIT)
|
|
SHSetValue(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME, REG_VAL_SCHEME_EDIT,
|
|
REG_SZ, pszSchemeName, CbFromCch(lstrlen(pszSchemeName) + 1));
|
|
}
|
|
|
|
if (dwFlags & (SCHEME_REFRESH | SCHEME_UPDATE))
|
|
{
|
|
DWORD dwUpdateFlags = AD_APPLY_FORCE | AD_APPLY_HTMLGEN | AD_APPLY_SAVE;
|
|
if (dwFlags & SCHEME_REFRESH)
|
|
dwUpdateFlags |= (AD_APPLY_REFRESH | AD_APPLY_DYNAMICREFRESH);
|
|
_Initialize();
|
|
_fUseDynamicHtml=FALSE;
|
|
ApplyChanges(dwUpdateFlags);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT GetGlobalScheme(LPWSTR pwszScheme, LPDWORD lpdwcchBuffer, DWORD dwFlags)
|
|
{
|
|
DWORD cbScheme = *lpdwcchBuffer * sizeof(pwszScheme[0]);
|
|
LONG lret = SHGetValueW(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME,
|
|
(dwFlags & SCHEME_EDIT) ? REG_VAL_SCHEME_EDIT : REG_VAL_SCHEME_DISPLAY, NULL,
|
|
pwszScheme, &cbScheme);
|
|
|
|
if (ERROR_SUCCESS == lret)
|
|
{
|
|
*lpdwcchBuffer = lstrlenW(pwszScheme);
|
|
}
|
|
return (lret == ERROR_SUCCESS ? S_OK : E_FAIL);
|
|
}
|
|
|
|
|
|
//
|
|
// GetScheme
|
|
//
|
|
//
|
|
HRESULT CActiveDesktop::GetScheme(LPWSTR pwszSchemeName, LPDWORD lpdwcchBuffer, DWORD dwFlags)
|
|
{
|
|
// Sanity checks
|
|
if (!pwszSchemeName || *lpdwcchBuffer == 0)
|
|
return E_INVALIDARG;
|
|
|
|
if (dwFlags & SCHEME_LOCAL)
|
|
{
|
|
if (!_pszScheme)
|
|
{
|
|
HRESULT hres;
|
|
// Special case if no local scheme has explicitly been selected yet.
|
|
// The default scheme is the global display scheme in this case.
|
|
if (SUCCEEDED(hres = GetGlobalScheme(pwszSchemeName, lpdwcchBuffer, SCHEME_DISPLAY)))
|
|
{
|
|
hres = SetScheme(pwszSchemeName, SCHEME_LOCAL);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
SHTCharToUnicode(_pszScheme, pwszSchemeName, *lpdwcchBuffer);
|
|
|
|
*lpdwcchBuffer = lstrlenW(pwszSchemeName);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
if (dwFlags & SCHEME_GLOBAL)
|
|
{
|
|
return GetGlobalScheme(pwszSchemeName, lpdwcchBuffer, dwFlags);
|
|
}
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
BOOL UpdateAllDesktopSubscriptions(IADesktopP2 *);
|
|
HRESULT CActiveDesktop::UpdateAllDesktopSubscriptions()
|
|
{
|
|
::UpdateAllDesktopSubscriptions(this);
|
|
return S_OK;
|
|
}
|
|
|
|
void CActiveDesktop::_GenerateHtmlBStrForComp(COMPONENTA *pComp, BSTR *pbstr)
|
|
{
|
|
ENTERPROC(2, "DS _GenerateHtmlBstrForComp");
|
|
|
|
if (_pStream = SHCreateMemStream(NULL, 0)) //Create a mem stream.
|
|
{
|
|
LARGE_INTEGER libMove = {0};
|
|
ULARGE_INTEGER libCurPos;
|
|
// Since _pStream is setup, the following call will generate the component HTML into
|
|
// that stream.
|
|
_GenerateHtmlComponent(pComp);
|
|
|
|
//Get the size of the stream generated.
|
|
if (SUCCEEDED(_pStream->Seek(libMove, STREAM_SEEK_CUR, &libCurPos)))
|
|
{
|
|
//Allocare a BSTR big enough to hold our component HTML code.
|
|
if (*pbstr = SysAllocStringLen(NULL, (libCurPos.LowPart)/sizeof(WCHAR)))
|
|
{
|
|
_pStream->Seek(libMove, STREAM_SEEK_SET, NULL);
|
|
_pStream->Read(*pbstr, libCurPos.LowPart, NULL);
|
|
}
|
|
}
|
|
|
|
//NOTE: The bStr is released by the caller.
|
|
|
|
ATOMICRELEASE(_pStream);
|
|
}
|
|
else
|
|
TraceMsg(TF_WARNING, "DS _GenerateHtmlBstrForComp unable to create a mem stream");
|
|
|
|
EXITPROC(2, "DS _GenerateHtmlBstrForComp");
|
|
}
|
|
|
|
|
|
void CActiveDesktop::_UpdateStyleOfElement(IHTMLElement *pElem, LPCOMPONENTA lpCompA)
|
|
{
|
|
IHTMLStyle *pHtmlStyle;
|
|
|
|
if (SUCCEEDED(pElem->get_style(&pHtmlStyle)))
|
|
{
|
|
long lPixelVal;
|
|
VARIANT vVal;
|
|
VARIANT vValNew;
|
|
|
|
|
|
if (SUCCEEDED(pHtmlStyle->get_pixelLeft(&lPixelVal)) && (lPixelVal != lpCompA->cpPos.iLeft))
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "iLeft changes from %d to %d", lPixelVal, lpCompA->cpPos.iLeft);
|
|
pHtmlStyle->put_pixelLeft((long)(lpCompA->cpPos.iLeft));
|
|
}
|
|
|
|
if (SUCCEEDED(pHtmlStyle->get_pixelTop(&lPixelVal)) && (lPixelVal != lpCompA->cpPos.iTop))
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "iTop changes from %d to %d", lPixelVal, lpCompA->cpPos.iTop);
|
|
pHtmlStyle->put_pixelTop((long)(lpCompA->cpPos.iTop));
|
|
}
|
|
|
|
VariantInit(&vVal);
|
|
|
|
if (SUCCEEDED(pHtmlStyle->get_width(&vVal))) //Get the width as BSTR to see if width attribute exists
|
|
{
|
|
//See if the width attribute exists now.
|
|
if ((vVal.vt == VT_BSTR) && (vVal.bstrVal == NULL))
|
|
{
|
|
// Width attribute does not exist for this element; This means that
|
|
// this element has the default width (may be a picture shown in it's original width).
|
|
if (lpCompA->cpPos.dwWidth != COMPONENT_DEFAULT_WIDTH)
|
|
{
|
|
//Component's new width is different from the default width. So, set the new width.
|
|
TraceMsg(TF_DYNAMICHTML, "dwWidth changes from default to %d", lpCompA->cpPos.dwWidth);
|
|
pHtmlStyle->put_pixelWidth((long)(lpCompA->cpPos.dwWidth));
|
|
}
|
|
//else, nothing to do! (the widths match exactly).
|
|
|
|
}
|
|
else
|
|
{
|
|
// Width attribute exists! That means that this element has a width other than the
|
|
// default width.
|
|
// See if the new width is the default width.
|
|
if (lpCompA->cpPos.dwWidth == COMPONENT_DEFAULT_WIDTH)
|
|
{
|
|
// The old width is NOT default; But, the new width is default. So, let's just
|
|
// remove the width attribute.
|
|
VariantInit(&vValNew);
|
|
vValNew.vt = VT_BSTR;
|
|
vValNew.bstrVal = NULL;
|
|
pHtmlStyle->put_width(vValNew);
|
|
|
|
VariantClear(&vValNew);
|
|
}
|
|
else
|
|
{
|
|
//Get the existing width in pixels.
|
|
if (SUCCEEDED(pHtmlStyle->get_pixelWidth(&lPixelVal)) && (((DWORD)lPixelVal) != lpCompA->cpPos.dwWidth))
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "dwWidth changes from %d to %d", lPixelVal, lpCompA->cpPos.dwWidth);
|
|
pHtmlStyle->put_pixelWidth((long)(lpCompA->cpPos.dwWidth));
|
|
}
|
|
//else, nothing else to do because the widths match!
|
|
}
|
|
|
|
}
|
|
VariantClear(&vVal);
|
|
}
|
|
|
|
if (SUCCEEDED(pHtmlStyle->get_height(&vVal))) //Get the height as BSTR to see if height attribute exists
|
|
{
|
|
// See if the height attribute exists.
|
|
if ((vVal.vt == VT_BSTR) && (vVal.bstrVal == NULL))
|
|
{
|
|
// Height attribute does not exist for this element; This means that
|
|
// this element has the default height (may be a picture shown in it's original height).
|
|
if (lpCompA->cpPos.dwHeight != COMPONENT_DEFAULT_HEIGHT)
|
|
{
|
|
//Component's new height is different from the default height. So, set the new height.
|
|
TraceMsg(TF_DYNAMICHTML, "dwHeight changes from default to %d", lpCompA->cpPos.dwHeight);
|
|
pHtmlStyle->put_pixelHeight((long)(lpCompA->cpPos.dwHeight));
|
|
}
|
|
//else, nothing to do! (the heights match exactly).
|
|
|
|
}
|
|
else
|
|
{
|
|
// Height attribute exists! That means that this element has a height other than the
|
|
// default height.
|
|
// See if the new height is the default height.
|
|
if (lpCompA->cpPos.dwHeight == COMPONENT_DEFAULT_HEIGHT)
|
|
{
|
|
// The old height is NOT default; But, the new height is default. So, let's just
|
|
// remove the height attribute.
|
|
VariantInit(&vValNew);
|
|
vValNew.vt = VT_BSTR;
|
|
vValNew.bstrVal = NULL;
|
|
pHtmlStyle->put_height(vValNew); //remove the height attribute!
|
|
|
|
VariantClear(&vValNew);
|
|
}
|
|
else
|
|
{
|
|
//Get the existing height in pixels and see if it is different.
|
|
if (SUCCEEDED(pHtmlStyle->get_pixelHeight(&lPixelVal)) && (((DWORD)lPixelVal) != lpCompA->cpPos.dwHeight))
|
|
{
|
|
//Since the new height is different, let's use set the new height!
|
|
TraceMsg(TF_DYNAMICHTML, "dwHeight changes from %d to %d", lPixelVal, lpCompA->cpPos.dwHeight);
|
|
pHtmlStyle->put_pixelHeight((long)(lpCompA->cpPos.dwHeight));
|
|
}
|
|
//else, nothing else to do because the heights match!
|
|
}
|
|
|
|
}
|
|
VariantClear(&vVal);
|
|
}
|
|
|
|
|
|
if (SUCCEEDED(pHtmlStyle->get_zIndex(&vVal)) && (vVal.vt == VT_I4) && (vVal.lVal != lpCompA->cpPos.izIndex))
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "ZIndex changes from %d to %d", vVal.lVal, lpCompA->cpPos.izIndex);
|
|
vVal.lVal = lpCompA->cpPos.izIndex;
|
|
pHtmlStyle->put_zIndex(vVal);
|
|
}
|
|
|
|
VariantClear(&vVal);
|
|
|
|
pHtmlStyle->Release();
|
|
}
|
|
|
|
//FEATURE: Should we check for and set the other attributes like "resizeable" etc.,?
|
|
}
|
|
|
|
BOOL CActiveDesktop::_UpdateIdOfElement(IHTMLElement *pElem, LPCOMPONENTA lpCompA)
|
|
{
|
|
BSTR bstrId;
|
|
BOOL fWholeElementReplaced = FALSE; //Assume that the item id does not change.
|
|
|
|
//Check if the Id of the component and the element matches.
|
|
if (SUCCEEDED(pElem->get_id(&bstrId))) //get the old id
|
|
{
|
|
|
|
if (((DWORD)StrToIntW(bstrId)) != lpCompA->dwID)
|
|
{
|
|
// The following technic does not work in some versions of MSHTML.DLL
|
|
// because IHTMLElement->put_id() does not work unless the doc
|
|
// is in "design mode".
|
|
TCHAR szNewId[MAXID_LENGTH];
|
|
BSTR bstrNewId;
|
|
HRESULT hr = StringCchPrintf(szNewId, ARRAYSIZE(szNewId), TEXT("%d"), lpCompA->dwID);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
TCHAR szOldId[MAXID_LENGTH];
|
|
if (SUCCEEDED(StringCchPrintf(szOldId, ARRAYSIZE(szOldId), TEXT("%d"), StrToIntW(bstrId))))
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: Id changes from %s to %s", szOldId, szNewId);
|
|
}
|
|
}
|
|
#endif //DEBUG
|
|
|
|
//The Ids do not match. So, let's set the new ID.
|
|
|
|
if (bstrNewId = SysAllocStringT(szNewId))
|
|
{
|
|
hr = pElem->put_id(bstrNewId);
|
|
SysFreeString(bstrNewId);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
//Replace the whole element's HTML with the newly generated HTML
|
|
BSTR bstrComp = 0;
|
|
|
|
_GenerateHtmlBStrForComp(lpCompA, &bstrComp);
|
|
if (bstrComp)
|
|
{
|
|
if (FAILED(hr = pElem->put_outerHTML(bstrComp)))
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: put_outerHTML failed");
|
|
fWholeElementReplaced = TRUE;
|
|
SysFreeString(bstrComp);
|
|
}
|
|
else
|
|
{
|
|
AssertMsg(FALSE, TEXT("DHTML: Unable to create html for comp"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//else the ids match; nothing to do!
|
|
SysFreeString(bstrId); //free the old id.
|
|
}
|
|
else
|
|
{
|
|
AssertMsg(FALSE, TEXT("DS Unable to get the id of the element"));
|
|
}
|
|
|
|
return fWholeElementReplaced;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::_UpdateHtmlElement(IHTMLElement *pElem)
|
|
{
|
|
VARIANT vData;
|
|
TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
|
|
TCHAR szSrcPath[INTERNET_MAX_URL_LENGTH];
|
|
LPTSTR lpszSrcPath;
|
|
COMPONENTA CompA;
|
|
int iIndex;
|
|
|
|
//If all components are disabled, then we nuke this component from HTML page.
|
|
if (!_co.fEnableComponents)
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: No item shown in this mode; so, deleting items");
|
|
pElem->put_outerHTML((BSTR)s_sstrEmpty.wsz);
|
|
|
|
return S_OK; //Nothing else to do!
|
|
}
|
|
|
|
VariantInit(&vData);
|
|
|
|
//First determine if the given element is currently a desktop item. (It could have been deleted)
|
|
//Get the element's "src" attribute.
|
|
if (FAILED(pElem->getAttribute((BSTR)s_sstrSRCMember.wsz, VARIANT_FALSE, &vData)) ||
|
|
(vData.vt == VT_NULL) ||
|
|
(vData.bstrVal == NULL))
|
|
{
|
|
//If the subscribed_url is not present, then it could be an object with a classid.
|
|
if (FAILED(pElem->getAttribute((BSTR)s_sstrclassid.wsz, VARIANT_FALSE, &vData)) ||
|
|
(vData.vt == VT_NULL))
|
|
{
|
|
//This element is does not have "src=" or "classid=" attributes. How did this ever
|
|
// become a desktop item with "name=deskmovr" or "name=deskmovrw"?? Hmmmmmm....!!!
|
|
#ifdef DEBUG
|
|
{
|
|
BSTR bstrHtmlForElem;
|
|
// Get the HTML corresponding to the element that does not have a subscribed URL
|
|
if (SUCCEEDED(pElem->get_outerHTML(&bstrHtmlForElem)))
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: Rogue element: %s", bstrHtmlForElem);
|
|
SysFreeString(bstrHtmlForElem);
|
|
}
|
|
}
|
|
TraceMsg(TF_WARNING, "DHTML: Unable to get the subscribed_url or classid");
|
|
#endif
|
|
//Since this element does not seem to be a valid desktop item, let's nuke it!
|
|
pElem->put_outerHTML((BSTR)s_sstrEmpty.wsz); //delete this element.
|
|
|
|
return (E_FAIL); //Nothing else to for this element! It's gone!!!
|
|
}
|
|
|
|
if ((vData.vt == VT_NULL) || (vData.bstrVal == NULL))
|
|
return E_FAIL;
|
|
|
|
ASSERT(vData.vt == VT_BSTR);
|
|
ASSERT(StrCmpNW(vData.bstrVal, L"clsid:", lstrlen(TEXT("clsid:"))) == 0);
|
|
SHUnicodeToTChar(vData.bstrVal + lstrlen(TEXT("clsid:")), szUrl, ARRAYSIZE(szUrl));
|
|
lpszSrcPath = szUrl; //For classid, the SrcPath and the Url are the same.
|
|
}
|
|
else
|
|
{
|
|
DWORD dwSize;
|
|
|
|
if (vData.bstrVal == NULL)
|
|
return (E_FAIL);
|
|
|
|
ASSERT(vData.vt == VT_BSTR);
|
|
SHUnicodeToTChar(vData.bstrVal, szUrl, ARRAYSIZE(szUrl));
|
|
|
|
dwSize = ARRAYSIZE(szSrcPath);
|
|
lpszSrcPath = szSrcPath;
|
|
if (FAILED(PathCreateFromUrl(szUrl, lpszSrcPath, &dwSize, 0)))
|
|
{
|
|
lpszSrcPath = szUrl;
|
|
}
|
|
}
|
|
|
|
VariantClear(&vData); //We made a TCHAR copy above. So, ok to free this.
|
|
|
|
CompA.dwSize = sizeof(CompA);
|
|
|
|
// First use the Source path to Find the component; This is much more efficient because it
|
|
// involves no conversion from Path to Url and vice-versa.
|
|
if ((iIndex = _FindComponentBySource(lpszSrcPath, &CompA)) < 0)
|
|
{
|
|
// Could not find component using SrcPath!
|
|
// Let's try using the SrcUrl; This is less efficient.
|
|
iIndex = _FindComponentBySrcUrl(szUrl, &CompA);
|
|
}
|
|
|
|
if ((iIndex>= 0) && (CompA.fChecked))
|
|
{
|
|
//The component is found and it is enabled.
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML:Updating desktop item with URL: %s", szUrl);
|
|
|
|
// If the id changes, we replace the whole HTML for that element, so, no need to check for
|
|
// the individual styles.
|
|
if (!_UpdateIdOfElement(pElem, &CompA))
|
|
_UpdateStyleOfElement(pElem, &CompA);
|
|
CompA.fDirty = TRUE; //Mark the component sothat we know that it had been updated.
|
|
UpdateComponentPrivate(iIndex, &CompA);
|
|
}
|
|
else
|
|
{
|
|
ASSERT((iIndex == -1) || (!CompA.fChecked)); //Component not found OR it is disabled!
|
|
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: Deleting desktop item with URL: %s, SrcPath:%s", szUrl, lpszSrcPath);
|
|
|
|
//The component is not present now. So, delete this element from the html page.
|
|
pElem->put_outerHTML((BSTR)s_sstrEmpty.wsz);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// This code enumerates and then updates all the desktop item elements in the active desktop based
|
|
// on the current status of the active desktop items in the CActiveDesktop object (The current
|
|
// status is initialized by reading from the registry when ActiveDesktop object is initialized).
|
|
//
|
|
HRESULT CActiveDesktop::_UpdateDesktopItemHtmlElements(IHTMLDocument2 *pDoc)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
IHTMLElementCollection *pAllElements;
|
|
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: Updating Desktop html elements dynamically");
|
|
|
|
if (!_fInitialized) //If not yet initialized, initialize now because we need _co.fEnableComponents.
|
|
_Initialize();
|
|
|
|
// We need to check for a change in the background color only if there is no wallpaper or
|
|
// the wallpaper is a picture.
|
|
if (IsWallpaperPicture(_szSelectedWallpaper))
|
|
{
|
|
COLORREF rgbDesktop;
|
|
TCHAR szRgbDesktop[10];
|
|
VARIANT vColor;
|
|
|
|
//Check to see if the background color has changed
|
|
rgbDesktop = GetSysColor(COLOR_DESKTOP);
|
|
|
|
hres = StringCchPrintf(szRgbDesktop, ARRAYSIZE(szRgbDesktop),
|
|
TEXT("#%02lx%02lx%02lx"), GetRValue(rgbDesktop), GetGValue(rgbDesktop), GetBValue(rgbDesktop));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pDoc->get_bgColor(&vColor);
|
|
if (SUCCEEDED(hres) && (vColor.vt == VT_BSTR))
|
|
{
|
|
BSTR bstrNewBgColor = SysAllocStringT(szRgbDesktop);
|
|
|
|
//Compare the new and the old strings.
|
|
if (StrCmpW(vColor.bstrVal, bstrNewBgColor))
|
|
{
|
|
BSTR bstrOldBgColor = vColor.bstrVal; //Save the old bstr.
|
|
//So, the colors are different. Set the new color.
|
|
vColor.bstrVal = bstrNewBgColor;
|
|
bstrNewBgColor = bstrOldBgColor; //Set it here sothat it is freed later.
|
|
|
|
if (FAILED(pDoc->put_bgColor(vColor)))
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: Unable to change the background color");
|
|
}
|
|
}
|
|
|
|
if (bstrNewBgColor)
|
|
SysFreeString(bstrNewBgColor);
|
|
|
|
VariantClear(&vColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Get a collection of All elements in the Document
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pDoc->get_all(&pAllElements);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
VARIANT vName, vIndex;
|
|
IDispatch *pDisp;
|
|
int i;
|
|
long lItemsEnumerated = 0;
|
|
long lLength = 0;
|
|
|
|
|
|
#ifdef DEBUG
|
|
pAllElements->get_length(&lLength);
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: Length of All elements:%d", lLength);
|
|
#endif
|
|
|
|
for(i = 0; i <= 1; i++)
|
|
{
|
|
//Collect all the elements that have the name="DeskMovr" and then name="DeskMovrW"
|
|
vName.vt = VT_BSTR;
|
|
vName.bstrVal = (BSTR)((i == 0) ? s_sstrDeskMovr.wsz : s_sstrDeskMovrW.wsz);
|
|
|
|
VariantInit(&vIndex); //We want to get all elements. So, vIndex is set to VT_EMPTY
|
|
|
|
if (SUCCEEDED(pAllElements->item(vName, vIndex, &pDisp)) && pDisp) //Collect all elements we want
|
|
{
|
|
IHTMLElementCollection *pDeskCollection;
|
|
if (SUCCEEDED(pDisp->QueryInterface(IID_IHTMLElementCollection, (void **)&pDeskCollection)))
|
|
{
|
|
IUnknown *pUnk;
|
|
IEnumVARIANT *pEnumVar;
|
|
|
|
if (SUCCEEDED(pDeskCollection->get_length(&lLength))) //Number of elements.
|
|
lItemsEnumerated += lLength; //Total number of items enumerated.
|
|
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: Enumerated %d number of elements", lLength);
|
|
|
|
//Get the enumerator
|
|
if (SUCCEEDED(pDeskCollection->get__newEnum(&pUnk)))
|
|
{
|
|
if (SUCCEEDED(pUnk->QueryInterface(IID_IEnumVARIANT, (void **)&pEnumVar)))
|
|
{
|
|
VARIANT vElem;
|
|
long lEnumCount = 0;
|
|
DWORD cElementsFetched;
|
|
|
|
while(SUCCEEDED(pEnumVar->Next(1, &vElem, &cElementsFetched)) && (cElementsFetched == 1))
|
|
{
|
|
IHTMLElement *pElem;
|
|
lEnumCount++;
|
|
// Access the element from the variant.....!
|
|
if ((vElem.vt == VT_DISPATCH) && SUCCEEDED(vElem.pdispVal->QueryInterface(IID_IHTMLElement, (void **)&pElem)))
|
|
{
|
|
_UpdateHtmlElement(pElem); //Update the desktop element's attributes.
|
|
pElem->Release();
|
|
}
|
|
VariantClear(&vElem);
|
|
}
|
|
//Number of items enumerated must be the same as the length
|
|
ASSERT(lEnumCount == lLength);
|
|
|
|
pEnumVar->Release();
|
|
}
|
|
pUnk->Release();
|
|
}
|
|
|
|
pDeskCollection->Release();
|
|
}
|
|
else
|
|
{
|
|
IHTMLElement *pElem;
|
|
|
|
// The QI(IID_IHTMLElementCollection) has failed. It may be because only one item
|
|
// was returned rather than a collection.
|
|
if (SUCCEEDED(pDisp->QueryInterface(IID_IHTMLElement, (void **)&pElem)))
|
|
{
|
|
_UpdateHtmlElement(pElem); //Update the desktop element's attributes.
|
|
pElem->Release();
|
|
}
|
|
else
|
|
TraceMsg(TF_WARNING, "DHTML: Unable to get a collection or a single element");
|
|
}
|
|
pDisp->Release();
|
|
}
|
|
} // for loop enumeating "DeskMovr" and "DeskMovrW" items.
|
|
|
|
pAllElements->Release();
|
|
}
|
|
}
|
|
|
|
// All the elements already present in the Doc have been updated. Now, let's add the
|
|
// new elements, if any.
|
|
if (_co.fEnableComponents)
|
|
_InsertNewDesktopItems(pDoc);
|
|
else
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: No components are to be shown in this mode;");
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::_InsertNewDesktopItems(IHTMLDocument2 *pDoc)
|
|
{
|
|
IHTMLElement *pBody;
|
|
|
|
if (SUCCEEDED(pDoc->get_body(&pBody)))
|
|
{
|
|
if (_hdsaComponent)
|
|
{
|
|
int i, iCount;
|
|
|
|
iCount = DSA_GetItemCount(_hdsaComponent);
|
|
for (i=0; i<iCount; i++)
|
|
{
|
|
COMPONENTA comp;
|
|
comp.dwSize = sizeof(comp);
|
|
|
|
if (DSA_GetItem(_hdsaComponent, i, &comp) != -1)
|
|
{
|
|
//Check if this is a newly added component AND it is enabled.
|
|
if ((!comp.fDirty) && comp.fChecked)
|
|
{
|
|
TraceMsg(TF_DYNAMICHTML, "DHTML: Inserted comp: %s", comp.szSource);
|
|
|
|
//Yup! This is a newly added component!
|
|
BSTR bstrComp = 0;
|
|
//This is a new component. Generate the HTML for the component.
|
|
_GenerateHtmlBStrForComp(&comp, &bstrComp);
|
|
|
|
//Insert the component.
|
|
pBody->insertAdjacentHTML((BSTR)s_sstrBeforeEnd.wsz, (BSTR)bstrComp);
|
|
|
|
//Free the string.
|
|
SysFreeString(bstrComp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DHTML: InsertNewComp: Unable to get component %d.", i);
|
|
}
|
|
}
|
|
}
|
|
|
|
pBody->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// This function takes a pointer to the ActiveDesktop's ole obj, reads all the changes to be done
|
|
// from the registry and makes those changes to the various elements through dynamic HTML interfaces.
|
|
//
|
|
HRESULT CActiveDesktop::MakeDynamicChanges(IOleObject *pOleObj)
|
|
{
|
|
|
|
IHTMLDocument2 *pDoc;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
ENTERPROC(2, "MakeDynamicChanges");
|
|
|
|
if (pOleObj && SUCCEEDED(pOleObj->QueryInterface(IID_IHTMLDocument2, (void **)&pDoc)))
|
|
{
|
|
// Enumerate all the active desktop components and ensure they are up to date.
|
|
_UpdateDesktopItemHtmlElements(pDoc);
|
|
|
|
pDoc->Release();
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "DHTML: MakeDynamicChanges: Unable to get IHTMLDocument2");
|
|
}
|
|
|
|
EXITPROC(2, "MakeDynamicChanges");
|
|
|
|
return(hres);
|
|
}
|
|
|
|
//
|
|
// SetSafeMode
|
|
//
|
|
// Either puts the active desktop in safemode or restores it to the previous
|
|
// scheme before safemode was entered.
|
|
//
|
|
HRESULT CActiveDesktop::SetSafeMode(DWORD dwFlags)
|
|
{
|
|
//
|
|
// Make sure we are in active desktop mode.
|
|
//
|
|
SHELLSTATE ss = {0};
|
|
BOOL fSetSafeMode = (dwFlags & SSM_SET) != 0;
|
|
|
|
SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
|
|
if (ss.fDesktopHTML)
|
|
{
|
|
//
|
|
// All we need to do is switch the "display" scheme to "safemode" in order to
|
|
// go into safemode. To go out, we just switch the "display" scheme back to the
|
|
// previous "edit" scheme.
|
|
//
|
|
WCHAR wszEdit[MAX_PATH];
|
|
WCHAR wszDisplay[MAX_PATH];
|
|
DWORD dwcch = MAX_PATH;
|
|
|
|
if (SUCCEEDED(GetScheme(wszEdit, &dwcch, SCHEME_GLOBAL | SCHEME_EDIT)))
|
|
{
|
|
dwcch = MAX_PATH;
|
|
if (SUCCEEDED(GetScheme(wszDisplay, &dwcch, SCHEME_GLOBAL | SCHEME_DISPLAY)))
|
|
{
|
|
BOOL fInSafeMode = (StrCmpW(wszDisplay, REG_DESKCOMP_SAFEMODE_SUFFIX_L) == 0);
|
|
|
|
if (fSetSafeMode != fInSafeMode)
|
|
{
|
|
LPWSTR lpwstr;
|
|
DWORD dwSchemeFlags = SCHEME_GLOBAL | SCHEME_DISPLAY;
|
|
if (dwFlags & SSM_REFRESH)
|
|
dwSchemeFlags |= SCHEME_REFRESH;
|
|
if (dwFlags & SSM_UPDATE)
|
|
dwSchemeFlags |= SCHEME_UPDATE;
|
|
|
|
lpwstr = fSetSafeMode ? REG_DESKCOMP_SAFEMODE_SUFFIX_L : wszEdit;
|
|
|
|
SetScheme(lpwstr, dwSchemeFlags);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// EnsureUpdateHTML
|
|
//
|
|
// Ensures that the current html file present on the disk is in sync
|
|
// with the registry information for the current active desktop scheme. If
|
|
// it is not in sync then a fresh copy of the file is generated from the
|
|
// registry for the current scheme.
|
|
//
|
|
HRESULT CActiveDesktop::EnsureUpdateHTML(void)
|
|
{
|
|
DWORD dwFlags = 0;
|
|
DWORD dwDataLength = sizeof(DWORD);
|
|
LONG lRet;
|
|
TCHAR szDeskcomp[MAX_PATH];
|
|
TCHAR szDesktopFile[MAX_PATH];
|
|
DWORD dwRestrictUpdate;
|
|
DWORD dwRestrict = SHRestricted2W(REST_NoChannelUI, NULL, 0);
|
|
DWORD dwSize = sizeof(dwRestrictUpdate);
|
|
BOOL fComponentsDirty = FALSE; //Assume that the components are NOT dirty!
|
|
DWORD dwVersion;
|
|
DWORD dwMinorVersion;
|
|
BOOL fStaleInfoInReg = FALSE;
|
|
BOOL fComponentsZoomDirty = FALSE;
|
|
static BOOL s_fNoDeskComp = (BOOL)-1;
|
|
static BOOL s_fNoWallpaper = (BOOL)-1;
|
|
BOOL fNoDeskComp = SHRestricted(REST_NODESKCOMP);
|
|
BOOL fNoWallpaper = SHRestricted(REST_NOHTMLWALLPAPER);
|
|
BOOL fAdminComponent = FALSE;
|
|
HKEY hkey = NULL;
|
|
HKEY hkeyTime;
|
|
FILETIME ftAdminCompKey;
|
|
|
|
|
|
if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, REG_DESKCOMP_COMPONENTS_ROOT, REG_VAL_GENERAL_RESTRICTUPDATE, NULL, &dwRestrictUpdate, &dwSize))
|
|
{
|
|
dwRestrictUpdate = 0;
|
|
}
|
|
|
|
GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_COMPONENTS, NULL);
|
|
|
|
//See if this branch of registry is old
|
|
if ((lRet = SHGetValue(HKEY_CURRENT_USER, szDeskcomp, REG_VAL_COMP_VERSION, NULL,
|
|
&dwVersion, &dwDataLength)) == ERROR_SUCCESS)
|
|
{
|
|
if (dwVersion < CUR_DESKHTML_VERSION)
|
|
{
|
|
fStaleInfoInReg = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//Major versions are equal. Check minor versions.
|
|
if ((lRet = SHGetValue(HKEY_CURRENT_USER, szDeskcomp, REG_VAL_COMP_MINOR_VERSION, NULL,
|
|
&dwMinorVersion, &dwDataLength)) == ERROR_SUCCESS)
|
|
{
|
|
if (dwMinorVersion != CUR_DESKHTML_MINOR_VERSION)
|
|
fStaleInfoInReg = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fStaleInfoInReg = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fStaleInfoInReg = TRUE;
|
|
}
|
|
|
|
dwDataLength = sizeof(DWORD);
|
|
|
|
//Check the dirty bit to see if we need to re-generate the desktop html
|
|
if ((lRet = SHGetValue(HKEY_CURRENT_USER, szDeskcomp, REG_VAL_COMP_GENFLAGS, NULL,
|
|
&dwFlags, &dwDataLength)) == ERROR_SUCCESS)
|
|
{
|
|
if (IsFlagSet(dwFlags, COMPONENTS_DIRTY))
|
|
fComponentsDirty = TRUE;
|
|
if (IsFlagSet(dwFlags, COMPONENTS_ZOOMDIRTY))
|
|
fComponentsZoomDirty = TRUE;
|
|
}
|
|
|
|
// See if we need to add/delete an administrator added desktop component now
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REG_DESKCOMP_ADMINCOMP_ROOT, 0, KEY_READ, &hkey))
|
|
{
|
|
FILETIME ftLast;
|
|
DWORD cbData = sizeof(ftLast);
|
|
DWORD dwType;
|
|
|
|
ZeroMemory(&ftLast, sizeof(ftLast));
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REG_DESKCOMP, 0, KEY_READ, &hkeyTime))
|
|
{
|
|
SHQueryValueEx(hkeyTime, TEXT("LastSyncedTime"), NULL, &dwType, (LPBYTE)&ftLast, &cbData);
|
|
RegCloseKey(hkeyTime);
|
|
}
|
|
|
|
RegQueryInfoKey(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ftAdminCompKey);
|
|
|
|
if (CompareFileTime(&ftAdminCompKey, &ftLast) == 1) {
|
|
WCHAR wszDisplay[MAX_PATH];
|
|
DWORD dwcch = MAX_PATH;
|
|
|
|
if (FAILED(GetScheme(wszDisplay, &dwcch, SCHEME_GLOBAL | SCHEME_DISPLAY)) ||
|
|
(StrCmpW(wszDisplay, REG_DESKCOMP_SAFEMODE_SUFFIX_L) != 0))
|
|
{
|
|
// We're not in safe mode, it's OK to add the components
|
|
fAdminComponent = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 99/03/23 #237632 vtan: If the monitor arrangement has been changed from underneath
|
|
// the user (perhaps by another user) then make sure that the components are in valid
|
|
// positions. If not then snap them back into the visible space and mark them as dirty
|
|
// so that the desktop.htt file is regenerated.
|
|
|
|
_Initialize();
|
|
if (_hdsaComponent)
|
|
{
|
|
int i, iComponentCount;;
|
|
|
|
iComponentCount = DSA_GetItemCount(_hdsaComponent);
|
|
for (i = 0; i < iComponentCount; ++i)
|
|
{
|
|
COMPONENTA *pComponent;
|
|
|
|
pComponent = reinterpret_cast<COMPONENTA*>(DSA_GetItemPtr(_hdsaComponent, i));
|
|
if (pComponent != NULL)
|
|
{
|
|
BOOL bChangedPosition = FALSE, bChangedSize = FALSE;
|
|
|
|
if (!SHIsTempDisplayMode()) //Modify the positions only if we are not in a temp mode change.
|
|
ValidateComponentPosition(&pComponent->cpPos, pComponent->dwCurItemState, pComponent->iComponentType, &bChangedPosition, &bChangedSize);
|
|
if (bChangedPosition || bChangedSize)
|
|
{
|
|
TBOOL(UpdateComponentPrivate(i, pComponent));
|
|
fComponentsDirty = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FAILED(GetPerUserFileName(szDesktopFile, ARRAYSIZE(szDesktopFile), DESKTOPHTML_FILENAME)))
|
|
{
|
|
szDesktopFile[0] = 0;
|
|
}
|
|
|
|
if (fComponentsDirty ||
|
|
fComponentsZoomDirty ||
|
|
fStaleInfoInReg ||
|
|
fAdminComponent ||
|
|
fNoDeskComp != s_fNoDeskComp ||
|
|
fNoWallpaper != s_fNoWallpaper ||
|
|
(dwRestrictUpdate != dwRestrict) ||
|
|
!PathFileExistsAndAttributes(szDesktopFile, NULL)) //See if the file exists!
|
|
{
|
|
|
|
// Clear out any html wallpaper if it exists and the restriction is set
|
|
if (fNoWallpaper != s_fNoWallpaper)
|
|
{
|
|
if (fNoWallpaper && !IsWallpaperPicture(_szSelectedWallpaper))
|
|
SetWallpaper(L"", 0);
|
|
s_fNoWallpaper = fNoWallpaper;
|
|
}
|
|
|
|
// Disable components if the restriction is set
|
|
if (fNoDeskComp != s_fNoDeskComp)
|
|
{
|
|
// We can't set fEnableComponents to FALSE because there is no way via the UI
|
|
// for the user to turn it back on again if the restriction is lifted. Instead we add
|
|
// special case code to _GenerateHtml that checks the restriction too.
|
|
|
|
// _co.fEnableComponents = !fNoDeskComp;
|
|
s_fNoDeskComp = fNoDeskComp;
|
|
}
|
|
|
|
if (fAdminComponent)
|
|
{
|
|
COMPONENT comp;
|
|
TCHAR pszAdminComp[INTERNET_MAX_URL_LENGTH];
|
|
CHAR szUrl[INTERNET_MAX_URL_LENGTH];
|
|
CHAR * pszUrl;
|
|
CHAR * pszUrlList;
|
|
TCHAR * aszAdminComp[] = {REG_VAL_ADMINCOMP_ADD, REG_VAL_ADMINCOMP_DELETE, NULL};
|
|
int i = 0;
|
|
|
|
comp.dwSize = sizeof(comp);
|
|
comp.dwCurItemState = IS_SPLIT | IS_ADJUSTLISTVIEW;
|
|
|
|
while (aszAdminComp[i])
|
|
{
|
|
dwDataLength = sizeof(pszAdminComp);
|
|
// The reg value contains an array of space separated urls - currently we support adding and deleting
|
|
// a desktop item via this mechanism.
|
|
if (SHQueryValueEx(hkey, aszAdminComp[i], NULL, NULL, (LPBYTE)pszAdminComp, &dwDataLength) == ERROR_SUCCESS)
|
|
{
|
|
SHTCharToAnsi(pszAdminComp, szUrl, ARRAYSIZE(szUrl));
|
|
pszUrlList = szUrl;
|
|
while (pszUrl = StrTokEx(&pszUrlList, " ")) {
|
|
SHAnsiToUnicode(pszUrl, comp.wszSource, ARRAYSIZE(comp.wszSource));
|
|
dwDataLength = ARRAYSIZE(comp.wszSource);
|
|
ParseURLFromOutsideSourceW(comp.wszSource, comp.wszSource, &dwDataLength, NULL);
|
|
if (lstrcmp(aszAdminComp[i], REG_VAL_ADMINCOMP_ADD) == 0)
|
|
{
|
|
AddUrl(NULL, (LPCWSTR)comp.wszSource, &comp, ADDURL_SILENT);
|
|
fComponentsZoomDirty = TRUE;
|
|
}
|
|
else
|
|
{
|
|
RemoveDesktopItem((LPCOMPONENT)&comp, 0);
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
SHSetValue(HKEY_CURRENT_USER, REG_DESKCOMP, TEXT("LastSyncedTime"), REG_BINARY, (LPVOID)&ftAdminCompKey, sizeof(ftAdminCompKey));
|
|
|
|
}
|
|
|
|
// Go through the entire list of desktop components and ensure any split/fullscreen
|
|
// components are at their correct size/location.
|
|
if (fComponentsZoomDirty)
|
|
{
|
|
if (_hdsaComponent)
|
|
{
|
|
int i;
|
|
for (i = 0; i < DSA_GetItemCount(_hdsaComponent); i++)
|
|
{
|
|
COMPONENTA * pcompT;
|
|
|
|
if (pcompT = (COMPONENTA *)DSA_GetItemPtr(_hdsaComponent, i))
|
|
{
|
|
if (ISZOOMED(pcompT))
|
|
{
|
|
BOOL fAdjustListview = (pcompT->dwCurItemState & IS_ADJUSTLISTVIEW);
|
|
ZoomComponent(&pcompT->cpPos, pcompT->dwCurItemState, fAdjustListview);
|
|
if (fAdjustListview)
|
|
pcompT->dwCurItemState &= ~IS_ADJUSTLISTVIEW;
|
|
}
|
|
}
|
|
}
|
|
SetDesktopFlags(COMPONENTS_ZOOMDIRTY, 0);
|
|
}
|
|
}
|
|
|
|
// NOTE #1: The above initialization would have changed the Z-order because of
|
|
// SortAndRationalize and so we need to APPLY_SAVE here.
|
|
// Warning: APPLY_SAVE changes the dwID field of components. This should not
|
|
// be a problem because we do this just before generating a new HTML file.
|
|
// NOTE #2: Do NOT use AD_APPLY_FORCE here. That sets the _fPatternDirty too and
|
|
// that causes a SystemParametersInfo() call which results in WM_SYSCOLORCHANGE
|
|
// and this causes a refresh. So, we set the dirty bit explicitly here.
|
|
|
|
_fDirty = TRUE; // See Note#2 above.
|
|
|
|
ApplyChanges(AD_APPLY_SAVE | AD_APPLY_HTMLGEN);
|
|
lRet = ERROR_SUCCESS;
|
|
if (dwRestrictUpdate != dwRestrict)
|
|
SHSetValue(HKEY_CURRENT_USER, REG_DESKCOMP_COMPONENTS_ROOT, REG_VAL_GENERAL_RESTRICTUPDATE, NULL, &dwRestrict, sizeof(dwRestrict));
|
|
}
|
|
|
|
if (hkey)
|
|
{
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return (lRet == ERROR_SUCCESS ? S_OK : E_FAIL);
|
|
}
|
|
|
|
//
|
|
// ReReadWallpaper()
|
|
// If the wallpaper was read when the active desktop was disabled, we would have read it from
|
|
// the old location. Now, if the active desktop is turned ON, then we need to re-read the wallpaper
|
|
// from the new location. We need to do this iff the wallpaper has not been changed in the mean-while
|
|
//
|
|
HRESULT CActiveDesktop::ReReadWallpaper(void)
|
|
{
|
|
if ((!_fDirty) || (!_co.fActiveDesktop)) //If nothing has changed OR if active desktop is OFF,
|
|
return(S_FALSE); // then nothing to do!
|
|
|
|
//ActiveDesktop is ON in our object. Read current shell state.
|
|
SHELLSTATE ss = {0};
|
|
|
|
SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
|
|
if (ss.fDesktopHTML)
|
|
return(S_FALSE); // Active Desktop state hasn't changed. So, nothing to do!
|
|
|
|
//So, Active desktop was originally OFF and now it is turned ON.
|
|
//If if someone changed the wallpaper, we should not mess with it.
|
|
if (_fWallpaperDirty || _fWallpaperChangedDuringInit)
|
|
return(S_FALSE);
|
|
|
|
// No one has changed the wallpaper. So, we must re-read it from the new wallpaper location
|
|
// sothat we get the correct wallpaper for the active desktop mode.
|
|
_ReadWallpaper(TRUE);
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
//
|
|
// GetADObjectFlags()
|
|
//
|
|
// Get the Active Desktop object's internal flags
|
|
//
|
|
HRESULT CActiveDesktop::GetADObjectFlags(LPDWORD lpdwFlags, DWORD dwMask)
|
|
{
|
|
ASSERT(lpdwFlags);
|
|
|
|
*lpdwFlags = 0; //Init the flags
|
|
|
|
if ((dwMask & GADOF_DIRTY) && _fDirty)
|
|
*lpdwFlags |= GADOF_DIRTY;
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT ForceFullRefresh(void)
|
|
{
|
|
HWND hwndShell = GetShellWindow();
|
|
|
|
//Force a SHRefresh with this dummy call
|
|
SHGetSetSettings(NULL, 0, TRUE);
|
|
SendMessage(hwndShell, DTM_MAKEHTMLCHANGES, (WPARAM)0, (LPARAM)0L);
|
|
//Can't use dynamic html. We have to refresh the whole page.
|
|
SendMessage(hwndShell, WM_WININICHANGE, SPI_SETDESKWALLPAPER, (LPARAM)c_szRefreshDesktop);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CActiveDesktop::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pszPropName && pVar)
|
|
{
|
|
hr = E_FAIL;
|
|
|
|
if (StrCmpIW(pszPropName, c_wszPropName_IgnorePolicies) == 0)
|
|
{
|
|
pVar->vt = VT_BOOL;
|
|
pVar->boolVal = (_fIgnoreAddRemovePolicies ? VARIANT_TRUE : VARIANT_TRUE);
|
|
hr = S_OK;
|
|
}
|
|
else if (StrCmpIW(pszPropName, c_wszPropName_TSPerfBGPolicy) == 0)
|
|
{
|
|
BOOL fPolicySet = (IsTSPerfFlagEnabled(TSPerFlag_NoADWallpaper) || IsTSPerfFlagEnabled(TSPerFlag_NoWallpaper)); //No policy is set!
|
|
|
|
pVar->vt = VT_BOOL;
|
|
pVar->boolVal = (fPolicySet ? VARIANT_TRUE : VARIANT_TRUE);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CActiveDesktop::Write(LPCOLESTR pszPropName, VARIANT *pVar)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pszPropName && pVar)
|
|
{
|
|
hr = E_FAIL;
|
|
|
|
if ((StrCmpIW(pszPropName, c_wszPropName_IgnorePolicies) == 0) && (VT_BOOL == pVar->vt))
|
|
{
|
|
_fIgnoreAddRemovePolicies = (VARIANT_TRUE == pVar->boolVal);
|
|
hr = S_OK;
|
|
}
|
|
else if ((StrCmpIW(pszPropName, c_wszPropName_TSPerfBGPolicy) == 0) && (VT_BOOL == pVar->vt))
|
|
{
|
|
ForceFullRefresh();
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/***
|
|
*char *StrTokEx(pstring, control) - tokenize string with delimiter in control
|
|
*
|
|
*Purpose:
|
|
* StrTokEx considers the string to consist of a sequence of zero or more
|
|
* text tokens separated by spans of one or more control chars. the first
|
|
* call, with string specified, returns a pointer to the first char of the
|
|
* first token, and will write a null char into pstring immediately
|
|
* following the returned token. when no tokens remain
|
|
* in pstring a NULL pointer is returned. remember the control chars with a
|
|
* bit map, one bit per ascii char. the null char is always a control char.
|
|
*
|
|
*Entry:
|
|
* char **pstring - ptr to ptr to string to tokenize
|
|
* char *control - string of characters to use as delimiters
|
|
*
|
|
*Exit:
|
|
* returns pointer to first token in string,
|
|
* returns NULL when no more tokens remain.
|
|
* pstring points to the beginning of the next token.
|
|
*
|
|
*WARNING!!!
|
|
* upon exit, the first delimiter in the input string will be replaced with '\0'
|
|
*
|
|
* copied from iert.lib
|
|
*******************************************************************************/
|
|
|
|
extern "C" char * __cdecl StrTokEx(char ** spstring, const char * scontrol)
|
|
{
|
|
unsigned char **pstring = (unsigned char**) spstring;
|
|
unsigned char *control = (unsigned char*) scontrol;
|
|
|
|
unsigned char *str;
|
|
const unsigned char *ctrl = control;
|
|
unsigned char map[32];
|
|
int count;
|
|
|
|
unsigned char *tokenstr;
|
|
|
|
if (*pstring == NULL)
|
|
return NULL;
|
|
|
|
/* Clear control map */
|
|
for (count = 0; count < 32; count++)
|
|
map[count] = 0;
|
|
|
|
/* Set bits in delimiter table */
|
|
do
|
|
{
|
|
map[*ctrl >> 3] |= (1 << (*ctrl & 7));
|
|
} while (*ctrl++);
|
|
|
|
/* Initialize str. */
|
|
str = *pstring;
|
|
|
|
/* Find beginning of token (skip over leading delimiters). Note that
|
|
* there is no token if this loop sets str to point to the terminal
|
|
* null (*str == '\0') */
|
|
while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
|
|
str++;
|
|
|
|
tokenstr = str;
|
|
|
|
/* Find the end of the token. If it is not the end of the string,
|
|
* put a null there. */
|
|
for ( ; *str ; str++ )
|
|
{
|
|
if ( map[*str >> 3] & (1 << (*str & 7)) )
|
|
{
|
|
*str++ = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* string now points to beginning of next token */
|
|
*pstring = str;
|
|
|
|
/* Determine if a token has been found. */
|
|
if ( tokenstr == str )
|
|
return NULL;
|
|
else
|
|
return (char*)tokenstr;
|
|
}
|