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