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

5760 lines
194 KiB

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. #include "..\deskfldr.h"
  4. #include "dutil.h"
  5. extern "C" char * __cdecl StrTokEx(char ** pstring, const char * control);
  6. #define DXA_GROWTH_CONST 10
  7. #define ZINDEX_START 1000
  8. #define MAXID_LENGTH 10 //Maximum number of digits in ID string plus 1.
  9. #if 0
  10. #define TF_DESKSTAT TF_CUSTOM2
  11. #define TF_DYNAMICHTML TF_CUSTOM1
  12. #else
  13. #define TF_DESKSTAT 0
  14. #define TF_DYNAMICHTML 0
  15. #endif
  16. IActiveDesktop *g_pActiveDesk = NULL;
  17. #define c_szRegStrDesktop REGSTR_PATH_DESKTOP
  18. #define c_szWallpaper REG_VAL_GENERAL_WALLPAPER
  19. #define c_szBackupWallpaper REG_VAL_GENERAL_BACKUPWALLPAPER
  20. #define c_szPattern TEXT("Pattern")
  21. #define c_szTileWall REG_VAL_GENERAL_TILEWALLPAPER
  22. #define c_szWallpaperStyle REG_VAL_GENERAL_WALLPAPERSTYLE
  23. #define c_szWallpaperTime REG_VAL_GENERAL_WALLPAPERTIME
  24. #define c_szWallpaperLocalTime REG_VAL_GENERAL_WALLPAPERLOCALTIME
  25. #define c_szRefreshDesktop TEXT("RefreshDesktop")
  26. #define c_szBufferedRefresh TEXT("BufferedRefresh")
  27. #define COMP_TYPE 0x00000003
  28. #define COMP_SELECTED 0x00002000
  29. #define COMP_NOSCROLL 0x00004000
  30. #ifdef DEBUG
  31. #define ENTERPROC EnterProcDS
  32. #define EXITPROC ExitProcDS
  33. void EnterProcDS(DWORD dwTraceLevel, LPSTR szFmt, ...);
  34. void ExitProcDS(DWORD dwTraceLevel, LPSTR szFmt, ...);
  35. extern DWORD g_dwDeskStatTrace;
  36. #else
  37. #ifndef CCOVER
  38. #pragma warning(disable:4002)
  39. #define ENTERPROC()
  40. #define EXITPROC()
  41. #else // ccover buildi
  42. // these are needed because of a bug in cl.exe that results in improper processing
  43. // of #pragma when run with cl -P, and then compiling
  44. #define ENTERPROC 1 ? (void) 0 : (void)
  45. #define EXITPROC 1 ? (void) 0 : (void)
  46. #endif //end of ccover
  47. #endif
  48. MAKE_CONST_BSTR(s_sstrBeforeEnd, L"BeforeEnd");
  49. MAKE_CONST_BSTR(s_sstrDeskMovr, L"DeskMovr");
  50. MAKE_CONST_BSTR(s_sstrDeskMovrW, L"DeskMovrW");
  51. MAKE_CONST_BSTR(s_sstrclassid, L"classid");
  52. MAKE_CONST_BSTR(s_sstrEmpty, L"");
  53. STDAPI ParseDesktopComponent(HWND hwndOwner, LPWSTR wszURL, COMPONENT *pInfo);
  54. WCHAR wUnicodeBOM = 0xfeff; // Little endian unicode Byte Order Mark.First byte:0xff, Second byte: 0xfe.
  55. //extern BOOL IsWallpaperDesktopV2(LPCTSTR lpszWallpaper);
  56. CReadFileObj::CReadFileObj(LPCTSTR lpszFileName)
  57. {
  58. //Open the file
  59. if ((_hFile = CreateFile(lpszFileName, GENERIC_READ, FILE_SHARE_READ,
  60. NULL, OPEN_EXISTING,
  61. FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
  62. {
  63. WCHAR wBOM;
  64. DWORD dwBytesRead = 0;
  65. if ((ReadFile(_hFile, (LPVOID)&wBOM, sizeof(WCHAR), &dwBytesRead, NULL)) &&
  66. (dwBytesRead == sizeof(WCHAR)))
  67. {
  68. if (wBOM == wUnicodeBOM)
  69. _iCharset = UNICODE_HTML_CHARSET;
  70. else
  71. {
  72. //Note: Anything other than the little endian unicode file is treated as ansi.
  73. _iCharset = ANSI_HTML_CHARSET;
  74. SetFilePointer(_hFile, 0L, NULL, FILE_BEGIN); //Seek to the begining of the file
  75. }
  76. }
  77. }
  78. }
  79. CReadFileObj::~CReadFileObj()
  80. {
  81. if (_hFile != INVALID_HANDLE_VALUE)
  82. {
  83. CloseHandle(_hFile);
  84. _hFile = NULL;
  85. }
  86. }
  87. //
  88. // This will read and if necessary convert between ANSI and UNICODE
  89. //
  90. HRESULT CReadFileObj::FileReadAndConvertChars(int iDestCharset, LPWSTR lpwszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead, UINT *puiCharsConverted)
  91. {
  92. HRESULT hres = S_OK;
  93. DWORD dwCharsRead = 0;
  94. DWORD dwTotalCharsConverted = 0;
  95. if (_hFile != INVALID_HANDLE_VALUE)
  96. {
  97. if (_iCharset == UNICODE_HTML_CHARSET)
  98. {
  99. if (iDestCharset == UNICODE_HTML_CHARSET)
  100. {
  101. hres = FileReadCharsW(lpwszBuff, uiCharsToRead, (UINT *)&dwCharsRead);
  102. dwTotalCharsConverted = dwCharsRead;
  103. }
  104. else
  105. {
  106. //Destination is ansi; Read the UNICODE source and convert to ANSI.
  107. WCHAR wszBuf[INTERNET_MAX_URL_LENGTH + 1]; //Temp buffer to read the UNICODE chars into.
  108. LPSTR lpszBuff = (LPSTR)lpwszBuff;
  109. DWORD dwTotalCharsToRead = (DWORD)uiCharsToRead;
  110. while(dwTotalCharsToRead)
  111. {
  112. DWORD dwCount;
  113. DWORD dwActuallyRead;
  114. // - 1 to give room for a null character at the end.
  115. dwCount = (DWORD)min(dwTotalCharsToRead, (ARRAYSIZE(wszBuf) - 1));
  116. if (ReadFile(_hFile, (LPSTR)wszBuf, dwCount*sizeof(WCHAR), &dwActuallyRead, NULL))
  117. {
  118. DWORD dwConverted;
  119. dwActuallyRead = dwActuallyRead/sizeof(WCHAR);
  120. //Null terminate the source buffer.
  121. wszBuf[dwActuallyRead] = L'\0'; //UNICODE null terminate the source.
  122. //Convert what we just read.
  123. dwConverted = SHUnicodeToAnsi(wszBuf, lpszBuff, dwActuallyRead+1); //+1 for null termination
  124. //Update the count & stuff.
  125. lpszBuff += dwConverted - 1; //Subtract the null.
  126. dwTotalCharsToRead -= dwActuallyRead;
  127. dwCharsRead += dwActuallyRead;
  128. dwTotalCharsConverted += dwConverted - 1; //Subtract the null.
  129. if (dwActuallyRead < dwCount)
  130. break; //We have reached the end of file.
  131. }
  132. else
  133. {
  134. hres = E_FAIL;
  135. break;
  136. }
  137. }
  138. }
  139. }
  140. else
  141. {
  142. //Source file is ANSI. Check the Destination.
  143. if (iDestCharset == ANSI_HTML_CHARSET)
  144. {
  145. //Destination is ANSI too! Cool! No need for conversion!
  146. hres = FileReadCharsA((LPSTR)lpwszBuff, uiCharsToRead, (UINT *)&dwCharsRead);
  147. dwTotalCharsConverted = dwCharsRead;
  148. }
  149. else
  150. {
  151. //Destination is UNICODE! Read the ansi and convert it to UNICODE!
  152. char szBuf[INTERNET_MAX_URL_LENGTH + 1]; //Temp buffer to read the ansi chars into.
  153. DWORD dwTotalCharsToRead = (DWORD)uiCharsToRead;
  154. while(dwTotalCharsToRead)
  155. {
  156. DWORD dwCount;
  157. DWORD dwActuallyRead;
  158. // - 1 to give room for a null character at the end.
  159. dwCount = (DWORD)min(dwTotalCharsToRead, (ARRAYSIZE(szBuf) - 1));
  160. if (ReadFile(_hFile, (LPSTR)szBuf, dwCount, &dwActuallyRead, NULL))
  161. {
  162. DWORD dwConverted;
  163. //Null terminate the source buffer.
  164. szBuf[dwActuallyRead] = '\0'; //ANSI null terminate the source.
  165. //Convert what we just read.
  166. dwConverted = SHAnsiToUnicode(szBuf, lpwszBuff, dwActuallyRead+1); //+1 for null termination
  167. //Update the count & stuff.
  168. lpwszBuff += dwConverted - 1; //Subtract the null.
  169. dwTotalCharsToRead -= dwActuallyRead;
  170. dwCharsRead += dwActuallyRead;
  171. dwTotalCharsConverted += dwConverted - 1; //Subtract the null.
  172. if (dwActuallyRead < dwCount)
  173. break; //We have reached the end of file.
  174. }
  175. else
  176. {
  177. hres = E_FAIL;
  178. break;
  179. }
  180. } //while
  181. }
  182. }
  183. }
  184. else
  185. hres = E_FAIL; //The file handle is bad.
  186. *puiCharsActuallyRead = (UINT)dwCharsRead;
  187. *puiCharsConverted = (UINT)dwTotalCharsConverted;
  188. return hres;
  189. }
  190. HRESULT CReadFileObj::FileReadCharsA(LPSTR lpszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead)
  191. {
  192. HRESULT hres = E_FAIL;
  193. DWORD dwCharsRead = 0;
  194. if ((_hFile != INVALID_HANDLE_VALUE) &&
  195. (_iCharset == ANSI_HTML_CHARSET) &&
  196. ReadFile(_hFile, (LPVOID)lpszBuff, (DWORD)(uiCharsToRead), &dwCharsRead, NULL))
  197. {
  198. dwCharsRead = dwCharsRead; //get the number of wchars read.
  199. hres = S_OK;
  200. }
  201. *puiCharsActuallyRead = (UINT)dwCharsRead;
  202. return hres;
  203. }
  204. //
  205. // NOTE: The uiCharsToRead must be atleast one less than the size of the buffer (lpwszBuff)
  206. // because one null may be written at the end of the buffer by SHAnsiToUnicode().
  207. //
  208. HRESULT CReadFileObj::FileReadCharsW(LPWSTR lpwszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead)
  209. {
  210. HRESULT hres = E_FAIL;
  211. DWORD dwCharsRead = 0;
  212. if ((_hFile != INVALID_HANDLE_VALUE) &&
  213. (_iCharset == UNICODE_HTML_CHARSET) &&
  214. ReadFile(_hFile, (LPVOID)lpwszBuff, (DWORD)(uiCharsToRead*sizeof(WCHAR)), &dwCharsRead, NULL))
  215. {
  216. dwCharsRead = dwCharsRead/sizeof(WCHAR); //get the number of wchars read.
  217. hres = S_OK;
  218. }
  219. *puiCharsActuallyRead = (UINT)dwCharsRead;
  220. return hres;
  221. }
  222. HRESULT CReadFileObj::FileSeekChars(LONG lCharOffset, DWORD dwOrigin)
  223. {
  224. HRESULT hres = E_FAIL;
  225. if (_hFile != INVALID_HANDLE_VALUE)
  226. {
  227. if (SetFilePointer(_hFile,
  228. lCharOffset*((_iCharset == UNICODE_HTML_CHARSET) ? sizeof(WCHAR) : sizeof(char)),
  229. NULL,
  230. dwOrigin) != INVALID_SET_FILE_POINTER)
  231. hres = S_OK;
  232. }
  233. return hres;
  234. }
  235. HRESULT CReadFileObj::FileGetCurCharOffset(LONG *plCharOffset)
  236. {
  237. HRESULT hres = E_FAIL;
  238. DWORD dwByteOffset = 0;
  239. *plCharOffset = 0;
  240. if (_hFile != INVALID_HANDLE_VALUE)
  241. {
  242. if ((dwByteOffset = SetFilePointer(_hFile,
  243. 0L,
  244. NULL,
  245. FILE_CURRENT)) != INVALID_SET_FILE_POINTER)
  246. {
  247. *plCharOffset = dwByteOffset/((_iCharset == UNICODE_HTML_CHARSET) ? sizeof(WCHAR) : sizeof(char));
  248. hres = S_OK;
  249. }
  250. }
  251. return hres;
  252. }
  253. BOOL GetStringFromReg(HKEY hkey,
  254. LPCTSTR lpszSubkey,
  255. LPCTSTR lpszValueName,
  256. LPCTSTR lpszDefault,
  257. LPTSTR lpszValue,
  258. DWORD cchSizeofValueBuff)
  259. {
  260. DWORD cb = cchSizeofValueBuff * sizeof(lpszValue[0]);
  261. BOOL fRet = (SHGetValue(hkey, lpszSubkey, lpszValueName, NULL, lpszValue, &cb) == ERROR_SUCCESS);
  262. // On failure use the default string.
  263. if (!fRet && lpszDefault)
  264. {
  265. StrCpyN(lpszValue, lpszDefault, cchSizeofValueBuff);
  266. }
  267. return fRet;
  268. }
  269. void GetWallpaperFileTime(LPCTSTR pszWallpaper, LPFILETIME lpftFileTime)
  270. {
  271. HANDLE hFile;
  272. BOOL fRet = FALSE;
  273. if ((hFile = CreateFile(pszWallpaper, GENERIC_READ, FILE_SHARE_READ,
  274. NULL, OPEN_EXISTING,
  275. FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
  276. {
  277. fRet = GetFileTime(hFile, NULL, NULL, lpftFileTime);
  278. CloseHandle(hFile);
  279. }
  280. if (!fRet)
  281. ZeroMemory(lpftFileTime, sizeof(FILETIME));
  282. // no return value
  283. }
  284. BOOL HasWallpaperReallyChanged(LPCTSTR pszRegKey, LPTSTR pszOldWallpaper, LPTSTR pszBackupWallpaper, DWORD dwOldWallpaperStyle, DWORD dwNewWallpaperStyle)
  285. {
  286. // we default to TRUE here.
  287. if ((dwOldWallpaperStyle == dwNewWallpaperStyle)
  288. && (0 == lstrcmpi(pszOldWallpaper, pszBackupWallpaper)))
  289. {
  290. // The wallpaper filename and style hasn't changed.
  291. // But, the content of this file could have changed.
  292. // See if the content has changed by looking at the
  293. // last-written date and time stamp on this file.
  294. FILETIME ftOld, ftBack;
  295. DWORD cbBack = sizeof(ftBack);
  296. // if either of these fail, then they will
  297. // remain Zero so the compare will
  298. // be successful.
  299. GetWallpaperFileTime(pszOldWallpaper, &ftOld);
  300. if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, pszRegKey, c_szWallpaperTime, NULL, &ftBack, &cbBack))
  301. ZeroMemory(&ftBack, sizeof(ftBack));
  302. //Get the last written time of the backup wallpaper from registry
  303. if (0 == CompareFileTime(&ftOld, &ftBack))
  304. return FALSE; // everything is the same!
  305. // Win2K QFE bug 10689 (AndrewGr)
  306. // same check, but instead of checking UTC time, check local time converted to UTC time
  307. // this is because FAT disks store local time, not UTC time
  308. FILETIME ftLocalBack, ftLocalBackUtc;
  309. cbBack = sizeof(ftLocalBack);
  310. if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, pszRegKey, c_szWallpaperLocalTime, NULL, &ftLocalBack, &cbBack))
  311. ZeroMemory(&ftLocalBack, sizeof(ftLocalBack));
  312. LocalFileTimeToFileTime(&ftLocalBack, &ftLocalBackUtc);
  313. if (ftOld.dwLowDateTime == ftLocalBackUtc.dwLowDateTime
  314. && (ftOld.dwHighDateTime == ftLocalBackUtc.dwHighDateTime))
  315. // everything is the same!
  316. return FALSE;
  317. }
  318. return TRUE;
  319. }
  320. //-------------------------------------------------------------------------------------------------------------//
  321. // Function: ReadWallpaperStyleFromReg()
  322. //
  323. // This function reads the "TileWallpaper" and the "WallpaperStyle" from the given location
  324. // in the registry.
  325. //
  326. //-------------------------------------------------------------------------------------------------------------//
  327. int GetIntFromReg(HKEY hKey,
  328. LPCTSTR lpszSubkey,
  329. LPCTSTR lpszNameValue,
  330. int iDefault)
  331. {
  332. TCHAR szValue[20];
  333. DWORD dwSizeofValueBuff = sizeof(szValue);
  334. int iRetValue = iDefault;
  335. DWORD dwType;
  336. if ((SHGetValue(hKey, lpszSubkey, lpszNameValue, &dwType, szValue,
  337. &dwSizeofValueBuff) == ERROR_SUCCESS) && dwSizeofValueBuff)
  338. {
  339. if (dwType == REG_SZ)
  340. {
  341. iRetValue = (int)StrToInt(szValue);
  342. }
  343. }
  344. return iRetValue;
  345. }
  346. void ReadWallpaperStyleFromReg(LPCTSTR pszRegKey, DWORD *pdwWallpaperStyle, BOOL fIgnorePlatforms)
  347. {
  348. if (GetIntFromReg(HKEY_CURRENT_USER, pszRegKey, c_szTileWall, WPSTYLE_TILE))
  349. {
  350. // "Tile" overrides the "Stretch" style.
  351. *pdwWallpaperStyle = WPSTYLE_TILE;
  352. }
  353. else
  354. {
  355. // else, STRETCH or CENTER.
  356. *pdwWallpaperStyle = GetIntFromReg(HKEY_CURRENT_USER, pszRegKey, c_szWallpaperStyle, WPSTYLE_CENTER);
  357. }
  358. }
  359. BOOL CActiveDesktop::_IsDisplayInSafeMode(void)
  360. {
  361. WCHAR wszDisplay[MAX_PATH];
  362. DWORD dwcch = MAX_PATH;
  363. return (SUCCEEDED(GetScheme(wszDisplay, &dwcch, SCHEME_GLOBAL | SCHEME_DISPLAY))
  364. && (0 == StrCmpW(wszDisplay, REG_DESKCOMP_SAFEMODE_SUFFIX_L)));
  365. }
  366. BOOL ReadPolicyForWallpaper(LPTSTR pszPolicy, DWORD cchPolicy)
  367. {
  368. BOOL fPolicySet = FALSE;
  369. DWORD cb = cchPolicy * sizeof(pszPolicy[0]);
  370. if ((SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_WP_POLICY, c_szWallpaper, NULL, pszPolicy, &cb) == ERROR_SUCCESS) && cb)
  371. {
  372. // even if this value was originally REG_SZ it may still
  373. // have environment vars in it for legacy reasons!
  374. PathExpandEnvStringsWrap(pszPolicy, cchPolicy);
  375. fPolicySet = TRUE; //Policy is there!
  376. }
  377. else
  378. {
  379. // See if the TS Perf policy is set to turn it off for perf.
  380. fPolicySet = (IsTSPerfFlagEnabled(TSPerFlag_NoADWallpaper) || IsTSPerfFlagEnabled(TSPerFlag_NoWallpaper)); //No policy is set!
  381. }
  382. return fPolicySet;
  383. }
  384. BOOL GetWallpaperPath(HKEY hKey, LPCTSTR pszKey, LPCTSTR pszValue, LPCTSTR pszFallBack, LPTSTR pszPath, DWORD cchSize)
  385. {
  386. BOOL fSucceeded = GetStringFromReg(hKey, pszKey, pszValue, pszFallBack, pszPath, cchSize);
  387. if (fSucceeded)
  388. {
  389. PathExpandEnvStringsWrap(pszPath, cchSize);
  390. }
  391. return fSucceeded;
  392. }
  393. BOOL ReadPolicyForWPStyle(LPDWORD lpdwStyle)
  394. {
  395. DWORD dwStyle;
  396. DWORD dwType;
  397. TCHAR szValue[20];
  398. DWORD dwSizeofValueBuff = sizeof(szValue);
  399. BOOL fRet = FALSE;
  400. // The caller can passin a NULL, if they are not interested in the actual value and they just
  401. // want to know if this policy is set or not.
  402. if (!lpdwStyle)
  403. lpdwStyle = &dwStyle;
  404. if ((SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_WP_POLICY, c_szWallpaperStyle, &dwType, szValue,
  405. &dwSizeofValueBuff) == ERROR_SUCCESS) && dwSizeofValueBuff)
  406. {
  407. if (dwType == REG_SZ)
  408. {
  409. *lpdwStyle = (DWORD)StrToInt(szValue);
  410. fRet = TRUE;
  411. }
  412. }
  413. return fRet;
  414. }
  415. void CActiveDesktop::_ReadWallpaper(BOOL fActiveDesktop)
  416. {
  417. ENTERPROC(2, "DS ReadWallpaper()");
  418. TCHAR lpszDeskcomp[MAX_PATH];
  419. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
  420. _fPolicyForWPName = ReadPolicyForWallpaper(_szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper));
  421. _fPolicyForWPStyle = ReadPolicyForWPStyle(&_wpo.dwStyle);
  422. //
  423. // Read in the wallpaper and style from the appropriate registry location.
  424. //
  425. LPCTSTR pszRegKey;
  426. if (fActiveDesktop)
  427. {
  428. pszRegKey = (LPCTSTR)lpszDeskcomp;
  429. TCHAR szOldWallpaper[MAX_PATH];
  430. DWORD dwOldWallpaperStyle;
  431. // Read the Wallpaper from the Old location.
  432. GetWallpaperPath(HKEY_CURRENT_USER, c_szRegStrDesktop, c_szWallpaper, c_szNULL, szOldWallpaper, ARRAYSIZE(szOldWallpaper));
  433. // Read wallpaper style from the old location.
  434. ReadWallpaperStyleFromReg((LPCTSTR)c_szRegStrDesktop, &dwOldWallpaperStyle, FALSE);
  435. // Read the wallpaper from the new location too!
  436. if ((!_fPolicyForWPName) || (_IsDisplayInSafeMode()))
  437. {
  438. if (!GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szWallpaper, szOldWallpaper, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper)))
  439. {
  440. pszRegKey = c_szRegStrDesktop;
  441. }
  442. }
  443. //Read wallpaper style from the new location too!
  444. if (!_fPolicyForWPStyle)
  445. ReadWallpaperStyleFromReg(pszRegKey, &_wpo.dwStyle, FALSE);
  446. //If there is a Safe mode scheme here do NOT attempt to change wallpaper
  447. if ((!_IsDisplayInSafeMode()) && (!_fPolicyForWPName))
  448. {
  449. //Read what is stored as "Backup" wallpaper.
  450. GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szBackupWallpaper, szOldWallpaper, _szBackupWallpaper, ARRAYSIZE(_szBackupWallpaper));
  451. //See if the Old wallpaper is differnet from the backed up wallpaper
  452. if (HasWallpaperReallyChanged(pszRegKey, szOldWallpaper, _szBackupWallpaper, dwOldWallpaperStyle, _wpo.dwStyle))
  453. {
  454. //They are different. This means that some other app has changed the "Old" wallpaper
  455. //after the last time we backed it up in the registry.
  456. // Make this wallpaper as the Selected wallpaper!
  457. lstrcpy(_szSelectedWallpaper, szOldWallpaper);
  458. _wpo.dwStyle = dwOldWallpaperStyle;
  459. _fWallpaperDirty = TRUE;
  460. _fWallpaperChangedDuringInit = TRUE;
  461. }
  462. }
  463. //Make a backup of the "Old" wallpaper
  464. lstrcpy(_szBackupWallpaper, szOldWallpaper);
  465. }
  466. else
  467. {
  468. pszRegKey = c_szRegStrDesktop; //Get it from the old location!
  469. //Since active desktop is not available, read wallpaper from old location.
  470. if (!_fPolicyForWPName)
  471. {
  472. GetWallpaperPath(HKEY_CURRENT_USER, pszRegKey, c_szWallpaper, c_szNULL, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper));
  473. }
  474. //Make a backup of the "Old" wallpaper
  475. lstrcpy(_szBackupWallpaper, _szSelectedWallpaper);
  476. //Read the wallpaper style
  477. if (!_fPolicyForWPStyle)
  478. ReadWallpaperStyleFromReg(pszRegKey, &_wpo.dwStyle, TRUE);
  479. }
  480. EXITPROC(2, "DS ReadWallpaper! (_szSelectedWP=>%s<)", _szSelectedWallpaper);
  481. }
  482. void CActiveDesktop::_ReadPattern(void)
  483. {
  484. ENTERPROC(2, "DS ReadPattern()");
  485. GetStringFromReg(HKEY_CURRENT_USER, c_szRegStrDesktop, c_szPattern, c_szNULL, _szSelectedPattern, ARRAYSIZE(_szSelectedPattern));
  486. EXITPROC(2, "DS ReadPattern! (_szSelectedPattern=>%s<)", _szSelectedPattern);
  487. }
  488. void CActiveDesktop::_ReadComponent(HKEY hkey, LPCTSTR pszComp)
  489. {
  490. ENTERPROC(2, "DS ReadComponent(hk=%08X,pszComp=>%s<)", hkey, pszComp);
  491. HKEY hkeyComp;
  492. if (RegOpenKeyEx(hkey, pszComp, 0, KEY_READ, &hkeyComp) == ERROR_SUCCESS)
  493. {
  494. DWORD cbSize;
  495. COMPONENTA comp;
  496. comp.dwSize = sizeof(COMPONENTA);
  497. //
  498. // Read in the source string.
  499. //
  500. cbSize = sizeof(comp.szSource);
  501. if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_SOURCE, NULL, NULL, (LPBYTE)&comp.szSource, &cbSize) != ERROR_SUCCESS)
  502. {
  503. comp.szSource[0] = TEXT('\0');
  504. }
  505. //
  506. // Read in the SubscribedURL string.
  507. //
  508. cbSize = sizeof(comp.szSubscribedURL);
  509. if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_SUBSCRIBED_URL, NULL, NULL, (LPBYTE)&comp.szSubscribedURL, &cbSize) != ERROR_SUCCESS)
  510. {
  511. comp.szSubscribedURL[0] = TEXT('\0');
  512. }
  513. //
  514. // Read in the Friendly name string.
  515. //
  516. cbSize = sizeof(comp.szFriendlyName);
  517. if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_NAME, NULL, NULL, (LPBYTE)&comp.szFriendlyName, &cbSize) != ERROR_SUCCESS)
  518. {
  519. comp.szFriendlyName[0] = TEXT('\0');
  520. }
  521. //
  522. // Read in and parse the flags.
  523. //
  524. DWORD dwFlags;
  525. cbSize = sizeof(dwFlags);
  526. if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_FLAGS, NULL, NULL, (LPBYTE)&dwFlags, &cbSize) != ERROR_SUCCESS)
  527. {
  528. dwFlags = 0;
  529. }
  530. comp.iComponentType = dwFlags & COMP_TYPE;
  531. comp.fChecked = (dwFlags & COMP_SELECTED) != 0;
  532. comp.fNoScroll = (dwFlags & COMP_NOSCROLL) != 0;
  533. comp.fDirty = FALSE; //Reading it fresh from registry; Can't be dirty!
  534. //
  535. // Read in the location.
  536. //
  537. cbSize = sizeof(comp.cpPos);
  538. if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_POSITION, NULL, NULL, (LPBYTE)&comp.cpPos, &cbSize) != ERROR_SUCCESS)
  539. {
  540. ZeroMemory(&comp.cpPos, sizeof(comp.cpPos));
  541. }
  542. //
  543. // In IE4.x, we have a very huge positive number (0x7fffffff) as the COMPONENT_TOP;
  544. // As a result some component's z-index overflowed into the negative range (0x80000003)
  545. // To fix this, we halved the COMPONENT_TOP (0x3fffffff) and also check for negative z-index
  546. // values and covert them to postive values.
  547. if (comp.cpPos.izIndex < 0)
  548. comp.cpPos.izIndex = COMPONENT_TOP;
  549. //
  550. // Make sure the cpPos.dwSize is set to correct value
  551. //
  552. comp.cpPos.dwSize = sizeof(COMPPOS);
  553. //
  554. // Read in the current ItemState
  555. //
  556. cbSize = sizeof(comp.dwCurItemState);
  557. if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_CURSTATE, NULL, NULL, (LPBYTE)&comp.dwCurItemState, &cbSize) != ERROR_SUCCESS)
  558. {
  559. //If the item state is missing, we must be reading from IE4 machine.
  560. comp.dwCurItemState = IS_NORMAL;
  561. }
  562. //
  563. // Read in the Original state info.
  564. //
  565. cbSize = sizeof(comp.csiOriginal);
  566. if ((SHQueryValueEx(hkeyComp, REG_VAL_COMP_ORIGINALSTATEINFO, NULL, NULL, (LPBYTE)&comp.csiOriginal, &cbSize) != ERROR_SUCCESS) ||
  567. (comp.csiOriginal.dwSize != sizeof(comp.csiOriginal)))
  568. {
  569. //If the item state is missing, we must be reading from IE4 machine.
  570. // Set the OriginalState to the default info.
  571. SetStateInfo(&comp.csiOriginal, &comp.cpPos, IS_NORMAL);
  572. comp.csiOriginal.dwHeight = comp.csiOriginal.dwWidth = COMPONENT_DEFAULT_WIDTH;
  573. }
  574. //
  575. // Read in the Restored state info.
  576. //
  577. cbSize = sizeof(comp.csiRestored);
  578. if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_RESTOREDSTATEINFO, NULL, NULL, (LPBYTE)&comp.csiRestored, &cbSize) != ERROR_SUCCESS)
  579. {
  580. //If the item state is missing, we must be reading from IE4 machine.
  581. // Set the restored State to the default info.
  582. SetStateInfo(&comp.csiRestored, &comp.cpPos, IS_NORMAL);
  583. }
  584. //
  585. // Add the component to the component list.
  586. //
  587. AddComponentPrivate(&comp, StrToInt(pszComp));
  588. //
  589. // Increment our counter so we know where to add any new
  590. // components after we're done.
  591. //
  592. _dwNextID++;
  593. RegCloseKey(hkeyComp);
  594. }
  595. EXITPROC(2, "DS ReadComponent!");
  596. }
  597. typedef struct _tagSortStruct {
  598. int ihdsaIndex;
  599. int izIndex;
  600. } SORTSTRUCT;
  601. int CALLBACK pfnComponentSort(LPVOID p1, LPVOID p2, LPARAM lParam)
  602. {
  603. SORTSTRUCT * pss1 = (SORTSTRUCT *)p1;
  604. SORTSTRUCT * pss2 = (SORTSTRUCT *)p2;
  605. if (pss1->izIndex > pss2->izIndex)
  606. return 1;
  607. if (pss1->izIndex < pss2->izIndex)
  608. return -1;
  609. return(0);
  610. }
  611. //
  612. // ModifyZIndex
  613. //
  614. // Little helper function to put the zindex of the windowed and windowless components
  615. // into correct buckets so that zorting will produce a correct order by zindex.
  616. //
  617. // If we don't do this then windowless components may end up zordering above windowed ones.
  618. //
  619. void ModifyZIndex(COMPONENTA * pcomp)
  620. {
  621. if (pcomp->cpPos.izIndex != COMPONENT_TOP) {
  622. if (!IsWindowLessComponent(pcomp))
  623. pcomp->cpPos.izIndex += COMPONENT_TOP_WINDOWLESS;
  624. }
  625. else
  626. {
  627. if (IsWindowLessComponent(pcomp))
  628. pcomp->cpPos.izIndex = COMPONENT_TOP_WINDOWLESS;
  629. }
  630. }
  631. //
  632. // SortAndRationalize
  633. //
  634. // SortAndRationalize will take an unsorted component list and sort it such that the components
  635. // come out in the correct z-index indicated order. It will also rebase the z-index values at
  636. // a known constant so that the z-index values will not grow endlessly. SortAndRationalize also
  637. // imposes windowed vs. windowless criteria to the zindex values such that windowless components
  638. // always zorder under windowed ones.
  639. //
  640. void CActiveDesktop::_SortAndRationalize(void)
  641. {
  642. int icComponents;
  643. HDPA hdpa;
  644. if (_hdsaComponent && ((icComponents = DSA_GetItemCount(_hdsaComponent)) > 1) && (hdpa = DPA_Create(0))) {
  645. COMPONENTA * pcomp;
  646. SORTSTRUCT * pss;
  647. int i, iCur = ZINDEX_START;
  648. BOOL fInsertFailed = FALSE;
  649. HDSA hdsaOld;
  650. // Go through each component and insert it's hdsa-index and zindex into the hdpa
  651. for (i = 0; i < icComponents; i++)
  652. {
  653. if (!(pss = (SORTSTRUCT *)LocalAlloc(LPTR, sizeof(SORTSTRUCT))))
  654. break;
  655. pcomp = (COMPONENTA *)DSA_GetItemPtr(_hdsaComponent, i);
  656. ModifyZIndex(pcomp);
  657. pss->ihdsaIndex = i;
  658. pss->izIndex = pcomp->cpPos.izIndex;
  659. if (DPA_AppendPtr(hdpa, (void FAR *)pss) == -1) {
  660. LocalFree((HANDLE)pss);
  661. break;
  662. }
  663. }
  664. // Sort the hdpa by zindex
  665. DPA_Sort(hdpa, pfnComponentSort, 0);
  666. // Save old values
  667. hdsaOld = _hdsaComponent;
  668. // Null out the old hdsa, so AddComponentPrivate will create a new one
  669. _hdsaComponent = NULL;
  670. // Now go through the sorted hdpa and update the component zindex with a ZINDEX_START based zindex, then
  671. // add the component to the new hdsa in sorted order.
  672. for (i = 0; i < icComponents; i++) {
  673. if (!(pss = (SORTSTRUCT *)DPA_GetPtr(hdpa, i)))
  674. break;
  675. // Get component and update it's zIndex and id
  676. pcomp = (COMPONENTA *)DSA_GetItemPtr(hdsaOld, pss->ihdsaIndex);
  677. pcomp->cpPos.izIndex = iCur;
  678. iCur += 2;
  679. // Free ptr
  680. LocalFree((HANDLE)pss);
  681. // Add to new hdsa in sorted order
  682. if (!fInsertFailed) {
  683. fInsertFailed = !AddComponentPrivate(pcomp, pcomp->dwID);
  684. }
  685. }
  686. // If we're completely successfull then destroy the old hdsa. Otherwise we need
  687. // to destroy the new one and restore the old one.
  688. if ((i == icComponents) && !fInsertFailed) {
  689. DSA_Destroy(hdsaOld);
  690. } else {
  691. if (_hdsaComponent)
  692. DSA_Destroy(_hdsaComponent);
  693. _hdsaComponent = hdsaOld;
  694. }
  695. DPA_Destroy(hdpa);
  696. }
  697. }
  698. void CActiveDesktop::_ReadComponents(BOOL fActiveDesktop)
  699. {
  700. ENTERPROC(2, "DS ReadComponents()");
  701. HKEY hkey;
  702. TCHAR lpszDeskcomp[MAX_PATH];
  703. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, _pszScheme);
  704. if (RegOpenKeyEx(HKEY_CURRENT_USER, lpszDeskcomp, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  705. {
  706. DWORD cbSize;
  707. int i = 0;
  708. TCHAR lpszSubkey[MAX_PATH];
  709. //
  710. // Read in the general settings.
  711. //
  712. DWORD dwSettings;
  713. cbSize = sizeof(dwSettings);
  714. if (SHQueryValueEx(hkey, REG_VAL_COMP_SETTINGS, NULL, NULL, (LPBYTE)&dwSettings, &cbSize) == ERROR_SUCCESS)
  715. {
  716. _co.fEnableComponents = (dwSettings & COMPSETTING_ENABLE) != 0;
  717. }
  718. _co.fActiveDesktop = fActiveDesktop;
  719. //
  720. // Read in all the desktop components
  721. //
  722. while (RegEnumKey(hkey, i, lpszSubkey, ARRAYSIZE(lpszSubkey)) == ERROR_SUCCESS)
  723. {
  724. _ReadComponent(hkey, lpszSubkey);
  725. i++;
  726. }
  727. _SortAndRationalize();
  728. RegCloseKey(hkey);
  729. }
  730. EXITPROC(2, "DS ReadComponents!");
  731. }
  732. void CActiveDesktop::_Initialize(void)
  733. {
  734. ENTERPROC(2, "DS Initialize()");
  735. if (!_fInitialized)
  736. {
  737. _fInitialized = TRUE;
  738. InitDeskHtmlGlobals();
  739. SHELLSTATE ss = {0};
  740. SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
  741. BOOL fActiveDesktop = BOOLIFY(ss.fDesktopHTML);
  742. _co.dwSize = sizeof(_co);
  743. _wpo.dwSize = sizeof(_wpo);
  744. //
  745. // This per-user registry branch may not exist for this user. Or, even if
  746. // it does exist, it may have some stale info. So ensure that atlreast the
  747. // default components are there and that the html version is current for this
  748. // branch of the registry!
  749. // If everything is current, the following function does nothing!
  750. //
  751. CDeskHtmlProp_RegUnReg(TRUE); //TRUE => install.
  752. _ReadWallpaper(fActiveDesktop);
  753. _ReadPattern();
  754. _ReadComponents(fActiveDesktop);
  755. // If we are in safemode, the we can not use Dynamic Html to make updates because
  756. // updates involve complete change of background Html.
  757. if (_IsDisplayInSafeMode())
  758. _fUseDynamicHtml = FALSE;
  759. else
  760. _fUseDynamicHtml = TRUE; //Any component added after the initialization must go through dynamic html.
  761. _fDirty = FALSE;
  762. _fNeedBodyEnd = FALSE;
  763. }
  764. EXITPROC(2, "DS Initialize!");
  765. }
  766. void CActiveDesktop::_SaveWallpaper(void)
  767. {
  768. ENTERPROC(2, "DS SaveWallpaper");
  769. TCHAR lpszDeskcomp[MAX_PATH];
  770. BOOL fNormalWallpaper;
  771. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
  772. //
  773. // Compute tiling string.
  774. //
  775. TCHAR szTiled[2];
  776. lstrcpy(szTiled, TEXT("0"));
  777. szTiled[0] = szTiled[0] + (TCHAR)(_wpo.dwStyle & WPSTYLE_TILE);
  778. //
  779. // Compute the Wallpaper styling string
  780. //
  781. TCHAR szWPStyle[2];
  782. lstrcpy(szWPStyle, TEXT("0"));
  783. //
  784. // NOTE: If WPSTYLE_TILE is set, we still want to say WallpaperStyle="0"; This won't hurt
  785. // because TileWallpaper="1" will over-ride this anyway.
  786. // The reason for this hack is that during memphis setup, they put a tiled wallpaper. Then we
  787. // write WallpaperStyle=1 and TileWallpaper=1 in new and old locations. Then, then change
  788. // the wallpaper and set TileWallpaper=0. Since the WallpaperStyle continues to be 1, they
  789. // get a tiled wallpaper finally. The following is to avoid this problem!
  790. //
  791. szWPStyle[0] = szWPStyle[0] + (TCHAR)(_wpo.dwStyle & WPSTYLE_STRETCH);
  792. //
  793. // Write out wallpaper settings in new active desktop area.
  794. //
  795. if (_fWallpaperDirty || _fWallpaperChangedDuringInit)
  796. {
  797. if (!_fPolicyForWPStyle)
  798. {
  799. SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
  800. c_szTileWall, REG_SZ, szTiled, CbFromCch(lstrlen(szTiled)+1));
  801. }
  802. //
  803. // Note: We do not write the Wallpaper Style string for older systems because we do not
  804. // want to over-write what PlusPack writes. However, for newer Operating systems, we
  805. // want to write the WallpaperStyle also.
  806. //
  807. if (!_fPolicyForWPStyle)
  808. {
  809. SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
  810. c_szWallpaperStyle, REG_SZ, szWPStyle, CbFromCch(lstrlen(szWPStyle)+1));
  811. }
  812. if (!_fPolicyForWPName)
  813. {
  814. SHRegSetPath(HKEY_CURRENT_USER, lpszDeskcomp, c_szWallpaper, _szSelectedWallpaper, 0);
  815. }
  816. }
  817. if (fNormalWallpaper = IsNormalWallpaper(_szSelectedWallpaper))
  818. {
  819. lstrcpyn(_szBackupWallpaper, _szSelectedWallpaper, ARRAYSIZE(_szBackupWallpaper));
  820. }
  821. if (!_fPolicyForWPName)
  822. {
  823. FILETIME ft, ftLocal;
  824. GetWallpaperFileTime(_szBackupWallpaper, &ft);
  825. FileTimeToLocalFileTime(&ft, &ftLocal); // for FAT systems to track across DST changes
  826. // Backup the "Old type" wallpaper's name here in the new location
  827. // sothat we can detect when this gets changed by some other app.
  828. SHRegSetPath(HKEY_CURRENT_USER, lpszDeskcomp, c_szBackupWallpaper, _szBackupWallpaper, 0);
  829. SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
  830. c_szWallpaperTime, REG_BINARY, &ft,
  831. sizeof(ft));
  832. SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
  833. c_szWallpaperLocalTime, REG_BINARY, &ftLocal,
  834. sizeof(ftLocal)); // AndrewGr save local time not UTC time
  835. }
  836. //
  837. // Even if this wallpaper is not valid in normal desktop (i.e., even if it is not a .BMP),
  838. // write it out in normal desktop registry area.
  839. //
  840. if (_fWallpaperDirty)
  841. {
  842. if (!_fPolicyForWPStyle)
  843. {
  844. SHSetValue(HKEY_CURRENT_USER, c_szRegStrDesktop,
  845. c_szTileWall, REG_SZ, szTiled, CbFromCch(lstrlen(szTiled)+1));
  846. }
  847. //
  848. // Note: We do not write the Wallpaper Style string for older systems because we do not
  849. // want to over-write what PlusPack writes. However, for newer Operating systems, we
  850. // want to write the WallpaperStyle also.
  851. //
  852. if (!_fPolicyForWPStyle)
  853. {
  854. SHSetValue(HKEY_CURRENT_USER, c_szRegStrDesktop,
  855. c_szWallpaperStyle, REG_SZ, szWPStyle, CbFromCch(lstrlen(szWPStyle)+1));
  856. }
  857. if (!_fPolicyForWPName)
  858. {
  859. SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
  860. (fNormalWallpaper ? _szSelectedWallpaper : _szBackupWallpaper),
  861. SPIF_UPDATEINIFILE);
  862. }
  863. }
  864. EXITPROC(2, "DS SaveWallpaper");
  865. }
  866. void CActiveDesktop::_SaveComponent(HKEY hkey, int iIndex, COMPONENTA *pcomp)
  867. {
  868. ENTERPROC(2, "DS SaveComponent(hkey=%08X,iIndex=%d,pcomp=%08X)", hkey, iIndex, pcomp);
  869. TCHAR szSubKey[8];
  870. HKEY hkeySub;
  871. wsprintf(szSubKey, TEXT("%d"), iIndex);
  872. if (RegCreateKey(hkey, szSubKey, &hkeySub) == ERROR_SUCCESS)
  873. {
  874. pcomp->fDirty = FALSE; //Since we are saving in the registry, reset this!
  875. //
  876. // Write out the source string and Friendly name string.
  877. //
  878. RegSetValueEx(hkeySub, REG_VAL_COMP_SOURCE, 0, REG_SZ, (LPBYTE)pcomp->szSource, (lstrlen(pcomp->szSource)+1)*sizeof(TCHAR));
  879. RegSetValueEx(hkeySub, REG_VAL_COMP_SUBSCRIBED_URL, 0, REG_SZ, (LPBYTE)pcomp->szSubscribedURL, (lstrlen(pcomp->szSubscribedURL)+1)*sizeof(TCHAR));
  880. RegSetValueEx(hkeySub, REG_VAL_COMP_NAME, 0, REG_SZ, (LPBYTE)pcomp->szFriendlyName, (lstrlen(pcomp->szFriendlyName)+1)*sizeof(TCHAR));
  881. //
  882. // Compute and write out flags.
  883. //
  884. DWORD dwFlags = 0;
  885. dwFlags |= pcomp->iComponentType;
  886. if (pcomp->fChecked)
  887. {
  888. dwFlags |= COMP_SELECTED;
  889. }
  890. if (pcomp->fNoScroll)
  891. {
  892. dwFlags |= COMP_NOSCROLL;
  893. }
  894. RegSetValueEx(hkeySub, REG_VAL_COMP_FLAGS, 0, REG_DWORD, (LPBYTE)&dwFlags, sizeof(dwFlags));
  895. //
  896. // Write out the position.
  897. //
  898. RegSetValueEx(hkeySub, REG_VAL_COMP_POSITION, 0, REG_BINARY, (LPBYTE)&pcomp->cpPos, sizeof(pcomp->cpPos));
  899. // Write out the Current state
  900. RegSetValueEx(hkeySub, REG_VAL_COMP_CURSTATE, 0, REG_DWORD, (LPBYTE)&pcomp->dwCurItemState, sizeof(pcomp->dwCurItemState));
  901. // Write out the Original State Info
  902. RegSetValueEx(hkeySub, REG_VAL_COMP_ORIGINALSTATEINFO, 0, REG_BINARY, (LPBYTE)&pcomp->csiOriginal, sizeof(pcomp->csiOriginal));
  903. // Write out the Restored State Info
  904. RegSetValueEx(hkeySub, REG_VAL_COMP_RESTOREDSTATEINFO, 0, REG_BINARY, (LPBYTE)&pcomp->csiRestored, sizeof(pcomp->csiRestored));
  905. RegCloseKey(hkeySub);
  906. }
  907. EXITPROC(2, "DS SaveComponent!");
  908. }
  909. void CActiveDesktop::_SaveComponents(void)
  910. {
  911. ENTERPROC(2, "DS SaveComponents");
  912. DWORD dwFlags = 0, dwDataLength = sizeof(dwFlags);
  913. int i;
  914. TCHAR lpszDeskcomp[MAX_PATH];
  915. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, _pszScheme);
  916. //
  917. // We need to preserve the old GENFLAGS, so read them now before we roach them.
  918. //
  919. SHGetValue(HKEY_CURRENT_USER, lpszDeskcomp, REG_VAL_COMP_GENFLAGS, NULL,
  920. &dwFlags, &dwDataLength);
  921. //
  922. // Delete the entire registry key.
  923. //
  924. SHDeleteKey(HKEY_CURRENT_USER, lpszDeskcomp);
  925. //
  926. // Recreate the registry key.
  927. //
  928. HKEY hkey;
  929. if (RegCreateKey(HKEY_CURRENT_USER, lpszDeskcomp, &hkey) == ERROR_SUCCESS)
  930. {
  931. //
  932. // Write out the version number.
  933. //
  934. DWORD dw = CUR_DESKHTML_VERSION;
  935. RegSetValueEx(hkey, REG_VAL_COMP_VERSION, 0, REG_DWORD, (LPBYTE)(&dw), sizeof(dw));
  936. dw = CUR_DESKHTML_MINOR_VERSION;
  937. RegSetValueEx(hkey, REG_VAL_COMP_MINOR_VERSION, 0, REG_DWORD, (LPBYTE)(&dw), sizeof(dw));
  938. //
  939. // Write out the general settings.
  940. //
  941. DWORD dwSettings = 0;
  942. if (_co.fEnableComponents)
  943. {
  944. dwSettings |= COMPSETTING_ENABLE;
  945. }
  946. RegSetValueEx(hkey, REG_VAL_COMP_SETTINGS, 0, REG_DWORD, (LPBYTE)&dwSettings, sizeof(dwSettings));
  947. //
  948. // Write out the general flags
  949. //
  950. RegSetValueEx(hkey, REG_VAL_COMP_GENFLAGS, 0, REG_DWORD, (LPBYTE)&dwFlags, sizeof(dwFlags));
  951. if (_hdsaComponent)
  952. {
  953. //
  954. // Write out the settings for each component
  955. //
  956. for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
  957. {
  958. COMPONENTA * pcomp;
  959. if (pcomp = (COMPONENTA *)DSA_GetItemPtr(_hdsaComponent, i))
  960. {
  961. pcomp->dwID = i;
  962. _SaveComponent(hkey, i, pcomp);
  963. }
  964. }
  965. }
  966. RegCloseKey(hkey);
  967. }
  968. EXITPROC(2, "DS SaveComponents");
  969. }
  970. void CActiveDesktop::_SavePattern(DWORD dwFlags)
  971. {
  972. ENTERPROC(2, "DS SavePattern()");
  973. if (_fPatternDirty && (dwFlags & SAVE_PATTERN_NAME))
  974. {
  975. //
  976. // Write out the pattern to the registry and INI files.
  977. //
  978. SystemParametersInfo(SPI_SETDESKPATTERN, 0, _szSelectedPattern, SPIF_UPDATEINIFILE);
  979. }
  980. if (IsValidPattern(_szSelectedPattern) && (dwFlags & GENERATE_PATTERN_FILE))
  981. {
  982. //
  983. // Write out the pattern as a BMP file for use in HTML.
  984. //
  985. TCHAR szBitmapFile[MAX_PATH];
  986. HANDLE hFileBitmap = INVALID_HANDLE_VALUE;
  987. if (SUCCEEDED(GetPerUserFileName(szBitmapFile, ARRAYSIZE(szBitmapFile), PATTERN_FILENAME)))
  988. {
  989. hFileBitmap = CreateFile(szBitmapFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  990. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, NULL);
  991. }
  992. if (hFileBitmap != INVALID_HANDLE_VALUE)
  993. {
  994. DWORD cbWritten;
  995. BITMAPFILEHEADER bmfh = {0};
  996. bmfh.bfType = 0x4D42; // 'BM'
  997. bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD) + 8*sizeof(DWORD);
  998. bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD);
  999. WriteFile(hFileBitmap, &bmfh, sizeof(bmfh), &cbWritten, NULL);
  1000. BITMAPINFOHEADER bmih = {0};
  1001. bmih.biSize = sizeof(BITMAPINFOHEADER);
  1002. bmih.biWidth = 8;
  1003. bmih.biHeight = 8;
  1004. bmih.biPlanes = 1;
  1005. bmih.biBitCount = 1;
  1006. bmih.biCompression = BI_RGB;
  1007. WriteFile(hFileBitmap, &bmih, sizeof(bmih), &cbWritten, NULL);
  1008. RGBQUAD argbTable[2] = {0};
  1009. DWORD rgb;
  1010. rgb = GetSysColor(COLOR_BACKGROUND);
  1011. argbTable[0].rgbBlue = GetBValue(rgb);
  1012. argbTable[0].rgbGreen = GetGValue(rgb);
  1013. argbTable[0].rgbRed = GetRValue(rgb);
  1014. rgb = GetSysColor(COLOR_WINDOWTEXT);
  1015. argbTable[1].rgbBlue = GetBValue(rgb);
  1016. argbTable[1].rgbGreen = GetGValue(rgb);
  1017. argbTable[1].rgbRed = GetRValue(rgb);
  1018. WriteFile(hFileBitmap, argbTable, sizeof(argbTable), &cbWritten, NULL);
  1019. DWORD adwBits[8];
  1020. PatternToDwords(_szSelectedPattern, adwBits);
  1021. WriteFile(hFileBitmap, adwBits, sizeof(adwBits), &cbWritten, NULL);
  1022. CloseHandle(hFileBitmap);
  1023. }
  1024. }
  1025. EXITPROC(2, "DS SavePattern!");
  1026. }
  1027. void CActiveDesktop::_WriteHtmlFromString(LPCTSTR psz)
  1028. {
  1029. ENTERPROC(3, "DS WriteHtmlFromString(psz=>%s<)", psz);
  1030. LPCWSTR pwsz;
  1031. WCHAR szBuf[INTERNET_MAX_URL_LENGTH];
  1032. UINT uiLen;
  1033. int cch;
  1034. if ((_pStream == NULL) && (_iDestFileCharset == ANSI_HTML_CHARSET))
  1035. {
  1036. cch = SHUnicodeToAnsi(psz, (LPSTR)szBuf, ARRAYSIZE(szBuf));
  1037. ASSERT(cch == lstrlenW((LPWSTR)psz)+1);
  1038. pwsz = (LPCWSTR)szBuf;
  1039. uiLen = lstrlenA((LPSTR)szBuf);
  1040. }
  1041. else
  1042. {
  1043. pwsz = psz;
  1044. uiLen = lstrlenW(pwsz);
  1045. }
  1046. UINT cbWritten;
  1047. _WriteHtmlW(pwsz, uiLen, &cbWritten);
  1048. EXITPROC(3, "DS WriteHtmlFromString!");
  1049. }
  1050. void CActiveDesktop::_WriteHtmlFromId(UINT uid)
  1051. {
  1052. ENTERPROC(3, "DS WriteHtmlFromId(uid=%d)", uid);
  1053. TCHAR szBuf[INTERNET_MAX_URL_LENGTH];
  1054. LoadString(HINST_THISDLL, uid, szBuf, ARRAYSIZE(szBuf));
  1055. _WriteHtmlFromString(szBuf);
  1056. EXITPROC(3, "DS WriteHtmlFromId!");
  1057. }
  1058. void CActiveDesktop::_WriteHtmlFromIdF(UINT uid, ...)
  1059. {
  1060. ENTERPROC(3, "DS WriteHtmlFromIdF(uid=%d,...)", uid);
  1061. TCHAR szBufFmt[INTERNET_MAX_URL_LENGTH];
  1062. TCHAR szBuf[INTERNET_MAX_URL_LENGTH];
  1063. LoadString(HINST_THISDLL, uid, szBufFmt, ARRAYSIZE(szBufFmt));
  1064. va_list arglist;
  1065. va_start(arglist, uid);
  1066. wvsprintf(szBuf, szBufFmt, arglist);
  1067. va_end(arglist);
  1068. _WriteHtmlFromString(szBuf);
  1069. EXITPROC(3, "DS WriteHtmlFromIdF!");
  1070. }
  1071. void CActiveDesktop::_WriteHtmlFromFile(LPCTSTR pszContents)
  1072. {
  1073. ENTERPROC(3, "DS WriteHtmlFromFile(pszContents=>%s<)", pszContents);
  1074. CReadFileObj *pReadFileObj = new CReadFileObj(pszContents);
  1075. if (pReadFileObj)
  1076. {
  1077. if (pReadFileObj->_hFile != INVALID_HANDLE_VALUE)
  1078. {
  1079. WCHAR wcBuf[INTERNET_MAX_URL_LENGTH + 1];
  1080. UINT uiCharCount = ARRAYSIZE(wcBuf) -1; //Leave room for null termination.
  1081. UINT uiCharsRead;
  1082. UINT uiCharsConverted;
  1083. int iDestCharset = (_pStream ? UNICODE_HTML_CHARSET : _iDestFileCharset);
  1084. while (SUCCEEDED(pReadFileObj->FileReadAndConvertChars(iDestCharset, wcBuf, uiCharCount, &uiCharsRead, &uiCharsConverted)) && uiCharsRead)
  1085. {
  1086. UINT cbWritten;
  1087. _WriteHtmlW(wcBuf, uiCharsConverted, &cbWritten);
  1088. if (uiCharsRead < uiCharCount)
  1089. {
  1090. break;
  1091. }
  1092. }
  1093. }
  1094. delete pReadFileObj;
  1095. }
  1096. EXITPROC(3, "DS WriteHtmlFromFile!");
  1097. }
  1098. void CActiveDesktop::_WriteHtmlFromReadFileObj(CReadFileObj *pFileObj, int iOffsetStart, int iOffsetEnd)
  1099. {
  1100. ENTERPROC(3, "DS WriteHtmlFromReadFileObj(pFileObj=%08X,iOffsetStart=%d,iOffsetEnd=%d)", pFileObj, iOffsetStart, iOffsetEnd);
  1101. if (iOffsetStart != -1)
  1102. {
  1103. pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
  1104. }
  1105. else
  1106. {
  1107. ASSERT(iOffsetEnd == -1);
  1108. iOffsetEnd = -1;
  1109. }
  1110. //Get the number of WIDECHARs to be written
  1111. UINT cchWrite = (iOffsetEnd == -1) ? 0xFFFFFFFF : (iOffsetEnd - iOffsetStart);
  1112. while (cchWrite)
  1113. {
  1114. WCHAR wcBuf[INTERNET_MAX_URL_LENGTH+1];
  1115. //
  1116. // Read a chunk.
  1117. //
  1118. UINT cchTryRead = (UINT)min(cchWrite, (ARRAYSIZE(wcBuf) - 1));
  1119. UINT cchActualRead;
  1120. HRESULT hres;
  1121. //Note: if we are reading ANSI, we still use the unicode buff; but cast it!
  1122. if (_iDestFileCharset == ANSI_HTML_CHARSET)
  1123. hres = pFileObj->FileReadCharsA((LPSTR)wcBuf, cchTryRead, &cchActualRead);
  1124. else
  1125. hres = pFileObj->FileReadCharsW(wcBuf, cchTryRead, &cchActualRead);
  1126. if (SUCCEEDED(hres) && cchActualRead)
  1127. {
  1128. //
  1129. // Write a chunk.
  1130. //
  1131. UINT cchWritten;
  1132. _WriteHtmlW(wcBuf, cchActualRead, &cchWritten);
  1133. if (cchActualRead < cchTryRead)
  1134. {
  1135. //
  1136. // End of file, all done.
  1137. //
  1138. break;
  1139. }
  1140. cchWrite -= cchActualRead;
  1141. }
  1142. else
  1143. {
  1144. //
  1145. // Error reading from file, all done.
  1146. //
  1147. break;
  1148. }
  1149. }
  1150. EXITPROC(3, "DS WriteHtmlFromHfile!");
  1151. }
  1152. int CActiveDesktop::_ScanForTagA(CReadFileObj *pFileObj, int iOffsetStart, LPCSTR pszTag)
  1153. {
  1154. ENTERPROC(2, "DS ScanForTagA(pFileObj=%08X,iOffsetStart=%d,pszTagA=>%s<)",
  1155. pFileObj, iOffsetStart, pszTag);
  1156. int iRet = -1;
  1157. BOOL fDoneReading = FALSE;
  1158. int iOffset;
  1159. DWORD cchTag = lstrlenA(pszTag);
  1160. pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
  1161. iOffset = iOffsetStart;
  1162. DWORD cchBuf = 0;
  1163. while (!fDoneReading)
  1164. {
  1165. char szBuf[INTERNET_MAX_URL_LENGTH+1];
  1166. //
  1167. // Fill in the buffer.
  1168. //
  1169. UINT cchTryRead = ARRAYSIZE(szBuf) - cchBuf - 1;
  1170. UINT cchRead;
  1171. if (SUCCEEDED(pFileObj->FileReadCharsA(&szBuf[cchBuf], cchTryRead, &cchRead)) && cchRead)
  1172. {
  1173. cchBuf += cchRead;
  1174. //
  1175. // Terminate the string.
  1176. //
  1177. szBuf[cchBuf] = '\0';
  1178. //
  1179. // Scan for the tag.
  1180. //
  1181. LPSTR pszTagInBuf = StrStrIA(szBuf, pszTag);
  1182. if (pszTagInBuf)
  1183. {
  1184. //
  1185. // Found the tag, compute the offset.
  1186. //
  1187. iRet = (int) (iOffset + pszTagInBuf - szBuf);
  1188. fDoneReading = TRUE;
  1189. }
  1190. else if (cchRead < cchTryRead)
  1191. {
  1192. //
  1193. // Ran out of file without finding tag.
  1194. //
  1195. fDoneReading = TRUE;
  1196. }
  1197. else
  1198. {
  1199. //
  1200. // Compute how many bytes we want to throw away
  1201. // from this buffer so we can read in more data.
  1202. // We don't want to throw away all the bytes because
  1203. // the tag we want may span two buffers.
  1204. //
  1205. DWORD cchSkip = cchBuf - cchTag;
  1206. //
  1207. // Advance the file offset.
  1208. //
  1209. iOffset += cchSkip;
  1210. //
  1211. // Reduce the buffer size.
  1212. //
  1213. cchBuf -= cchSkip;
  1214. //
  1215. // Move the kept bytes to the beginning of the buffer.
  1216. //
  1217. MoveMemory(szBuf, szBuf + cchSkip, cchBuf);
  1218. }
  1219. }
  1220. else
  1221. {
  1222. fDoneReading = TRUE;
  1223. }
  1224. }
  1225. EXITPROC(2, "DS ScanForTagA=%d", iRet);
  1226. return iRet;
  1227. }
  1228. int CActiveDesktop::_ScanForTagW(CReadFileObj *pFileObj, int iOffsetStart, LPCWSTR pwszTag)
  1229. {
  1230. ENTERPROC(2, "DS ScanForTag(pFileObj=%08X,iOffsetStart=%d,pszTagA=>%s<)",
  1231. pFileObj, iOffsetStart, pwszTag);
  1232. int iRet = -1;
  1233. BOOL fDoneReading = FALSE;
  1234. int iOffset;
  1235. DWORD cchTag = lstrlenW(pwszTag);
  1236. pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
  1237. iOffset = iOffsetStart;
  1238. DWORD cchBuf = 0;
  1239. while (!fDoneReading)
  1240. {
  1241. WCHAR wszBuf[INTERNET_MAX_URL_LENGTH+1];
  1242. //
  1243. // Fill in the buffer.
  1244. //
  1245. UINT cchTryRead = ARRAYSIZE(wszBuf) - cchBuf - 1;
  1246. UINT cchRead;
  1247. if (SUCCEEDED(pFileObj->FileReadCharsW(&wszBuf[cchBuf], cchTryRead, &cchRead)) && cchRead)
  1248. {
  1249. cchBuf += cchRead;
  1250. //
  1251. // Terminate the string.
  1252. //
  1253. wszBuf[cchBuf] = L'\0';
  1254. //
  1255. // Scan for the tag.
  1256. //
  1257. LPWSTR pwszTagInBuf = StrStrIW(wszBuf, pwszTag);
  1258. if (pwszTagInBuf)
  1259. {
  1260. //
  1261. // Found the tag, compute the offset.
  1262. //
  1263. iRet = (int) (iOffset + pwszTagInBuf - wszBuf);
  1264. fDoneReading = TRUE;
  1265. }
  1266. else if (cchRead < cchTryRead)
  1267. {
  1268. //
  1269. // Ran out of file without finding tag.
  1270. //
  1271. fDoneReading = TRUE;
  1272. }
  1273. else
  1274. {
  1275. //
  1276. // Compute how many bytes we want to throw away
  1277. // from this buffer so we can read in more data.
  1278. // We don't want to throw away all the bytes because
  1279. // the tag we want may span two buffers.
  1280. //
  1281. DWORD cchSkip = cchBuf - cchTag;
  1282. //
  1283. // Advance the file offset.
  1284. //
  1285. iOffset += cchSkip;
  1286. //
  1287. // Reduce the buffer size.
  1288. //
  1289. cchBuf -= cchSkip;
  1290. //
  1291. // Move the kept bytes to the beginning of the buffer.
  1292. //
  1293. MoveMemory(wszBuf, wszBuf + cchSkip, cchBuf*sizeof(WCHAR));
  1294. }
  1295. }
  1296. else
  1297. {
  1298. fDoneReading = TRUE;
  1299. }
  1300. }
  1301. EXITPROC(2, "DS ScanForTag=%d", iRet);
  1302. return iRet;
  1303. }
  1304. int CActiveDesktop::_ScanTagEntriesA(CReadFileObj *pReadFileObj, int iOffsetStart, TAGENTRYA *pte, int cte)
  1305. {
  1306. ENTERPROC(2, "DS ScanTagEntriesA(pReadFileObj=%08X,iOffsetStart=%d,pte=%08X,cte=%d)",
  1307. pReadFileObj, iOffsetStart, pte, cte);
  1308. int iRet = -1;
  1309. int i;
  1310. for (i=0; i<cte; i++,pte++)
  1311. {
  1312. iRet = _ScanForTagA(pReadFileObj, iOffsetStart, pte->pszTag);
  1313. if (iRet != -1)
  1314. {
  1315. if (pte->fSkipPast)
  1316. {
  1317. iRet += lstrlenA(pte->pszTag);
  1318. }
  1319. break;
  1320. }
  1321. }
  1322. EXITPROC(2, "DS ScanTagEntriesA=%d", iRet);
  1323. return iRet;
  1324. }
  1325. int CActiveDesktop::_ScanTagEntriesW(CReadFileObj *pReadFileObj, int iOffsetStart, TAGENTRYW *pte, int cte)
  1326. {
  1327. ENTERPROC(2, "DS ScanTagEntriesW(pReadFileObj=%08X,iOffsetStart=%d,pte=%08X,cte=%d)",
  1328. pReadFileObj, iOffsetStart, pte, cte);
  1329. int iRet = -1;
  1330. int i;
  1331. for (i=0; i<cte; i++,pte++)
  1332. {
  1333. iRet = _ScanForTagW(pReadFileObj, iOffsetStart, pte->pwszTag);
  1334. if (iRet != -1)
  1335. {
  1336. if (pte->fSkipPast)
  1337. {
  1338. iRet += lstrlenW(pte->pwszTag);
  1339. }
  1340. break;
  1341. }
  1342. }
  1343. EXITPROC(2, "DS ScanTagEntriesW=%d", iRet);
  1344. return iRet;
  1345. }
  1346. void CActiveDesktop::_ParseAnsiInputHtmlFile( LPTSTR szSelectedWallpaper, int *piOffsetBase, int *piOffsetComp)
  1347. {
  1348. //
  1349. // Figure out where to insert the base href tag.
  1350. //
  1351. int iOffsetBase = 0, iBaseTagStart;
  1352. BOOL fUseBaseHref;
  1353. LONG lOffsetDueToBOM = 0; //Character Offset due to the Byte Order Mark.
  1354. //1 for UNICODE and 0 for ANSI files.
  1355. // 98/11/11 #248047 vtan: This code looks for a <BASE HREF=...> tag.
  1356. // It used to use a scan for "<BASE" and assume that this was the
  1357. // desired tag. HTML allows a "<BASEFONT>" tag which was being
  1358. // mistaken for a "<BASE HREF=...>" tag. The code now looks for the
  1359. // same string but looks at the character following the "<BASE" to
  1360. // see if it's a white-space character.
  1361. fUseBaseHref = TRUE;
  1362. _pReadFileObjHtmlBkgd->FileGetCurCharOffset(&lOffsetDueToBOM);
  1363. iOffsetBase = (int)lOffsetDueToBOM;
  1364. iBaseTagStart = _ScanForTagA(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, "<BASE");
  1365. if (iBaseTagStart != -1)
  1366. {
  1367. UINT uiCountChars, uiTryToRead;
  1368. char szBaseTagBuffer[6+1]; // allow for "<BASEx" plus a NULL.
  1369. _pReadFileObjHtmlBkgd->FileSeekChars(iBaseTagStart, FILE_BEGIN);
  1370. uiTryToRead = ARRAYSIZE(szBaseTagBuffer) - 1;
  1371. if (SUCCEEDED(_pReadFileObjHtmlBkgd->FileReadCharsA(szBaseTagBuffer, uiTryToRead, &uiCountChars)) && uiCountChars)
  1372. {
  1373. char ch;
  1374. ch = szBaseTagBuffer[5];
  1375. fUseBaseHref = ((ch != ' ') &&
  1376. (ch != '\r') &&
  1377. (ch != '\n') && // this covers the UNIX line break scheme
  1378. (ch != '\t'));
  1379. }
  1380. }
  1381. if (fUseBaseHref)
  1382. {
  1383. TAGENTRYA rgteBase[] = {
  1384. { "<HEAD>", TRUE, },
  1385. { "<BODY", FALSE, },
  1386. { "<HTML>", TRUE, },
  1387. };
  1388. iOffsetBase = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, rgteBase, ARRAYSIZE(rgteBase));
  1389. if (iOffsetBase == -1)
  1390. {
  1391. iOffsetBase = (int)lOffsetDueToBOM;
  1392. }
  1393. }
  1394. //
  1395. // Figure out where to insert the components.
  1396. //
  1397. TAGENTRYA rgteComponents[] = {
  1398. { "</BODY>", FALSE, },
  1399. { "</HTML>", FALSE, },
  1400. };
  1401. int iOffsetComponents = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteComponents, ARRAYSIZE(rgteComponents));
  1402. //
  1403. // Write out the initial HTML up to the <HEAD> tag.
  1404. //
  1405. _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, iOffsetBase);
  1406. //
  1407. // Write out the base tag.
  1408. //
  1409. if (fUseBaseHref)
  1410. {
  1411. //BASE tag must point to the base "URL". So, don't strip out the filename.
  1412. _WriteHtmlFromIdF(IDS_BASE_TAG, szSelectedWallpaper);
  1413. }
  1414. // Figure out where to insert the DIV clause
  1415. TAGENTRYA rgteBodyStart[] = {
  1416. { "<BODY", FALSE, },
  1417. };
  1418. int iOffsetBodyStart = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteBodyStart, ARRAYSIZE(rgteBodyStart));
  1419. // Write out HTML until after the <BODY ......>
  1420. if (iOffsetBodyStart == -1)
  1421. { // the <BODY> tag is not found, so we need to insert it.
  1422. // Copy over stuff until </HEAD>
  1423. TAGENTRYA rgteHeadEnd[] = {
  1424. { "</HEAD>", TRUE, },
  1425. };
  1426. int iOffsetHeadEnd = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteHeadEnd, ARRAYSIZE(rgteHeadEnd));
  1427. if (iOffsetHeadEnd != -1)
  1428. {
  1429. _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetHeadEnd);
  1430. iOffsetBase = iOffsetHeadEnd;
  1431. }
  1432. _WriteHtmlFromIdF(IDS_BODY_CENTER_WP2); // "<BODY>"
  1433. _fNeedBodyEnd = TRUE;
  1434. }
  1435. else
  1436. {
  1437. TAGENTRYA rgteBodyEnd[] = {
  1438. { ">", TRUE, },
  1439. };
  1440. int iOffsetBodyEnd = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBodyStart, rgteBodyEnd, ARRAYSIZE(rgteBodyEnd));
  1441. if (iOffsetBodyEnd == -1)
  1442. { // An error in the HTML.
  1443. iOffsetBodyEnd = iOffsetBodyStart; // FEATURE: We need a better recovery idea.
  1444. }
  1445. _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetBodyEnd);
  1446. iOffsetBase = iOffsetBodyEnd;
  1447. }
  1448. *piOffsetBase = iOffsetBase;
  1449. *piOffsetComp = iOffsetComponents;
  1450. }
  1451. void CActiveDesktop::_GenerateHtmlHeader(void)
  1452. {
  1453. ENTERPROC(2, "DS GenerateHtmlHeader()");
  1454. EnumMonitorsArea ema;
  1455. GetMonitorSettings(&ema);
  1456. RECT rcViewAreas[LV_MAX_WORKAREAS]; // WorkArea minus toolbar/tray areas
  1457. int nViewAreas = ARRAYSIZE(rcViewAreas);
  1458. // Get the ViewAreas
  1459. if (!GetViewAreas(rcViewAreas, &nViewAreas))
  1460. {
  1461. nViewAreas = 0;
  1462. }
  1463. //Assume that the final Deskstat.htt that we generate is going to be in UNICODE.
  1464. //This will change to ANSI only if the background html wallpaper is ANSI (determined later)
  1465. _iDestFileCharset = UNICODE_HTML_CHARSET;
  1466. //
  1467. // Write out the background and color.
  1468. //
  1469. TCHAR szSelectedWallpaper[INTERNET_MAX_URL_LENGTH];
  1470. // If the wallpaper does not have a directory specified (this may happen if other apps. change this value),
  1471. // we have to figure it out.
  1472. GetWallpaperWithPath(_szSelectedWallpaper, szSelectedWallpaper, ARRAYSIZE(szSelectedWallpaper));
  1473. BOOL fValidWallpaper = GetFileAttributes(szSelectedWallpaper) != 0xFFFFFFFF;
  1474. if (_fSingleItem || IsWallpaperPicture(szSelectedWallpaper) || !fValidWallpaper)
  1475. {
  1476. //
  1477. // Write the BOM for UNICODE
  1478. //
  1479. if (_hFileHtml)
  1480. {
  1481. DWORD cbWritten;
  1482. WriteFile(_hFileHtml, (LPCSTR)&wUnicodeBOM, sizeof(wUnicodeBOM), &cbWritten, NULL);
  1483. }
  1484. // To account for the vagaries of the desktop browser (it's TopLeft starts from the TopLeft
  1485. // of the Desktop ViewArea instead of the TopLeft of the monitor, as might be expected)
  1486. // which happens only in the case of one active monitor systems, we add the width of the
  1487. // tray/toolbars to the co-ordinates of the DIV section of each monitor's wallpaper.
  1488. int iLeft, iTop;
  1489. if (nViewAreas == 1)
  1490. {
  1491. iLeft = rcViewAreas[0].left - ema.rcVirtualMonitor.left;
  1492. iTop = rcViewAreas[0].top - ema.rcVirtualMonitor.top;
  1493. }
  1494. else
  1495. {
  1496. iLeft = 0;
  1497. iTop = 0;
  1498. }
  1499. //
  1500. // Write out the standard header.
  1501. //
  1502. UINT i;
  1503. for (i=IDS_COMMENT_BEGIN; i<IDS_BODY_BEGIN; i++)
  1504. {
  1505. _WriteHtmlFromIdF(i);
  1506. }
  1507. //
  1508. // Write out the body tag, with background bitmap.
  1509. //
  1510. DWORD rgbDesk;
  1511. rgbDesk = GetSysColor(COLOR_DESKTOP);
  1512. TCHAR szBitmapFile[MAX_PATH];
  1513. if (FAILED(GetPerUserFileName(szBitmapFile, ARRAYSIZE(szBitmapFile), PATTERN_FILENAME)))
  1514. {
  1515. szBitmapFile[0] = 0;
  1516. }
  1517. if (!_fSingleItem && _szSelectedWallpaper[0] && fValidWallpaper)
  1518. {
  1519. TCHAR szWallpaperUrl[INTERNET_MAX_URL_LENGTH];
  1520. DWORD cch = ARRAYSIZE(szWallpaperUrl);
  1521. UrlCreateFromPath(szSelectedWallpaper, szWallpaperUrl, &cch, URL_INTERNAL_PATH);
  1522. switch (_wpo.dwStyle)
  1523. {
  1524. case WPSTYLE_TILE:
  1525. //
  1526. // Ignore the pattern, tile the wallpaper as background.
  1527. //
  1528. _WriteHtmlFromIdF(IDS_BODY_BEGIN2, szWallpaperUrl, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1529. break;
  1530. case WPSTYLE_CENTER:
  1531. if (IsValidPattern(_szSelectedPattern))
  1532. {
  1533. //
  1534. // Tile the pattern as the main background.
  1535. //
  1536. _WriteHtmlFromIdF(IDS_BODY_BEGIN2, szBitmapFile, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1537. if (_fBackgroundHtml) // We are generating the HTML for preview
  1538. {
  1539. _WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP, szWallpaperUrl);
  1540. }
  1541. else
  1542. {
  1543. //
  1544. // Write out a DIV section for a centered, untiled wallpaper.
  1545. //
  1546. // write it out for each monitor.
  1547. for(int i = 0; i < ema.iMonitors; i++)
  1548. {
  1549. _WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP2,
  1550. ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
  1551. ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
  1552. ema.rcMonitor[i].right - ema.rcMonitor[i].left,
  1553. ema.rcMonitor[i].bottom - ema.rcMonitor[i].top,
  1554. szWallpaperUrl);
  1555. }
  1556. }
  1557. }
  1558. else
  1559. {
  1560. //
  1561. // Write out a non-tiled, centered wallpaper as background.
  1562. //
  1563. if (_fBackgroundHtml) // We are generating the HTML for preview
  1564. {
  1565. _WriteHtmlFromIdF(IDS_BODY_CENTER_WP, szWallpaperUrl, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1566. }
  1567. else
  1568. {
  1569. _WriteHtmlFromIdF(IDS_BODY_CENTER_WP2, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1570. // write it out for each monitor.
  1571. for(int i = 0; i < ema.iMonitors; i++)
  1572. {
  1573. _WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP2,
  1574. ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
  1575. ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
  1576. ema.rcMonitor[i].right - ema.rcMonitor[i].left,
  1577. ema.rcMonitor[i].bottom - ema.rcMonitor[i].top,
  1578. szWallpaperUrl);
  1579. }
  1580. }
  1581. }
  1582. break;
  1583. case WPSTYLE_STRETCH:
  1584. //
  1585. // Ignore the pattern, create a DIV section of the wallpaper
  1586. // stretched to 100% of the screen.
  1587. //
  1588. _WriteHtmlFromIdF(IDS_BODY_BEGIN2, c_szNULL, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1589. if (_fBackgroundHtml) // We are generating the HTML for preview
  1590. {
  1591. _WriteHtmlFromIdF(IDS_STRETCH_WALLPAPER, szWallpaperUrl);
  1592. }
  1593. else
  1594. {
  1595. // stretch it for each monitor.
  1596. for(int i = 0; i < ema.iMonitors; i++)
  1597. {
  1598. _WriteHtmlFromIdF(IDS_DIV_START3, ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
  1599. ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
  1600. ema.rcMonitor[i].right - ema.rcMonitor[i].left,
  1601. ema.rcMonitor[i].bottom - ema.rcMonitor[i].top);
  1602. _WriteHtmlFromIdF(IDS_STRETCH_WALLPAPER, szWallpaperUrl);
  1603. _WriteHtmlFromId(IDS_DIV_END);
  1604. }
  1605. }
  1606. break;
  1607. }
  1608. }
  1609. else
  1610. {
  1611. //
  1612. // Ignore the wallpaper, generate either a tiled pattern
  1613. // or solid color background.
  1614. //
  1615. _WriteHtmlFromIdF(IDS_BODY_BEGIN2, !_fSingleItem && IsValidPattern(_szSelectedPattern) ? szBitmapFile : c_szNULL, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1616. }
  1617. }
  1618. else
  1619. {
  1620. if ((_pReadFileObjHtmlBkgd = new CReadFileObj(szSelectedWallpaper)) &&
  1621. (_pReadFileObjHtmlBkgd->_hFile != INVALID_HANDLE_VALUE))
  1622. {
  1623. //The final Desktop.htt will be in ANSI only if the source html file is also in ansi.
  1624. //So, get the type from the selected wallpaper object.
  1625. _iDestFileCharset = _pReadFileObjHtmlBkgd->_iCharset;
  1626. //
  1627. // Write the BOM for UNICODE
  1628. //
  1629. if (_hFileHtml && (_iDestFileCharset == UNICODE_HTML_CHARSET))
  1630. {
  1631. DWORD cbWritten;
  1632. WriteFile(_hFileHtml, (LPCSTR)&wUnicodeBOM, sizeof(wUnicodeBOM), &cbWritten, NULL);
  1633. }
  1634. //
  1635. // Figure out where to insert the base href tag.
  1636. //
  1637. int iOffsetBase = 0;
  1638. int iOffsetComponents;
  1639. // 98/11/11 #248047 vtan: This code looks for a <BASE HREF=...> tag.
  1640. // It used to use a scan for "<BASE" and assume that this was the
  1641. // desired tag. HTML allows a "<BASEFONT>" tag which was being
  1642. // mistaken for a "<BASE HREF=...>" tag. The code now looks for the
  1643. // same string but looks at the character following the "<BASE" to
  1644. // see if it's a white-space character.
  1645. if (_iDestFileCharset == ANSI_HTML_CHARSET)
  1646. {
  1647. //The following function parses the ANSI input html file and finds various offsets
  1648. _ParseAnsiInputHtmlFile(szSelectedWallpaper, &iOffsetBase, &iOffsetComponents);
  1649. }
  1650. else
  1651. {
  1652. //The following code parses the UNICODE input html wallpaper file.
  1653. int iBaseTagStart;
  1654. BOOL fUseBaseHref;
  1655. LONG lOffsetDueToBOM = 0; //Character Offset due to the Byte Order Mark.
  1656. //1 for UNICODE and 0 for ANSI files.
  1657. fUseBaseHref = TRUE;
  1658. _pReadFileObjHtmlBkgd->FileGetCurCharOffset(&lOffsetDueToBOM);
  1659. iOffsetBase = (int)lOffsetDueToBOM;
  1660. iBaseTagStart = _ScanForTagW(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, L"<BASE");
  1661. if (iBaseTagStart != -1)
  1662. {
  1663. UINT uiCountChars, uiTryToRead;
  1664. WCHAR wszBaseTagBuffer[6+1]; // allow for "<BASEx" plus a NULL.
  1665. _pReadFileObjHtmlBkgd->FileSeekChars(iBaseTagStart, FILE_BEGIN);
  1666. uiTryToRead = ARRAYSIZE(wszBaseTagBuffer) - 1;
  1667. if (SUCCEEDED(_pReadFileObjHtmlBkgd->FileReadCharsW(wszBaseTagBuffer, uiTryToRead, &uiCountChars)) && uiCountChars)
  1668. {
  1669. WCHAR wc;
  1670. wc = wszBaseTagBuffer[5];
  1671. fUseBaseHref = ((wc != L' ') &&
  1672. (wc != L'\r') &&
  1673. (wc != L'\n') && // this covers the UNIX line break scheme
  1674. (wc != L'\t'));
  1675. }
  1676. }
  1677. if (fUseBaseHref)
  1678. {
  1679. TAGENTRYW rgteBase[] = {
  1680. { L"<HEAD>", TRUE, },
  1681. { L"<BODY", FALSE, },
  1682. { L"<HTML>", TRUE, },
  1683. };
  1684. iOffsetBase = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, rgteBase, ARRAYSIZE(rgteBase));
  1685. if (iOffsetBase == -1)
  1686. {
  1687. iOffsetBase = (int)lOffsetDueToBOM;
  1688. }
  1689. }
  1690. //
  1691. // Figure out where to insert the components.
  1692. //
  1693. TAGENTRYW rgteComponents[] = {
  1694. { L"</BODY>", FALSE, },
  1695. { L"</HTML>", FALSE, },
  1696. };
  1697. iOffsetComponents = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteComponents, ARRAYSIZE(rgteComponents));
  1698. //
  1699. // Write out the initial HTML up to the <HEAD> tag.
  1700. //
  1701. _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, iOffsetBase);
  1702. //
  1703. // Write out the base tag.
  1704. //
  1705. if (fUseBaseHref)
  1706. {
  1707. //BASE tag must point to the base "URL". So, don't strip out the filename.
  1708. _WriteHtmlFromIdF(IDS_BASE_TAG, szSelectedWallpaper);
  1709. }
  1710. // Figure out where to insert the DIV clause
  1711. TAGENTRYW rgteBodyStart[] = {
  1712. { L"<BODY", FALSE, },
  1713. };
  1714. int iOffsetBodyStart = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteBodyStart, ARRAYSIZE(rgteBodyStart));
  1715. // Write out HTML until after the <BODY ......>
  1716. if (iOffsetBodyStart == -1)
  1717. { // the <BODY> tag is not found, so we need to insert it.
  1718. // Copy over stuff until </HEAD>
  1719. TAGENTRYW rgteHeadEnd[] = {
  1720. { L"</HEAD>", TRUE, },
  1721. };
  1722. int iOffsetHeadEnd = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteHeadEnd, ARRAYSIZE(rgteHeadEnd));
  1723. if (iOffsetHeadEnd != -1)
  1724. {
  1725. _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetHeadEnd);
  1726. iOffsetBase = iOffsetHeadEnd;
  1727. }
  1728. _WriteHtmlFromIdF(IDS_BODY_CENTER_WP2); // "<BODY>"
  1729. _fNeedBodyEnd = TRUE;
  1730. }
  1731. else
  1732. {
  1733. TAGENTRYW rgteBodyEnd[] = {
  1734. { L">", TRUE, },
  1735. };
  1736. int iOffsetBodyEnd = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBodyStart, rgteBodyEnd, ARRAYSIZE(rgteBodyEnd));
  1737. if (iOffsetBodyEnd == -1)
  1738. { // An error in the HTML.
  1739. iOffsetBodyEnd = iOffsetBodyStart; // FEATURE: We need a better recovery idea.
  1740. }
  1741. _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetBodyEnd);
  1742. iOffsetBase = iOffsetBodyEnd;
  1743. }
  1744. }
  1745. // Insert the DIV clause
  1746. if (ema.iMonitors > 1)
  1747. {
  1748. int iIndexPrimaryMonitor;
  1749. HMONITOR hMonitorPrimary;
  1750. MONITORINFO monitorInfo;
  1751. // 99/03/23 #275429 vtan: We used GetViewAreas() to fill in rcViewAreas above.
  1752. // The code here used to assume that [0] ALWAYS referred to the primary monitor.
  1753. // This isn't the case if the monitor settings are changed without a restart.
  1754. // In order to compensate for this and always render the wallpaper into the
  1755. // primary monitor, a search is performed to find a (left, top) that matches
  1756. // one of the work areas and this is used as the primary monitor. If none can
  1757. // be found then default to the old algorithm.
  1758. hMonitorPrimary = GetPrimaryMonitor();
  1759. monitorInfo.cbSize = sizeof(monitorInfo);
  1760. TBOOL(GetMonitorInfo(hMonitorPrimary, &monitorInfo));
  1761. iIndexPrimaryMonitor = -1;
  1762. for (int i = 0; (iIndexPrimaryMonitor < 0) && (i < nViewAreas); ++i)
  1763. {
  1764. if ((monitorInfo.rcWork.left == rcViewAreas[i].left) && (monitorInfo.rcWork.top == rcViewAreas[i].top))
  1765. {
  1766. iIndexPrimaryMonitor = i;
  1767. }
  1768. }
  1769. if (iIndexPrimaryMonitor < 0)
  1770. iIndexPrimaryMonitor = 0;
  1771. if ((nViewAreas <= 0) || (rcViewAreas[iIndexPrimaryMonitor].right == rcViewAreas[iIndexPrimaryMonitor].left))
  1772. // The second case could occur on bootup
  1773. {
  1774. // Some error occured when getting the ViewAreas. Recover from the error by using the workarea.
  1775. // Get the workarea of the primary monitor, since HTML wallpapers are displayed only there.
  1776. GetMonitorWorkArea(hMonitorPrimary, &rcViewAreas[iIndexPrimaryMonitor]);
  1777. }
  1778. _WriteHtmlFromIdF(IDS_DIV_START3,
  1779. rcViewAreas[iIndexPrimaryMonitor].left - ema.rcVirtualMonitor.left,
  1780. rcViewAreas[iIndexPrimaryMonitor].top - ema.rcVirtualMonitor.top,
  1781. rcViewAreas[iIndexPrimaryMonitor].right - rcViewAreas[iIndexPrimaryMonitor].left,
  1782. rcViewAreas[iIndexPrimaryMonitor].bottom - rcViewAreas[iIndexPrimaryMonitor].top);
  1783. }
  1784. //
  1785. // Write out HTML from after <HEAD> tag to just before </BODY> tag.
  1786. //
  1787. _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetComponents);
  1788. if (ema.iMonitors > 1)
  1789. {
  1790. _WriteHtmlFromId(IDS_DIV_END);
  1791. }
  1792. }
  1793. else
  1794. {
  1795. if (_pReadFileObjHtmlBkgd)
  1796. delete _pReadFileObjHtmlBkgd;
  1797. _pReadFileObjHtmlBkgd = NULL;
  1798. }
  1799. }
  1800. EXITPROC(2, "DS GenerateHtmlHeader!");
  1801. }
  1802. void CActiveDesktop::_WriteResizeable(COMPONENTA *pcomp)
  1803. {
  1804. TCHAR szResizeable[3];
  1805. szResizeable[0] = TEXT('\0');
  1806. //If Resize is set, then the comp is resizeable in both X and Y directions!
  1807. if (pcomp->cpPos.fCanResize)
  1808. lstrcat(szResizeable, TEXT("XY"));
  1809. else
  1810. {
  1811. if (pcomp->cpPos.fCanResizeX)
  1812. lstrcat(szResizeable, TEXT("X"));
  1813. if (pcomp->cpPos.fCanResizeY)
  1814. lstrcat(szResizeable, TEXT("Y"));
  1815. }
  1816. _WriteHtmlFromIdF(IDS_RESIZEABLE, szResizeable);
  1817. }
  1818. void CActiveDesktop::_WriteHtmlW(LPCWSTR wcBuf, UINT cchToWrite, UINT *pcchWritten)
  1819. {
  1820. ULONG cchWritten = 0;
  1821. UINT uiSize;
  1822. if (_pStream)
  1823. {
  1824. uiSize = sizeof(WCHAR);
  1825. _pStream->Write((LPVOID)wcBuf, cchToWrite * uiSize, &cchWritten);
  1826. }
  1827. else
  1828. {
  1829. ASSERT(_hFileHtml);
  1830. uiSize = (_iDestFileCharset == ANSI_HTML_CHARSET) ? sizeof(char) : sizeof(WCHAR);
  1831. WriteFile(_hFileHtml, (LPCVOID)wcBuf, cchToWrite * uiSize, &cchWritten, NULL);
  1832. }
  1833. *pcchWritten = (UINT)(cchWritten/uiSize); //Convert to number of chars.
  1834. }
  1835. void CActiveDesktop::_GenerateHtmlPicture(COMPONENTA *pcomp)
  1836. {
  1837. ENTERPROC(2, "DS GenerateHtmlPicture(pcomp=%08X)");
  1838. //
  1839. // Write out the image src HTML.
  1840. //
  1841. TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  1842. DWORD cch=ARRAYSIZE(szUrl);
  1843. if (FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &cch, 0)))
  1844. {
  1845. lstrcpy(szUrl, pcomp->szSource);
  1846. }
  1847. _WriteHtmlFromIdF(IDS_IMAGE_BEGIN2, pcomp->dwID, szUrl);
  1848. //
  1849. // Write out whether this image is resizeable or not!
  1850. //
  1851. _WriteResizeable(pcomp);
  1852. //
  1853. // Write out the URL that must be used for subscription purposes.
  1854. //
  1855. _WriteHtmlFromIdF(IDS_SUBSCRIBEDURL, pcomp->szSubscribedURL);
  1856. //
  1857. // Write out the image location HTML.
  1858. //
  1859. if ((pcomp->cpPos.dwWidth == COMPONENT_DEFAULT_WIDTH) &&
  1860. (pcomp->cpPos.dwHeight == COMPONENT_DEFAULT_HEIGHT))
  1861. {
  1862. _WriteHtmlFromIdF(IDS_IMAGE_LOCATION, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.izIndex);
  1863. }
  1864. else
  1865. {
  1866. _WriteHtmlFromIdF(IDS_IMAGE_SIZE, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop,
  1867. pcomp->cpPos.dwWidth, pcomp->cpPos.dwHeight, pcomp->cpPos.izIndex);
  1868. }
  1869. EXITPROC(2, "DS GenerateHtmlPicture!");
  1870. }
  1871. void CActiveDesktop::_GenerateHtmlDoc(COMPONENTA *pcomp)
  1872. {
  1873. ENTERPROC(2, "DS GenerateHtmlDoc(pcomp=%08X)");
  1874. TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  1875. DWORD dwSize = ARRAYSIZE(szUrl);
  1876. LPTSTR lpszUrl = szUrl;
  1877. if (FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &dwSize, 0)))
  1878. lpszUrl = pcomp->szSource;
  1879. //
  1880. // Write out the DIV header HTML.
  1881. //
  1882. _WriteHtmlFromIdF(IDS_DIV_START2, pcomp->dwID, lpszUrl);
  1883. //
  1884. // Write out whether this component is resizeable or not!
  1885. //
  1886. _WriteResizeable(pcomp);
  1887. //
  1888. // Write out the DIV location HTML.
  1889. //
  1890. _WriteHtmlFromIdF(IDS_DIV_SIZE, pcomp->cpPos.dwHeight, _fSingleItem ? 0 : pcomp->cpPos.iLeft,
  1891. _fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.dwWidth, pcomp->cpPos.izIndex);
  1892. //
  1893. // Extract the doc contents directly into the HTML.
  1894. //
  1895. _WriteHtmlFromFile(pcomp->szSource);
  1896. //
  1897. // Close the DIV section.
  1898. //
  1899. _WriteHtmlFromId(IDS_DIV_END);
  1900. EXITPROC(2, "DS GenerateHtmlDoc!");
  1901. }
  1902. void CActiveDesktop::_GenerateHtmlSite(COMPONENTA *pcomp)
  1903. {
  1904. ENTERPROC(2, "DS GenerateHtmlSite(pcomp=%08X)");
  1905. //
  1906. // Write out the frame src HTML.
  1907. //
  1908. TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  1909. DWORD cch=ARRAYSIZE(szUrl);
  1910. if (FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &cch, 0)))
  1911. {
  1912. lstrcpy(szUrl, pcomp->szSource);
  1913. }
  1914. DWORD currentURLLength, maximumURLLength;
  1915. TCHAR *pURL, formatBuffer[0x0100];
  1916. // 98/09/29 #211384 vtan: There is a limitation in wvsprintf.
  1917. // It only allows 2048 bytes in its buffer. If the URL is
  1918. // longer than 1024 characters less the IDS_IFRAME_BEGIN2
  1919. // string length less the component ID less "scrolling=no"
  1920. // if the component cannot be scrolled then the URL string
  1921. // will not be correctly inserted into the IDS_IFRAME_BEGIN2
  1922. // string and there will be a missing end-quote and trident
  1923. // will fail to render desktop.htt correctly.
  1924. // To correct against this the followING limits the length of
  1925. // the URL to this maximum and truncates any characters
  1926. // beyond the limit so that the IDS_IFRAME_BEGIN2 string
  1927. // contains its end-quote and trident does not barf.
  1928. // The above condition is a boundary condition and this
  1929. // check is quick so that the calculations that follow do
  1930. // not have to be executed repeatedly.
  1931. currentURLLength = lstrlen(szUrl);
  1932. if (currentURLLength > 768) // a hard-coded limit
  1933. {
  1934. maximumURLLength = 1024; // wvsprintf limit
  1935. LoadString(HINST_THISDLL, IDS_IFRAME_BEGIN2, formatBuffer, ARRAYSIZE(formatBuffer));
  1936. maximumURLLength -= lstrlen(formatBuffer); // IDS_IFRAME_BEGIN2
  1937. maximumURLLength -= 16; // pcomp->dwID
  1938. maximumURLLength -= lstrlen(TEXT("scrolling=no")); // pcomp->fNoScroll
  1939. if (currentURLLength > maximumURLLength)
  1940. szUrl[maximumURLLength] = static_cast<TCHAR>('\0');
  1941. }
  1942. _WriteHtmlFromIdF(IDS_IFRAME_BEGIN2, pcomp->dwID, szUrl, pcomp->fNoScroll ? TEXT("scrolling=no") : c_szNULL);
  1943. //
  1944. // Write out whether this Component is resizeable or not!
  1945. //
  1946. _WriteResizeable(pcomp);
  1947. // 98/09/29 #211384 vtan: See above.
  1948. currentURLLength = lstrlen(pcomp->szSubscribedURL);
  1949. if (currentURLLength > 768)
  1950. {
  1951. lstrcpy(szUrl, pcomp->szSubscribedURL);
  1952. maximumURLLength = 1024;
  1953. LoadString(HINST_THISDLL, IDS_SUBSCRIBEDURL, formatBuffer, ARRAYSIZE(formatBuffer));
  1954. maximumURLLength -= lstrlen(formatBuffer); // IDS_SUBSCRIBEDURL
  1955. if (currentURLLength > maximumURLLength)
  1956. szUrl[maximumURLLength] = static_cast<TCHAR>('\0');
  1957. pURL = szUrl;
  1958. }
  1959. else
  1960. pURL = pcomp->szSubscribedURL;
  1961. //
  1962. // Write out the URL that must be used for subscription purposes.
  1963. //
  1964. _WriteHtmlFromIdF(IDS_SUBSCRIBEDURL, pURL);
  1965. //
  1966. // Write out the frame location HTML.
  1967. //
  1968. _WriteHtmlFromIdF(IDS_IFRAME_SIZE, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop,
  1969. pcomp->cpPos.dwWidth, pcomp->cpPos.dwHeight, pcomp->cpPos.izIndex);
  1970. EXITPROC(2, "DS GenerateHtmlSite!");
  1971. }
  1972. void CActiveDesktop::_GenerateHtmlControl(COMPONENTA *pcomp)
  1973. {
  1974. ENTERPROC(2, "DS GenerateHtmlControl(pcomp=%08X)");
  1975. ASSERT(pcomp);
  1976. // Did the Administrator restrict "Channel UI"?
  1977. if (SHRestricted2W(REST_NoChannelUI, NULL, 0))
  1978. {
  1979. TCHAR szChannelOCGUID[GUIDSTR_MAX];
  1980. SHStringFromGUID(CLSID_ChannelOC, szChannelOCGUID, ARRAYSIZE(szChannelOCGUID));
  1981. if (!StrCmpNI(pcomp->szSource, &(szChannelOCGUID[1]), lstrlen(pcomp->szSource)-3))
  1982. {
  1983. // Yes, so we need to hide the Channel Desktop Component.
  1984. // Return here before we generate it.
  1985. return;
  1986. }
  1987. }
  1988. //
  1989. // Write out the control HTML.
  1990. //
  1991. // First the control header
  1992. _WriteHtmlFromIdF(IDS_CONTROL_1, pcomp->dwID);
  1993. // then the size
  1994. _WriteHtmlFromIdF(IDS_CONTROL_2, pcomp->cpPos.dwHeight, _fSingleItem ? 0 : pcomp->cpPos.iLeft,
  1995. _fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.dwWidth, pcomp->cpPos.izIndex);
  1996. //
  1997. // Write out whether this Control is resizeable or not!
  1998. //
  1999. _WriteResizeable(pcomp);
  2000. // Finally the rest of the control
  2001. _WriteHtmlFromIdF(IDS_CONTROL_3, pcomp->szSource);
  2002. EXITPROC(2, "DS GenerateHtmlControl!");
  2003. }
  2004. void CActiveDesktop::_GenerateHtmlComponent(COMPONENTA *pcomp)
  2005. {
  2006. ENTERPROC(2, "DS GenerateHtmlComponent(pcomp=%08X)");
  2007. switch(pcomp->iComponentType)
  2008. {
  2009. case COMP_TYPE_PICTURE:
  2010. _GenerateHtmlPicture(pcomp);
  2011. break;
  2012. case COMP_TYPE_HTMLDOC:
  2013. _GenerateHtmlDoc(pcomp);
  2014. break;
  2015. case COMP_TYPE_WEBSITE:
  2016. _GenerateHtmlSite(pcomp);
  2017. break;
  2018. case COMP_TYPE_CONTROL:
  2019. _GenerateHtmlControl(pcomp);
  2020. break;
  2021. }
  2022. EXITPROC(2, "DS GenerateHtmlComponent!");
  2023. }
  2024. void CActiveDesktop::_GenerateHtmlFooter(void)
  2025. {
  2026. ENTERPROC(2, "DS GenerateHtmlFooter()");
  2027. //
  2028. // Write out the deskmovr object.
  2029. //
  2030. if (!_fNoDeskMovr)
  2031. {
  2032. TCHAR szDeskMovrFile[MAX_PATH];
  2033. if (GetWindowsDirectory(szDeskMovrFile, ARRAYSIZE(szDeskMovrFile)) != 0)
  2034. {
  2035. lstrcat(szDeskMovrFile, DESKMOVR_FILENAME);
  2036. _WriteHtmlFromFile(szDeskMovrFile);
  2037. }
  2038. }
  2039. //
  2040. // Write out the concluding HTML tags.
  2041. //
  2042. if (_pReadFileObjHtmlBkgd)
  2043. {
  2044. if (_fNeedBodyEnd)
  2045. { // We had introduced the <BODY> tag by ourselves.
  2046. _WriteHtmlFromId(IDS_BODY_END2);
  2047. _fNeedBodyEnd = FALSE;
  2048. }
  2049. _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, -1, -1);
  2050. delete _pReadFileObjHtmlBkgd; //Close the file and cleanup!
  2051. _pReadFileObjHtmlBkgd = NULL;
  2052. }
  2053. else
  2054. {
  2055. _WriteHtmlFromId(IDS_BODY_END);
  2056. }
  2057. EXITPROC(2, "DS GenerateHtmlFooter!");
  2058. }
  2059. void CActiveDesktop::_GenerateHtml(void)
  2060. {
  2061. ENTERPROC(2, "DS GenerateHtml()");
  2062. TCHAR szHtmlFile[MAX_PATH];
  2063. //
  2064. // Compute the filename.
  2065. //
  2066. szHtmlFile[0] = TEXT('\0');
  2067. if (SUCCEEDED(GetPerUserFileName(szHtmlFile, ARRAYSIZE(szHtmlFile), DESKTOPHTML_FILENAME)))
  2068. {
  2069. // Recreate the file.
  2070. _hFileHtml = CreateFile(szHtmlFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  2071. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, NULL);
  2072. if (_hFileHtml != INVALID_HANDLE_VALUE)
  2073. {
  2074. _GenerateHtmlHeader();
  2075. if (_co.fEnableComponents && _hdsaComponent && DSA_GetItemCount(_hdsaComponent) &&
  2076. !SHRestricted(REST_NODESKCOMP))
  2077. {
  2078. int i;
  2079. for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
  2080. {
  2081. COMPONENTA comp;
  2082. comp.dwSize = sizeof(COMPONENTA);
  2083. if ((DSA_GetItem(_hdsaComponent, i, &comp) != -1) && (comp.fChecked))
  2084. {
  2085. _GenerateHtmlComponent(&comp);
  2086. }
  2087. }
  2088. }
  2089. _GenerateHtmlFooter();
  2090. CloseHandle(_hFileHtml);
  2091. SetDesktopFlags(COMPONENTS_DIRTY, 0);
  2092. }
  2093. else
  2094. {
  2095. // 99/05/19 #340772 vtan: If unable to open desktop.htt it's probably
  2096. // in use by another process or task (perhaps trident is trying to
  2097. // render it). In this case mark it dirty so that it will get recreated
  2098. // - yet again but this time with more current data.
  2099. SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
  2100. }
  2101. }
  2102. EXITPROC(2, "DS GenerateHtml!");
  2103. }
  2104. HRESULT CActiveDesktop::GenerateDesktopItemHtml(LPCWSTR pwszFileName, COMPONENT *pcomp, DWORD dwReserved)
  2105. {
  2106. HRESULT hres = E_FAIL;
  2107. ENTERPROC(2, "DS GenerateComponentHtml(pcomp=%08X)", pcomp);
  2108. LPTSTR pszFileName;
  2109. //Check for the input parameters
  2110. if (!pwszFileName || (pcomp && (pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT))))
  2111. return E_INVALIDARG;
  2112. ASSERT(!dwReserved); // These should be 0
  2113. pszFileName = (LPTSTR)pwszFileName;
  2114. //
  2115. // Create the file.
  2116. //
  2117. _hFileHtml = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  2118. FILE_ATTRIBUTE_NORMAL, NULL);
  2119. if (_hFileHtml != INVALID_HANDLE_VALUE)
  2120. {
  2121. _fNoDeskMovr = TRUE;
  2122. _fBackgroundHtml = TRUE;
  2123. //Check if we need to add a component
  2124. if (pcomp)
  2125. {
  2126. COMPONENTA CompA;
  2127. CompA.dwSize = sizeof(CompA);
  2128. WideCompToMultiComp(pcomp, &CompA);
  2129. _fSingleItem = TRUE;
  2130. _GenerateHtmlHeader();
  2131. _GenerateHtmlComponent(&CompA);
  2132. _GenerateHtmlFooter();
  2133. _fSingleItem = FALSE;
  2134. }
  2135. else
  2136. {
  2137. //generate just the header and the footer with proper
  2138. // wallpaper and pattern info!
  2139. _GenerateHtmlHeader();
  2140. _GenerateHtmlFooter();
  2141. }
  2142. _fBackgroundHtml = FALSE;
  2143. _fNoDeskMovr = FALSE;
  2144. CloseHandle(_hFileHtml);
  2145. hres = S_OK;
  2146. }
  2147. _hFileHtml = NULL;
  2148. EXITPROC(2, "DS GenerateComponentHtml=%d", hres);
  2149. return hres;
  2150. }
  2151. //
  2152. // AddUrl
  2153. //
  2154. //
  2155. HRESULT CActiveDesktop::AddUrl(HWND hwnd, LPCWSTR pszSourceW, LPCOMPONENT pcomp, DWORD dwFlags)
  2156. {
  2157. LPTSTR pszExt;
  2158. HRESULT fOkay = TRUE;
  2159. BOOL fExtIsCdf,fPathIsUrl;
  2160. BOOL fSubscribed = FALSE;
  2161. COMPONENT compLocal;
  2162. COMPONENTA compA;
  2163. TCHAR szSource[INTERNET_MAX_URL_LENGTH];
  2164. // 98/08/28 vtan #202777: The following if statement sanitizes parameters
  2165. // passed to AddUrl(). The statements following the "||" are executed
  2166. // despite the for pcomp against NULL. This causes an access violation
  2167. // and an exception to be thrown.
  2168. #if 0
  2169. //Check for the input parameters.
  2170. if (!pszSourceW || (pcomp &&
  2171. ((pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT))) ||
  2172. ((pcomp->dwSize == sizeof(*pcomp)) && !VALIDATESTATE(pcomp->dwCurItemState))))
  2173. return E_INVALIDARG;
  2174. #else
  2175. // The following performs the same comparison but is spread into three
  2176. // separate comparisons. As performance is not a critical issue here
  2177. // but correctness is this makes the tests clear and understandable.
  2178. // The invalid conditions are described.
  2179. // Validate input parameters. Invalid parameters are:
  2180. // 1) NULL pszSourceW
  2181. // 2) pcomp->dwSize for a COMPONENT struct but invalid pcomp->dwCurItemState
  2182. // 3) pcomp->dwSize is not for a COMPONENT struct nor for a IE4COMPONENT struct
  2183. if (pszSourceW == NULL)
  2184. return(E_INVALIDARG);
  2185. if (pcomp != NULL)
  2186. {
  2187. if ((pcomp->dwSize == sizeof(*pcomp)) && !VALIDATESTATE(pcomp->dwCurItemState))
  2188. return(E_INVALIDARG);
  2189. if ((pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT)))
  2190. return(E_INVALIDARG);
  2191. }
  2192. #endif
  2193. // Catch folks that call our API's to add components and prevent them from doing
  2194. // so if the restriction is in place.
  2195. if (SHIsRestricted(NULL, REST_NOADDDESKCOMP))
  2196. return E_ACCESSDENIED;
  2197. if (!pcomp)
  2198. {
  2199. pcomp = &compLocal;
  2200. pcomp->dwSize = sizeof(compLocal);
  2201. pcomp->dwCurItemState = IS_NORMAL;
  2202. }
  2203. // Attempt to come up with a reasonable window handle if none is passed in. ParseDesktopComponent
  2204. // will fail to attempt to create a subscription if a NULL window handle is passed in.
  2205. if (!hwnd)
  2206. hwnd = GetLastActivePopup(GetActiveWindow());
  2207. compA.dwSize = sizeof(compA);
  2208. compA.dwCurItemState = (pcomp->dwSize != sizeof(IE4COMPONENT)) ? pcomp->dwCurItemState : IS_NORMAL;
  2209. SHUnicodeToTChar(pszSourceW, szSource, ARRAYSIZE(szSource));
  2210. pszExt = PathFindExtension(szSource);
  2211. fExtIsCdf = lstrcmpi(pszExt, TEXT(".CDF")) == 0;
  2212. fPathIsUrl = PathIsURL(szSource) && !UrlIsFileUrl(szSource);
  2213. if (FindComponent(szSource, (g_pActiveDesk ? g_pActiveDesk : this)))
  2214. {
  2215. if (dwFlags & ADDURL_SILENT)
  2216. {
  2217. lstrcpy(compA.szSource, szSource);
  2218. MultiCompToWideComp(&compA, pcomp);
  2219. RemoveDesktopItem(pcomp, 0);
  2220. }
  2221. else
  2222. {
  2223. // This is a long string. So,...
  2224. TCHAR szMsg[512];
  2225. TCHAR szMsg2[256];
  2226. TCHAR szTitle[128];
  2227. LoadString(HINST_THISDLL, IDS_COMP_EXISTS, szMsg, ARRAYSIZE(szMsg));
  2228. LoadString(HINST_THISDLL, IDS_COMP_EXISTS_2, szMsg2, ARRAYSIZE(szMsg2));
  2229. StrCatBuff(szMsg, szMsg2, ARRAYSIZE(szMsg));
  2230. LoadString(HINST_THISDLL, IDS_COMP_TITLE, szTitle, ARRAYSIZE(szTitle));
  2231. MessageBox(hwnd, szMsg, szTitle, MB_OK);
  2232. fOkay = FALSE;
  2233. }
  2234. }
  2235. if (fOkay && CheckForExistingSubscription(szSource))
  2236. {
  2237. if ((dwFlags & ADDURL_SILENT) ||
  2238. (ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_SUBSCRIBED),
  2239. MAKEINTRESOURCE(IDS_COMP_TITLE), MB_YESNO) == IDYES))
  2240. {
  2241. DeleteFromSubscriptionList(szSource);
  2242. }
  2243. else
  2244. {
  2245. fOkay = FALSE;
  2246. }
  2247. }
  2248. if (fOkay)
  2249. {
  2250. if (fPathIsUrl || fExtIsCdf)
  2251. {
  2252. HRESULT hr;
  2253. IProgressDialog * pProgressDlg = NULL;
  2254. DECLAREWAITCURSOR;
  2255. // 98/12/16 vtan #250938: Cannot add new components that are not
  2256. // local with ICW run to completion. Tell the user and launch ICW.
  2257. if (!IsICWCompleted())
  2258. {
  2259. if ((dwFlags & ADDURL_SILENT) == 0)
  2260. {
  2261. ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_ICW_ADD), MAKEINTRESOURCE(IDS_COMP_ICW_TITLE), MB_OK);
  2262. LaunchICW();
  2263. }
  2264. fOkay = FALSE;
  2265. }
  2266. else
  2267. {
  2268. SetWaitCursor();
  2269. // ParseDesktopComponent can hang for a long time, we need some sort of progress
  2270. // UI up before we call it.
  2271. if (!(dwFlags & ADDURL_SILENT) && !fExtIsCdf)
  2272. {
  2273. if (pProgressDlg = CProgressDialog_CreateInstance(IDS_COMP_TITLE, IDA_ISEARCH, g_hinst))
  2274. {
  2275. TCHAR szConnecting[80];
  2276. LoadString(HINST_THISDLL, IDS_CONNECTING, szConnecting, ARRAYSIZE(szConnecting));
  2277. pProgressDlg->SetLine(1, szConnecting, FALSE, NULL);
  2278. pProgressDlg->SetLine(2, szSource, TRUE, NULL);
  2279. pProgressDlg->StartProgressDialog(hwnd, NULL, PROGDLG_AUTOTIME | PROGDLG_NOPROGRESSBAR, NULL);
  2280. }
  2281. }
  2282. hr = ParseDesktopComponent(hwnd, szSource, pcomp);
  2283. if (pProgressDlg)
  2284. {
  2285. pProgressDlg->StopProgressDialog();
  2286. fOkay = !pProgressDlg->HasUserCancelled(); // User may have cancelled the progress dialog
  2287. pProgressDlg->Release();
  2288. }
  2289. ResetWaitCursor();
  2290. if (hr == S_FALSE) // User cancelled operation via subscription download dialog
  2291. fOkay = FALSE;
  2292. if (fOkay)
  2293. {
  2294. if (SUCCEEDED(hr))
  2295. {
  2296. //
  2297. // Convert ed's wide thinggy to multi.
  2298. //
  2299. WideCompToMultiComp(pcomp, &compA);
  2300. fSubscribed = TRUE;
  2301. }
  2302. else if (!fExtIsCdf)
  2303. {
  2304. //
  2305. // This is some non-CDF url.
  2306. //
  2307. CreateComponent(&compA, szSource);
  2308. }
  2309. else
  2310. {
  2311. //
  2312. // We barfed on a CDF, bring up an error message.
  2313. //
  2314. if (!(dwFlags & ADDURL_SILENT))
  2315. {
  2316. ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_BADURL),
  2317. MAKEINTRESOURCE(IDS_COMP_TITLE), MB_OK);
  2318. }
  2319. fOkay = FALSE;
  2320. }
  2321. }
  2322. }
  2323. }
  2324. else
  2325. {
  2326. //
  2327. // This is just some local file.
  2328. //
  2329. CreateComponent(&compA, szSource);
  2330. }
  2331. }
  2332. if (fOkay && fPathIsUrl && !fSubscribed)
  2333. {
  2334. //
  2335. // Run subscription code on URLs if CDF code hasn't already.
  2336. //
  2337. if (dwFlags & ADDURL_SILENT)
  2338. {
  2339. ISubscriptionMgr *psm;
  2340. if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  2341. CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&psm)))
  2342. {
  2343. //We need to zero init this structure except the cbSize field.
  2344. SUBSCRIPTIONINFO siDefault = {sizeof(SUBSCRIPTIONINFO)};
  2345. //This field is already initialized above.
  2346. //siDefault.cbSize = sizeof(siDefault);
  2347. psm->CreateSubscription(hwnd, szSource, szSource, CREATESUBS_NOUI, SUBSTYPE_DESKTOPURL, &siDefault);
  2348. psm->UpdateSubscription(szSource);
  2349. psm->Release();
  2350. }
  2351. }
  2352. else
  2353. {
  2354. HRESULT hres = CreateSubscriptionsWizard(SUBSTYPE_DESKTOPURL, szSource, NULL, hwnd);
  2355. if (!SUCCEEDED(hres)) //Some error, or the user chose Cancel - we should fail.
  2356. {
  2357. ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_BADSUBSCRIBE),
  2358. MAKEINTRESOURCE(IDS_COMP_TITLE), MB_OK);
  2359. }
  2360. fOkay = (hres == S_OK); //could be S_FALSE, which means CreateSubscription was cancelled
  2361. //so we don't display the above error, but we don't create the DTI
  2362. }
  2363. }
  2364. MultiCompToWideComp(&compA, pcomp);
  2365. if (fOkay)
  2366. {
  2367. AddDesktopItem(pcomp, 0);
  2368. return S_OK;
  2369. }
  2370. else
  2371. {
  2372. return E_FAIL;
  2373. }
  2374. }
  2375. void CActiveDesktop::_SaveSettings(DWORD dwFlags)
  2376. {
  2377. ENTERPROC(2, "DS SaveSettings()");
  2378. if (dwFlags & AD_APPLY_SAVE)
  2379. {
  2380. // Don't ever modify the safemode settings
  2381. TCHAR lpszDeskcomp[MAX_PATH];
  2382. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
  2383. if (!StrStr(lpszDeskcomp, REG_DESKCOMP_SAFEMODE_SUFFIX))
  2384. {
  2385. //
  2386. // Write out registry settings.
  2387. //
  2388. _SaveWallpaper();
  2389. _SaveComponents();
  2390. _SavePattern(SAVE_PATTERN_NAME);
  2391. }
  2392. };
  2393. if (dwFlags & AD_APPLY_HTMLGEN)
  2394. {
  2395. //We need to generate the Patten.bmp file too!
  2396. _SavePattern(GENERATE_PATTERN_FILE);
  2397. //
  2398. // Write out HTML file.
  2399. //
  2400. _GenerateHtml();
  2401. }
  2402. // The 3rd largest hang found by WindowsUpdate crash uploader has been that the Desktop hwnd hangs
  2403. // and the display CPYU
  2404. #define SENDMESSAGE_TIMEOUT (10 * 1000)
  2405. if (dwFlags & AD_APPLY_REFRESH)
  2406. {
  2407. HWND hwndShell = GetShellWindow();
  2408. SHELLSTATE ss = {0};
  2409. DWORD_PTR pdwTemp = 0;
  2410. SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
  2411. BOOL fWasActiveDesktop = BOOLIFY(ss.fDesktopHTML);
  2412. BOOL fIsActiveDesktop = BOOLIFY(_co.fActiveDesktop);
  2413. if (fIsActiveDesktop && !IsICWCompleted())
  2414. TBOOL(DisableUndisplayableComponents(this));
  2415. if (fIsActiveDesktop != fWasActiveDesktop)
  2416. {
  2417. if (hwndShell)
  2418. {
  2419. SendMessageTimeout(hwndShell, WM_WININICHANGE, SPI_SETDESKWALLPAPER, (LPARAM)TEXT("ToggleDesktop"), SMTO_NORMAL, SENDMESSAGE_TIMEOUT, &pdwTemp);
  2420. }
  2421. //Force a SHRefresh with this dummy call
  2422. SHGetSetSettings(NULL, 0, TRUE);
  2423. }
  2424. else if (fIsActiveDesktop && hwndShell)
  2425. {
  2426. //See if we can simply make the changes dynamically instead of refreshing the whole page
  2427. // 98/09/22 #182982 vtan: Use dynamic HTML to refresh only if specifically told by a flag.
  2428. if (_fUseDynamicHtml && (dwFlags & AD_APPLY_DYNAMICREFRESH))
  2429. {
  2430. SendMessageTimeout(hwndShell, DTM_MAKEHTMLCHANGES, (WPARAM)0, (LPARAM)0L, SMTO_NORMAL, SENDMESSAGE_TIMEOUT, &pdwTemp);
  2431. }
  2432. else
  2433. {
  2434. //Can't use dynamic html. We have to refresh the whole page.
  2435. SendMessageTimeout(hwndShell, WM_WININICHANGE, SPI_SETDESKWALLPAPER,
  2436. (LPARAM)((dwFlags & AD_APPLY_BUFFERED_REFRESH) ? c_szBufferedRefresh : c_szRefreshDesktop), SMTO_NORMAL, SENDMESSAGE_TIMEOUT, &pdwTemp);
  2437. }
  2438. }
  2439. _fUseDynamicHtml = TRUE;
  2440. }
  2441. //
  2442. // Data is no longer dirty.
  2443. //
  2444. _fDirty = FALSE;
  2445. _fWallpaperDirty = FALSE;
  2446. _fWallpaperChangedDuringInit = FALSE;
  2447. _fPatternDirty = FALSE;
  2448. EXITPROC(2, "DS SaveSettings!");
  2449. }
  2450. ULONG CActiveDesktop::AddRef(void)
  2451. {
  2452. ENTERPROC(1, "DS AddRef()");
  2453. _cRef++;
  2454. EXITPROC(1, "DS AddRef=%d", _cRef);
  2455. return _cRef;
  2456. }
  2457. // pwzPath: The path where the temp files go (%userprofile%/windows)
  2458. // pszFile: The original file name ("Joe's Vacation Picture.jpg")
  2459. // pszInUse: The wallpaper in use.
  2460. HRESULT _DeleteUnusedTempFiles(IN LPCWSTR pwzPath, IN LPCTSTR pszFile)
  2461. {
  2462. HRESULT hr = S_OK;
  2463. TCHAR szTemplate[MAX_PATH];
  2464. WIN32_FIND_DATA findFileData;
  2465. LPCTSTR pszFileName = PathFindFileName(pszFile);
  2466. wnsprintf(szTemplate, ARRAYSIZE(szTemplate), TEXT("%ls\\Wallpaper*.bmp"), pwzPath);
  2467. HANDLE hFindFile = FindFirstFile(szTemplate, &findFileData);
  2468. if (INVALID_HANDLE_VALUE != hFindFile)
  2469. {
  2470. do
  2471. {
  2472. // Is this an old template? (Different name than we are currently using?
  2473. // Also, don't delete the wallpaper that is in use.
  2474. if (StrCmpI(findFileData.cFileName, pszFileName))
  2475. {
  2476. DeleteFile(szTemplate); // Yes so delete it.
  2477. }
  2478. }
  2479. while (FindNextFile(hFindFile, &findFileData));
  2480. FindClose(hFindFile);
  2481. }
  2482. return hr;
  2483. }
  2484. // nIndex: The file to try.
  2485. // pszInUse: This is the file we should skip because it's in use.
  2486. // pwzPath: On the way in, this is the selected wallpaper to convert.
  2487. // On the way out, this is is the converted file.
  2488. HRESULT _ConvertToTempFile(IN int nIndex, IN LPCWSTR pwzTempPath, IN LPTSTR pwzPath, IN int cchSize)
  2489. {
  2490. HRESULT hr = E_FAIL;
  2491. WCHAR wzNewFile[MAX_PATH];
  2492. LPCWSTR pszFileName = PathFindFileName(pwzPath);
  2493. if (pszFileName)
  2494. {
  2495. wnsprintfW(wzNewFile, ARRAYSIZE(wzNewFile), L"%s\\Wallpaper%d.bmp", pwzTempPath, nIndex);
  2496. hr = SHConvertGraphicsFile(pwzPath, wzNewFile, SHCGF_REPLACEFILE);
  2497. // This may fail for one of many reasons, and we just fall back to the old behavior if it fails.
  2498. // This may fail if they don't have write permission of the disk, run out of disk space, or
  2499. // this is a file type that we don't support.
  2500. if (SUCCEEDED(hr))
  2501. {
  2502. StrCpyNW(pwzPath, wzNewFile, cchSize);
  2503. }
  2504. }
  2505. return hr;
  2506. }
  2507. BOOL _DoFileWriteTimesMatch(IN LPCWSTR pszFile1, IN LPFILETIME pftLastWrite2)
  2508. {
  2509. BOOL fMatch = FALSE;
  2510. HANDLE hFile1 = CreateFile(pszFile1, GENERIC_READ, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, NULL);
  2511. if (INVALID_HANDLE_VALUE != hFile1)
  2512. {
  2513. FILETIME ftLastWrite1;
  2514. if (GetFileTime(hFile1, NULL, NULL, &ftLastWrite1))
  2515. {
  2516. fMatch = ((0 == CompareFileTime(&ftLastWrite1, pftLastWrite2)) ? TRUE : FALSE);
  2517. }
  2518. CloseHandle(hFile1);
  2519. }
  2520. return fMatch;
  2521. }
  2522. // pszFile: On the way in, this will contain the full path to the original file.
  2523. // On the way out, if we succeed, it will be modified to the temp file
  2524. // that is the converted equivalent of the file on the way in.
  2525. HRESULT CActiveDesktop::_ConvertFileToTempBitmap(IN LPWSTR pszFile, IN int cchSize)
  2526. {
  2527. HRESULT hr = E_FAIL;
  2528. WCHAR wzPath[MAX_PATH];
  2529. if (S_OK == SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wzPath) &&
  2530. PathAppend(wzPath, TEXT("Microsoft")))
  2531. {
  2532. WCHAR szOriginalFile[MAX_PATH];
  2533. CreateDirectoryW(wzPath, NULL); // Create this since it may not exist.
  2534. StrCpyNW(szOriginalFile, pszFile, ARRAYSIZE(szOriginalFile));
  2535. // Let's try the modified names to come up with something we can use.
  2536. for (int nIndex = 1; FAILED(hr) && (nIndex < 100); nIndex++)
  2537. {
  2538. hr = _ConvertToTempFile(nIndex, wzPath, pszFile, cchSize);
  2539. }
  2540. if (SUCCEEDED(hr))
  2541. {
  2542. _DeleteUnusedTempFiles(wzPath, pszFile);
  2543. }
  2544. }
  2545. return hr;
  2546. }
  2547. #define SZ_REGKEY_CONTROLPANEL_DESKTOP TEXT("Control Panel\\Desktop")
  2548. #define SZ_REGVALUE_CONVERTED_WALLPAPER TEXT("ConvertedWallpaper")
  2549. #define SZ_REGVALUE_ORIGINAL_WALLPAPER TEXT("OriginalWallpaper") // We store this to find when someone changed the wallpaper around us
  2550. #define SZ_REGVALUE_WALLPAPER TEXT("Wallpaper")
  2551. #define SZ_REGVALUE_CONVERTED_WP_LASTWRITE TEXT("ConvertedWallpaper Last WriteTime")
  2552. HRESULT CActiveDesktop::_SaveTempWallpaperSettings(void)
  2553. {
  2554. HRESULT hr = E_FAIL;
  2555. // When we converted a non-.BMP wallpaper to a .bmp temp file,
  2556. // we keep the name of the original wallpaper path stored in _szSelectedWallpaper.
  2557. // We need to save that.
  2558. if (_szSelectedWallpaper)
  2559. {
  2560. hr = S_OK;
  2561. DWORD cbSize = sizeof(_szSelectedWallpaper[0]) * (lstrlen(_szSelectedWallpaper) + 1);
  2562. Str_SetPtr(&_pszOrigLastApplied, _szSelectedWallpaper);
  2563. // ISSUE: CONVERTED and ORIGINAL are backwards, but we shipped beta1 like this so we can't change it... blech
  2564. DWORD dwError = SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CONVERTED_WALLPAPER, REG_SZ, _szSelectedWallpaper, cbSize);
  2565. hr = HRESULT_FROM_WIN32(dwError);
  2566. if (SUCCEEDED(hr))
  2567. {
  2568. Str_SetPtrW(&_pszWallpaperInUse, _szSelectedWallpaper);
  2569. cbSize = sizeof(_szSelectedWallpaperConverted[0]) * (lstrlen(_szSelectedWallpaperConverted) + 1);
  2570. Str_SetPtr(&_pszOrigLastApplied, _szSelectedWallpaper);
  2571. dwError = SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_ORIGINAL_WALLPAPER, REG_SZ, (void *) _szSelectedWallpaperConverted, cbSize);
  2572. hr = HRESULT_FROM_WIN32(dwError);
  2573. if (SUCCEEDED(hr))
  2574. {
  2575. dwError = SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_WALLPAPER, REG_SZ, (void *) _szSelectedWallpaperConverted, cbSize);
  2576. hr = HRESULT_FROM_WIN32(dwError);
  2577. }
  2578. // Set date/time stamp of the original file (_szSelectedWallpaper) so we can later determine if the user changed the original.
  2579. if (_szSelectedWallpaper[0])
  2580. {
  2581. HANDLE hFile = CreateFile(_szSelectedWallpaper, GENERIC_READ, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
  2582. NULL, OPEN_EXISTING, 0, NULL);
  2583. if (INVALID_HANDLE_VALUE != hFile)
  2584. {
  2585. if (GetFileTime(hFile, NULL, NULL, &_ftLastWrite))
  2586. {
  2587. dwError = SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CONTROLPANEL_DESKTOP, SZ_REGVALUE_CONVERTED_WP_LASTWRITE, REG_BINARY, &_ftLastWrite, sizeof(_ftLastWrite));
  2588. hr = HRESULT_FROM_WIN32(dwError);
  2589. }
  2590. CloseHandle(hFile);
  2591. }
  2592. }
  2593. else
  2594. {
  2595. ULARGE_INTEGER * puli = (ULARGE_INTEGER *) &_ftLastWrite;
  2596. puli->QuadPart = 0;
  2597. }
  2598. }
  2599. }
  2600. return hr;
  2601. }
  2602. HRESULT CActiveDesktop::ApplyChanges(DWORD dwFlags)
  2603. {
  2604. HRESULT hres = E_FAIL;
  2605. ENTERPROC(1, "DS Apply(dwFlags=%08X)", dwFlags);
  2606. BOOL fActiveDesktop = FALSE; // default to disable active desktop
  2607. // determine if we should enable active desktop
  2608. if (SHRestricted(REST_FORCEACTIVEDESKTOPON))
  2609. {
  2610. // if policy requires active desktop, then use that
  2611. fActiveDesktop = TRUE;
  2612. }
  2613. else
  2614. {
  2615. // if desktop components are locked -> active desktop is on
  2616. DWORD dwDesktopFlags = GetDesktopFlags();
  2617. if (dwDesktopFlags & COMPONENTS_LOCKED)
  2618. {
  2619. fActiveDesktop = TRUE;
  2620. }
  2621. else
  2622. {
  2623. // if desktop icons are hidden -> active desktop is on
  2624. SHELLSTATE ss;
  2625. SHGetSetSettings(&ss, SSF_HIDEICONS, FALSE);
  2626. if (ss.fHideIcons)
  2627. {
  2628. fActiveDesktop = TRUE;
  2629. }
  2630. }
  2631. }
  2632. // Convert the background if needed.
  2633. // if background is not a .bmp --> active desktop is on if we can't auto-convert
  2634. if (!IsNormalWallpaper(_szSelectedWallpaper))
  2635. {
  2636. BOOL fBitmapWallpaper = FALSE;
  2637. // create the factory
  2638. IShellImageDataFactory* pImgFact;
  2639. if (SUCCEEDED(CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellImageDataFactory, &pImgFact))))
  2640. {
  2641. IShellImageData * pImage;
  2642. if (SUCCEEDED(pImgFact->CreateImageFromFile(_szSelectedWallpaper, &pImage)))
  2643. {
  2644. // PERF: cache decoded data
  2645. if (SUCCEEDED(pImage->Decode(SHIMGDEC_DEFAULT, 0, 0)))
  2646. {
  2647. if (S_FALSE == pImage->IsTransparent() &&
  2648. S_FALSE == pImage->IsAnimated())
  2649. {
  2650. StrCpyNW(_szSelectedWallpaperConverted, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaperConverted));
  2651. HRESULT hrConvert = _ConvertFileToTempBitmap(_szSelectedWallpaperConverted, ARRAYSIZE(_szSelectedWallpaperConverted));
  2652. if (SUCCEEDED(hrConvert))
  2653. {
  2654. if (S_OK == hrConvert) // if we actually had to convert (we may have already done the conversion)
  2655. {
  2656. _fDirty = TRUE; // if we converted, then we have changed the background and must persist it
  2657. _SaveTempWallpaperSettings();
  2658. StrCpyNW(_szSelectedWallpaper, _szSelectedWallpaperConverted, ARRAYSIZE(_szSelectedWallpaper));
  2659. }
  2660. fBitmapWallpaper = TRUE;
  2661. }
  2662. }
  2663. }
  2664. pImage->Release();
  2665. }
  2666. pImgFact->Release();
  2667. }
  2668. if (!fBitmapWallpaper)
  2669. {
  2670. fActiveDesktop = TRUE;
  2671. }
  2672. }
  2673. if (!fActiveDesktop)
  2674. {
  2675. // if any elements are checked --> active desktop is on
  2676. if (_hdsaComponent)
  2677. {
  2678. INT cComponents = DSA_GetItemCount(_hdsaComponent);
  2679. for (INT i = 0; i < cComponents; i++)
  2680. {
  2681. COMPONENTA* pComponent = (COMPONENTA*)DSA_GetItemPtr(_hdsaComponent, i);
  2682. if (pComponent && pComponent->fChecked)
  2683. {
  2684. fActiveDesktop = TRUE;
  2685. break;
  2686. }
  2687. }
  2688. }
  2689. }
  2690. if (_co.fActiveDesktop != fActiveDesktop)
  2691. {
  2692. _co.fActiveDesktop = fActiveDesktop;
  2693. _fDirty = TRUE;
  2694. }
  2695. if (dwFlags & AD_APPLY_FORCE)
  2696. {
  2697. _fDirty = TRUE;
  2698. _fWallpaperDirty = TRUE;
  2699. _fPatternDirty = TRUE;
  2700. }
  2701. if (_fDirty || _fWallpaperChangedDuringInit)
  2702. {
  2703. _SaveSettings(dwFlags);
  2704. }
  2705. hres = S_OK;
  2706. EXITPROC(1, "DS ApplyChanges=%d", hres);
  2707. return hres;
  2708. }
  2709. ULONG CActiveDesktop::Release(void)
  2710. {
  2711. UINT nRet = --_cRef;
  2712. ENTERPROC(1, "DS Release()");
  2713. if (_cRef == 0)
  2714. {
  2715. delete this;
  2716. }
  2717. EXITPROC(1, "DS Release=%d", nRet);
  2718. return nRet;
  2719. }
  2720. CActiveDesktop::CActiveDesktop()
  2721. {
  2722. _cRef = 1;
  2723. _fNoDeskMovr = FALSE;
  2724. _fBackgroundHtml = FALSE;
  2725. _fUseDynamicHtml = TRUE;
  2726. _hdsaComponent = NULL;
  2727. _pszScheme = NULL;
  2728. DllAddRef();
  2729. }
  2730. CActiveDesktop::~CActiveDesktop()
  2731. {
  2732. if (_hdsaComponent)
  2733. {
  2734. DSA_Destroy(_hdsaComponent);
  2735. }
  2736. if (_pszScheme)
  2737. {
  2738. LocalFree((HANDLE)_pszScheme);
  2739. }
  2740. DllRelease();
  2741. }
  2742. HRESULT CActiveDesktop::GetWallpaper(LPWSTR pwszWallpaper, UINT cchWallpaper, DWORD dwReserved)
  2743. {
  2744. HRESULT hres = E_INVALIDARG;
  2745. ENTERPROC(1, "DS GetWallpaper(pszWallpaper=%08X,cchWallpaper=%d)", pwszWallpaper, cchWallpaper);
  2746. ASSERT(!dwReserved); // These should be 0
  2747. if (pwszWallpaper && cchWallpaper)
  2748. {
  2749. StrCpyN(pwszWallpaper, _szSelectedWallpaper, cchWallpaper);
  2750. if ( cchWallpaper < wcslen(_szSelectedWallpaper) )
  2751. {
  2752. hres = MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_MORE_DATA );
  2753. }
  2754. else
  2755. {
  2756. hres = S_OK;
  2757. }
  2758. }
  2759. else
  2760. {
  2761. TraceMsg(TF_WARNING, "DS GetWallpaper unable to return wallpaper");
  2762. }
  2763. EXITPROC(1, "DS GetWallpaper=%d", hres);
  2764. return hres;
  2765. }
  2766. HRESULT CActiveDesktop::SetWallpaper(LPCWSTR pwszWallpaper, DWORD dwReserved)
  2767. {
  2768. HRESULT hres = E_INVALIDARG;
  2769. WCHAR szTemp[MAX_PATH];
  2770. ASSERT(!dwReserved); // These should be 0
  2771. if (_fPolicyForWPName) // If a policy exists, the caller can not change the wallpaper.
  2772. return S_FALSE;
  2773. if (pwszWallpaper)
  2774. {
  2775. StrCpyN(szTemp, pwszWallpaper, ARRAYSIZE(szTemp));
  2776. PathExpandEnvStringsWrap(szTemp, ARRAYSIZE(szTemp)); // We unexpand only when we persist.
  2777. if (lstrcmp(_szSelectedWallpaper, szTemp) != 0)
  2778. {
  2779. lstrcpyn(_szSelectedWallpaper, szTemp, ARRAYSIZE(_szSelectedWallpaper));
  2780. _fWallpaperDirty = TRUE;
  2781. _fDirty = TRUE;
  2782. _fUseDynamicHtml = FALSE; //Setting wallpaper causes a lot of change; So, can't use dynamic html
  2783. }
  2784. hres = S_OK;
  2785. }
  2786. ENTERPROC(1, "DS SetWallpaper(pszWallpaper=>%s<)", pwszWallpaper ? szTemp : TEXT("(NULL)"));
  2787. EXITPROC(1, "DS SetWallpaper=%d", hres);
  2788. return hres;
  2789. }
  2790. HRESULT CActiveDesktop::GetWallpaperOptions(WALLPAPEROPT *pwpo, DWORD dwReserved)
  2791. {
  2792. HRESULT hres = E_INVALIDARG;
  2793. ENTERPROC(1, "DS GetWallpaperOptions(pwpo=%08X)");
  2794. ASSERT(!dwReserved); // These should be 0
  2795. if ((pwpo) && (pwpo->dwSize == sizeof(*pwpo)))
  2796. {
  2797. *pwpo = _wpo;
  2798. hres = S_OK;
  2799. }
  2800. else
  2801. {
  2802. TraceMsg(TF_WARNING, "DS GetWallpaperOptions could not return options");
  2803. }
  2804. EXITPROC(1, "DS GetWallpaperOptions=%d", hres);
  2805. return hres;
  2806. }
  2807. HRESULT CActiveDesktop::SetWallpaperOptions(LPCWALLPAPEROPT pwpo, DWORD dwReserved)
  2808. {
  2809. HRESULT hres = E_INVALIDARG;
  2810. ENTERPROC(1, "DS SetWallpaperOptions(pwpo=%08X)", pwpo);
  2811. ASSERT(!dwReserved); // These should be 0
  2812. if (_fPolicyForWPStyle) //If a policy exists for wallpaper style, the caller can not change it.
  2813. return S_FALSE;
  2814. if ((pwpo) && (pwpo->dwSize == sizeof(*pwpo)))
  2815. {
  2816. _wpo = *pwpo;
  2817. _fWallpaperDirty = TRUE;
  2818. _fDirty = TRUE;
  2819. _fUseDynamicHtml = FALSE; //Changing wallpaper options causes us to regenerate the whole thing.
  2820. hres = S_OK;
  2821. }
  2822. else
  2823. {
  2824. TraceMsg(TF_WARNING, "DS SetWallpaperOptions could not set options");
  2825. }
  2826. EXITPROC(1, "DS SetWallpaperOptions=%d", hres);
  2827. return hres;
  2828. }
  2829. HRESULT CActiveDesktop::GetPattern(LPWSTR pwszPattern, UINT cchPattern, DWORD dwReserved)
  2830. {
  2831. HRESULT hres = S_OK;
  2832. ENTERPROC(1, "DS GetPattern(psz=%08X,cch=%d)", pwszPattern, cchPattern);
  2833. ASSERT(!dwReserved); // These should be 0
  2834. if (!pwszPattern || (cchPattern == 0))
  2835. return (E_INVALIDARG);
  2836. StrCpyN(pwszPattern, _szSelectedPattern, cchPattern);
  2837. EXITPROC(1, "DS GetPattern=%d", hres);
  2838. return hres;
  2839. }
  2840. HRESULT CActiveDesktop::SetPattern(LPCWSTR pwszPattern, DWORD dwReserved)
  2841. {
  2842. HRESULT hres = E_INVALIDARG;
  2843. LPCTSTR pszPattern;
  2844. ASSERT(!dwReserved); // These should be 0
  2845. if (pwszPattern)
  2846. {
  2847. pszPattern = pwszPattern;
  2848. if (lstrcmp(_szSelectedPattern, pszPattern) != 0)
  2849. {
  2850. lstrcpyn(_szSelectedPattern, pszPattern, ARRAYSIZE(_szSelectedPattern));
  2851. _fPatternDirty = TRUE;
  2852. _fDirty = TRUE;
  2853. _fUseDynamicHtml = FALSE; //Setting pattern causes us to regenerate the whole thing.
  2854. hres = S_OK;
  2855. }
  2856. else
  2857. hres = E_FAIL;
  2858. }
  2859. ENTERPROC(1, "DS SetPattern(psz=>%s<)", pwszPattern ? pszPattern : TEXT("(NULL)"));
  2860. EXITPROC(1, "DS SetPattern=%d", hres);
  2861. return hres;
  2862. }
  2863. HRESULT CActiveDesktop::GetDesktopItemOptions(COMPONENTSOPT *pco, DWORD dwReserved)
  2864. {
  2865. HRESULT hres = E_INVALIDARG;
  2866. ENTERPROC(1, "DS GetComponentsOptions(pco=%08X)", pco);
  2867. ASSERT(!dwReserved); // These should be 0
  2868. if (pco && (pco->dwSize == sizeof(*pco)))
  2869. {
  2870. *pco = _co;
  2871. hres = S_OK;
  2872. }
  2873. else
  2874. {
  2875. TraceMsg(TF_WARNING, "DS GetComponentsOptions unable to return options");
  2876. }
  2877. EXITPROC(1, "DS GetComponentsOptions=%d", hres);
  2878. return hres;
  2879. }
  2880. HRESULT CActiveDesktop::SetDesktopItemOptions(LPCCOMPONENTSOPT pco, DWORD dwReserved)
  2881. {
  2882. HRESULT hres = E_INVALIDARG;
  2883. ENTERPROC(1, "DS SetComponentsOptions(pco=%08X)", pco);
  2884. ASSERT(!dwReserved); // These should be 0
  2885. if (pco && (pco->dwSize == sizeof(*pco)))
  2886. {
  2887. _co = *pco;
  2888. _fDirty = TRUE;
  2889. hres = S_OK;
  2890. }
  2891. else
  2892. {
  2893. TraceMsg(TF_WARNING, "DS SetComponentsOptions unable to set options");
  2894. }
  2895. EXITPROC(1, "DS SetComponentsOptions=%d", hres);
  2896. return hres;
  2897. }
  2898. //
  2899. // SetStateInfo()
  2900. // This function simply sets up the COMPSTATEINFO structure passed using the current
  2901. // position and size from the COMPPOS structure and the itemState passed.
  2902. //
  2903. void SetStateInfo(COMPSTATEINFO *pCompStateInfo, COMPPOS *pCompPos, DWORD dwItemState)
  2904. {
  2905. pCompStateInfo->dwSize = sizeof(*pCompStateInfo);
  2906. pCompStateInfo->iLeft = pCompPos->iLeft;
  2907. pCompStateInfo->iTop = pCompPos->iTop;
  2908. pCompStateInfo->dwWidth = pCompPos->dwWidth;
  2909. pCompStateInfo->dwHeight = pCompPos->dwHeight;
  2910. pCompStateInfo->dwItemState = dwItemState;
  2911. }
  2912. void ConvertCompStruct(COMPONENTA *pCompDest, COMPONENTA *pCompSrc, BOOL fPubToPriv)
  2913. {
  2914. pCompDest -> dwID = pCompSrc -> dwID;
  2915. pCompDest -> iComponentType = pCompSrc -> iComponentType;
  2916. pCompDest -> fChecked = pCompSrc -> fChecked;
  2917. pCompDest -> fDirty = pCompSrc -> fDirty;
  2918. pCompDest -> fNoScroll = pCompSrc -> fNoScroll;
  2919. pCompDest -> cpPos = pCompSrc -> cpPos;
  2920. if (fPubToPriv)
  2921. {
  2922. COMPONENT *pComp = (COMPONENT *)pCompSrc;
  2923. pCompDest->dwSize = sizeof(COMPONENTA);
  2924. SHUnicodeToTChar(pComp->wszSource, pCompDest->szSource, ARRAYSIZE(pCompDest->szSource));
  2925. SHUnicodeToTChar(pComp->wszFriendlyName, pCompDest->szFriendlyName, ARRAYSIZE(pCompDest->szFriendlyName));
  2926. SHUnicodeToTChar(pComp->wszSubscribedURL, pCompDest->szSubscribedURL, ARRAYSIZE(pCompDest->szSubscribedURL));
  2927. //Check to see if the public component is from IE4 app (old size)
  2928. if (pCompSrc->dwSize == sizeof(COMPONENT))
  2929. {
  2930. // Since the dest component is the same size as the most current structure, all fields
  2931. // are valid.
  2932. // CAUTION: The following fields are at a different offset in public and private
  2933. // structures. So, you need to use pcomp instead of pCompSrc for example.
  2934. pCompDest->dwCurItemState = pComp->dwCurItemState;
  2935. pCompDest->csiOriginal = pComp->csiOriginal;
  2936. pCompDest->csiRestored = pComp->csiRestored;
  2937. }
  2938. else
  2939. {
  2940. // Since the size did not match, we assume that this is an older structure.
  2941. // Since the older struct does not have any Original and Restored sizes, let's copy
  2942. // the default values.
  2943. IE4COMPONENT *pIE4Comp = (IE4COMPONENT *)pCompSrc;
  2944. pCompDest->dwCurItemState = IS_NORMAL;
  2945. SetStateInfo(&pCompDest->csiOriginal, &pIE4Comp->cpPos, IS_NORMAL);
  2946. SetStateInfo(&pCompDest->csiRestored, &pIE4Comp->cpPos, IS_NORMAL);
  2947. }
  2948. }
  2949. else
  2950. {
  2951. COMPONENT *pComp = (COMPONENT *)pCompDest;
  2952. if (pCompDest->dwSize != sizeof(COMPONENT))
  2953. pCompDest->dwSize = sizeof(IE4COMPONENT);
  2954. SHTCharToUnicode(pCompSrc->szSource, pComp->wszSource, ARRAYSIZE(pComp->wszSource));
  2955. SHTCharToUnicode(pCompSrc->szFriendlyName, pComp->wszFriendlyName, ARRAYSIZE(pComp->wszFriendlyName));
  2956. SHTCharToUnicode(pCompSrc->szSubscribedURL, pComp->wszSubscribedURL, ARRAYSIZE(pComp->wszSubscribedURL));
  2957. //Check to see if the public component is from IE4 app (old size)
  2958. if (pComp->dwSize == sizeof(COMPONENT))
  2959. {
  2960. // Since the dest component is the same size as the most current structure, all fields
  2961. // are valid.
  2962. // CAUTION: The following fields are at a different offset in public and private
  2963. // structures. So, you need to use pcomp instead of pCompDest for example.
  2964. pComp->dwCurItemState = pCompSrc->dwCurItemState;
  2965. pComp->csiOriginal = pCompSrc->csiOriginal;
  2966. pComp->csiRestored = pCompSrc->csiRestored;
  2967. }
  2968. // else, the dest component is IE4COMPONENT and the additional fields are not there.
  2969. }
  2970. }
  2971. HRESULT CActiveDesktop::_AddDTIWithUIPrivateA(HWND hwnd, LPCCOMPONENT pComp, DWORD dwFlags)
  2972. {
  2973. HRESULT hres = E_FAIL;
  2974. PCWSTR pszUrl = pComp->wszSource;
  2975. int nScheme = GetUrlScheme(pszUrl);
  2976. DWORD dwCurItemState;
  2977. if ((URL_SCHEME_INVALID == nScheme) || (URL_SCHEME_UNKNOWN == nScheme))
  2978. {
  2979. TCHAR szFullyQualified[INTERNET_MAX_URL_LENGTH];
  2980. DWORD cchSize = ARRAYSIZE(szFullyQualified);
  2981. if (SUCCEEDED(ParseURLFromOutsideSource(pszUrl, szFullyQualified, &cchSize, NULL)))
  2982. nScheme = GetUrlScheme(szFullyQualified);
  2983. }
  2984. // Is this URL valid to subscribe to? Did the caller specify they want use
  2985. // to try to subscribe to it?
  2986. if ((URL_SCHEME_FILE != nScheme) && (URL_SCHEME_ABOUT != nScheme) &&
  2987. IsFlagSet(dwFlags, DTI_ADDUI_DISPSUBWIZARD) && hwnd)
  2988. {
  2989. //Create a subscription.
  2990. hres = CreateSubscriptionsWizard(SUBSTYPE_DESKTOPURL, pszUrl, NULL, hwnd);
  2991. if (hres != S_OK)
  2992. {
  2993. return hres;
  2994. }
  2995. }
  2996. //
  2997. // Add the component to the registry.
  2998. //
  2999. // PERF: This function creates a second COM objects.
  3000. // We need to Inline the functionality.
  3001. if (pComp->dwSize == sizeof(IE4COMPONENT))
  3002. dwCurItemState = IS_NORMAL;
  3003. else
  3004. dwCurItemState = pComp->dwCurItemState;
  3005. hres = AddRemoveDesktopComponentNoUI(TRUE, AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH, pszUrl, NULL, pComp->iComponentType,
  3006. pComp->cpPos.iLeft, pComp->cpPos.iTop, pComp->cpPos.dwWidth, pComp->cpPos.dwHeight, TRUE, dwCurItemState) ? S_OK : E_FAIL;
  3007. return hres;
  3008. }
  3009. #define STC_DESKTOPCOMPONENT 0x00000002
  3010. STDAPI SubscribeToCDF(HWND hwndParent, LPCWSTR pwzUrl, DWORD dwCDFTypes);
  3011. HRESULT CActiveDesktop::AddDesktopItemWithUI(HWND hwnd, LPCOMPONENT pComp, DWORD dwFlags)
  3012. {
  3013. HRESULT hres = E_FAIL;
  3014. // We need to support IE4 apps calling with the old component structure too!
  3015. // We use the size field to detect IE4 v/s newer apps!
  3016. if (!pComp ||
  3017. ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))) ||
  3018. ((pComp->dwSize == sizeof(*pComp)) && !VALIDATESTATE(pComp->dwCurItemState)) ||
  3019. ((pComp->iComponentType < 0) || (pComp->iComponentType > COMP_TYPE_MAX))) //Validate the component type
  3020. return E_INVALIDARG;
  3021. // Catch folks that call our API's to add components and prevent them from doing
  3022. // so if the restriction is in place.
  3023. if (SHIsRestricted(NULL, REST_NOADDDESKCOMP))
  3024. return E_ACCESSDENIED;
  3025. // Check if the component already exists.
  3026. BOOL fCompExists = FALSE;
  3027. int cComp;
  3028. GetDesktopItemCount(&cComp, 0);
  3029. int i;
  3030. COMPONENT comp;
  3031. comp.dwSize = sizeof(COMPONENT); //This needs to be initialized for ConvertCompStruc to work!
  3032. COMPONENTA compA;
  3033. TCHAR szSource[INTERNET_MAX_URL_LENGTH];
  3034. SHUnicodeToTChar(pComp->wszSource, szSource, ARRAYSIZE(szSource));
  3035. for (i=0; i<cComp && !fCompExists; i++)
  3036. {
  3037. compA.dwSize = sizeof(compA);
  3038. if (GetComponentPrivate(i, &compA)
  3039. && lstrcmpi(szSource, compA.szSource) == 0)
  3040. {
  3041. fCompExists = TRUE;
  3042. ConvertCompStruct((COMPONENTA *)&comp, &compA, FALSE);
  3043. break;
  3044. }
  3045. }
  3046. BOOL fAskToInstall;
  3047. if (ZoneCheckUrlW(pComp->wszSource, URLACTION_SHELL_INSTALL_DTITEMS, (PUAF_NOUI), NULL) == S_OK)
  3048. {
  3049. fAskToInstall = TRUE;
  3050. }
  3051. else
  3052. {
  3053. fAskToInstall = FALSE;
  3054. }
  3055. if (S_OK != ZoneCheckUrlW(pComp->wszSource, URLACTION_SHELL_INSTALL_DTITEMS, (hwnd ? (PUAF_FORCEUI_FOREGROUND | PUAF_WARN_IF_DENIED) : PUAF_NOUI), NULL))
  3056. return E_ACCESSDENIED;
  3057. BOOL fCompSubDeleted = FALSE;
  3058. SUBSCRIPTIONINFO si = {sizeof(SUBSCRIPTIONINFO)};
  3059. // si.bstrUserName = NULL;
  3060. // si.bstrPassword = NULL;
  3061. // si.bstrFriendlyName = NULL;
  3062. //
  3063. // Confirmation dialog.
  3064. //
  3065. if (hwnd)
  3066. {
  3067. if (fCompExists)
  3068. {
  3069. //Prompt the user to delete the existing ADI.
  3070. // This is a long string. So,...
  3071. TCHAR szMsg[512];
  3072. TCHAR szMsg2[256];
  3073. TCHAR szTitle[128];
  3074. LoadString(HINST_THISDLL, IDS_COMP_EXISTS, szMsg, ARRAYSIZE(szMsg));
  3075. LoadString(HINST_THISDLL, IDS_COMP_EXISTS_2, szMsg2, ARRAYSIZE(szMsg2));
  3076. lstrcat(szMsg, szMsg2);
  3077. LoadString(HINST_THISDLL, IDS_COMP_TITLE, szTitle, ARRAYSIZE(szTitle));
  3078. MessageBox(hwnd, szMsg, szTitle, MB_OK);
  3079. return E_FAIL;
  3080. #if 0
  3081. comp.dwSize = sizeof(comp);
  3082. //Prompt the user to reinstall the ADI.
  3083. if (ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_CONFIRM_ADI_REINSTALL),
  3084. MAKEINTRESOURCE(IDS_COMP_TITLE), MB_YESNO) != IDYES)
  3085. {
  3086. return E_FAIL; //User choses not to install this desktop component!
  3087. }
  3088. else
  3089. {
  3090. ISubscriptionMgr *psm;
  3091. if (SUCCEEDED(hres = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  3092. CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&psm)))
  3093. {
  3094. si.cbSize = sizeof(si);
  3095. si.fUpdateFlags = SUBSINFO_ALLFLAGS;
  3096. //Backup and remove the subscription also
  3097. hres = psm->GetSubscriptionInfo(comp.wszSubscribedURL, &si);
  3098. if (SUCCEEDED(hres))
  3099. {
  3100. hres = RemoveDesktopItem(&comp, 0);
  3101. if (SUCCEEDED(hres))
  3102. {
  3103. psm->DeleteSubscription(comp.wszSubscribedURL, NULL);
  3104. ApplyChanges(AD_APPLY_SAVE);
  3105. fCompSubDeleted = TRUE;
  3106. // Set the new component to be enabled
  3107. pComp->fChecked = TRUE;
  3108. }
  3109. }
  3110. psm->Release();
  3111. }
  3112. else
  3113. {
  3114. TraceMsg(TF_WARNING, "CActiveDesktop::AddDesktopItemWithUI : CoCreateInstance for CLSID_SubscriptionMgr failed.");
  3115. }
  3116. }
  3117. #endif
  3118. }
  3119. else if (fAskToInstall)
  3120. {
  3121. if (ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_CONFIRM_ADD),
  3122. MAKEINTRESOURCE(IDS_INTERNET_EXPLORER), MB_YESNO) != IDYES)
  3123. {
  3124. return E_FAIL; //User choses not to install this desktop component!
  3125. }
  3126. }
  3127. }
  3128. hres = SubscribeToCDF(hwnd, pComp->wszSubscribedURL, STC_DESKTOPCOMPONENT);
  3129. switch(hres)
  3130. {
  3131. case E_INVALIDARG:
  3132. {
  3133. // E_UNEXPECTED is returned from SubscribeToCDFUrlA() when the URL doesn't point to
  3134. // a CDF file, so we assume it's a web page.
  3135. hres = _AddDTIWithUIPrivateA(hwnd, pComp, dwFlags);
  3136. if (hres != S_OK && fCompSubDeleted) // Restore the old component
  3137. {
  3138. hres = AddDesktopItem(&comp, 0);
  3139. if (SUCCEEDED(hres))
  3140. {
  3141. ISubscriptionMgr *psm;
  3142. if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr, NULL,
  3143. CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&psm)))
  3144. {
  3145. si.cbSize = sizeof(si);
  3146. psm->CreateSubscription(hwnd, comp.wszSubscribedURL, si.bstrFriendlyName, CREATESUBS_NOUI, SUBSTYPE_DESKTOPURL, &si);
  3147. psm->Release();
  3148. }
  3149. else
  3150. {
  3151. TraceMsg(TF_WARNING, "CActiveDesktop::AddDesktopItemWithUI : CoCreateInstance for CLSID_SubscriptionMgr failed.");
  3152. }
  3153. }
  3154. }
  3155. ApplyChanges(AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH);
  3156. }
  3157. break;
  3158. case E_ACCESSDENIED:
  3159. // The file was a CDF but didn't contain Desktop Component Information
  3160. if (hwnd)
  3161. {
  3162. TCHAR szMsg[MAX_PATH];
  3163. TCHAR szTitle[MAX_PATH];
  3164. LoadString(HINST_THISDLL, IDS_ADDCOMP_ERROR_CDFNODTI, szMsg, ARRAYSIZE(szMsg));
  3165. LoadString(HINST_THISDLL, IDS_INTERNET_EXPLORER, szTitle, ARRAYSIZE(szTitle));
  3166. MessageBox(hwnd, szMsg, szTitle, MB_OK);
  3167. }
  3168. break;
  3169. case E_UNEXPECTED:
  3170. // This was a CDF but it was misauthored.
  3171. if (hwnd)
  3172. {
  3173. TCHAR szMsg[MAX_PATH];
  3174. TCHAR szTitle[MAX_PATH];
  3175. LoadString(HINST_THISDLL, IDS_ADDCOMP_ERROR_CDFINALID, szMsg, ARRAYSIZE(szMsg));
  3176. LoadString(HINST_THISDLL, IDS_INTERNET_EXPLORER, szTitle, ARRAYSIZE(szTitle));
  3177. MessageBox(hwnd, szMsg, szTitle, MB_OK);
  3178. }
  3179. break;
  3180. default:
  3181. break;
  3182. }
  3183. if (hwnd && SUCCEEDED(hres))
  3184. {
  3185. // If the active desktop is currently OFF, we need to turn it ON
  3186. SHELLSTATE ss = {0};
  3187. SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
  3188. if (!ss.fDesktopHTML)
  3189. {
  3190. COMPONENTSOPT co;
  3191. co.dwSize = sizeof(COMPONENTSOPT);
  3192. GetDesktopItemOptions(&co, 0);
  3193. co.fActiveDesktop = TRUE;
  3194. SetDesktopItemOptions(&co, 0);
  3195. ApplyChanges(AD_APPLY_REFRESH | AD_APPLY_DYNAMICREFRESH);
  3196. }
  3197. }
  3198. if (fCompSubDeleted)
  3199. {
  3200. if (si.bstrUserName)
  3201. {
  3202. SysFreeString(si.bstrUserName);
  3203. }
  3204. if (si.bstrPassword)
  3205. {
  3206. SysFreeString(si.bstrPassword);
  3207. }
  3208. if (si.bstrFriendlyName)
  3209. {
  3210. SysFreeString(si.bstrFriendlyName);
  3211. }
  3212. }
  3213. return hres;
  3214. }
  3215. void RestoreComponent(HDSA hdsaComponents, COMPONENTA * pcomp)
  3216. {
  3217. int i;
  3218. // If we are split then set the bit saying that the listview needs to be adjusted. This is done
  3219. // when we check the state of desktop.htm in EnsureUpdateHtml.
  3220. // Note: Do this only if this component is enabled.
  3221. if ((pcomp->dwCurItemState & IS_SPLIT) && (pcomp->fChecked))
  3222. {
  3223. pcomp->dwCurItemState |= IS_ADJUSTLISTVIEW;
  3224. SetDesktopFlags(COMPONENTS_ZOOMDIRTY, COMPONENTS_ZOOMDIRTY);
  3225. }
  3226. for (i = 0; i < DSA_GetItemCount(hdsaComponents); i++)
  3227. {
  3228. COMPONENTA * pcompT;
  3229. if (pcompT = (COMPONENTA *)DSA_GetItemPtr(hdsaComponents, i))
  3230. {
  3231. // If this component is split/fullscreen and is different from the source component
  3232. // but it is at the same location then it must be on this monitor (work area) so restore it.
  3233. if (ISZOOMED(pcompT) &&
  3234. lstrcmpi(pcomp->szSource, pcompT->szSource) &&
  3235. (pcomp->cpPos.iTop == pcompT->cpPos.iTop) &&
  3236. ((pcomp->cpPos.iLeft + pcomp->cpPos.dwWidth) == (pcompT->cpPos.iLeft + pcompT->cpPos.dwWidth)))
  3237. {
  3238. pcompT->dwCurItemState = pcompT->csiRestored.dwItemState;
  3239. pcompT->cpPos.iLeft = pcompT->csiRestored.iLeft;
  3240. pcompT->cpPos.iTop = pcompT->csiRestored.iTop;
  3241. pcompT->cpPos.dwWidth = pcompT->csiRestored.dwWidth;
  3242. pcompT->cpPos.dwHeight = pcompT->csiRestored.dwHeight;
  3243. pcompT->cpPos.izIndex = COMPONENT_TOP;
  3244. pcompT->fDirty = TRUE;
  3245. break;
  3246. }
  3247. }
  3248. }
  3249. }
  3250. HRESULT CActiveDesktop::AddDesktopItem(LPCCOMPONENT pComp, DWORD dwReserved)
  3251. {
  3252. HRESULT hres = E_FAIL;
  3253. COMPONENTA CompA;
  3254. CompA.dwSize = sizeof(CompA);
  3255. ASSERT(!dwReserved); // These should be 0
  3256. // We need to support IE4 apps calling with the old component structure too!
  3257. // We use the size field to detect IE4 v/s newer apps!
  3258. if (!pComp ||
  3259. ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))) ||
  3260. ((pComp->dwSize == sizeof(*pComp)) && !VALIDATESTATE(pComp->dwCurItemState)))
  3261. return E_INVALIDARG;
  3262. // Catch folks that call our API's to add components and prevent them from doing
  3263. // so if the restriction is in place.
  3264. if ((!_fIgnoreAddRemovePolicies) && (SHIsRestricted(NULL, REST_NOADDDESKCOMP)))
  3265. return E_ACCESSDENIED;
  3266. // Convert the external structure to the internal format
  3267. ConvertCompStruct(&CompA, (COMPONENTA *)pComp, TRUE);
  3268. // If the component is already present, then fail the call!
  3269. if (_FindComponentBySource(CompA.szSource, &CompA) > -1)
  3270. return hres;
  3271. //Make sure that the COMPPOS size field is set before we add it!
  3272. CompA.cpPos.dwSize = sizeof(COMPPOS);
  3273. PositionComponent(&CompA, &CompA.cpPos, CompA.iComponentType, TRUE);
  3274. if (_hdsaComponent && ISZOOMED(&CompA))
  3275. RestoreComponent(_hdsaComponent, &CompA);
  3276. //Make sure the this component's fDirty flag is off.
  3277. CompA.fDirty = FALSE;
  3278. // Set the dummy bit here - this forces folks to do bitwise testing on the dwCurItemState field
  3279. // instead of testing for equality. This will allow us to expand use of the field down the
  3280. // road without compatibility problems.
  3281. CompA.dwCurItemState |= IS_INTERNALDUMMYBIT;
  3282. if (AddComponentPrivate(&CompA, _dwNextID++))
  3283. {
  3284. // It might be cheaper to attempt to insert the component in the
  3285. // correct z-order but it's less code to just call _SortAndRationalize
  3286. // after the insertion is done.
  3287. _SortAndRationalize();
  3288. hres = S_OK;
  3289. }
  3290. return(hres);
  3291. }
  3292. BOOL CActiveDesktop::AddComponentPrivate(COMPONENTA *pcomp, DWORD dwID)
  3293. {
  3294. BOOL fRet = FALSE;
  3295. ENTERPROC(1, "DS AddComponent(pcomp=%08X)", pcomp);
  3296. if (pcomp)
  3297. {
  3298. if (_hdsaComponent == NULL)
  3299. {
  3300. _hdsaComponent = DSA_Create(sizeof(COMPONENTA), DXA_GROWTH_CONST);
  3301. }
  3302. if (_hdsaComponent)
  3303. {
  3304. pcomp->dwID = dwID;
  3305. if (DSA_AppendItem(_hdsaComponent, pcomp) != -1)
  3306. {
  3307. _fDirty = TRUE;
  3308. fRet = TRUE;
  3309. }
  3310. else
  3311. {
  3312. TraceMsg(TF_WARNING, "DS AddComponent unable to append DSA");
  3313. }
  3314. }
  3315. else
  3316. {
  3317. TraceMsg(TF_WARNING, "DS AddComponent unable to create DSA");
  3318. }
  3319. }
  3320. else
  3321. {
  3322. TraceMsg(TF_WARNING, "DS AddComponent unable to add a component");
  3323. }
  3324. EXITPROC(1, "DS AddComponent=%d", fRet);
  3325. return fRet;
  3326. }
  3327. //
  3328. // This finds out if a given component already exists by comparing the szSource
  3329. // If so, it fills out the correct dwID and returns the index.
  3330. //
  3331. int CActiveDesktop::_FindComponentBySource(LPTSTR lpszSource, COMPONENTA *pComp)
  3332. {
  3333. int iRet = -1;
  3334. ENTERPROC(2, "DS FindComponentIdBySource(pComp=%8X)", pComp);
  3335. if (_hdsaComponent)
  3336. {
  3337. int i;
  3338. for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
  3339. {
  3340. COMPONENTA comp;
  3341. comp.dwSize = sizeof(COMPONENTA);
  3342. if (DSA_GetItem(_hdsaComponent, i, &comp) != -1)
  3343. {
  3344. if (!lstrcmpi(comp.szSource, lpszSource))
  3345. {
  3346. *pComp = comp;
  3347. iRet = i;
  3348. break;
  3349. }
  3350. }
  3351. else
  3352. {
  3353. TraceMsg(TF_WARNING, "DS FindComponentIndexByID unable to get a component");
  3354. }
  3355. }
  3356. }
  3357. EXITPROC(2, "DS FindComponentIdBySource=%d", iRet);
  3358. return iRet;
  3359. }
  3360. int CActiveDesktop::_FindComponentIndexByID(DWORD dwID)
  3361. {
  3362. int iRet = -1;
  3363. ENTERPROC(2, "DS FindComponentIndexByID(dwID=%d)", dwID);
  3364. if (_hdsaComponent)
  3365. {
  3366. int i;
  3367. for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
  3368. {
  3369. COMPONENTA comp;
  3370. comp.dwSize = sizeof(COMPONENTA);
  3371. if (DSA_GetItem(_hdsaComponent, i, &comp) != -1)
  3372. {
  3373. if (comp.dwID == dwID)
  3374. {
  3375. iRet = i;
  3376. break;
  3377. }
  3378. }
  3379. else
  3380. {
  3381. TraceMsg(TF_WARNING, "DS FindComponentIndexByID unable to get a component");
  3382. }
  3383. }
  3384. }
  3385. EXITPROC(2, "DS FindComponent=%d", iRet);
  3386. return iRet;
  3387. }
  3388. //
  3389. // This function is to be used only in special situations. Given a Url, it finds a component
  3390. // that has the src= pointed to that url. Note that what we have is szSource is something like
  3391. // "c:\foo\bar.bmp"; But, what is passed to this function is "file://c:/foo/bar.htm"
  3392. //
  3393. // Warning: This function does a conversion from Path to Url for every component before
  3394. // comparing with the given Url. This is in-efficient. We do it this way because converting
  3395. // the given Url ,which was converted to url from path, back to Path may not result in the
  3396. // original path. In other words a round-trip from path to Url and back to path may not result
  3397. // in the path that was originally entered by the end-user.
  3398. //
  3399. int CActiveDesktop::_FindComponentBySrcUrl(LPTSTR lpszSrcUrl, COMPONENTA *pComp)
  3400. {
  3401. int iRet = -1;
  3402. ENTERPROC(2, "DS FindComponentBySrcUrl(pComp=%8X)", pComp);
  3403. if (_hdsaComponent)
  3404. {
  3405. int i;
  3406. for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
  3407. {
  3408. COMPONENTA comp;
  3409. comp.dwSize = sizeof(COMPONENTA);
  3410. if (DSA_GetItem(_hdsaComponent, i, &comp) != -1)
  3411. {
  3412. TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  3413. LPTSTR lpszUrl = szUrl;
  3414. DWORD dwSize;
  3415. //Convert the szSource to Url
  3416. dwSize = ARRAYSIZE(szUrl);
  3417. if (FAILED(UrlCreateFromPath(comp.szSource, lpszUrl, &dwSize, 0)))
  3418. lpszUrl = comp.szSource;
  3419. if (!lstrcmpi(lpszUrl, lpszSrcUrl))
  3420. {
  3421. *pComp = comp;
  3422. iRet = i;
  3423. break;
  3424. }
  3425. }
  3426. else
  3427. {
  3428. TraceMsg(TF_WARNING, "DS FindComponentBySrcUrl unable to get a component");
  3429. }
  3430. }
  3431. }
  3432. EXITPROC(2, "DS FindComponentBySrcUrl=%d", iRet);
  3433. return iRet;
  3434. }
  3435. HRESULT CActiveDesktop:: GetDesktopItemByID(ULONG_PTR dwID, COMPONENT *pcomp, DWORD dwReserved)
  3436. {
  3437. HRESULT hres = E_FAIL;
  3438. ENTERPROC(1, "DS GetComponentByID(dwID=%d,pcomp=%08X)", dwID, pcomp);
  3439. COMPONENTA CompA;
  3440. ASSERT(!dwReserved); // These should be 0
  3441. // We need to support IE4 apps calling with the old component structure too!
  3442. // We use the size field to detect IE4 v/s newer apps!
  3443. if (!pcomp || ((pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT))))
  3444. return E_INVALIDARG;
  3445. if (pcomp)
  3446. {
  3447. int index = _FindComponentIndexByID((DWORD)dwID);
  3448. if (index != -1)
  3449. {
  3450. if (DSA_GetItem(_hdsaComponent, index, &CompA) != -1)
  3451. {
  3452. hres = S_OK;
  3453. }
  3454. else
  3455. {
  3456. TraceMsg(TF_WARNING, "DS GetComponentByID unable to get component");
  3457. }
  3458. }
  3459. else
  3460. {
  3461. TraceMsg(TF_WARNING, "DS GetComponentByID unable to find component");
  3462. }
  3463. }
  3464. else
  3465. {
  3466. TraceMsg(TF_WARNING, "DS GetComponentByID given NULL pcomp");
  3467. }
  3468. if (SUCCEEDED(hres))
  3469. {
  3470. MultiCompToWideComp(&CompA, pcomp);
  3471. }
  3472. EXITPROC(1, "DS GetComponentByID=%d", hres);
  3473. return hres;
  3474. }
  3475. HRESULT CActiveDesktop::RemoveDesktopItem(LPCCOMPONENT pComp, DWORD dwReserved)
  3476. {
  3477. COMPONENTA CompA, CompToDelete;
  3478. int iIndex;
  3479. HRESULT hres = E_FAIL;
  3480. ASSERT(!dwReserved); // These should be 0
  3481. // We need to support IE4 apps calling with the old component structure too!
  3482. // We use the size field to detect IE4 v/s newer apps!
  3483. if (!pComp || ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))))
  3484. return E_INVALIDARG;
  3485. CompA.dwSize = sizeof(CompA);
  3486. CompToDelete.dwSize = sizeof(CompToDelete);
  3487. //Convert the struct to internal struct.
  3488. ConvertCompStruct(&CompA, (COMPONENTA *)pComp, TRUE);
  3489. // See if the component already exists.
  3490. iIndex = _FindComponentBySource(CompA.szSource, &CompToDelete);
  3491. if (iIndex > -1)
  3492. {
  3493. if (RemoveComponentPrivate(iIndex, &CompToDelete))
  3494. {
  3495. hres = S_OK;
  3496. }
  3497. }
  3498. return(hres);
  3499. }
  3500. BOOL CActiveDesktop::RemoveComponentPrivate(int iIndex, COMPONENTA *pcomp)
  3501. {
  3502. BOOL fRet = FALSE;
  3503. ENTERPROC(1, "DS RemoveComponent(pcomp=%08X)", pcomp);
  3504. if (_hdsaComponent)
  3505. {
  3506. if (iIndex == -1)
  3507. iIndex = _FindComponentIndexByID(pcomp->dwID);
  3508. if (iIndex != -1)
  3509. {
  3510. if (DSA_DeleteItem(_hdsaComponent, iIndex) != -1)
  3511. {
  3512. _fDirty = TRUE;
  3513. fRet = TRUE;
  3514. }
  3515. else
  3516. {
  3517. TraceMsg(TF_WARNING, "DS RemoveComponent could not remove an item");
  3518. }
  3519. }
  3520. else
  3521. {
  3522. TraceMsg(TF_WARNING, "DS RemoveComponent could not find item to remove");
  3523. }
  3524. }
  3525. else
  3526. {
  3527. TraceMsg(TF_WARNING, "DS RemoveComponent has no components to remove");
  3528. }
  3529. EXITPROC(1, "DS RemoveComponent=%d", fRet);
  3530. return fRet;
  3531. }
  3532. HRESULT CActiveDesktop::_CopyComponent(COMPONENTA *pCompDest, COMPONENTA *pCompSrc, DWORD dwFlags)
  3533. {
  3534. //Copy only those elements mentioned in the flag!
  3535. // if (dwFlags & COMP_ELEM_ID)
  3536. // pCompDest->dwID = pCompSrc->dwID;
  3537. if (dwFlags & COMP_ELEM_TYPE)
  3538. pCompDest-> iComponentType = pCompSrc->iComponentType;
  3539. if (dwFlags & COMP_ELEM_CHECKED)
  3540. pCompDest-> fChecked = pCompSrc->fChecked;
  3541. if (dwFlags & COMP_ELEM_DIRTY)
  3542. pCompDest-> fDirty = pCompSrc-> fDirty;
  3543. if (dwFlags & COMP_ELEM_NOSCROLL)
  3544. pCompDest-> fNoScroll = pCompSrc-> fNoScroll;
  3545. if (dwFlags & COMP_ELEM_POS_LEFT)
  3546. pCompDest-> cpPos.iLeft= pCompSrc->cpPos.iLeft;
  3547. if (dwFlags & COMP_ELEM_POS_TOP)
  3548. pCompDest-> cpPos.iTop= pCompSrc->cpPos.iTop;
  3549. if (dwFlags & COMP_ELEM_SIZE_WIDTH)
  3550. pCompDest-> cpPos.dwWidth= pCompSrc->cpPos.dwWidth;
  3551. if (dwFlags & COMP_ELEM_SIZE_HEIGHT)
  3552. pCompDest-> cpPos.dwHeight= pCompSrc->cpPos.dwHeight;
  3553. if (dwFlags & COMP_ELEM_POS_ZINDEX)
  3554. pCompDest-> cpPos.izIndex= pCompSrc->cpPos.izIndex;
  3555. if (dwFlags & COMP_ELEM_SOURCE)
  3556. lstrcpy(pCompDest->szSource, pCompSrc->szSource);
  3557. if (dwFlags & COMP_ELEM_FRIENDLYNAME)
  3558. lstrcpy(pCompDest->szFriendlyName, pCompSrc->szFriendlyName);
  3559. if (dwFlags & COMP_ELEM_SUBSCRIBEDURL)
  3560. lstrcpy(pCompDest->szSubscribedURL, pCompSrc->szSubscribedURL);
  3561. if (dwFlags & COMP_ELEM_ORIGINAL_CSI)
  3562. pCompDest->csiOriginal = pCompSrc->csiOriginal;
  3563. if (dwFlags & COMP_ELEM_RESTORED_CSI)
  3564. {
  3565. pCompDest->csiRestored = pCompSrc->csiRestored;
  3566. // 98/08/21 vtan #174542: When changing csiRestored using the Active
  3567. // Desktop API and the component is zoomed the csiRestored information
  3568. // needs to be copied to the cpPos field as well as this is where the
  3569. // actual information is stored when the component is restored. This
  3570. // is only applicable to the case when the component is zoomed.
  3571. if (ISZOOMED(pCompDest))
  3572. {
  3573. pCompDest->cpPos.iLeft = pCompSrc->csiRestored.iLeft;
  3574. pCompDest->cpPos.iTop = pCompSrc->csiRestored.iTop;
  3575. pCompDest->cpPos.dwWidth = pCompSrc->csiRestored.dwWidth;
  3576. pCompDest->cpPos.dwHeight = pCompSrc->csiRestored.dwHeight;
  3577. }
  3578. }
  3579. if (dwFlags & COMP_ELEM_CURITEMSTATE) // Only allow the modification of the public bits - propagate the internal bits unchanged.
  3580. pCompDest->dwCurItemState = (pCompDest->dwCurItemState & IS_VALIDINTERNALBITS) | (pCompSrc->dwCurItemState & ~IS_VALIDINTERNALBITS);
  3581. return(S_OK);
  3582. }
  3583. HRESULT CActiveDesktop::GetDesktopItemBySource(LPCWSTR lpcwszSource, LPCOMPONENT pComp, DWORD dwFlags)
  3584. {
  3585. COMPONENTA CompNew;
  3586. HRESULT hres = E_FAIL;
  3587. int iIndex;
  3588. //Passing a NULL to SHUnicodeToTChar causes a fault. So, let's fail it.
  3589. if (lpcwszSource == NULL)
  3590. return E_INVALIDARG;
  3591. // We need to support IE4 apps calling with the old component structure too!
  3592. // We use the size field to detect IE4 v/s newer apps!
  3593. if (!pComp || ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))))
  3594. return E_INVALIDARG;
  3595. CompNew.dwSize = sizeof(COMPONENTA);
  3596. SHUnicodeToTChar(lpcwszSource, CompNew.szSource, ARRAYSIZE(CompNew.szSource));
  3597. iIndex = _FindComponentBySource(CompNew.szSource, &CompNew);
  3598. if (iIndex > -1)
  3599. {
  3600. MultiCompToWideComp(&CompNew, pComp);
  3601. hres = S_OK;
  3602. }
  3603. return(hres);
  3604. }
  3605. HRESULT CActiveDesktop::ModifyDesktopItem(LPCCOMPONENT pComp, DWORD dwFlags)
  3606. {
  3607. COMPONENTA CompA, CompNew;
  3608. HRESULT hres = E_FAIL;
  3609. int iIndex = -1;
  3610. // We need to support IE4 apps calling with the old component structure too!
  3611. // We use the size field to detect IE4 v/s newer apps!
  3612. if (!pComp || ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))))
  3613. return E_INVALIDARG;
  3614. CompA.dwSize = sizeof(COMPONENTA);
  3615. CompNew.dwSize = sizeof(COMPONENTA);
  3616. //Convert public param structure to private param structure.
  3617. ConvertCompStruct(&CompA, (COMPONENTA *)pComp, TRUE);
  3618. //See if this component already exists.
  3619. iIndex = _FindComponentBySource(CompA.szSource, &CompNew);
  3620. if (iIndex > -1)
  3621. {
  3622. _CopyComponent(&CompNew, &CompA, dwFlags);
  3623. if (dwFlags & (COMP_ELEM_POS_LEFT | COMP_ELEM_POS_TOP | COMP_ELEM_SIZE_WIDTH | COMP_ELEM_SIZE_HEIGHT | COMP_ELEM_CHECKED | COMP_ELEM_CURITEMSTATE))
  3624. PositionComponent(&CompNew, &CompNew.cpPos, CompNew.iComponentType, FALSE);
  3625. if (ISZOOMED(&CompNew))
  3626. RestoreComponent(_hdsaComponent, &CompNew);
  3627. CompNew.fDirty = TRUE; //Since the component is modified, we set the dirty bit!
  3628. if (UpdateComponentPrivate(iIndex, &CompNew))
  3629. hres = S_OK;
  3630. }
  3631. return(hres);
  3632. }
  3633. BOOL CActiveDesktop::UpdateComponentPrivate(int iIndex, COMPONENTA *pcomp)
  3634. {
  3635. BOOL fRet = FALSE;
  3636. ENTERPROC(1, "DS UpdateComponentPrivate(pcomp=%08X)", pcomp);
  3637. if (_hdsaComponent)
  3638. {
  3639. if (iIndex == -1)
  3640. iIndex = _FindComponentIndexByID(pcomp->dwID);
  3641. if (iIndex != -1)
  3642. {
  3643. if (DSA_SetItem(_hdsaComponent, iIndex, pcomp) != -1)
  3644. {
  3645. _fDirty = TRUE;
  3646. fRet = TRUE;
  3647. }
  3648. else
  3649. {
  3650. TraceMsg(TF_WARNING, "DS UpdateComponent could not update an item");
  3651. }
  3652. }
  3653. else
  3654. {
  3655. TraceMsg(TF_WARNING, "DS UpdateComponent could not find item to update");
  3656. }
  3657. }
  3658. else
  3659. {
  3660. TraceMsg(TF_WARNING, "DS UpdateComponent has no components to update");
  3661. }
  3662. EXITPROC(1, "DS UpdateComponent=%d", fRet);
  3663. return fRet;
  3664. }
  3665. HRESULT CActiveDesktop::GetDesktopItemCount(LPINT lpiCount, DWORD dwReserved)
  3666. {
  3667. if (!lpiCount)
  3668. return (E_INVALIDARG);
  3669. *lpiCount = 0;
  3670. ENTERPROC(1, "DS GetComponentsCount()");
  3671. ASSERT(!dwReserved); // These should be 0
  3672. if (_hdsaComponent)
  3673. {
  3674. *lpiCount = DSA_GetItemCount(_hdsaComponent);
  3675. }
  3676. EXITPROC(1, "DS GetComponentsCount=%d", *lpiCount);
  3677. return S_OK;
  3678. }
  3679. HRESULT CActiveDesktop::GetDesktopItem(int nComponent, COMPONENT *pComp, DWORD dwReserved)
  3680. {
  3681. COMPONENTA CompA;
  3682. ASSERT(!dwReserved); // These should be 0
  3683. // We need to support IE4 apps calling with the old component structure too!
  3684. // We use the size field to detect IE4 v/s newer apps!
  3685. if ((nComponent < 0) || !pComp || ((pComp->dwSize != sizeof(*pComp)) && (pComp->dwSize != sizeof(IE4COMPONENT))))
  3686. return E_INVALIDARG;
  3687. CompA.dwSize = sizeof(COMPONENTA);
  3688. if (GetComponentPrivate(nComponent, &CompA))
  3689. {
  3690. //Convert the structure to the Public form.
  3691. ConvertCompStruct((COMPONENTA *)pComp, &CompA, FALSE);
  3692. return(S_OK);
  3693. }
  3694. else
  3695. return(E_FAIL);
  3696. }
  3697. BOOL CActiveDesktop::GetComponentPrivate(int nComponent, COMPONENTA *pcomp)
  3698. {
  3699. BOOL fRet = FALSE;
  3700. ENTERPROC(1, "DS GetComponent(nComponent=%d,pcomp=%08X)", nComponent, pcomp);
  3701. if (_hdsaComponent && pcomp && (nComponent < DSA_GetItemCount(_hdsaComponent)))
  3702. {
  3703. if (DSA_GetItem(_hdsaComponent, nComponent, pcomp) != -1)
  3704. {
  3705. fRet = TRUE;
  3706. }
  3707. else
  3708. {
  3709. TraceMsg(TF_WARNING, "DS GetComponent unable to get a component");
  3710. }
  3711. }
  3712. else
  3713. {
  3714. TraceMsg(TF_WARNING, "DS GetComponent does not have a DSA");
  3715. }
  3716. EXITPROC(1, "DS GetComponent=%d", fRet);
  3717. return fRet;
  3718. }
  3719. HRESULT CActiveDesktop::QueryInterface(REFIID riid, LPVOID *ppvObj)
  3720. {
  3721. if (IsEqualIID(riid, IID_IActiveDesktop))
  3722. {
  3723. *ppvObj = (IActiveDesktop *)this;
  3724. _Initialize();
  3725. }
  3726. else if (IsEqualIID(riid, IID_IUnknown))
  3727. {
  3728. *ppvObj = (IActiveDesktop *)this;
  3729. }
  3730. else if (IsEqualIID(riid, IID_IActiveDesktopP))
  3731. {
  3732. *ppvObj = (IActiveDesktopP *)this;
  3733. }
  3734. else if (IsEqualIID(riid, IID_IADesktopP2))
  3735. {
  3736. *ppvObj = (IADesktopP2 *)this;
  3737. }
  3738. else if (IsEqualIID(riid, IID_IPropertyBag))
  3739. {
  3740. *ppvObj = (IPropertyBag *)this;
  3741. }
  3742. else
  3743. {
  3744. *ppvObj = NULL;
  3745. return E_NOINTERFACE;
  3746. }
  3747. AddRef();
  3748. return S_OK;
  3749. }
  3750. // Helper function so that it's easy to create one internally
  3751. // Actually, it's not ver much help any more...
  3752. STDAPI CActiveDesktop_InternalCreateInstance(LPUNKNOWN * ppunk, REFIID riid)
  3753. {
  3754. return CActiveDesktop_CreateInstance(NULL, riid, (void **)ppunk);
  3755. }
  3756. // Our class factory create instance code
  3757. STDAPI CActiveDesktop_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut)
  3758. {
  3759. TraceMsg(TF_DESKSTAT, "CActiveDesktop- CreateInstance");
  3760. CActiveDesktop *pad = new CActiveDesktop();
  3761. if (pad)
  3762. {
  3763. HRESULT hres = pad->QueryInterface(riid, ppvOut);
  3764. pad->Release();
  3765. return hres;
  3766. }
  3767. *ppvOut = NULL;
  3768. return E_OUTOFMEMORY;
  3769. }
  3770. #ifdef DEBUG
  3771. //
  3772. // FEATURE - Move g_dwDeskStatTrace into ccshell.ini to prevent recompiles.
  3773. //
  3774. DWORD g_dwDeskStatTrace = 2;
  3775. static DWORD g_dwIndent = 0;
  3776. static const TCHAR c_szDotDot[] = TEXT("..");
  3777. #define MAX_INDENTATION_VALUE 0x20
  3778. void EnterProcDS(DWORD dwTraceLevel, LPSTR pszFmt, ...)
  3779. {
  3780. TCHAR szFmt[1000];
  3781. TCHAR szOutput[1000];
  3782. va_list arglist;
  3783. SHAnsiToTChar(pszFmt, szFmt, ARRAYSIZE(szFmt));
  3784. if (dwTraceLevel <= g_dwDeskStatTrace)
  3785. {
  3786. szOutput[0] = TEXT('\0');
  3787. for (DWORD i=0; i<g_dwIndent; i++)
  3788. {
  3789. lstrcat(szOutput, c_szDotDot);
  3790. }
  3791. va_start(arglist, pszFmt);
  3792. wvsprintf(szOutput + lstrlen(szOutput), szFmt, arglist);
  3793. va_end(arglist);
  3794. TraceMsg(TF_DESKSTAT, "%s", szOutput);
  3795. // We don't want this value to get out of hand because of
  3796. // unmatched Enter and Exit calls in functions (which will
  3797. // trash the stack).
  3798. if (g_dwIndent < MAX_INDENTATION_VALUE)
  3799. g_dwIndent++;
  3800. }
  3801. }
  3802. void ExitProcDS(DWORD dwTraceLevel, LPSTR pszFmt, ...)
  3803. {
  3804. TCHAR szFmt[1000];
  3805. TCHAR szOutput[1000];
  3806. va_list arglist;
  3807. SHAnsiToTChar(pszFmt, szFmt, ARRAYSIZE(szFmt));
  3808. if (dwTraceLevel <= g_dwDeskStatTrace)
  3809. {
  3810. //This can happen if the Enter and Exit procs are unmatched.
  3811. if (g_dwIndent > 0)
  3812. g_dwIndent--;
  3813. szOutput[0] = TEXT('\0');
  3814. for (DWORD i=0; i<g_dwIndent; i++)
  3815. {
  3816. lstrcat(szOutput, c_szDotDot);
  3817. }
  3818. va_start(arglist, pszFmt);
  3819. wvsprintf(szOutput + lstrlen(szOutput), szFmt, arglist);
  3820. va_end(arglist);
  3821. TraceMsg(TF_DESKSTAT, "%s", szOutput);
  3822. }
  3823. }
  3824. #endif
  3825. /*************************************************************************
  3826. *
  3827. * IActiveDesktopP methods and helper functions
  3828. *
  3829. * IActiveDesktopP is a private interface used to implement helper
  3830. * functionality that is used internally by the various shell binaries.
  3831. *
  3832. * Notes:
  3833. * Getting an interface to IActiveDesktopP does not initialize the state
  3834. * of the object such that member functions are able to call IActiveDesktop
  3835. * member functions. This is so that it is a more lightweight implementation
  3836. * and also simplifies the implementation of SetScheme. If a subsequent QI for
  3837. * IActiveDesktop is performed then it will initialize properly and any member
  3838. * function can then be called.
  3839. *
  3840. *************************************************************************/
  3841. //
  3842. // SetScheme
  3843. //
  3844. // Used to set the current scheme that the object will read and write to
  3845. // when it is initialized. This method must be called before a subsequent
  3846. // QI to IActiveDesktop is made.
  3847. //
  3848. HRESULT CActiveDesktop::SetScheme(LPCWSTR pwszSchemeName, DWORD dwFlags)
  3849. {
  3850. LPTSTR pszSchemeName, pszAlloc;
  3851. int icch;
  3852. // Can't set the local scheme after we've been initialized...we can fix this
  3853. // later if necessary but for now it's simplest this way.
  3854. if (_fInitialized && (dwFlags & SCHEME_LOCAL))
  3855. return E_FAIL;
  3856. // Sanity checks
  3857. if (!pwszSchemeName || ((icch = lstrlenW(pwszSchemeName)) > MAX_PATH - 1))
  3858. return E_INVALIDARG;
  3859. pszSchemeName = (LPTSTR)pwszSchemeName;
  3860. if (dwFlags & SCHEME_CREATE)
  3861. {
  3862. HRESULT hres;
  3863. HKEY hkey, hkey2;
  3864. if (ERROR_SUCCESS == (hres = RegCreateKey(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME_LOCATION, &hkey)))
  3865. {
  3866. if (ERROR_SUCCESS == (hres = RegCreateKey(hkey, pszSchemeName, &hkey2)))
  3867. RegCloseKey(hkey2);
  3868. RegCloseKey(hkey);
  3869. }
  3870. if (FAILED(hres))
  3871. return hres;
  3872. }
  3873. if (dwFlags & SCHEME_LOCAL)
  3874. {
  3875. // The local case is easy - just copy the string to our local variable,
  3876. // it will be used when IActiveDesktop is initialized.
  3877. if (!(pszAlloc = (LPTSTR)LocalAlloc(LPTR, (icch + 1) * sizeof(TCHAR))))
  3878. return E_OUTOFMEMORY;
  3879. if (_pszScheme)
  3880. LocalFree((HANDLE)_pszScheme);
  3881. _pszScheme = pszAlloc;
  3882. lstrcpy(_pszScheme, pszSchemeName);
  3883. }
  3884. if (dwFlags & SCHEME_GLOBAL)
  3885. {
  3886. // Update the registry with the new global scheme value
  3887. if (dwFlags & SCHEME_DISPLAY)
  3888. SHSetValue(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME, REG_VAL_SCHEME_DISPLAY,
  3889. REG_SZ, pszSchemeName, CbFromCch(lstrlen(pszSchemeName) + 1));
  3890. if (dwFlags & SCHEME_EDIT)
  3891. SHSetValue(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME, REG_VAL_SCHEME_EDIT,
  3892. REG_SZ, pszSchemeName, CbFromCch(lstrlen(pszSchemeName) + 1));
  3893. }
  3894. if (dwFlags & (SCHEME_REFRESH | SCHEME_UPDATE))
  3895. {
  3896. DWORD dwUpdateFlags = AD_APPLY_FORCE | AD_APPLY_HTMLGEN | AD_APPLY_SAVE;
  3897. if (dwFlags & SCHEME_REFRESH)
  3898. dwUpdateFlags |= (AD_APPLY_REFRESH | AD_APPLY_DYNAMICREFRESH);
  3899. _Initialize();
  3900. _fUseDynamicHtml=FALSE;
  3901. ApplyChanges(dwUpdateFlags);
  3902. }
  3903. return S_OK;
  3904. }
  3905. HRESULT GetGlobalScheme(LPWSTR pwszScheme, LPDWORD lpdwcchBuffer, DWORD dwFlags)
  3906. {
  3907. DWORD cbScheme = *lpdwcchBuffer * sizeof(pwszScheme[0]);
  3908. LONG lret = SHGetValueW(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME,
  3909. (dwFlags & SCHEME_EDIT) ? REG_VAL_SCHEME_EDIT : REG_VAL_SCHEME_DISPLAY, NULL,
  3910. pwszScheme, &cbScheme);
  3911. if (ERROR_SUCCESS == lret)
  3912. {
  3913. *lpdwcchBuffer = lstrlenW(pwszScheme);
  3914. }
  3915. return (lret == ERROR_SUCCESS ? S_OK : E_FAIL);
  3916. }
  3917. //
  3918. // GetScheme
  3919. //
  3920. //
  3921. HRESULT CActiveDesktop::GetScheme(LPWSTR pwszSchemeName, LPDWORD lpdwcchBuffer, DWORD dwFlags)
  3922. {
  3923. // Sanity checks
  3924. if (!pwszSchemeName || *lpdwcchBuffer == 0)
  3925. return E_INVALIDARG;
  3926. if (dwFlags & SCHEME_LOCAL)
  3927. {
  3928. if (!_pszScheme)
  3929. {
  3930. HRESULT hres;
  3931. // Special case if no local scheme has explicitly been selected yet.
  3932. // The default scheme is the global display scheme in this case.
  3933. if (SUCCEEDED(hres = GetGlobalScheme(pwszSchemeName, lpdwcchBuffer, SCHEME_DISPLAY)))
  3934. {
  3935. hres = SetScheme(pwszSchemeName, SCHEME_LOCAL);
  3936. }
  3937. return hres;
  3938. }
  3939. SHTCharToUnicode(_pszScheme, pwszSchemeName, *lpdwcchBuffer);
  3940. *lpdwcchBuffer = lstrlenW(pwszSchemeName);
  3941. return S_OK;
  3942. }
  3943. if (dwFlags & SCHEME_GLOBAL)
  3944. {
  3945. return GetGlobalScheme(pwszSchemeName, lpdwcchBuffer, dwFlags);
  3946. }
  3947. return E_INVALIDARG;
  3948. }
  3949. BOOL UpdateAllDesktopSubscriptions(IADesktopP2 *);
  3950. HRESULT CActiveDesktop::UpdateAllDesktopSubscriptions()
  3951. {
  3952. ::UpdateAllDesktopSubscriptions(this);
  3953. return S_OK;
  3954. }
  3955. void CActiveDesktop::_GenerateHtmlBStrForComp(COMPONENTA *pComp, BSTR *pbstr)
  3956. {
  3957. ENTERPROC(2, "DS _GenerateHtmlBstrForComp");
  3958. if (_pStream = SHCreateMemStream(NULL, 0)) //Create a mem stream.
  3959. {
  3960. LARGE_INTEGER libMove = {0};
  3961. ULARGE_INTEGER libCurPos;
  3962. // Since _pStream is setup, the following call will generate the component HTML into
  3963. // that stream.
  3964. _GenerateHtmlComponent(pComp);
  3965. //Get the size of the stream generated.
  3966. _pStream->Seek(libMove, STREAM_SEEK_CUR, &libCurPos);
  3967. //Allocare a BSTR big enough to hold our component HTML code.
  3968. if (*pbstr = SysAllocStringLen(NULL, (libCurPos.LowPart)/sizeof(WCHAR)))
  3969. {
  3970. _pStream->Seek(libMove, STREAM_SEEK_SET, NULL);
  3971. _pStream->Read(*pbstr, libCurPos.LowPart, NULL);
  3972. }
  3973. //NOTE: The bStr is released by the caller.
  3974. ATOMICRELEASE(_pStream);
  3975. }
  3976. else
  3977. TraceMsg(TF_WARNING, "DS _GenerateHtmlBstrForComp unable to create a mem stream");
  3978. EXITPROC(2, "DS _GenerateHtmlBstrForComp");
  3979. }
  3980. void CActiveDesktop::_UpdateStyleOfElement(IHTMLElement *pElem, LPCOMPONENTA lpCompA)
  3981. {
  3982. IHTMLStyle *pHtmlStyle;
  3983. if (SUCCEEDED(pElem->get_style(&pHtmlStyle)))
  3984. {
  3985. long lPixelVal;
  3986. VARIANT vVal;
  3987. VARIANT vValNew;
  3988. if (SUCCEEDED(pHtmlStyle->get_pixelLeft(&lPixelVal)) && (lPixelVal != lpCompA->cpPos.iLeft))
  3989. {
  3990. TraceMsg(TF_DYNAMICHTML, "iLeft changes from %d to %d", lPixelVal, lpCompA->cpPos.iLeft);
  3991. pHtmlStyle->put_pixelLeft((long)(lpCompA->cpPos.iLeft));
  3992. }
  3993. if (SUCCEEDED(pHtmlStyle->get_pixelTop(&lPixelVal)) && (lPixelVal != lpCompA->cpPos.iTop))
  3994. {
  3995. TraceMsg(TF_DYNAMICHTML, "iTop changes from %d to %d", lPixelVal, lpCompA->cpPos.iTop);
  3996. pHtmlStyle->put_pixelTop((long)(lpCompA->cpPos.iTop));
  3997. }
  3998. VariantInit(&vVal);
  3999. if (SUCCEEDED(pHtmlStyle->get_width(&vVal))) //Get the width as BSTR to see if width attribute exists
  4000. {
  4001. //See if the width attribute exists now.
  4002. if ((vVal.vt == VT_BSTR) && (vVal.bstrVal == NULL))
  4003. {
  4004. // Width attribute does not exist for this element; This means that
  4005. // this element has the default width (may be a picture shown in it's original width).
  4006. if (lpCompA->cpPos.dwWidth != COMPONENT_DEFAULT_WIDTH)
  4007. {
  4008. //Component's new width is different from the default width. So, set the new width.
  4009. TraceMsg(TF_DYNAMICHTML, "dwWidth changes from default to %d", lpCompA->cpPos.dwWidth);
  4010. pHtmlStyle->put_pixelWidth((long)(lpCompA->cpPos.dwWidth));
  4011. }
  4012. //else, nothing to do! (the widths match exactly).
  4013. }
  4014. else
  4015. {
  4016. // Width attribute exists! That means that this element has a width other than the
  4017. // default width.
  4018. // See if the new width is the default width.
  4019. if (lpCompA->cpPos.dwWidth == COMPONENT_DEFAULT_WIDTH)
  4020. {
  4021. // The old width is NOT default; But, the new width is default. So, let's just
  4022. // remove the width attribute.
  4023. VariantInit(&vValNew);
  4024. vValNew.vt = VT_BSTR;
  4025. vValNew.bstrVal = NULL;
  4026. pHtmlStyle->put_width(vValNew);
  4027. VariantClear(&vValNew);
  4028. }
  4029. else
  4030. {
  4031. //Get the existing width in pixels.
  4032. if (SUCCEEDED(pHtmlStyle->get_pixelWidth(&lPixelVal)) && (((DWORD)lPixelVal) != lpCompA->cpPos.dwWidth))
  4033. {
  4034. TraceMsg(TF_DYNAMICHTML, "dwWidth changes from %d to %d", lPixelVal, lpCompA->cpPos.dwWidth);
  4035. pHtmlStyle->put_pixelWidth((long)(lpCompA->cpPos.dwWidth));
  4036. }
  4037. //else, nothing else to do because the widths match!
  4038. }
  4039. }
  4040. VariantClear(&vVal);
  4041. }
  4042. if (SUCCEEDED(pHtmlStyle->get_height(&vVal))) //Get the height as BSTR to see if height attribute exists
  4043. {
  4044. // See if the height attribute exists.
  4045. if ((vVal.vt == VT_BSTR) && (vVal.bstrVal == NULL))
  4046. {
  4047. // Height attribute does not exist for this element; This means that
  4048. // this element has the default height (may be a picture shown in it's original height).
  4049. if (lpCompA->cpPos.dwHeight != COMPONENT_DEFAULT_HEIGHT)
  4050. {
  4051. //Component's new height is different from the default height. So, set the new height.
  4052. TraceMsg(TF_DYNAMICHTML, "dwHeight changes from default to %d", lpCompA->cpPos.dwHeight);
  4053. pHtmlStyle->put_pixelHeight((long)(lpCompA->cpPos.dwHeight));
  4054. }
  4055. //else, nothing to do! (the heights match exactly).
  4056. }
  4057. else
  4058. {
  4059. // Height attribute exists! That means that this element has a height other than the
  4060. // default height.
  4061. // See if the new height is the default height.
  4062. if (lpCompA->cpPos.dwHeight == COMPONENT_DEFAULT_HEIGHT)
  4063. {
  4064. // The old height is NOT default; But, the new height is default. So, let's just
  4065. // remove the height attribute.
  4066. VariantInit(&vValNew);
  4067. vValNew.vt = VT_BSTR;
  4068. vValNew.bstrVal = NULL;
  4069. pHtmlStyle->put_height(vValNew); //remove the height attribute!
  4070. VariantClear(&vValNew);
  4071. }
  4072. else
  4073. {
  4074. //Get the existing height in pixels and see if it is different.
  4075. if (SUCCEEDED(pHtmlStyle->get_pixelHeight(&lPixelVal)) && (((DWORD)lPixelVal) != lpCompA->cpPos.dwHeight))
  4076. {
  4077. //Since the new height is different, let's use set the new height!
  4078. TraceMsg(TF_DYNAMICHTML, "dwHeight changes from %d to %d", lPixelVal, lpCompA->cpPos.dwHeight);
  4079. pHtmlStyle->put_pixelHeight((long)(lpCompA->cpPos.dwHeight));
  4080. }
  4081. //else, nothing else to do because the heights match!
  4082. }
  4083. }
  4084. VariantClear(&vVal);
  4085. }
  4086. if (SUCCEEDED(pHtmlStyle->get_zIndex(&vVal)) && (vVal.vt == VT_I4) && (vVal.lVal != lpCompA->cpPos.izIndex))
  4087. {
  4088. TraceMsg(TF_DYNAMICHTML, "ZIndex changes from %d to %d", vVal.lVal, lpCompA->cpPos.izIndex);
  4089. vVal.lVal = lpCompA->cpPos.izIndex;
  4090. pHtmlStyle->put_zIndex(vVal);
  4091. }
  4092. VariantClear(&vVal);
  4093. pHtmlStyle->Release();
  4094. }
  4095. //FEATURE: Should we check for and set the other attributes like "resizeable" etc.,?
  4096. }
  4097. BOOL CActiveDesktop::_UpdateIdOfElement(IHTMLElement *pElem, LPCOMPONENTA lpCompA)
  4098. {
  4099. BSTR bstrId;
  4100. BOOL fWholeElementReplaced = FALSE; //Assume that the item id does not change.
  4101. //Check if the Id of the component and the element matches.
  4102. if (SUCCEEDED(pElem->get_id(&bstrId))) //get the old id
  4103. {
  4104. if (((DWORD)StrToIntW(bstrId)) != lpCompA->dwID)
  4105. {
  4106. // The following technic does not work in some versions of MSHTML.DLL
  4107. // because IHTMLElement->put_id() does not work unless the doc
  4108. // is in "design mode".
  4109. TCHAR szNewId[MAXID_LENGTH];
  4110. BSTR bstrNewId;
  4111. HRESULT hr = S_OK;
  4112. wsprintf(szNewId, TEXT("%d"), lpCompA->dwID);
  4113. #ifdef DEBUG
  4114. {
  4115. TCHAR szOldId[MAXID_LENGTH];
  4116. wsprintf(szOldId, TEXT("%d"), StrToIntW(bstrId));
  4117. TraceMsg(TF_DYNAMICHTML, "DHTML: Id changes from %s to %s", szOldId, szNewId);
  4118. }
  4119. #endif //DEBUG
  4120. //The Ids do not match. So, let's set the new ID.
  4121. if (bstrNewId = SysAllocStringT(szNewId))
  4122. {
  4123. hr = pElem->put_id(bstrNewId);
  4124. SysFreeString(bstrNewId);
  4125. }
  4126. if (FAILED(hr))
  4127. {
  4128. //Replace the whole element's HTML with the newly generated HTML
  4129. BSTR bstrComp = 0;
  4130. _GenerateHtmlBStrForComp(lpCompA, &bstrComp);
  4131. if (bstrComp)
  4132. {
  4133. if (FAILED(hr = pElem->put_outerHTML(bstrComp)))
  4134. TraceMsg(TF_DYNAMICHTML, "DHTML: put_outerHTML failed");
  4135. fWholeElementReplaced = TRUE;
  4136. SysFreeString(bstrComp);
  4137. }
  4138. else
  4139. {
  4140. AssertMsg(FALSE, TEXT("DHTML: Unable to create html for comp"));
  4141. }
  4142. }
  4143. }
  4144. //else the ids match; nothing to do!
  4145. SysFreeString(bstrId); //free the old id.
  4146. }
  4147. else
  4148. {
  4149. AssertMsg(FALSE, TEXT("DS Unable to get the id of the element"));
  4150. }
  4151. return fWholeElementReplaced;
  4152. }
  4153. HRESULT CActiveDesktop::_UpdateHtmlElement(IHTMLElement *pElem)
  4154. {
  4155. VARIANT vData;
  4156. TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  4157. TCHAR szSrcPath[INTERNET_MAX_URL_LENGTH];
  4158. LPTSTR lpszSrcPath;
  4159. COMPONENTA CompA;
  4160. int iIndex;
  4161. //If all components are disabled, then we nuke this component from HTML page.
  4162. if (!_co.fEnableComponents)
  4163. {
  4164. TraceMsg(TF_DYNAMICHTML, "DHTML: No item shown in this mode; so, deleting items");
  4165. pElem->put_outerHTML((BSTR)s_sstrEmpty.wsz);
  4166. return S_OK; //Nothing else to do!
  4167. }
  4168. VariantInit(&vData);
  4169. //First determine if the given element is currently a desktop item. (It could have been deleted)
  4170. //Get the element's "src" attribute.
  4171. if (FAILED(pElem->getAttribute((BSTR)s_sstrSRCMember.wsz, VARIANT_FALSE, &vData)) ||
  4172. (vData.vt == VT_NULL) ||
  4173. (vData.bstrVal == NULL))
  4174. {
  4175. //If the subscribed_url is not present, then it could be an object with a classid.
  4176. if (FAILED(pElem->getAttribute((BSTR)s_sstrclassid.wsz, VARIANT_FALSE, &vData)) ||
  4177. (vData.vt == VT_NULL))
  4178. {
  4179. //This element is does not have "src=" or "classid=" attributes. How did this ever
  4180. // become a desktop item with "name=deskmovr" or "name=deskmovrw"?? Hmmmmmm....!!!
  4181. #ifdef DEBUG
  4182. {
  4183. BSTR bstrHtmlForElem;
  4184. // Get the HTML corresponding to the element that does not have a subscribed URL
  4185. if (SUCCEEDED(pElem->get_outerHTML(&bstrHtmlForElem)))
  4186. {
  4187. TraceMsg(TF_DYNAMICHTML, "DHTML: Rogue element: %s", bstrHtmlForElem);
  4188. SysFreeString(bstrHtmlForElem);
  4189. }
  4190. }
  4191. TraceMsg(TF_WARNING, "DHTML: Unable to get the subscribed_url or classid");
  4192. #endif
  4193. //Since this element does not seem to be a valid desktop item, let's nuke it!
  4194. pElem->put_outerHTML((BSTR)s_sstrEmpty.wsz); //delete this element.
  4195. return (E_FAIL); //Nothing else to for this element! It's gone!!!
  4196. }
  4197. if ((vData.vt == VT_NULL) || (vData.bstrVal == NULL))
  4198. return E_FAIL;
  4199. ASSERT(vData.vt == VT_BSTR);
  4200. ASSERT(StrCmpNW(vData.bstrVal, L"clsid:", lstrlen(TEXT("clsid:"))) == 0);
  4201. SHUnicodeToTChar(vData.bstrVal + lstrlen(TEXT("clsid:")), szUrl, ARRAYSIZE(szUrl));
  4202. lpszSrcPath = szUrl; //For classid, the SrcPath and the Url are the same.
  4203. }
  4204. else
  4205. {
  4206. DWORD dwSize;
  4207. if (vData.bstrVal == NULL)
  4208. return (E_FAIL);
  4209. ASSERT(vData.vt == VT_BSTR);
  4210. SHUnicodeToTChar(vData.bstrVal, szUrl, ARRAYSIZE(szUrl));
  4211. dwSize = ARRAYSIZE(szSrcPath);
  4212. lpszSrcPath = szSrcPath;
  4213. if (FAILED(PathCreateFromUrl(szUrl, lpszSrcPath, &dwSize, 0)))
  4214. {
  4215. lpszSrcPath = szUrl;
  4216. }
  4217. }
  4218. VariantClear(&vData); //We made a TCHAR copy above. So, ok to free this.
  4219. CompA.dwSize = sizeof(CompA);
  4220. // First use the Source path to Find the component; This is much more efficient because it
  4221. // involves no conversion from Path to Url and vice-versa.
  4222. if ((iIndex = _FindComponentBySource(lpszSrcPath, &CompA)) < 0)
  4223. {
  4224. // Could not find component using SrcPath!
  4225. // Let's try using the SrcUrl; This is less efficient.
  4226. iIndex = _FindComponentBySrcUrl(szUrl, &CompA);
  4227. }
  4228. if ((iIndex>= 0) && (CompA.fChecked))
  4229. {
  4230. //The component is found and it is enabled.
  4231. TraceMsg(TF_DYNAMICHTML, "DHTML:Updating desktop item with URL: %s", szUrl);
  4232. // If the id changes, we replace the whole HTML for that element, so, no need to check for
  4233. // the individual styles.
  4234. if (!_UpdateIdOfElement(pElem, &CompA))
  4235. _UpdateStyleOfElement(pElem, &CompA);
  4236. CompA.fDirty = TRUE; //Mark the component sothat we know that it had been updated.
  4237. UpdateComponentPrivate(iIndex, &CompA);
  4238. }
  4239. else
  4240. {
  4241. ASSERT((iIndex == -1) || (!CompA.fChecked)); //Component not found OR it is disabled!
  4242. TraceMsg(TF_DYNAMICHTML, "DHTML: Deleting desktop item with URL: %s, SrcPath:%s", szUrl, lpszSrcPath);
  4243. //The component is not present now. So, delete this element from the html page.
  4244. pElem->put_outerHTML((BSTR)s_sstrEmpty.wsz);
  4245. }
  4246. return S_OK;
  4247. }
  4248. //
  4249. // This code enumerates and then updates all the desktop item elements in the active desktop based
  4250. // on the current status of the active desktop items in the CActiveDesktop object (The current
  4251. // status is initialized by reading from the registry when ActiveDesktop object is initialized).
  4252. //
  4253. HRESULT CActiveDesktop::_UpdateDesktopItemHtmlElements(IHTMLDocument2 *pDoc)
  4254. {
  4255. HRESULT hres = S_OK;
  4256. IHTMLElementCollection *pAllElements;
  4257. TraceMsg(TF_DYNAMICHTML, "DHTML: Updating Desktop html elements dynamically");
  4258. if (!_fInitialized) //If not yet initialized, initialize now because we need _co.fEnableComponents.
  4259. _Initialize();
  4260. // We need to check for a change in the background color only if there is no wallpaper or
  4261. // the wallpaper is a picture.
  4262. if (IsWallpaperPicture(_szSelectedWallpaper))
  4263. {
  4264. COLORREF rgbDesktop;
  4265. TCHAR szRgbDesktop[10];
  4266. VARIANT vColor;
  4267. //Check to see if the background color has changed
  4268. rgbDesktop = GetSysColor(COLOR_DESKTOP);
  4269. wsprintf(szRgbDesktop, TEXT("#%02lx%02lx%02lx"), GetRValue(rgbDesktop),
  4270. GetGValue(rgbDesktop),
  4271. GetBValue(rgbDesktop));
  4272. if (SUCCEEDED(pDoc->get_bgColor(&vColor)) && (vColor.vt == VT_BSTR))
  4273. {
  4274. BSTR bstrNewBgColor = SysAllocStringT(szRgbDesktop);
  4275. //Compare the new and the old strings.
  4276. if (StrCmpW(vColor.bstrVal, bstrNewBgColor))
  4277. {
  4278. BSTR bstrOldBgColor = vColor.bstrVal; //Save the old bstr.
  4279. //So, the colors are different. Set the new color.
  4280. vColor.bstrVal = bstrNewBgColor;
  4281. bstrNewBgColor = bstrOldBgColor; //Set it here sothat it is freed later.
  4282. if (FAILED(pDoc->put_bgColor(vColor)))
  4283. {
  4284. TraceMsg(TF_DYNAMICHTML, "DHTML: Unable to change the background color");
  4285. }
  4286. }
  4287. if (bstrNewBgColor)
  4288. SysFreeString(bstrNewBgColor);
  4289. VariantClear(&vColor);
  4290. }
  4291. }
  4292. //Get a collection of All elements in the Document
  4293. if (SUCCEEDED(pDoc->get_all(&pAllElements)))
  4294. {
  4295. VARIANT vName, vIndex;
  4296. IDispatch *pDisp;
  4297. int i;
  4298. long lItemsEnumerated = 0;
  4299. long lLength = 0;
  4300. #ifdef DEBUG
  4301. pAllElements->get_length(&lLength);
  4302. TraceMsg(TF_DYNAMICHTML, "DHTML: Length of All elements:%d", lLength);
  4303. #endif
  4304. for(i = 0; i <= 1; i++)
  4305. {
  4306. //Collect all the elements that have the name="DeskMovr" and then name="DeskMovrW"
  4307. vName.vt = VT_BSTR;
  4308. vName.bstrVal = (BSTR)((i == 0) ? s_sstrDeskMovr.wsz : s_sstrDeskMovrW.wsz);
  4309. VariantInit(&vIndex); //We want to get all elements. So, vIndex is set to VT_EMPTY
  4310. if (SUCCEEDED(pAllElements->item(vName, vIndex, &pDisp)) && pDisp) //Collect all elements we want
  4311. {
  4312. IHTMLElementCollection *pDeskCollection;
  4313. if (SUCCEEDED(pDisp->QueryInterface(IID_IHTMLElementCollection, (void **)&pDeskCollection)))
  4314. {
  4315. IUnknown *pUnk;
  4316. IEnumVARIANT *pEnumVar;
  4317. if (SUCCEEDED(pDeskCollection->get_length(&lLength))) //Number of elements.
  4318. lItemsEnumerated += lLength; //Total number of items enumerated.
  4319. TraceMsg(TF_DYNAMICHTML, "DHTML: Enumerated %d number of elements", lLength);
  4320. //Get the enumerator
  4321. if (SUCCEEDED(pDeskCollection->get__newEnum(&pUnk)))
  4322. {
  4323. if (SUCCEEDED(pUnk->QueryInterface(IID_IEnumVARIANT, (void **)&pEnumVar)))
  4324. {
  4325. VARIANT vElem;
  4326. long lEnumCount = 0;
  4327. DWORD cElementsFetched;
  4328. while(SUCCEEDED(pEnumVar->Next(1, &vElem, &cElementsFetched)) && (cElementsFetched == 1))
  4329. {
  4330. IHTMLElement *pElem;
  4331. lEnumCount++;
  4332. // Access the element from the variant.....!
  4333. if ((vElem.vt == VT_DISPATCH) && SUCCEEDED(vElem.pdispVal->QueryInterface(IID_IHTMLElement, (void **)&pElem)))
  4334. {
  4335. _UpdateHtmlElement(pElem); //Update the desktop element's attributes.
  4336. pElem->Release();
  4337. }
  4338. VariantClear(&vElem);
  4339. }
  4340. //Number of items enumerated must be the same as the length
  4341. ASSERT(lEnumCount == lLength);
  4342. pEnumVar->Release();
  4343. }
  4344. pUnk->Release();
  4345. }
  4346. pDeskCollection->Release();
  4347. }
  4348. else
  4349. {
  4350. IHTMLElement *pElem;
  4351. // The QI(IID_IHTMLElementCollection) has failed. It may be because only one item
  4352. // was returned rather than a collection.
  4353. if (SUCCEEDED(pDisp->QueryInterface(IID_IHTMLElement, (void **)&pElem)))
  4354. {
  4355. _UpdateHtmlElement(pElem); //Update the desktop element's attributes.
  4356. pElem->Release();
  4357. }
  4358. else
  4359. TraceMsg(TF_WARNING, "DHTML: Unable to get a collection or a single element");
  4360. }
  4361. pDisp->Release();
  4362. }
  4363. } // for loop enumeating "DeskMovr" and "DeskMovrW" items.
  4364. pAllElements->Release();
  4365. }
  4366. // All the elements already present in the Doc have been updated. Now, let's add the
  4367. // new elements, if any.
  4368. if (_co.fEnableComponents)
  4369. _InsertNewDesktopItems(pDoc);
  4370. else
  4371. {
  4372. TraceMsg(TF_DYNAMICHTML, "DHTML: No components are to be shown in this mode;");
  4373. }
  4374. return hres;
  4375. }
  4376. HRESULT CActiveDesktop::_InsertNewDesktopItems(IHTMLDocument2 *pDoc)
  4377. {
  4378. IHTMLElement *pBody;
  4379. if (SUCCEEDED(pDoc->get_body(&pBody)))
  4380. {
  4381. if (_hdsaComponent)
  4382. {
  4383. int i, iCount;
  4384. iCount = DSA_GetItemCount(_hdsaComponent);
  4385. for (i=0; i<iCount; i++)
  4386. {
  4387. COMPONENTA comp;
  4388. comp.dwSize = sizeof(comp);
  4389. if (DSA_GetItem(_hdsaComponent, i, &comp) != -1)
  4390. {
  4391. //Check if this is a newly added component AND it is enabled.
  4392. if ((!comp.fDirty) && comp.fChecked)
  4393. {
  4394. TraceMsg(TF_DYNAMICHTML, "DHTML: Inserted comp: %s", comp.szSource);
  4395. //Yup! This is a newly added component!
  4396. BSTR bstrComp = 0;
  4397. //This is a new component. Generate the HTML for the component.
  4398. _GenerateHtmlBStrForComp(&comp, &bstrComp);
  4399. //Insert the component.
  4400. pBody->insertAdjacentHTML((BSTR)s_sstrBeforeEnd.wsz, (BSTR)bstrComp);
  4401. //Free the string.
  4402. SysFreeString(bstrComp);
  4403. }
  4404. }
  4405. else
  4406. {
  4407. TraceMsg(TF_WARNING, "DHTML: InsertNewComp: Unable to get component %d.", i);
  4408. }
  4409. }
  4410. }
  4411. pBody->Release();
  4412. }
  4413. return S_OK;
  4414. }
  4415. //
  4416. // This function takes a pointer to the ActiveDesktop's ole obj, reads all the changes to be done
  4417. // from the registry and makes those changes to the various elements through dynamic HTML interfaces.
  4418. //
  4419. HRESULT CActiveDesktop::MakeDynamicChanges(IOleObject *pOleObj)
  4420. {
  4421. IHTMLDocument2 *pDoc;
  4422. HRESULT hres = E_FAIL;
  4423. ENTERPROC(2, "MakeDynamicChanges");
  4424. if (pOleObj && SUCCEEDED(pOleObj->QueryInterface(IID_IHTMLDocument2, (void **)&pDoc)))
  4425. {
  4426. // Enumerate all the active desktop components and ensure they are up to date.
  4427. _UpdateDesktopItemHtmlElements(pDoc);
  4428. pDoc->Release();
  4429. }
  4430. else
  4431. {
  4432. TraceMsg(TF_WARNING, "DHTML: MakeDynamicChanges: Unable to get IHTMLDocument2");
  4433. }
  4434. EXITPROC(2, "MakeDynamicChanges");
  4435. return(hres);
  4436. }
  4437. //
  4438. // SetSafeMode
  4439. //
  4440. // Either puts the active desktop in safemode or restores it to the previous
  4441. // scheme before safemode was entered.
  4442. //
  4443. HRESULT CActiveDesktop::SetSafeMode(DWORD dwFlags)
  4444. {
  4445. //
  4446. // Make sure we are in active desktop mode.
  4447. //
  4448. SHELLSTATE ss = {0};
  4449. BOOL fSetSafeMode = (dwFlags & SSM_SET) != 0;
  4450. SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
  4451. if (ss.fDesktopHTML)
  4452. {
  4453. //
  4454. // All we need to do is switch the "display" scheme to "safemode" in order to
  4455. // go into safemode. To go out, we just switch the "display" scheme back to the
  4456. // previous "edit" scheme.
  4457. //
  4458. WCHAR wszEdit[MAX_PATH];
  4459. WCHAR wszDisplay[MAX_PATH];
  4460. DWORD dwcch = MAX_PATH;
  4461. if (SUCCEEDED(GetScheme(wszEdit, &dwcch, SCHEME_GLOBAL | SCHEME_EDIT)))
  4462. {
  4463. dwcch = MAX_PATH;
  4464. if (SUCCEEDED(GetScheme(wszDisplay, &dwcch, SCHEME_GLOBAL | SCHEME_DISPLAY)))
  4465. {
  4466. BOOL fInSafeMode = (StrCmpW(wszDisplay, REG_DESKCOMP_SAFEMODE_SUFFIX_L) == 0);
  4467. if (fSetSafeMode != fInSafeMode)
  4468. {
  4469. LPWSTR lpwstr;
  4470. DWORD dwSchemeFlags = SCHEME_GLOBAL | SCHEME_DISPLAY;
  4471. if (dwFlags & SSM_REFRESH)
  4472. dwSchemeFlags |= SCHEME_REFRESH;
  4473. if (dwFlags & SSM_UPDATE)
  4474. dwSchemeFlags |= SCHEME_UPDATE;
  4475. lpwstr = fSetSafeMode ? REG_DESKCOMP_SAFEMODE_SUFFIX_L : wszEdit;
  4476. SetScheme(lpwstr, dwSchemeFlags);
  4477. }
  4478. }
  4479. }
  4480. }
  4481. return S_OK;
  4482. }
  4483. //
  4484. // EnsureUpdateHTML
  4485. //
  4486. // Ensures that the current html file present on the disk is in sync
  4487. // with the registry information for the current active desktop scheme. If
  4488. // it is not in sync then a fresh copy of the file is generated from the
  4489. // registry for the current scheme.
  4490. //
  4491. HRESULT CActiveDesktop::EnsureUpdateHTML(void)
  4492. {
  4493. DWORD dwFlags = 0;
  4494. DWORD dwDataLength = sizeof(DWORD);
  4495. LONG lRet;
  4496. TCHAR lpszDeskcomp[MAX_PATH];
  4497. TCHAR szDesktopFile[MAX_PATH];
  4498. DWORD dwRestrictUpdate;
  4499. DWORD dwRestrict = SHRestricted2W(REST_NoChannelUI, NULL, 0);
  4500. DWORD dwSize = sizeof(dwRestrictUpdate);
  4501. BOOL fComponentsDirty = FALSE; //Assume that the components are NOT dirty!
  4502. DWORD dwVersion;
  4503. DWORD dwMinorVersion;
  4504. BOOL fStaleInfoInReg = FALSE;
  4505. BOOL fComponentsZoomDirty = FALSE;
  4506. static BOOL s_fNoDeskComp = (BOOL)-1;
  4507. static BOOL s_fNoWallpaper = (BOOL)-1;
  4508. BOOL fNoDeskComp = SHRestricted(REST_NODESKCOMP);
  4509. BOOL fNoWallpaper = SHRestricted(REST_NOHTMLWALLPAPER);
  4510. BOOL fAdminComponent = FALSE;
  4511. HKEY hkey = NULL;
  4512. HKEY hkeyTime;
  4513. FILETIME ftAdminCompKey;
  4514. if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, REG_DESKCOMP_COMPONENTS_ROOT, REG_VAL_GENERAL_RESTRICTUPDATE, NULL, &dwRestrictUpdate, &dwSize))
  4515. dwRestrictUpdate = 0;
  4516. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, NULL);
  4517. //See if this branch of registry is old
  4518. if ((lRet = SHGetValue(HKEY_CURRENT_USER, lpszDeskcomp, REG_VAL_COMP_VERSION, NULL,
  4519. &dwVersion, &dwDataLength)) == ERROR_SUCCESS)
  4520. {
  4521. if (dwVersion < CUR_DESKHTML_VERSION)
  4522. fStaleInfoInReg = TRUE;
  4523. else
  4524. {
  4525. //Major versions are equal. Check minor versions.
  4526. if ((lRet = SHGetValue(HKEY_CURRENT_USER, (LPCTSTR)lpszDeskcomp, REG_VAL_COMP_MINOR_VERSION, NULL,
  4527. &dwMinorVersion, &dwDataLength)) == ERROR_SUCCESS)
  4528. {
  4529. if (dwMinorVersion != CUR_DESKHTML_MINOR_VERSION)
  4530. fStaleInfoInReg = TRUE;
  4531. }
  4532. else
  4533. fStaleInfoInReg = TRUE;
  4534. }
  4535. }
  4536. else
  4537. fStaleInfoInReg = TRUE;
  4538. dwDataLength = sizeof(DWORD);
  4539. //Check the dirty bit to see if we need to re-generate the desktop html
  4540. if ((lRet = SHGetValue(HKEY_CURRENT_USER, (LPCTSTR)lpszDeskcomp, REG_VAL_COMP_GENFLAGS, NULL,
  4541. &dwFlags, &dwDataLength)) == ERROR_SUCCESS)
  4542. {
  4543. if (IsFlagSet(dwFlags, COMPONENTS_DIRTY))
  4544. fComponentsDirty = TRUE;
  4545. if (IsFlagSet(dwFlags, COMPONENTS_ZOOMDIRTY))
  4546. fComponentsZoomDirty = TRUE;
  4547. }
  4548. // See if we need to add/delete an administrator added desktop component now
  4549. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REG_DESKCOMP_ADMINCOMP_ROOT, 0, KEY_READ, &hkey))
  4550. {
  4551. FILETIME ftLast;
  4552. DWORD cbData = SIZEOF(ftLast);
  4553. DWORD dwType;
  4554. ZeroMemory(&ftLast, SIZEOF(ftLast));
  4555. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REG_DESKCOMP, 0, KEY_READ, &hkeyTime))
  4556. {
  4557. SHQueryValueEx(hkeyTime, TEXT("LastSyncedTime"), NULL, &dwType, (LPBYTE)&ftLast, &cbData);
  4558. RegCloseKey(hkeyTime);
  4559. }
  4560. RegQueryInfoKey(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ftAdminCompKey);
  4561. if (CompareFileTime(&ftAdminCompKey, &ftLast) == 1) {
  4562. WCHAR wszDisplay[MAX_PATH];
  4563. DWORD dwcch = MAX_PATH;
  4564. if (FAILED(GetScheme(wszDisplay, &dwcch, SCHEME_GLOBAL | SCHEME_DISPLAY)) ||
  4565. (StrCmpW(wszDisplay, REG_DESKCOMP_SAFEMODE_SUFFIX_L) != 0))
  4566. {
  4567. // We're not in safe mode, it's OK to add the components
  4568. fAdminComponent = TRUE;
  4569. }
  4570. }
  4571. }
  4572. // 99/03/23 #237632 vtan: If the monitor arrangement has been changed from underneath
  4573. // the user (perhaps by another user) then make sure that the components are in valid
  4574. // positions. If not then snap them back into the visible space and mark them as dirty
  4575. // so that the desktop.htt file is regenerated.
  4576. _Initialize();
  4577. if (_hdsaComponent)
  4578. {
  4579. int i, iComponentCount;;
  4580. iComponentCount = DSA_GetItemCount(_hdsaComponent);
  4581. for (i = 0; i < iComponentCount; ++i)
  4582. {
  4583. COMPONENTA *pComponent;
  4584. pComponent = reinterpret_cast<COMPONENTA*>(DSA_GetItemPtr(_hdsaComponent, i));
  4585. if (pComponent != NULL)
  4586. {
  4587. bool bChangedPosition = FALSE, bChangedSize = FALSE;
  4588. if (!SHIsTempDisplayMode()) //Modify the positions only if we are not in a temp mode change.
  4589. ValidateComponentPosition(&pComponent->cpPos, pComponent->dwCurItemState, pComponent->iComponentType, &bChangedPosition, &bChangedSize);
  4590. if (bChangedPosition || bChangedSize)
  4591. {
  4592. TBOOL(UpdateComponentPrivate(i, pComponent));
  4593. fComponentsDirty = true;
  4594. }
  4595. }
  4596. }
  4597. }
  4598. if (FAILED(GetPerUserFileName(szDesktopFile, ARRAYSIZE(szDesktopFile), DESKTOPHTML_FILENAME)))
  4599. {
  4600. szDesktopFile[0] = 0;
  4601. }
  4602. if (fComponentsDirty ||
  4603. fComponentsZoomDirty ||
  4604. fStaleInfoInReg ||
  4605. fAdminComponent ||
  4606. fNoDeskComp != s_fNoDeskComp ||
  4607. fNoWallpaper != s_fNoWallpaper ||
  4608. (dwRestrictUpdate != dwRestrict) ||
  4609. !PathFileExistsAndAttributes(szDesktopFile, NULL)) //See if the file exists!
  4610. {
  4611. // Clear out any html wallpaper if it exists and the restriction is set
  4612. if (fNoWallpaper != s_fNoWallpaper)
  4613. {
  4614. if (fNoWallpaper && !IsWallpaperPicture(_szSelectedWallpaper))
  4615. SetWallpaper(L"", 0);
  4616. s_fNoWallpaper = fNoWallpaper;
  4617. }
  4618. // Disable components if the restriction is set
  4619. if (fNoDeskComp != s_fNoDeskComp)
  4620. {
  4621. // We can't set fEnableComponents to FALSE because there is no way via the UI
  4622. // for the user to turn it back on again if the restriction is lifted. Instead we add
  4623. // special case code to _GenerateHtml that checks the restriction too.
  4624. // _co.fEnableComponents = !fNoDeskComp;
  4625. s_fNoDeskComp = fNoDeskComp;
  4626. }
  4627. if (fAdminComponent)
  4628. {
  4629. COMPONENT comp;
  4630. TCHAR pszAdminComp[INTERNET_MAX_URL_LENGTH];
  4631. CHAR szUrl[INTERNET_MAX_URL_LENGTH];
  4632. CHAR * pszUrl;
  4633. CHAR * pszUrlList;
  4634. TCHAR * aszAdminComp[] = {REG_VAL_ADMINCOMP_ADD, REG_VAL_ADMINCOMP_DELETE, NULL};
  4635. int i = 0;
  4636. comp.dwSize = sizeof(comp);
  4637. comp.dwCurItemState = IS_SPLIT | IS_ADJUSTLISTVIEW;
  4638. while (aszAdminComp[i])
  4639. {
  4640. dwDataLength = sizeof(pszAdminComp);
  4641. // The reg value contains an array of space separated urls - currently we support adding and deleting
  4642. // a desktop item via this mechanism.
  4643. if (SHQueryValueEx(hkey, aszAdminComp[i], NULL, NULL, (LPBYTE)pszAdminComp, &dwDataLength) == ERROR_SUCCESS)
  4644. {
  4645. SHTCharToAnsi(pszAdminComp, szUrl, ARRAYSIZE(szUrl));
  4646. pszUrlList = szUrl;
  4647. while (pszUrl = StrTokEx(&pszUrlList, " ")) {
  4648. SHAnsiToUnicode(pszUrl, comp.wszSource, ARRAYSIZE(comp.wszSource));
  4649. dwDataLength = ARRAYSIZE(comp.wszSource);
  4650. ParseURLFromOutsideSourceW(comp.wszSource, comp.wszSource, &dwDataLength, NULL);
  4651. if (lstrcmp(aszAdminComp[i], REG_VAL_ADMINCOMP_ADD) == 0)
  4652. {
  4653. AddUrl(NULL, (LPCWSTR)comp.wszSource, &comp, ADDURL_SILENT);
  4654. fComponentsZoomDirty = TRUE;
  4655. }
  4656. else
  4657. {
  4658. RemoveDesktopItem((LPCOMPONENT)&comp, 0);
  4659. }
  4660. }
  4661. }
  4662. i++;
  4663. }
  4664. SHSetValue(HKEY_CURRENT_USER, REG_DESKCOMP, TEXT("LastSyncedTime"), REG_BINARY, (LPVOID)&ftAdminCompKey, SIZEOF(ftAdminCompKey));
  4665. }
  4666. // Go through the entire list of desktop components and ensure any split/fullscreen
  4667. // components are at their correct size/location.
  4668. if (fComponentsZoomDirty)
  4669. {
  4670. if (_hdsaComponent)
  4671. {
  4672. int i;
  4673. for (i = 0; i < DSA_GetItemCount(_hdsaComponent); i++)
  4674. {
  4675. COMPONENTA * pcompT;
  4676. if (pcompT = (COMPONENTA *)DSA_GetItemPtr(_hdsaComponent, i))
  4677. {
  4678. if (ISZOOMED(pcompT))
  4679. {
  4680. BOOL fAdjustListview = (pcompT->dwCurItemState & IS_ADJUSTLISTVIEW);
  4681. ZoomComponent(&pcompT->cpPos, pcompT->dwCurItemState, fAdjustListview);
  4682. if (fAdjustListview)
  4683. pcompT->dwCurItemState &= ~IS_ADJUSTLISTVIEW;
  4684. }
  4685. }
  4686. }
  4687. SetDesktopFlags(COMPONENTS_ZOOMDIRTY, 0);
  4688. }
  4689. }
  4690. // NOTE #1: The above initialization would have changed the Z-order because of
  4691. // SortAndRationalize and so we need to APPLY_SAVE here.
  4692. // Warning: APPLY_SAVE changes the dwID field of components. This should not
  4693. // be a problem because we do this just before generating a new HTML file.
  4694. // NOTE #2: Do NOT use AD_APPLY_FORCE here. That sets the _fPatternDirty too and
  4695. // that causes a SystemParametersInfo() call which results in WM_SYSCOLORCHANGE
  4696. // and this causes a refresh. So, we set the dirty bit explicitly here.
  4697. _fDirty = TRUE; // See Note#2 above.
  4698. ApplyChanges(AD_APPLY_SAVE | AD_APPLY_HTMLGEN);
  4699. lRet = ERROR_SUCCESS;
  4700. if (dwRestrictUpdate != dwRestrict)
  4701. SHSetValue(HKEY_CURRENT_USER, REG_DESKCOMP_COMPONENTS_ROOT, REG_VAL_GENERAL_RESTRICTUPDATE, NULL, &dwRestrict, sizeof(dwRestrict));
  4702. }
  4703. if (hkey)
  4704. {
  4705. RegCloseKey(hkey);
  4706. }
  4707. return (lRet == ERROR_SUCCESS ? S_OK : E_FAIL);
  4708. }
  4709. //
  4710. // ReReadWallpaper()
  4711. // If the wallpaper was read when the active desktop was disabled, we would have read it from
  4712. // the old location. Now, if the active desktop is turned ON, then we need to re-read the wallpaper
  4713. // from the new location. We need to do this iff the wallpaper has not been changed in the mean-while
  4714. //
  4715. HRESULT CActiveDesktop::ReReadWallpaper(void)
  4716. {
  4717. if ((!_fDirty) || (!_co.fActiveDesktop)) //If nothing has changed OR if active desktop is OFF,
  4718. return(S_FALSE); // then nothing to do!
  4719. //ActiveDesktop is ON in our object. Read current shell state.
  4720. SHELLSTATE ss = {0};
  4721. SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
  4722. if (ss.fDesktopHTML)
  4723. return(S_FALSE); // Active Desktop state hasn't changed. So, nothing to do!
  4724. //So, Active desktop was originally OFF and now it is turned ON.
  4725. //If if someone changed the wallpaper, we should not mess with it.
  4726. if (_fWallpaperDirty || _fWallpaperChangedDuringInit)
  4727. return(S_FALSE);
  4728. // No one has changed the wallpaper. So, we must re-read it from the new wallpaper location
  4729. // sothat we get the correct wallpaper for the active desktop mode.
  4730. _ReadWallpaper(TRUE);
  4731. return(S_OK);
  4732. }
  4733. //
  4734. // GetADObjectFlags()
  4735. //
  4736. // Get the Active Desktop object's internal flags
  4737. //
  4738. HRESULT CActiveDesktop::GetADObjectFlags(LPDWORD lpdwFlags, DWORD dwMask)
  4739. {
  4740. ASSERT(lpdwFlags);
  4741. *lpdwFlags = 0; //Init the flags
  4742. if ((dwMask & GADOF_DIRTY) && _fDirty)
  4743. *lpdwFlags |= GADOF_DIRTY;
  4744. return(S_OK);
  4745. }
  4746. HRESULT ForceFullRefresh(void)
  4747. {
  4748. HWND hwndShell = GetShellWindow();
  4749. //Force a SHRefresh with this dummy call
  4750. SHGetSetSettings(NULL, 0, TRUE);
  4751. SendMessage(hwndShell, DTM_MAKEHTMLCHANGES, (WPARAM)0, (LPARAM)0L);
  4752. //Can't use dynamic html. We have to refresh the whole page.
  4753. SendMessage(hwndShell, WM_WININICHANGE, SPI_SETDESKWALLPAPER, (LPARAM)c_szRefreshDesktop);
  4754. return S_OK;
  4755. }
  4756. HRESULT CActiveDesktop::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  4757. {
  4758. HRESULT hr = E_INVALIDARG;
  4759. if (pszPropName && pVar)
  4760. {
  4761. hr = E_FAIL;
  4762. if (StrCmpIW(pszPropName, c_wszPropName_IgnorePolicies) == 0)
  4763. {
  4764. pVar->vt = VT_BOOL;
  4765. pVar->boolVal = (_fIgnoreAddRemovePolicies ? VARIANT_TRUE : VARIANT_TRUE);
  4766. hr = S_OK;
  4767. }
  4768. else if (StrCmpIW(pszPropName, c_wszPropName_TSPerfBGPolicy) == 0)
  4769. {
  4770. BOOL fPolicySet = (IsTSPerfFlagEnabled(TSPerFlag_NoADWallpaper) || IsTSPerfFlagEnabled(TSPerFlag_NoWallpaper)); //No policy is set!
  4771. pVar->vt = VT_BOOL;
  4772. pVar->boolVal = (fPolicySet ? VARIANT_TRUE : VARIANT_TRUE);
  4773. hr = S_OK;
  4774. }
  4775. }
  4776. return hr;
  4777. }
  4778. HRESULT CActiveDesktop::Write(LPCOLESTR pszPropName, VARIANT *pVar)
  4779. {
  4780. HRESULT hr = E_INVALIDARG;
  4781. if (pszPropName && pVar)
  4782. {
  4783. hr = E_FAIL;
  4784. if ((StrCmpIW(pszPropName, c_wszPropName_IgnorePolicies) == 0) && (VT_BOOL == pVar->vt))
  4785. {
  4786. _fIgnoreAddRemovePolicies = (VARIANT_TRUE == pVar->boolVal);
  4787. hr = S_OK;
  4788. }
  4789. else if ((StrCmpIW(pszPropName, c_wszPropName_TSPerfBGPolicy) == 0) && (VT_BOOL == pVar->vt))
  4790. {
  4791. ForceFullRefresh();
  4792. hr = S_OK;
  4793. }
  4794. }
  4795. return hr;
  4796. }
  4797. /***
  4798. *char *StrTokEx(pstring, control) - tokenize string with delimiter in control
  4799. *
  4800. *Purpose:
  4801. * StrTokEx considers the string to consist of a sequence of zero or more
  4802. * text tokens separated by spans of one or more control chars. the first
  4803. * call, with string specified, returns a pointer to the first char of the
  4804. * first token, and will write a null char into pstring immediately
  4805. * following the returned token. when no tokens remain
  4806. * in pstring a NULL pointer is returned. remember the control chars with a
  4807. * bit map, one bit per ascii char. the null char is always a control char.
  4808. *
  4809. *Entry:
  4810. * char **pstring - ptr to ptr to string to tokenize
  4811. * char *control - string of characters to use as delimiters
  4812. *
  4813. *Exit:
  4814. * returns pointer to first token in string,
  4815. * returns NULL when no more tokens remain.
  4816. * pstring points to the beginning of the next token.
  4817. *
  4818. *WARNING!!!
  4819. * upon exit, the first delimiter in the input string will be replaced with '\0'
  4820. *
  4821. * copied from iert.lib
  4822. *******************************************************************************/
  4823. extern "C" char * __cdecl StrTokEx(char ** spstring, const char * scontrol)
  4824. {
  4825. unsigned char **pstring = (unsigned char**) spstring;
  4826. unsigned char *control = (unsigned char*) scontrol;
  4827. unsigned char *str;
  4828. const unsigned char *ctrl = control;
  4829. unsigned char map[32];
  4830. int count;
  4831. unsigned char *tokenstr;
  4832. if (*pstring == NULL)
  4833. return NULL;
  4834. /* Clear control map */
  4835. for (count = 0; count < 32; count++)
  4836. map[count] = 0;
  4837. /* Set bits in delimiter table */
  4838. do
  4839. {
  4840. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  4841. } while (*ctrl++);
  4842. /* Initialize str. */
  4843. str = *pstring;
  4844. /* Find beginning of token (skip over leading delimiters). Note that
  4845. * there is no token if this loop sets str to point to the terminal
  4846. * null (*str == '\0') */
  4847. while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
  4848. str++;
  4849. tokenstr = str;
  4850. /* Find the end of the token. If it is not the end of the string,
  4851. * put a null there. */
  4852. for ( ; *str ; str++ )
  4853. {
  4854. if ( map[*str >> 3] & (1 << (*str & 7)) )
  4855. {
  4856. *str++ = '\0';
  4857. break;
  4858. }
  4859. }
  4860. /* string now points to beginning of next token */
  4861. *pstring = str;
  4862. /* Determine if a token has been found. */
  4863. if ( tokenstr == str )
  4864. return NULL;
  4865. else
  4866. return (char*)tokenstr;
  4867. }