Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5760 lines
194 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.
#if 0
#define TF_DESKSTAT TF_CUSTOM2
#define TF_DYNAMICHTML TF_CUSTOM1
#else
#define TF_DESKSTAT 0
#define TF_DYNAMICHTML 0
#endif
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,
LPCTSTR lpszDefault,
LPTSTR lpszValue,
DWORD cchSizeofValueBuff)
{
DWORD cb = cchSizeofValueBuff * sizeof(lpszValue[0]);
BOOL fRet = (SHGetValue(hkey, lpszSubkey, lpszValueName, NULL, lpszValue, &cb) == ERROR_SUCCESS);
// On failure use the default string.
if (!fRet && lpszDefault)
{
StrCpyN(lpszValue, lpszDefault, cchSizeofValueBuff);
}
return fRet;
}
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!
PathExpandEnvStringsWrap(pszPolicy, cchPolicy);
fPolicySet = TRUE; //Policy is there!
}
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;
}
BOOL GetWallpaperPath(HKEY hKey, LPCTSTR pszKey, LPCTSTR pszValue, LPCTSTR pszFallBack, LPTSTR pszPath, DWORD cchSize)
{
BOOL fSucceeded = GetStringFromReg(hKey, pszKey, pszValue, pszFallBack, pszPath, cchSize);
if (fSucceeded)
{
PathExpandEnvStringsWrap(pszPath, cchSize);
}
return fSucceeded;
}
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;
}
void CActiveDesktop::_ReadWallpaper(BOOL fActiveDesktop)
{
ENTERPROC(2, "DS ReadWallpaper()");
TCHAR lpszDeskcomp[MAX_PATH];
GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), 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 = (LPCTSTR)lpszDeskcomp;
TCHAR szOldWallpaper[MAX_PATH];
DWORD dwOldWallpaperStyle;
// Read the Wallpaper from the Old location.
GetWallpaperPath(HKEY_CURRENT_USER, c_szRegStrDesktop, c_szWallpaper, c_szNULL, szOldWallpaper, ARRAYSIZE(szOldWallpaper));
// Read wallpaper style from the old location.
ReadWallpaperStyleFromReg((LPCTSTR)c_szRegStrDesktop, &dwOldWallpaperStyle, FALSE);
// Read the wallpaper from the new location too!
if ((!_fPolicyForWPName) || (_IsDisplayInSafeMode()))
{
if (!GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szWallpaper, szOldWallpaper, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper)))
{
pszRegKey = c_szRegStrDesktop;
}
}
//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.
GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szBackupWallpaper, szOldWallpaper, _szBackupWallpaper, ARRAYSIZE(_szBackupWallpaper));
//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!
lstrcpy(_szSelectedWallpaper, szOldWallpaper);
_wpo.dwStyle = dwOldWallpaperStyle;
_fWallpaperDirty = TRUE;
_fWallpaperChangedDuringInit = TRUE;
}
}
//Make a backup of the "Old" wallpaper
lstrcpy(_szBackupWallpaper, szOldWallpaper);
}
else
{
pszRegKey = c_szRegStrDesktop; //Get it from the old location!
//Since active desktop is not available, read wallpaper from old location.
if (!_fPolicyForWPName)
{
GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szWallpaper, c_szNULL, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper));
}
//Make a backup of the "Old" wallpaper
lstrcpy(_szBackupWallpaper, _szSelectedWallpaper);
//Read the wallpaper style
if (!_fPolicyForWPStyle)
ReadWallpaperStyleFromReg(pszRegKey, &_wpo.dwStyle, TRUE);
}
EXITPROC(2, "DS ReadWallpaper! (_szSelectedWP=>%s<)", _szSelectedWallpaper);
}
void CActiveDesktop::_ReadPattern(void)
{
ENTERPROC(2, "DS ReadPattern()");
GetStringFromReg(HKEY_CURRENT_USER, c_szRegStrDesktop, c_szPattern, c_szNULL, _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 lpszDeskcomp[MAX_PATH];
GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, _pszScheme);
if (RegOpenKeyEx(HKEY_CURRENT_USER, lpszDeskcomp, 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 lpszDeskcomp[MAX_PATH];
BOOL fNormalWallpaper;
GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
//
// Compute tiling string.
//
TCHAR szTiled[2];
lstrcpy(szTiled, TEXT("0"));
szTiled[0] = szTiled[0] + (TCHAR)(_wpo.dwStyle & WPSTYLE_TILE);
//
// Compute the Wallpaper styling string
//
TCHAR szWPStyle[2];
lstrcpy(szWPStyle, TEXT("0"));
//
// 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] = szWPStyle[0] + (TCHAR)(_wpo.dwStyle & WPSTYLE_STRETCH);
//
// Write out wallpaper settings in new active desktop area.
//
if (_fWallpaperDirty || _fWallpaperChangedDuringInit)
{
if (!_fPolicyForWPStyle)
{
SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
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, lpszDeskcomp,
c_szWallpaperStyle, REG_SZ, szWPStyle, CbFromCch(lstrlen(szWPStyle)+1));
}
if (!_fPolicyForWPName)
{
SHRegSetPath(HKEY_CURRENT_USER, lpszDeskcomp, c_szWallpaper, _szSelectedWallpaper, 0);
}
}
if (fNormalWallpaper = IsNormalWallpaper(_szSelectedWallpaper))
{
lstrcpyn(_szBackupWallpaper, _szSelectedWallpaper, ARRAYSIZE(_szBackupWallpaper));
}
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, lpszDeskcomp, c_szBackupWallpaper, _szBackupWallpaper, 0);
SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
c_szWallpaperTime, REG_BINARY, &ft,
sizeof(ft));
SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
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;
wsprintf(szSubKey, TEXT("%d"), iIndex);
if (RegCreateKey(hkey, szSubKey, &hkeySub) == ERROR_SUCCESS)
{
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 lpszDeskcomp[MAX_PATH];
GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, _pszScheme);
//
// We need to preserve the old GENFLAGS, so read them now before we roach them.
//
SHGetValue(HKEY_CURRENT_USER, lpszDeskcomp, REG_VAL_COMP_GENFLAGS, NULL,
&dwFlags, &dwDataLength);
//
// Delete the entire registry key.
//
SHDeleteKey(HKEY_CURRENT_USER, lpszDeskcomp);
//
// Recreate the registry key.
//
HKEY hkey;
if (RegCreateKey(HKEY_CURRENT_USER, lpszDeskcomp, &hkey) == ERROR_SUCCESS)
{
//
// 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);
wvsprintf(szBuf, szBufFmt, arglist);
va_end(arglist);
_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);
}
}
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(WCHAR));
}
}
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.
GetWallpaperWithPath(_szSelectedWallpaper, szSelectedWallpaper, ARRAYSIZE(szSelectedWallpaper));
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];
szResizeable[0] = TEXT('\0');
//If Resize is set, then the comp is resizeable in both X and Y directions!
if (pcomp->cpPos.fCanResize)
lstrcat(szResizeable, TEXT("XY"));
else
{
if (pcomp->cpPos.fCanResizeX)
lstrcat(szResizeable, TEXT("X"));
if (pcomp->cpPos.fCanResizeY)
lstrcat(szResizeable, TEXT("Y"));
}
_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);
if (FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &cch, 0)))
{
lstrcpy(szUrl, pcomp->szSource);
}
_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)))
{
lstrcpy(szUrl, pcomp->szSource);
}
DWORD currentURLLength, maximumURLLength;
TCHAR *pURL, formatBuffer[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, formatBuffer, ARRAYSIZE(formatBuffer));
maximumURLLength -= lstrlen(formatBuffer); // 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)
{
lstrcpy(szUrl, pcomp->szSubscribedURL);
maximumURLLength = 1024;
LoadString(HINST_THISDLL, IDS_SUBSCRIBEDURL, formatBuffer, ARRAYSIZE(formatBuffer));
maximumURLLength -= lstrlen(formatBuffer); // IDS_SUBSCRIBEDURL
if (currentURLLength > maximumURLLength)
szUrl[maximumURLLength] = static_cast<TCHAR>('\0');
pURL = szUrl;
}
else
pURL = pcomp->szSubscribedURL;
//
// Write out the URL that must be used for subscription purposes.
//
_WriteHtmlFromIdF(IDS_SUBSCRIBEDURL, pURL);
//
// 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)) != 0)
{
lstrcat(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);
LPTSTR pszFileName;
//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
pszFileName = (LPTSTR)pwszFileName;
//
// Create the file.
//
_hFileHtml = CreateFile(pszFileName, 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)
{
lstrcpy(compA.szSource, szSource);
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));
StrCatBuff(szMsg, szMsg2, ARRAYSIZE(szMsg));
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 lpszDeskcomp[MAX_PATH];
GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
if (!StrStr(lpszDeskcomp, 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)
{
HRESULT hr = S_OK;
TCHAR szTemplate[MAX_PATH];
WIN32_FIND_DATA findFileData;
LPCTSTR pszFileName = PathFindFileName(pszFile);
wnsprintf(szTemplate, ARRAYSIZE(szTemplate), TEXT("%ls\\Wallpaper*.bmp"), pwzPath);
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)
{
wnsprintfW(wzNewFile, ARRAYSIZE(wzNewFile), L"%s\\Wallpaper%d.bmp", pwzTempPath, nIndex);
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))
{
StrCpyNW(pwzPath, wzNewFile, cchSize);
}
}
return hr;
}
BOOL _DoFileWriteTimesMatch(IN LPCWSTR pszFile1, IN LPFILETIME pftLastWrite2)
{
BOOL fMatch = FALSE;
HANDLE hFile1 = CreateFile(pszFile1, GENERIC_READ, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE != hFile1)
{
FILETIME ftLastWrite1;
if (GetFileTime(hFile1, NULL, NULL, &ftLastWrite1))
{
fMatch = ((0 == CompareFileTime(&ftLastWrite1, pftLastWrite2)) ? TRUE : FALSE);
}
CloseHandle(hFile1);
}
return fMatch;
}
// 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")))
{
WCHAR szOriginalFile[MAX_PATH];
CreateDirectoryW(wzPath, NULL); // Create this since it may not exist.
StrCpyNW(szOriginalFile, pszFile, ARRAYSIZE(szOriginalFile));
// 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 = E_FAIL;
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;
if (SUCCEEDED(CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellImageDataFactory, &pImgFact))))
{
IShellImageData * pImage;
if (SUCCEEDED(pImgFact->CreateImageFromFile(_szSelectedWallpaper, &pImage)))
{
// PERF: cache decoded data
if (SUCCEEDED(pImage->Decode(SHIMGDEC_DEFAULT, 0, 0)))
{
if (S_FALSE == pImage->IsTransparent() &&
S_FALSE == pImage->IsAnimated())
{
StrCpyNW(_szSelectedWallpaperConverted, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaperConverted));
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();
StrCpyNW(_szSelectedWallpaper, _szSelectedWallpaperConverted, ARRAYSIZE(_szSelectedWallpaper));
}
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);
}
hres = S_OK;
EXITPROC(1, "DS ApplyChanges=%d", hres);
return hres;
}
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)
{
StrCpyN(pwszWallpaper, _szSelectedWallpaper, cchWallpaper);
if ( cchWallpaper < wcslen(_szSelectedWallpaper) )
{
hres = MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_MORE_DATA );
}
else
{
hres = S_OK;
}
}
else
{
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)
{
StrCpyN(szTemp, pwszWallpaper, ARRAYSIZE(szTemp));
PathExpandEnvStringsWrap(szTemp, ARRAYSIZE(szTemp)); // We unexpand only when we persist.
if (lstrcmp(_szSelectedWallpaper, szTemp) != 0)
{
lstrcpyn(_szSelectedWallpaper, szTemp, ARRAYSIZE(_szSelectedWallpaper));
_fWallpaperDirty = TRUE;
_fDirty = TRUE;
_fUseDynamicHtml = FALSE; //Setting wallpaper causes a lot of change; So, can't use dynamic html
}
hres = S_OK;
}
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 = S_OK;
ENTERPROC(1, "DS GetPattern(psz=%08X,cch=%d)", pwszPattern, cchPattern);
ASSERT(!dwReserved); // These should be 0
if (!pwszPattern || (cchPattern == 0))
return (E_INVALIDARG);
StrCpyN(pwszPattern, _szSelectedPattern, cchPattern);
EXITPROC(1, "DS GetPattern=%d", hres);
return hres;
}
HRESULT CActiveDesktop::SetPattern(LPCWSTR pwszPattern, DWORD dwReserved)
{
HRESULT hres = E_INVALIDARG;
LPCTSTR pszPattern;
ASSERT(!dwReserved); // These should be 0
if (pwszPattern)
{
pszPattern = pwszPattern;
if (lstrcmp(_szSelectedPattern, pszPattern) != 0)
{
lstrcpyn(_szSelectedPattern, pszPattern, ARRAYSIZE(_szSelectedPattern));
_fPatternDirty = TRUE;
_fDirty = TRUE;
_fUseDynamicHtml = FALSE; //Setting pattern causes us to regenerate the whole thing.
hres = S_OK;
}
else
hres = E_FAIL;
}
ENTERPROC(1, "DS SetPattern(psz=>%s<)", pwszPattern ? pszPattern : TEXT("(NULL)"));
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));
lstrcat(szMsg, szMsg2);
LoadString(HINST_THISDLL, IDS_COMP_TITLE, szTitle, ARRAYSIZE(szTitle));
MessageBox(hwnd, szMsg, szTitle, MB_OK);
return E_FAIL;
#if 0
comp.dwSize = sizeof(comp);
//Prompt the user to reinstall the ADI.
if (ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_CONFIRM_ADI_REINSTALL),
MAKEINTRESOURCE(IDS_COMP_TITLE), MB_YESNO) != IDYES)
{
return E_FAIL; //User choses not to install this desktop component!
}
else
{
ISubscriptionMgr *psm;
if (SUCCEEDED(hres = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&psm)))
{
si.cbSize = sizeof(si);
si.fUpdateFlags = SUBSINFO_ALLFLAGS;
//Backup and remove the subscription also
hres = psm->GetSubscriptionInfo(comp.wszSubscribedURL, &si);
if (SUCCEEDED(hres))
{
hres = RemoveDesktopItem(&comp, 0);
if (SUCCEEDED(hres))
{
psm->DeleteSubscription(comp.wszSubscribedURL, NULL);
ApplyChanges(AD_APPLY_SAVE);
fCompSubDeleted = TRUE;
// Set the new component to be enabled
pComp->fChecked = TRUE;
}
}
psm->Release();
}
else
{
TraceMsg(TF_WARNING, "CActiveDesktop::AddDesktopItemWithUI : CoCreateInstance for CLSID_SubscriptionMgr failed.");
}
}
#endif
}
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)
{
//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)
lstrcpy(pCompDest->szSource, pCompSrc->szSource);
if (dwFlags & COMP_ELEM_FRIENDLYNAME)
lstrcpy(pCompDest->szFriendlyName, pCompSrc->szFriendlyName);
if (dwFlags & COMP_ELEM_SUBSCRIBEDURL)
lstrcpy(pCompDest->szSubscribedURL, pCompSrc->szSubscribedURL);
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(S_OK);
}
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)
{
_CopyComponent(&CompNew, &CompA, dwFlags);
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];
TCHAR szOutput[1000];
va_list arglist;
SHAnsiToTChar(pszFmt, szFmt, ARRAYSIZE(szFmt));
if (dwTraceLevel <= g_dwDeskStatTrace)
{
szOutput[0] = TEXT('\0');
for (DWORD i=0; i<g_dwIndent; i++)
{
lstrcat(szOutput, c_szDotDot);
}
va_start(arglist, pszFmt);
wvsprintf(szOutput + lstrlen(szOutput), szFmt, arglist);
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++)
{
lstrcat(szOutput, c_szDotDot);
}
va_start(arglist, pszFmt);
wvsprintf(szOutput + lstrlen(szOutput), szFmt, arglist);
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)
{
HRESULT hres;
HKEY hkey, hkey2;
if (ERROR_SUCCESS == (hres = RegCreateKey(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME_LOCATION, &hkey)))
{
if (ERROR_SUCCESS == (hres = RegCreateKey(hkey, pszSchemeName, &hkey2)))
RegCloseKey(hkey2);
RegCloseKey(hkey);
}
if (FAILED(hres))
return hres;
}
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;
lstrcpy(_pszScheme, pszSchemeName);
}
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.
_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 = S_OK;
wsprintf(szNewId, TEXT("%d"), lpCompA->dwID);
#ifdef DEBUG
{
TCHAR szOldId[MAXID_LENGTH];
wsprintf(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);
wsprintf(szRgbDesktop, TEXT("#%02lx%02lx%02lx"), GetRValue(rgbDesktop),
GetGValue(rgbDesktop),
GetBValue(rgbDesktop));
if (SUCCEEDED(pDoc->get_bgColor(&vColor)) && (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(pDoc->get_all(&pAllElements)))
{
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 lpszDeskcomp[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(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, NULL);
//See if this branch of registry is old
if ((lRet = SHGetValue(HKEY_CURRENT_USER, lpszDeskcomp, 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, (LPCTSTR)lpszDeskcomp, 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, (LPCTSTR)lpszDeskcomp, 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;
}