deskstat.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 188k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. #ifdef _WIN64
  4. extern "C" char * __cdecl StrTokEx(char ** pstring, const char * control);
  5. #else
  6. #include <iert.h>
  7. #endif
  8. #define DXA_GROWTH_CONST 10
  9. #define ZINDEX_START 1000
  10. #define MAXID_LENGTH    10  //Maximum number of digits in ID string plus 1.
  11. #if 0
  12. #define TF_DESKSTAT     TF_CUSTOM2
  13. #define TF_DYNAMICHTML  TF_CUSTOM1
  14. #else
  15. #define TF_DESKSTAT     0
  16. #define TF_DYNAMICHTML  0
  17. #endif
  18. IActiveDesktop *g_pActiveDesk = NULL;
  19. #define c_szRegStrDesktop REGSTR_PATH_DESKTOP
  20. #define c_szWallpaper  REG_VAL_GENERAL_WALLPAPER
  21. #define c_szBackupWallpaper REG_VAL_GENERAL_BACKUPWALLPAPER
  22. #define c_szPattern TEXT("Pattern")
  23. #define c_szTileWall REG_VAL_GENERAL_TILEWALLPAPER
  24. #define c_szWallpaperStyle REG_VAL_GENERAL_WALLPAPERSTYLE
  25. #define c_szWallpaperTime REG_VAL_GENERAL_WALLPAPERTIME
  26. #define c_szRefreshDesktop TEXT("RefreshDesktop")
  27. #define c_szBufferedRefresh TEXT("BufferedRefresh")
  28. #define COMP_TYPE               0x00000003
  29. #define COMP_SELECTED           0x00002000
  30. #define COMP_NOSCROLL           0x00004000
  31. #ifdef DEBUG
  32. #define ENTERPROC EnterProcDS
  33. #define EXITPROC ExitProcDS
  34. void EnterProcDS(DWORD dwTraceLevel, LPSTR szFmt, ...);
  35. void ExitProcDS(DWORD dwTraceLevel, LPSTR szFmt, ...);
  36. extern DWORD g_dwDeskStatTrace;
  37. #else
  38. #ifndef CCOVER
  39. #pragma warning(disable:4002)
  40. #define ENTERPROC()
  41. #define EXITPROC()
  42. #else // ccover buildi
  43. // these are needed because of a bug in cl.exe that results in improper processing
  44. // of #pragma when run with cl -P, and then compiling
  45. #define ENTERPROC 1 ? (void) 0 : (void)
  46. #define EXITPROC 1 ? (void) 0 : (void)
  47. #endif //end of ccover 
  48. #endif
  49. MAKE_CONST_BSTR(s_sstrBeforeEnd,       L"BeforeEnd");
  50. MAKE_CONST_BSTR(s_sstrDeskMovr,        L"DeskMovr");
  51. MAKE_CONST_BSTR(s_sstrDeskMovrW,       L"DeskMovrW");
  52. MAKE_CONST_BSTR(s_sstrclassid,         L"classid");
  53. MAKE_CONST_BSTR(s_sstrEmpty,           L"");
  54. STDAPI ParseDesktopComponent(HWND hwndOwner, LPWSTR wszURL, COMPONENT *pInfo);
  55. WCHAR   wUnicodeBOM =  0xfeff; // Little endian unicode Byte Order Mark.First byte:0xff, Second byte: 0xfe.
  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.         
  66.         if((ReadFile(_hFile, (LPVOID)&wBOM, sizeof(WCHAR), &dwBytesRead, NULL)) && 
  67.            (dwBytesRead == sizeof(WCHAR)))
  68.         {
  69.             if(wBOM == wUnicodeBOM)
  70.                 _iCharset = UNICODE_HTML_CHARSET;
  71.             else
  72.             {
  73.                 //Note: Anything other than the little endian unicode file is treated as ansi.
  74.                 _iCharset = ANSI_HTML_CHARSET;
  75.                 SetFilePointer(_hFile, 0L, NULL, FILE_BEGIN);  //Seek to the begining of the file
  76.             }
  77.         }
  78.     }
  79. }
  80. CReadFileObj::~CReadFileObj()
  81. {
  82.     if(_hFile != INVALID_HANDLE_VALUE)
  83.     {
  84.         CloseHandle(_hFile);
  85.         _hFile = NULL;
  86.     }
  87. }
  88. //
  89. // This will read and if necessary convert between ANSI and UNICODE
  90. //
  91. //
  92. // NOTE: The uiCharsToRead must be atleast one less than the size of the buffer (lpwszBuff)
  93. // because one null may be written at the end of the buffer by SHAnsiToUnicode().
  94. //
  95. HRESULT CReadFileObj::FileReadAndConvertChars(int iDestCharset, LPWSTR lpwszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead, UINT *puiCharsConverted)
  96. {
  97.     HRESULT hres = S_OK;
  98.     DWORD dwCharsRead = 0;
  99.     DWORD dwTotalCharsConverted = 0;
  100.     if(_hFile != INVALID_HANDLE_VALUE)
  101.     {
  102.         if(_iCharset == UNICODE_HTML_CHARSET)
  103.         {
  104.             if(iDestCharset == UNICODE_HTML_CHARSET)
  105.             {
  106.                 hres = FileReadCharsW(lpwszBuff, uiCharsToRead, (UINT *)&dwCharsRead);
  107.                 dwTotalCharsConverted = dwCharsRead;
  108.             }
  109.             else
  110.             {
  111.                 //Destination is ansi; Read the UNICODE source and convert to ANSI.
  112.                 WCHAR  wszBuf[INTERNET_MAX_URL_LENGTH + 1];  //Temp buffer to read the UNICODE chars into.
  113.                 LPSTR lpszBuff = (LPSTR)lpwszBuff;
  114.                 DWORD  dwTotalCharsToRead = (DWORD)uiCharsToRead;
  115.     
  116.                 while(dwTotalCharsToRead)
  117.                 {
  118.                     DWORD dwCount;
  119.                     DWORD dwActuallyRead;
  120.                     
  121.                     // - 1 to give room for a null character at the end.
  122.                     dwCount = min(dwTotalCharsToRead, (ARRAYSIZE(wszBuf) - 1));
  123.                     if(ReadFile(_hFile, (LPSTR)wszBuf, dwCount*sizeof(WCHAR), &dwActuallyRead, NULL))
  124.                     {
  125.                         DWORD dwConverted;
  126.                         dwActuallyRead = dwActuallyRead/sizeof(WCHAR);
  127.                         
  128.                         //Null terminate the source buffer.
  129.                         wszBuf[dwActuallyRead] = L'';  //UNICODE null terminate the source.
  130.                         //Convert what we just read.
  131.                         dwConverted = SHUnicodeToAnsi(wszBuf, lpszBuff, dwActuallyRead+1); //+1 for null termination
  132.                         //Update the count & stuff.
  133.                         lpszBuff += dwConverted - 1;  //Subtract the null.
  134.                         dwTotalCharsToRead -= dwActuallyRead;
  135.                         dwCharsRead += dwActuallyRead;
  136.                         dwTotalCharsConverted += dwConverted - 1; //Subtract the null.
  137.                     
  138.                         if(dwActuallyRead < dwCount)
  139.                             break;  //We have reached the end of file.
  140.                     }
  141.                     else
  142.                     {
  143.                         hres = E_FAIL;
  144.                         break;
  145.                     }
  146.                 }
  147.             }
  148.         }
  149.         else
  150.         {
  151.             //Source file is ANSI. Check the Destination.
  152.             if(iDestCharset == ANSI_HTML_CHARSET)
  153.             {
  154.                 //Destination is ANSI too! Cool! No need for conversion!
  155.                 hres = FileReadCharsA((LPSTR)lpwszBuff, uiCharsToRead, (UINT *)&dwCharsRead);
  156.                 dwTotalCharsConverted = dwCharsRead;
  157.             }
  158.             else
  159.             {
  160.                 //Destination is UNICODE!  Read the ansi and convert it to UNICODE!
  161.                 char  szBuf[INTERNET_MAX_URL_LENGTH + 1];  //Temp buffer to read the ansi chars into.
  162.                 DWORD  dwTotalCharsToRead = (DWORD)uiCharsToRead;
  163.                 while(dwTotalCharsToRead)
  164.                 {
  165.                     DWORD dwCount;
  166.                     DWORD dwActuallyRead;
  167.                     // - 1 to give room for a null character at the end.
  168.                     dwCount = min(dwTotalCharsToRead, (ARRAYSIZE(szBuf) - 1));
  169.                     if(ReadFile(_hFile, (LPSTR)szBuf, dwCount, &dwActuallyRead, NULL))
  170.                     {
  171.                         DWORD dwConverted;
  172.                         //Null terminate the source buffer.
  173.                         szBuf[dwActuallyRead] = '';  //ANSI null terminate the source.
  174.                         //Convert what we just read.
  175.                         dwConverted = SHAnsiToUnicode(szBuf, lpwszBuff, dwActuallyRead+1); //+1 for null termination
  176.                         //Update the count & stuff.
  177.                         lpwszBuff += dwConverted - 1;  //Subtract the null.
  178.                         dwTotalCharsToRead -= dwActuallyRead;
  179.                         dwCharsRead += dwActuallyRead;
  180.                         dwTotalCharsConverted += dwConverted - 1; //Subtract the null.
  181.                     
  182.                         if(dwActuallyRead < dwCount)
  183.                             break;  //We have reached the end of file.
  184.                     }
  185.                     else
  186.                     {
  187.                         hres = E_FAIL;
  188.                         break;
  189.                     }
  190.                 } //while
  191.             }
  192.         }
  193.     }
  194.     else
  195.         hres = E_FAIL;  //The file handle is bad.
  196.     *puiCharsActuallyRead = (UINT)dwCharsRead;
  197.     *puiCharsConverted = (UINT)dwTotalCharsConverted;
  198.     return hres; 
  199. }
  200. HRESULT CReadFileObj::FileReadCharsA(LPSTR lpszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead)
  201. {
  202.     HRESULT hres = E_FAIL;
  203.     DWORD dwCharsRead = 0;
  204.     
  205.     if ((_hFile != INVALID_HANDLE_VALUE) && 
  206.         (_iCharset == ANSI_HTML_CHARSET) &&
  207.         ReadFile(_hFile, (LPVOID)lpszBuff, (DWORD)(uiCharsToRead), &dwCharsRead, NULL))
  208.     {
  209.         dwCharsRead = dwCharsRead; //get the number of wchars read.
  210.         hres = S_OK;
  211.     }
  212.     *puiCharsActuallyRead = (UINT)dwCharsRead;
  213.     return hres; 
  214. }
  215. HRESULT CReadFileObj::FileReadCharsW(LPWSTR lpwszBuff, UINT uiCharsToRead, UINT *puiCharsActuallyRead)
  216. {
  217.     HRESULT hres = E_FAIL;
  218.     DWORD dwCharsRead = 0;
  219.     
  220.     if ((_hFile != INVALID_HANDLE_VALUE) && 
  221.         (_iCharset == UNICODE_HTML_CHARSET) &&
  222.         ReadFile(_hFile, (LPVOID)lpwszBuff, (DWORD)(uiCharsToRead*sizeof(WCHAR)), &dwCharsRead, NULL))
  223.     {
  224.         dwCharsRead = dwCharsRead/sizeof(WCHAR); //get the number of wchars read.
  225.         hres = S_OK;
  226.     }
  227.     *puiCharsActuallyRead = (UINT)dwCharsRead;
  228.     return hres; 
  229. }
  230. HRESULT CReadFileObj::FileSeekChars(LONG  lCharOffset, DWORD dwOrigin)
  231. {
  232.     HRESULT hres = E_FAIL;
  233.     if(_hFile != INVALID_HANDLE_VALUE)
  234.     {
  235.         if(SetFilePointer(_hFile, 
  236.                     lCharOffset*((_iCharset == UNICODE_HTML_CHARSET) ? sizeof(WCHAR) : sizeof(char)),
  237.                     NULL,
  238.                     dwOrigin) != INVALID_SET_FILE_POINTER)
  239.             hres = S_OK;
  240.     }
  241.     return hres;
  242. }
  243. HRESULT CReadFileObj::FileGetCurCharOffset(LONG  *plCharOffset)
  244. {
  245.     HRESULT hres = E_FAIL;
  246.     DWORD   dwByteOffset = 0;
  247.     *plCharOffset = 0;
  248.     if(_hFile != INVALID_HANDLE_VALUE)
  249.     {
  250.         if((dwByteOffset = SetFilePointer(_hFile, 
  251.                                             0L,
  252.                                             NULL,
  253.                                             FILE_CURRENT)) != INVALID_SET_FILE_POINTER)
  254.         {
  255.             *plCharOffset = dwByteOffset/((_iCharset == UNICODE_HTML_CHARSET) ? sizeof(WCHAR) : sizeof(char));
  256.             hres = S_OK;
  257.         }
  258.     }
  259.     return hres;
  260. }
  261. int GetIntFromReg(HKEY    hKey,
  262.                   LPCTSTR lpszSubkey,
  263.                   LPCTSTR lpszNameValue,
  264.                   int     iDefault)
  265. {
  266.     TCHAR szValue[20];
  267.     DWORD dwSizeofValueBuff = SIZEOF(szValue);
  268.     int iRetValue = iDefault;
  269.     DWORD dwType;
  270.     if ((SHGetValue(hKey, lpszSubkey, lpszNameValue, &dwType,(LPBYTE)szValue,
  271.                    &dwSizeofValueBuff) == ERROR_SUCCESS) && dwSizeofValueBuff)
  272.     {
  273.         if (dwType == REG_SZ)
  274.         {
  275.             iRetValue = (int)StrToInt(szValue);
  276.         }
  277.     }
  278.     return iRetValue;
  279. }
  280. BOOL GetStringFromReg(HKEY    hkey,
  281.               LPCTSTR lpszSubkey,
  282.               LPCTSTR lpszValueName,
  283.               LPCTSTR lpszDefault,
  284.               LPTSTR  lpszValue,
  285.               DWORD   cchSizeofValueBuff)
  286. {
  287.     BOOL fRet = FALSE;
  288.     DWORD dwType;
  289.     cchSizeofValueBuff *= sizeof(TCHAR);
  290.     if (SHGetValue(hkey, lpszSubkey, lpszValueName, &dwType, lpszValue, &cchSizeofValueBuff) == ERROR_SUCCESS)
  291.     {
  292.         fRet = TRUE;
  293.     }
  294.     //
  295.     // On failure use the default string.
  296.     //
  297.     if (!fRet && lpszDefault)
  298.     {
  299.         lstrcpy(lpszValue, lpszDefault);
  300.     }
  301.     return fRet;
  302. }
  303. void GetWallpaperFileTime(LPCTSTR pszWallpaper, LPFILETIME lpftFileTime)
  304. {
  305.     HANDLE   hFile;
  306.     BOOL fRet = FALSE;
  307.     if((hFile = CreateFile(pszWallpaper, GENERIC_READ, FILE_SHARE_READ,
  308.             NULL, OPEN_EXISTING,
  309.             FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
  310.     {
  311.         fRet = GetFileTime(hFile, NULL, NULL, lpftFileTime);
  312.         CloseHandle(hFile);
  313.     }
  314.     if (!fRet)
  315.         ZeroMemory(lpftFileTime, SIZEOF(FILETIME));
  316.     //  no return value
  317. }
  318. BOOL  HasWallpaperReallyChanged(LPCTSTR pszRegKey, LPTSTR pszOldWallpaper, LPTSTR pszBackupWallpaper, DWORD dwOldWallpaperStyle, DWORD dwNewWallpaperStyle)
  319. {
  320.     //  we default to TRUE here.
  321.     
  322.     if ((dwOldWallpaperStyle == dwNewWallpaperStyle)
  323.     && (0 == lstrcmpi(pszOldWallpaper, pszBackupWallpaper)))
  324.     {
  325.         // The wallpaper filename and style hasn't changed. 
  326.         //  But, the content of this file could have changed. 
  327.         //  See if the content has changed by looking at the 
  328.         // last-written date and time stamp on this file.
  329.         FILETIME ftOld, ftBack;
  330.         DWORD dwType, cbBack = SIZEOF(ftBack);
  331.         //  if either of these fail, then they will
  332.         //  remain Zero  so the compare will
  333.         //  be successful.
  334.         GetWallpaperFileTime(pszOldWallpaper, &ftOld);
  335.         if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, pszRegKey, c_szWallpaperTime, &dwType, &ftBack, &cbBack))
  336.             ZeroMemory(&ftBack, SIZEOF(ftBack));
  337.         //Get the last written time of the backup wallpaper from registry
  338.         if (ftOld.dwLowDateTime == ftBack.dwLowDateTime
  339.         && (ftOld.dwHighDateTime == ftBack.dwHighDateTime))
  340.             //  everything is the same!
  341.             return FALSE;
  342.     }
  343.     
  344.     return TRUE;
  345. }
  346. //-------------------------------------------------------------------------------------------------------------//
  347. //  Function: ReadWallpaperStyleFromReg()
  348. //
  349. // This function reads the "TileWallpaper" and the "WallpaperStyle" from the given location
  350. // in the registry.
  351. //
  352. //-------------------------------------------------------------------------------------------------------------//
  353. void ReadWallpaperStyleFromReg(LPCTSTR pszRegKey, DWORD *pdwWallpaperStyle, BOOL fIgnorePlatforms)
  354. {
  355.     //Do not read "Stretch" bits for older platforms.
  356.     if(fIgnorePlatforms || g_bRunOnMemphis || g_bRunOnNT5)
  357.         *pdwWallpaperStyle = GetIntFromReg(HKEY_CURRENT_USER, pszRegKey, c_szWallpaperStyle, WPSTYLE_CENTER);
  358.     else
  359.         *pdwWallpaperStyle = WPSTYLE_CENTER;
  360.     if (GetIntFromReg(HKEY_CURRENT_USER, pszRegKey, c_szTileWall, WPSTYLE_TILE))
  361.     {
  362.         //
  363.         // "Tile" overrides the "Stretch" style.
  364.         //
  365.         *pdwWallpaperStyle = WPSTYLE_TILE;
  366.     }
  367.     // else, STRETCH or CENTER.
  368. }
  369. BOOL CActiveDesktop::_IsDisplayInSafeMode(void)
  370. {
  371.     WCHAR wszDisplay[MAX_PATH];
  372.     DWORD dwcch = MAX_PATH;
  373.     return (SUCCEEDED(GetScheme(wszDisplay, &dwcch, SCHEME_GLOBAL | SCHEME_DISPLAY)) 
  374.             && (0 == StrCmpW(wszDisplay, REG_DESKCOMP_SAFEMODE_SUFFIX_L)));
  375. }
  376. BOOL ReadPolicyForWallpaper(LPTSTR  lpszPolicyForWallpaper, DWORD dwSizeofBuff)
  377. {
  378.     TCHAR   szWallpaperName[MAX_PATH];
  379.     DWORD   dwType;
  380.     
  381.     if(!lpszPolicyForWallpaper)
  382.     {
  383.         lpszPolicyForWallpaper = szWallpaperName;
  384.         dwSizeofBuff = ARRAYSIZE(szWallpaperName);
  385.     }
  386.     if((SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_WP_POLICY, c_szWallpaper, &dwType,(LPBYTE)lpszPolicyForWallpaper,
  387.                    &dwSizeofBuff) == ERROR_SUCCESS) && dwSizeofBuff)
  388.         return TRUE;  //Policy is there!
  389.     else
  390.         return FALSE; //No policy is set!
  391. }
  392. BOOL ReadPolicyForWPStyle(LPDWORD  lpdwStyle)
  393. {
  394.     DWORD   dwStyle;
  395.     DWORD   dwType;
  396.     TCHAR   szValue[20];
  397.     DWORD   dwSizeofValueBuff = ARRAYSIZE(szValue);
  398.     BOOL    fRet = FALSE;
  399.     // The caller can passin a NULL, if they are not interested in the actual value and they just
  400.     // want to know if this policy is set or not.
  401.     if(!lpdwStyle)  
  402.         lpdwStyle = &dwStyle;
  403.     if ((SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_WP_POLICY, c_szWallpaperStyle, &dwType,(LPBYTE)szValue,
  404.                    &dwSizeofValueBuff) == ERROR_SUCCESS) && dwSizeofValueBuff)
  405.     {
  406.         if(dwType == REG_SZ)
  407.         {
  408.             *lpdwStyle = (DWORD)StrToInt(szValue);
  409.             fRet = TRUE;
  410.         }
  411.     }
  412.     return fRet;
  413. }
  414. void CActiveDesktop::_ReadWallpaper(BOOL fActiveDesktop)
  415. {
  416.     ENTERPROC(2, "DS ReadWallpaper()");
  417.     TCHAR lpszDeskcomp[MAX_PATH];
  418.     GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
  419.     _fPolicyForWPName = ReadPolicyForWallpaper(_szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper));
  420.     _fPolicyForWPStyle = ReadPolicyForWPStyle(&_wpo.dwStyle);
  421.     
  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.         GetStringFromReg(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 (!GetStringFromReg(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.         
  447.         //If there is a Safe mode scheme here do NOT attempt to change wallpaper
  448.         if((!_IsDisplayInSafeMode()) && (!_fPolicyForWPName))
  449.         {
  450.             //Read what is stored as "Backup" wallpaper.
  451.             GetStringFromReg(HKEY_CURRENT_USER, pszRegKey, c_szBackupWallpaper, szOldWallpaper, _szBackupWallpaper, ARRAYSIZE(_szBackupWallpaper));
  452.     
  453.             //See if the Old wallpaper is differnet from the backed up wallpaper
  454.             if(HasWallpaperReallyChanged(pszRegKey, szOldWallpaper, _szBackupWallpaper, dwOldWallpaperStyle, _wpo.dwStyle))
  455.             {
  456.                 //They are different. This means that some other app has changed the "Old" wallpaper
  457.                 //after the last time we backed it up in the registry.
  458.                 // Make this wallpaper as the Selected wallpaper!
  459. #ifdef WE_WANT_DEFAULT_WALLPAPER
  460.                 // The following hack is needed only if we want default wallpapers. For example, when
  461.                 // we port shell code to Win2000 millenium, we may want a default wallpaper in which case,
  462.                 // we need to enable the following hack and also in the deskcls.cpp file.
  463.                 //
  464.                 // This is a kinda hack, but the best possible solution right now. The scenario is as follows.
  465.                 // The Memphis setup guys replace what the user specifies as the wallpaper in the old location
  466.                 // and restore it after setup is complete. But, SetDefaultWallpaper() gets called bet. these
  467.                 // two times and we are supposed to take a decision on whether to set the default htm wallpaper or not,
  468.                 // depending on what the user had set before the installation. The solution is to delay making
  469.                 // this decision until after the setup guys have restored the user's wallpaper. We do this in
  470.                 // CActiveDesktop::_ReadWallpaper(). We specify that SetDefaultWallpaper() was called by setting
  471.                 // the backup wallpaper in the new location to the default wallpaper.
  472.                 TCHAR szDefaultWallpaper[MAX_PATH];
  473.                 GetDefaultWallpaper(szDefaultWallpaper, SIZECHARS(szDefaultWallpaper));
  474.                 if(lstrcmp(_szBackupWallpaper, szDefaultWallpaper) == 0
  475.                     && (!szOldWallpaper[0] || lstrcmp(szOldWallpaper, g_szNone) == 0))
  476.                 {
  477.                     lstrcpy(_szSelectedWallpaper, szDefaultWallpaper);
  478.                 }
  479.                 else
  480.                 {
  481.                     lstrcpy(_szSelectedWallpaper, szOldWallpaper);
  482.                 }
  483. #else  // WE_WANT_DEFAULT_WALLPAPER
  484.                 lstrcpy(_szSelectedWallpaper, szOldWallpaper);
  485. #endif // WE_WANT_DEFAULT_WALLPAPER
  486.                 _wpo.dwStyle = dwOldWallpaperStyle;
  487.                 _fWallpaperDirty = TRUE;
  488.                 _fWallpaperChangedDuringInit = TRUE;
  489.             }
  490.         }
  491.         //Make a backup of the "Old" wallpaper
  492.         lstrcpy(_szBackupWallpaper, szOldWallpaper);
  493.     }
  494.     else
  495.     {
  496.         pszRegKey = c_szRegStrDesktop; //Get it from the old location!
  497.         //Since active desktop is not available, read wallpaper from old location.
  498.         if(!_fPolicyForWPName)
  499.             GetStringFromReg(HKEY_CURRENT_USER, pszRegKey, c_szWallpaper, c_szNULL, _szSelectedWallpaper, ARRAYSIZE(_szSelectedWallpaper));
  500.         //Make a backup of the "Old" wallpaper
  501.         lstrcpy(_szBackupWallpaper, _szSelectedWallpaper);
  502.         //Read the wallpaper style
  503.         if(!_fPolicyForWPStyle)
  504.             ReadWallpaperStyleFromReg(pszRegKey, &_wpo.dwStyle, TRUE);
  505.     }
  506.     EXITPROC(2, "DS ReadWallpaper! (_szSelectedWP=>%s<)", _szSelectedWallpaper);
  507. }
  508. void CActiveDesktop::_ReadPattern(void)
  509. {
  510.     ENTERPROC(2, "DS ReadPattern()");
  511.     GetStringFromReg(HKEY_CURRENT_USER, c_szRegStrDesktop, c_szPattern, c_szNULL, _szSelectedPattern, ARRAYSIZE(_szSelectedPattern));
  512.     EXITPROC(2, "DS ReadPattern! (_szSelectedPattern=>%s<)", _szSelectedPattern);
  513. }
  514. void CActiveDesktop::_ReadComponent(HKEY hkey, LPCTSTR pszComp)
  515. {
  516.     ENTERPROC(2, "DS ReadComponent(hk=%08X,pszComp=>%s<)", hkey, pszComp);
  517.     HKEY hkeyComp;
  518.     if (RegOpenKeyEx(hkey, pszComp, 0, KEY_READ, &hkeyComp) == ERROR_SUCCESS)
  519.     {
  520.         DWORD cbSize, dwType;
  521.         COMPONENTA comp;
  522.         comp.dwSize = sizeof(COMPONENTA);
  523.         //
  524.         // Read in the source string.
  525.         //
  526.         cbSize = SIZEOF(comp.szSource);
  527.         if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_SOURCE, NULL, &dwType, (LPBYTE)&comp.szSource, &cbSize) != ERROR_SUCCESS)
  528.         {
  529.             comp.szSource[0] = TEXT('');
  530.         }
  531.         //
  532.         // Read in the SubscribedURL string.
  533.         //
  534.         cbSize = SIZEOF(comp.szSubscribedURL);
  535.         if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_SUBSCRIBED_URL, NULL, &dwType, (LPBYTE)&comp.szSubscribedURL, &cbSize) != ERROR_SUCCESS)
  536.         {
  537.             comp.szSubscribedURL[0] = TEXT('');
  538.         }
  539.         //
  540.         // Read in the Friendly name string.
  541.         //
  542.         cbSize = SIZEOF(comp.szFriendlyName);
  543.         if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_NAME, NULL, &dwType, (LPBYTE)&comp.szFriendlyName, &cbSize) != ERROR_SUCCESS)
  544.         {
  545.             comp.szFriendlyName[0] = TEXT('');
  546.         }
  547.         //
  548.         // Read in and parse the flags.
  549.         //
  550.         DWORD dwFlags;
  551.         cbSize = SIZEOF(dwFlags);
  552.         if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_FLAGS, NULL, &dwType, (LPBYTE)&dwFlags, &cbSize) != ERROR_SUCCESS)
  553.         {
  554.             dwFlags = 0;
  555.         }
  556.         comp.iComponentType = dwFlags & COMP_TYPE;
  557.         comp.fChecked = (dwFlags & COMP_SELECTED) != 0;
  558.         comp.fNoScroll = (dwFlags & COMP_NOSCROLL) != 0;
  559.         comp.fDirty = FALSE;    //Reading it fresh from registry; Can't be dirty!
  560.         //
  561.         // Read in the location.
  562.         //
  563.         cbSize = SIZEOF(comp.cpPos);
  564.         if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_POSITION, NULL, &dwType, (LPBYTE)&comp.cpPos, &cbSize) != ERROR_SUCCESS)
  565.         {
  566.             ZeroMemory(&comp.cpPos, SIZEOF(comp.cpPos));
  567.         }
  568.         //
  569.         // In IE4.x, we have a very huge positive number (0x7fffffff) as the COMPONENT_TOP;
  570.         // As a result some component's z-index overflowed into the negative range (0x80000003)
  571.         // To fix this, we halved the COMPONENT_TOP (0x3fffffff) and also check for negative z-index
  572.         // values and covert them to postive values.
  573.         if(comp.cpPos.izIndex < 0)
  574.             comp.cpPos.izIndex = COMPONENT_TOP;
  575.         //
  576.         // Make sure the cpPos.dwSize is set to correct value
  577.         //
  578.         comp.cpPos.dwSize = sizeof(COMPPOS);
  579.         //
  580.         //  Read in the current ItemState
  581.         //
  582.         cbSize = SIZEOF(comp.dwCurItemState);
  583.         if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_CURSTATE, NULL, &dwType, (LPBYTE)&comp.dwCurItemState, &cbSize) != ERROR_SUCCESS)
  584.         {
  585.             //If the item state is missing, we must be reading from IE4 machine.
  586.             comp.dwCurItemState = IS_NORMAL;
  587.         }
  588.         //
  589.         //  Read in the Original state info.
  590.         //
  591.         cbSize = SIZEOF(comp.csiOriginal);
  592.         if ((SHQueryValueEx(hkeyComp, REG_VAL_COMP_ORIGINALSTATEINFO, NULL, &dwType, (LPBYTE)&comp.csiOriginal, &cbSize) != ERROR_SUCCESS) ||
  593.             (comp.csiOriginal.dwSize != SIZEOF(comp.csiOriginal)))
  594.         {
  595.             //If the item state is missing, we must be reading from IE4 machine.
  596.             // Set the OriginalState to the default info.
  597.             SetStateInfo(&comp.csiOriginal, &comp.cpPos, IS_NORMAL);
  598.             comp.csiOriginal.dwHeight = comp.csiOriginal.dwWidth = COMPONENT_DEFAULT_WIDTH;
  599.         }
  600.         //
  601.         //  Read in the Restored state info.
  602.         //
  603.         cbSize = SIZEOF(comp.csiRestored);
  604.         if (SHQueryValueEx(hkeyComp, REG_VAL_COMP_RESTOREDSTATEINFO, NULL, &dwType, (LPBYTE)&comp.csiRestored, &cbSize) != ERROR_SUCCESS)
  605.         {
  606.             //If the item state is missing, we must be reading from IE4 machine.
  607.             // Set the restored State to the default info.
  608.             SetStateInfo(&comp.csiRestored, &comp.cpPos, IS_NORMAL);
  609.         }
  610.         //
  611.         // Add the component to the component list.
  612.         //
  613.         AddComponentPrivate(&comp, StrToInt(pszComp));
  614.         //
  615.         // Increment our counter so we know where to add any new
  616.         // components after we're done.
  617.         //
  618.         _dwNextID++;
  619.         RegCloseKey(hkeyComp);
  620.     }
  621.     EXITPROC(2, "DS ReadComponent!");
  622. }
  623. typedef struct _tagSortStruct {
  624.     int ihdsaIndex;
  625.     int izIndex;
  626. } SORTSTRUCT;
  627. int CALLBACK pfnComponentSort(LPVOID p1, LPVOID p2, LPARAM lParam)
  628. {
  629.     SORTSTRUCT * pss1 = (SORTSTRUCT *)p1;
  630.     SORTSTRUCT * pss2 = (SORTSTRUCT *)p2;
  631.     if (pss1->izIndex > pss2->izIndex)
  632.         return 1;
  633.     if (pss1->izIndex < pss2->izIndex)
  634.         return -1;
  635.     return(0);
  636. }
  637. //
  638. // ModifyZIndex
  639. //
  640. // Little helper function to put the zindex of the windowed and windowless components
  641. // into correct buckets so that zorting will produce a correct order by zindex.
  642. //
  643. // If we don't do this then windowless components may end up zordering above windowed ones.
  644. //
  645. void ModifyZIndex(COMPONENTA * pcomp)
  646. {
  647.     if (pcomp->cpPos.izIndex != COMPONENT_TOP) {
  648.         if (!IsWindowLessComponent(pcomp))
  649.             pcomp->cpPos.izIndex += COMPONENT_TOP_WINDOWLESS;
  650.     }
  651.     else
  652.     {
  653.         if (IsWindowLessComponent(pcomp))
  654.             pcomp->cpPos.izIndex = COMPONENT_TOP_WINDOWLESS;
  655.     }
  656. }
  657. //
  658. // SortAndRationalize
  659. //
  660. // SortAndRationalize will take an unsorted component list and sort it such that the components
  661. // come out in the correct z-index indicated order.  It will also rebase the z-index values at
  662. // a known constant so that the z-index values will not grow endlessly.  SortAndRationalize also
  663. // imposes windowed vs. windowless criteria to the zindex values such that windowless components
  664. // always zorder under windowed ones.
  665. //
  666. void CActiveDesktop::_SortAndRationalize(void)
  667. {
  668.     int icComponents;
  669.     HDPA hdpa;
  670.     if (_hdsaComponent && ((icComponents = DSA_GetItemCount(_hdsaComponent)) > 1) && (hdpa = DPA_Create(0))) {
  671.         COMPONENTA * pcomp;
  672.         SORTSTRUCT * pss;
  673.         int i, iCur = ZINDEX_START;
  674.         BOOL fInsertFailed = FALSE;
  675.         HDSA hdsaOld;
  676.         // Go through each component and insert it's hdsa-index and zindex into the hdpa
  677.         for (i = 0; i < icComponents; i++)
  678.         {
  679.             if (!(pss = (SORTSTRUCT *)LocalAlloc(LPTR, sizeof(SORTSTRUCT))))
  680.                 break;
  681.             pcomp = (COMPONENTA *)DSA_GetItemPtr(_hdsaComponent, i);
  682.             ModifyZIndex(pcomp);
  683.             pss->ihdsaIndex = i;
  684.             pss->izIndex = pcomp->cpPos.izIndex;
  685.             if (DPA_AppendPtr(hdpa, (void FAR *)pss) == -1) {
  686.                 LocalFree((HANDLE)pss);
  687.                 break;
  688.             }
  689.         }
  690.         // Sort the hdpa by zindex
  691.         DPA_Sort(hdpa, pfnComponentSort, 0);
  692.         // Save old values
  693.         hdsaOld = _hdsaComponent;
  694.         // Null out the old hdsa, so AddComponentPrivate will create a new one
  695.         _hdsaComponent = NULL;
  696.         // Now go through the sorted hdpa and update the component zindex with a ZINDEX_START based zindex, then
  697.         // add the component to the new hdsa in sorted order.
  698.         for (i = 0; i < icComponents; i++) {
  699.             if (!(pss = (SORTSTRUCT *)DPA_GetPtr(hdpa, i)))
  700.                 break;
  701.             // Get component and update it's zIndex and id
  702.             pcomp = (COMPONENTA *)DSA_GetItemPtr(hdsaOld, pss->ihdsaIndex);
  703.             pcomp->cpPos.izIndex = iCur;
  704.             iCur += 2;
  705.             // Free ptr
  706.             LocalFree((HANDLE)pss);
  707.             // Add to new hdsa in sorted order
  708.             if (!fInsertFailed) {
  709.                 fInsertFailed = !AddComponentPrivate(pcomp, pcomp->dwID);
  710.             }
  711.         }
  712.         // If we're completely successfull then destroy the old hdsa.  Otherwise we need
  713.         // to destroy the new one and restore the old one.
  714.         if ((i == icComponents) && !fInsertFailed) {
  715.             DSA_Destroy(hdsaOld);
  716.         } else {
  717.             if (_hdsaComponent)
  718.             DSA_Destroy(_hdsaComponent);
  719.             _hdsaComponent = hdsaOld;
  720.         }
  721.         DPA_Destroy(hdpa);
  722.     }
  723. }
  724. void CActiveDesktop::_ReadComponents(BOOL fActiveDesktop)
  725. {
  726.     ENTERPROC(2, "DS ReadComponents()");
  727.     HKEY hkey;
  728.     TCHAR lpszDeskcomp[MAX_PATH];
  729.     GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, _pszScheme);
  730.     if (RegOpenKeyEx(HKEY_CURRENT_USER, lpszDeskcomp, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  731.     {
  732.         DWORD cbSize, dwType;
  733.         int i = 0;
  734.         TCHAR lpszSubkey[MAX_PATH];
  735.         //
  736.         // Read in the general settings.
  737.         //
  738.         DWORD dwSettings;
  739.         cbSize = SIZEOF(dwSettings);
  740.         if (SHQueryValueEx(hkey, REG_VAL_COMP_SETTINGS, NULL, &dwType, (LPBYTE)&dwSettings, &cbSize) == ERROR_SUCCESS)
  741.         {
  742.             _co.fEnableComponents = (dwSettings & COMPSETTING_ENABLE) != 0;
  743.         }
  744.         _co.fActiveDesktop = fActiveDesktop;
  745.         //
  746.         // Read in all the desktop components
  747.         //
  748.         while (RegEnumKey(hkey, i, lpszSubkey, ARRAYSIZE(lpszSubkey)) == ERROR_SUCCESS)
  749.         {
  750.             _ReadComponent(hkey, lpszSubkey);
  751.             i++;
  752.         }
  753.         _SortAndRationalize();
  754.         RegCloseKey(hkey);
  755.     }
  756.     EXITPROC(2, "DS ReadComponents!");
  757. }
  758. void CActiveDesktop::_Initialize(void)
  759. {
  760.     ENTERPROC(2, "DS Initialize()");
  761.     if (!_fInitialized)
  762.     {
  763.         _fInitialized = TRUE;
  764.         InitDeskHtmlGlobals();
  765.         SHELLSTATE ss = {0};
  766.         SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
  767.         
  768.         BOOL fActiveDesktop = BOOLIFY(ss.fDesktopHTML);
  769.         
  770.         _co.dwSize = SIZEOF(_co);
  771.         _wpo.dwSize = SIZEOF(_wpo);
  772.         //
  773.         // This per-user registry branch may not exist for this user. Or, even if
  774.         // it does exist, it may have some stale info. So ensure that atlreast the 
  775.         // default components are there and that the html version is current for this
  776.         // branch of the registry!
  777.         //  If everything is current, the following function does nothing!
  778.         //
  779.         CDeskHtmlProp_RegUnReg(TRUE);  //TRUE => install.
  780.         _ReadWallpaper(fActiveDesktop);
  781.         _ReadPattern();
  782.         _ReadComponents(fActiveDesktop);
  783.         // If we are in safemode, the we can not use Dynamic Html to make updates because
  784.         // updates involve complete change of background Html.
  785.         if(_IsDisplayInSafeMode())
  786.             _fUseDynamicHtml = FALSE;
  787.         else
  788.             _fUseDynamicHtml = TRUE;        //Any component added after the initialization must go through dynamic html.
  789.         _fDirty = FALSE;
  790.         _fNeedBodyEnd = FALSE;
  791.     }
  792.     EXITPROC(2, "DS Initialize!");
  793. }
  794. void CActiveDesktop::_SaveWallpaper(void)
  795. {
  796.     ENTERPROC(2, "DS SaveWallpaper");
  797.     TCHAR lpszDeskcomp[MAX_PATH];
  798.     BOOL    fNormalWallpaper;
  799.     GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, _pszScheme);
  800.     //
  801.     // Compute tiling string.
  802.     //
  803.     TCHAR szTiled[2];
  804.     lstrcpy(szTiled, TEXT("0"));
  805.     szTiled[0] = szTiled[0] + (TCHAR)(_wpo.dwStyle & WPSTYLE_TILE);
  806.     //
  807.     // Compute the Wallpaper styling string
  808.     //
  809.     TCHAR       szWPStyle[2];
  810.     lstrcpy(szWPStyle, TEXT("0"));
  811.     //
  812.     // NOTE: If WPSTYLE_TILE is set, we still want to say WallpaperStyle="0"; This won't hurt
  813.     // because TileWallpaper="1" will over-ride this anyway.
  814.     // The reason for this hack is that during memphis setup, they put a tiled wallpaper. Then we
  815.     // write WallpaperStyle=1 and TileWallpaper=1 in new and old locations. Then, then change
  816.     // the wallpaper and set TileWallpaper=0. Since the WallpaperStyle continues to be 1, they 
  817.     // get a tiled wallpaper finally. The following is to avoid this problem!
  818.     // 
  819.     szWPStyle[0] = szWPStyle[0] + (TCHAR)(_wpo.dwStyle & WPSTYLE_STRETCH);
  820.     
  821.     //
  822.     // Write out wallpaper settings in new active desktop area.
  823.     //
  824.     if(_fWallpaperDirty || _fWallpaperChangedDuringInit)
  825.     {
  826.         if(!_fPolicyForWPStyle)
  827.         {
  828.             SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
  829.                 c_szTileWall, REG_SZ, (LPBYTE)szTiled, SIZEOF(TCHAR)*(lstrlen(szTiled)+1));
  830.         }
  831.         //
  832.         // Note: We do not write the Wallpaper Style string for older systems because we do not
  833.         // want to over-write what PlusPack writes. However, for newer Operating systems, we 
  834.         // want to write the WallpaperStyle also.
  835.         //
  836.         if((g_bRunOnMemphis || g_bRunOnNT5) && (!_fPolicyForWPStyle))
  837.         {
  838.             SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
  839.                 c_szWallpaperStyle, REG_SZ, (LPBYTE)szWPStyle, SIZEOF(TCHAR)*(lstrlen(szWPStyle)+1));
  840.         }
  841.         if(!_fPolicyForWPName)
  842.             SHRegSetPath(HKEY_CURRENT_USER, lpszDeskcomp, c_szWallpaper, _szSelectedWallpaper, 0);
  843.     }
  844.     if(fNormalWallpaper = IsNormalWallpaper(_szSelectedWallpaper))
  845.     {
  846.         lstrcpyn(_szBackupWallpaper, _szSelectedWallpaper, ARRAYSIZE(_szBackupWallpaper));
  847.     }
  848.     if(!_fPolicyForWPName)
  849.     {
  850.         FILETIME ft;
  851.         GetWallpaperFileTime(_szBackupWallpaper, &ft);
  852.         // Backup the "Old type" wallpaper's name here in the new location
  853.         // sothat we can detect when this gets changed by some other app.
  854.         SHRegSetPath(HKEY_CURRENT_USER, lpszDeskcomp, c_szBackupWallpaper, _szBackupWallpaper, 0);
  855.         SHSetValue(HKEY_CURRENT_USER, lpszDeskcomp,
  856.                 c_szWallpaperTime, REG_BINARY, (LPBYTE)&ft,
  857.                 SIZEOF(ft));    
  858.     }
  859.     
  860.     //
  861.     // Even if this wallpaper is not valid in normal desktop (i.e., even if it is not a .BMP),
  862.     // write it out in normal desktop registry area.
  863.     //
  864.     if (_fWallpaperDirty)
  865.     {
  866.         if(!_fPolicyForWPStyle)
  867.         {
  868.             SHSetValue(HKEY_CURRENT_USER, c_szRegStrDesktop,
  869.                     c_szTileWall, REG_SZ, (LPBYTE)szTiled, SIZEOF(TCHAR)*(lstrlen(szTiled)+1));
  870.         }
  871.         //
  872.         // Note: We do not write the Wallpaper Style string for older systems because we do not
  873.         // want to over-write what PlusPack writes. However, for newer Operating systems, we 
  874.         // want to write the WallpaperStyle also.
  875.         //
  876.         if((g_bRunOnMemphis || g_bRunOnNT5) && (!_fPolicyForWPStyle))
  877.         {
  878.             SHSetValue(HKEY_CURRENT_USER, c_szRegStrDesktop,
  879.                         c_szWallpaperStyle, REG_SZ, (LPBYTE)szWPStyle, SIZEOF(TCHAR)*(lstrlen(szWPStyle)+1));
  880.         }
  881.         if(!_fPolicyForWPName)
  882.         {
  883.             SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 
  884.                     (fNormalWallpaper ? _szSelectedWallpaper : _szBackupWallpaper),
  885.                      SPIF_UPDATEINIFILE);
  886.         }
  887.     }
  888.     EXITPROC(2, "DS SaveWallpaper");
  889. }
  890. void CActiveDesktop::_SaveComponent(HKEY hkey, int iIndex, COMPONENTA *pcomp)
  891. {
  892.     ENTERPROC(2, "DS SaveComponent(hkey=%08X,iIndex=%d,pcomp=%08X)", hkey, iIndex, pcomp);
  893.     TCHAR szSubKey[8];
  894.     HKEY hkeySub;
  895.     wsprintf(szSubKey, TEXT("%d"), iIndex);
  896.     if (RegCreateKey(hkey, szSubKey, &hkeySub) == ERROR_SUCCESS)
  897.     {
  898.         pcomp->fDirty = FALSE; //Since we are saving in the registry, reset this!
  899.         //
  900.         // Write out the source string and Friendly name string.
  901.         //
  902.         RegSetValueEx(hkeySub, REG_VAL_COMP_SOURCE, 0, REG_SZ, (LPBYTE)pcomp->szSource, (lstrlen(pcomp->szSource)+1)*SIZEOF(TCHAR));
  903.         RegSetValueEx(hkeySub, REG_VAL_COMP_SUBSCRIBED_URL, 0, REG_SZ, (LPBYTE)pcomp->szSubscribedURL, (lstrlen(pcomp->szSubscribedURL)+1)*SIZEOF(TCHAR));
  904.         RegSetValueEx(hkeySub, REG_VAL_COMP_NAME, 0, REG_SZ, (LPBYTE)pcomp->szFriendlyName, (lstrlen(pcomp->szFriendlyName)+1)*SIZEOF(TCHAR));
  905.         //
  906.         // Compute and write out flags.
  907.         //
  908.         DWORD dwFlags = 0;
  909.         dwFlags |= pcomp->iComponentType;
  910.         if (pcomp->fChecked)
  911.         {
  912.             dwFlags |= COMP_SELECTED;
  913.         }
  914.         if (pcomp->fNoScroll)
  915.         {
  916.             dwFlags |= COMP_NOSCROLL;
  917.         }
  918.         RegSetValueEx(hkeySub, REG_VAL_COMP_FLAGS, 0, REG_DWORD, (LPBYTE)&dwFlags, SIZEOF(dwFlags));
  919.         //
  920.         // Write out the position.
  921.         //
  922.         RegSetValueEx(hkeySub, REG_VAL_COMP_POSITION, 0, REG_BINARY, (LPBYTE)&pcomp->cpPos, SIZEOF(pcomp->cpPos));
  923.         //  Write out the Current state
  924.         RegSetValueEx(hkeySub, REG_VAL_COMP_CURSTATE, 0, REG_DWORD, (LPBYTE)&pcomp->dwCurItemState, SIZEOF(pcomp->dwCurItemState));
  925.         //  Write out the Original State Info
  926.         RegSetValueEx(hkeySub, REG_VAL_COMP_ORIGINALSTATEINFO, 0, REG_BINARY, (LPBYTE)&pcomp->csiOriginal, SIZEOF(pcomp->csiOriginal));
  927.         
  928.         //  Write out the Restored State Info
  929.         RegSetValueEx(hkeySub, REG_VAL_COMP_RESTOREDSTATEINFO, 0, REG_BINARY, (LPBYTE)&pcomp->csiRestored, SIZEOF(pcomp->csiRestored));
  930.         RegCloseKey(hkeySub);
  931.     }
  932.     EXITPROC(2, "DS SaveComponent!");
  933. }
  934. void CActiveDesktop::_SaveComponents(void)
  935. {
  936.     ENTERPROC(2, "DS SaveComponents");
  937.     DWORD dwType, dwFlags = 0, dwDataLength = SIZEOF(dwFlags);
  938.     int i;
  939.     TCHAR lpszDeskcomp[MAX_PATH];
  940.     GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, _pszScheme);
  941.     //
  942.     // We need to preserve the old GENFLAGS, so read them now before we roach them.
  943.     //
  944.     SHGetValue(HKEY_CURRENT_USER, (LPCTSTR)lpszDeskcomp, REG_VAL_COMP_GENFLAGS, &dwType,
  945.                             (LPBYTE)(&dwFlags), &dwDataLength);
  946.     //
  947.     // Delete the entire registry key.
  948.     //
  949.     SHDeleteKey(HKEY_CURRENT_USER, lpszDeskcomp);
  950.     //
  951.     // Recreate the registry key.
  952.     //
  953.     HKEY hkey;
  954.     if (RegCreateKey(HKEY_CURRENT_USER, lpszDeskcomp, &hkey) == ERROR_SUCCESS)
  955.     {
  956.         //
  957.         // Write out the version number.
  958.         //
  959.         DWORD dw = CUR_DESKHTML_VERSION;
  960.         RegSetValueEx(hkey, REG_VAL_COMP_VERSION, 0, REG_DWORD, (LPBYTE)(&dw), SIZEOF(dw));
  961.         dw = CUR_DESKHTML_MINOR_VERSION;
  962.         RegSetValueEx(hkey, REG_VAL_COMP_MINOR_VERSION, 0, REG_DWORD, (LPBYTE)(&dw), SIZEOF(dw));
  963.     
  964.         //
  965.         // Write out the general settings.
  966.         //
  967.         DWORD dwSettings = 0;
  968.         if (_co.fEnableComponents)
  969.         {
  970.             dwSettings |= COMPSETTING_ENABLE;
  971.         }
  972.         RegSetValueEx(hkey, REG_VAL_COMP_SETTINGS, 0, REG_DWORD, (LPBYTE)&dwSettings, SIZEOF(dwSettings));
  973.         //
  974.         // Write out the general flags
  975.         //
  976.         RegSetValueEx(hkey, REG_VAL_COMP_GENFLAGS, 0, REG_DWORD, (LPBYTE)&dwFlags, SIZEOF(dwFlags));
  977.         if (_hdsaComponent)
  978.         {
  979.             //
  980.             // Write out the settings for each component
  981.             //
  982.             for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
  983.             {
  984.                 COMPONENTA * pcomp;
  985.                 if (pcomp = (COMPONENTA *)DSA_GetItemPtr(_hdsaComponent, i))
  986.                 {
  987.                     pcomp->dwID = i;
  988.                     _SaveComponent(hkey, i, pcomp);
  989.                 }
  990.             }
  991.         }
  992.         RegCloseKey(hkey);
  993.     }
  994.     EXITPROC(2, "DS SaveComponents");
  995. }
  996. void CActiveDesktop::_SavePattern(DWORD dwFlags)
  997. {
  998.     ENTERPROC(2, "DS SavePattern()");
  999.     if (_fPatternDirty && (dwFlags & SAVE_PATTERN_NAME))
  1000.     {
  1001.         //
  1002.         // Write out the pattern to the registry and INI files.
  1003.         //
  1004.         SystemParametersInfo(SPI_SETDESKPATTERN, 0, _szSelectedPattern, SPIF_UPDATEINIFILE);
  1005.     }
  1006.     if (IsValidPattern(_szSelectedPattern) && (dwFlags & GENERATE_PATTERN_FILE))
  1007.     {
  1008.         //
  1009.         // Write out the pattern as a BMP file for use in HTML.
  1010.         //
  1011.         TCHAR szBitmapFile[MAX_PATH];
  1012.         GetPerUserFileName(szBitmapFile, ARRAYSIZE(szBitmapFile), PATTERN_FILENAME);
  1013.         HANDLE hFileBitmap;
  1014.         hFileBitmap = CreateFile(szBitmapFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  1015.                                     FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, NULL);
  1016.         if (hFileBitmap != INVALID_HANDLE_VALUE)
  1017.         {
  1018.             DWORD cbWritten;
  1019.             BITMAPFILEHEADER bmfh = {0};
  1020.             bmfh.bfType = 0x4D42;   // 'BM'
  1021.             bmfh.bfSize = SIZEOF(BITMAPFILEHEADER) + SIZEOF(BITMAPINFOHEADER) + 2*SIZEOF(RGBQUAD) + 8*SIZEOF(DWORD);
  1022.             bmfh.bfOffBits = SIZEOF(BITMAPFILEHEADER) + SIZEOF(BITMAPINFOHEADER) + 2*SIZEOF(RGBQUAD);
  1023.             WriteFile(hFileBitmap, &bmfh, SIZEOF(bmfh), &cbWritten, NULL);
  1024.             BITMAPINFOHEADER bmih = {0};
  1025.             bmih.biSize = SIZEOF(BITMAPINFOHEADER);
  1026.             bmih.biWidth = 8;
  1027.             bmih.biHeight = 8;
  1028.             bmih.biPlanes = 1;
  1029.             bmih.biBitCount = 1;
  1030.             bmih.biCompression = BI_RGB;
  1031.             WriteFile(hFileBitmap, &bmih, SIZEOF(bmih), &cbWritten, NULL);
  1032.             RGBQUAD argbTable[2] = {0};
  1033.             DWORD rgb;
  1034.             rgb = GetSysColor(COLOR_BACKGROUND);
  1035.             argbTable[0].rgbBlue = GetBValue(rgb);
  1036.             argbTable[0].rgbGreen = GetGValue(rgb);
  1037.             argbTable[0].rgbRed = GetRValue(rgb);
  1038.             rgb = GetSysColor(COLOR_WINDOWTEXT);
  1039.             argbTable[1].rgbBlue = GetBValue(rgb);
  1040.             argbTable[1].rgbGreen = GetGValue(rgb);
  1041.             argbTable[1].rgbRed = GetRValue(rgb);
  1042.             WriteFile(hFileBitmap, argbTable, SIZEOF(argbTable), &cbWritten, NULL);
  1043.             DWORD adwBits[8];
  1044.             PatternToDwords(_szSelectedPattern, adwBits);
  1045.             WriteFile(hFileBitmap, adwBits, SIZEOF(adwBits), &cbWritten, NULL);
  1046.             CloseHandle(hFileBitmap);
  1047.         }
  1048.     }
  1049.     EXITPROC(2, "DS SavePattern!");
  1050. }
  1051. void CActiveDesktop::_WriteHtmlFromString(LPCTSTR psz)
  1052. {
  1053.     ENTERPROC(3, "DS WriteHtmlFromString(psz=>%s<)", psz);
  1054.     LPCWSTR  pwsz;
  1055.     WCHAR   szBuf[INTERNET_MAX_URL_LENGTH];
  1056.     UINT    uiLen;
  1057.     int     cch;
  1058. #ifdef UNICODE
  1059.     if((_pStream == NULL) && (_iDestFileCharset == ANSI_HTML_CHARSET))
  1060.     {
  1061.         cch = SHUnicodeToAnsi(psz, (LPSTR)szBuf, ARRAYSIZE(szBuf));
  1062.         ASSERT(cch == lstrlenW((LPWSTR)psz)+1);
  1063.         pwsz = (LPCWSTR)szBuf;
  1064.         uiLen = lstrlenA((LPSTR)szBuf);
  1065.     }
  1066.     else
  1067.     {
  1068.         pwsz = psz;
  1069.         uiLen = lstrlenW(pwsz);
  1070.     }
  1071. #else
  1072.     if((_pStream == NULL) && (_iDestFileCharset == ANSI_HTML_CHARSET))
  1073.     {
  1074.         pwsz = (LPWSTR)psz;
  1075.         uiLen = lstrlenA(psz);
  1076.     }
  1077.     else
  1078.     {
  1079.         cch = SHAnsiToUnicode(psz, szBuf, ARRAYSIZE(szBuf));
  1080.         ASSERT(cch == lstrlenA(psz)+1);
  1081.         pwsz = (LPCWSTR)szBuf;
  1082.         uiLen = lstrlenW(pwsz);
  1083.     }
  1084. #endif
  1085.     UINT cbWritten;
  1086.     _WriteHtmlW(pwsz, uiLen, &cbWritten);
  1087.     
  1088.     EXITPROC(3, "DS WriteHtmlFromString!");
  1089. }
  1090. void CActiveDesktop::_WriteHtmlFromId(UINT uid)
  1091. {
  1092.     ENTERPROC(3, "DS WriteHtmlFromId(uid=%d)", uid);
  1093.     TCHAR szBuf[INTERNET_MAX_URL_LENGTH];
  1094.     LoadString(HINST_THISDLL, uid, szBuf, ARRAYSIZE(szBuf));
  1095.     _WriteHtmlFromString(szBuf);
  1096.     EXITPROC(3, "DS WriteHtmlFromId!");
  1097. }
  1098. void CActiveDesktop::_WriteHtmlFromIdF(UINT uid, ...)
  1099. {
  1100.     ENTERPROC(3, "DS WriteHtmlFromIdF(uid=%d,...)", uid);
  1101.     TCHAR szBufFmt[INTERNET_MAX_URL_LENGTH];
  1102.     TCHAR szBuf[INTERNET_MAX_URL_LENGTH];
  1103.     LoadString(HINST_THISDLL, uid, szBufFmt, ARRAYSIZE(szBufFmt));
  1104.     va_list arglist;
  1105.     va_start(arglist, uid);
  1106.     wvsprintf(szBuf, szBufFmt, arglist);
  1107.     va_end(arglist);
  1108.     _WriteHtmlFromString(szBuf);
  1109.     EXITPROC(3, "DS WriteHtmlFromIdF!");
  1110. }
  1111. void CActiveDesktop::_WriteHtmlFromFile(LPCTSTR pszContents)
  1112. {
  1113.     ENTERPROC(3, "DS WriteHtmlFromFile(pszContents=>%s<)", pszContents);
  1114.     
  1115.     CReadFileObj *pReadFileObj = new CReadFileObj(pszContents);
  1116.     if (pReadFileObj)
  1117.     {
  1118.         if(pReadFileObj->_hFile != INVALID_HANDLE_VALUE)
  1119.         {
  1120.             WCHAR wcBuf[INTERNET_MAX_URL_LENGTH + 1];
  1121.             UINT uiCharCount = ARRAYSIZE(wcBuf) -1; //Leave room for null termination.
  1122.             UINT uiCharsRead;
  1123.             UINT uiCharsConverted;
  1124.             int iDestCharset = (_pStream ? UNICODE_HTML_CHARSET : _iDestFileCharset);
  1125.             while (SUCCEEDED(pReadFileObj->FileReadAndConvertChars(iDestCharset, wcBuf, uiCharCount, &uiCharsRead, &uiCharsConverted)) && uiCharsRead)
  1126.             {
  1127.                 UINT cbWritten;
  1128.             
  1129.                 _WriteHtmlW(wcBuf, uiCharsConverted, &cbWritten);
  1130.             
  1131.                 if (uiCharsRead < uiCharCount)
  1132.                 {
  1133.                     break;
  1134.                 }
  1135.             }
  1136.         }
  1137.         delete pReadFileObj;
  1138.     }
  1139.     
  1140.     EXITPROC(3, "DS WriteHtmlFromFile!");
  1141. }
  1142. void CActiveDesktop::_WriteHtmlFromReadFileObj(CReadFileObj *pFileObj, int iOffsetStart, int iOffsetEnd)
  1143. {
  1144.     ENTERPROC(3, "DS WriteHtmlFromReadFileObj(pFileObj=%08X,iOffsetStart=%d,iOffsetEnd=%d)", pFileObj, iOffsetStart, iOffsetEnd);
  1145.     if (iOffsetStart != -1)
  1146.     {
  1147.         pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
  1148.     }
  1149.     else
  1150.     {
  1151.         ASSERT(iOffsetEnd == -1);
  1152.         iOffsetEnd = -1;
  1153.     }
  1154.     //Get the number of WIDECHARs to be written
  1155.     UINT cchWrite = (iOffsetEnd == -1) ? 0xFFFFFFFF : (iOffsetEnd - iOffsetStart);
  1156.     while (cchWrite)
  1157.     {
  1158.         WCHAR wcBuf[INTERNET_MAX_URL_LENGTH+1];
  1159.         //
  1160.         // Read a chunk.
  1161.         //
  1162.         UINT cchTryRead = min(cchWrite, (ARRAYSIZE(wcBuf) - 1));
  1163.         UINT cchActualRead;
  1164.         HRESULT hres;
  1165.         //Note: if we are reading ANSI, we still use the unicode buff; but cast it!
  1166.         if(_iDestFileCharset == ANSI_HTML_CHARSET)
  1167.             hres = pFileObj->FileReadCharsA((LPSTR)wcBuf, cchTryRead, &cchActualRead);
  1168.         else
  1169.             hres = pFileObj->FileReadCharsW(wcBuf, cchTryRead, &cchActualRead);
  1170.             
  1171.         if(SUCCEEDED(hres) && cchActualRead)
  1172.         {
  1173.             //
  1174.             // Write a chunk.
  1175.             //
  1176.             UINT cchWritten;
  1177.             
  1178.             _WriteHtmlW(wcBuf, cchActualRead, &cchWritten);
  1179.             
  1180.             if (cchActualRead < cchTryRead)
  1181.             {
  1182.                 //
  1183.                 // End of file, all done.
  1184.                 //
  1185.                 break;
  1186.             }
  1187.             cchWrite -= cchActualRead;
  1188.         }
  1189.         else
  1190.         {
  1191.             //
  1192.             // Error reading from file, all done.
  1193.             //
  1194.             break;
  1195.         }
  1196.     }
  1197.     EXITPROC(3, "DS WriteHtmlFromHfile!");
  1198. }
  1199. int CActiveDesktop::_ScanForTagA(CReadFileObj *pFileObj, int iOffsetStart, LPCSTR pszTag)
  1200. {
  1201.     ENTERPROC(2, "DS ScanForTagA(pFileObj=%08X,iOffsetStart=%d,pszTagA=>%s<)",
  1202.     pFileObj, iOffsetStart, pszTag);
  1203.     int iRet = -1;
  1204.     BOOL fDoneReading = FALSE;
  1205.     int iOffset;
  1206.     DWORD cchTag = lstrlenA(pszTag);
  1207.     pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
  1208.     iOffset = iOffsetStart;
  1209.     DWORD cchBuf = 0;
  1210.     while (!fDoneReading)
  1211.     {
  1212.         char szBuf[INTERNET_MAX_URL_LENGTH+1];
  1213.         //
  1214.         // Fill in the buffer.
  1215.         //
  1216.         UINT cchTryRead = ARRAYSIZE(szBuf) - cchBuf - 1;
  1217.         UINT cchRead;
  1218.         if(SUCCEEDED(pFileObj->FileReadCharsA(&szBuf[cchBuf], cchTryRead, &cchRead)) && cchRead)
  1219.         {
  1220.             cchBuf += cchRead;
  1221.             //
  1222.             // Terminate the string.
  1223.             //
  1224.             szBuf[cchBuf] = '';
  1225.             //
  1226.             // Scan for the tag.
  1227.             //
  1228.             LPSTR pszTagInBuf = StrStrIA(szBuf, pszTag);
  1229.             if (pszTagInBuf)
  1230.             {
  1231.                 //
  1232.                 // Found the tag, compute the offset.
  1233.                 //
  1234.                 iRet = (int) (iOffset + pszTagInBuf - szBuf);
  1235.                 fDoneReading = TRUE;
  1236.             }
  1237.             else if (cchRead < cchTryRead)
  1238.             {
  1239.                 //
  1240.                 // Ran out of file without finding tag.
  1241.                 //
  1242.                 fDoneReading = TRUE;
  1243.             }
  1244.             else
  1245.             {
  1246.                 //
  1247.                 // Compute how many bytes we want to throw away
  1248.                 // from this buffer so we can read in more data.
  1249.                 // We don't want to throw away all the bytes because
  1250.                 // the tag we want may span two buffers.
  1251.                 //
  1252.                 DWORD cchSkip = cchBuf - cchTag;
  1253.                 //
  1254.                 // Advance the file offset.
  1255.                 //
  1256.                 iOffset += cchSkip;
  1257.                 //
  1258.                 // Reduce the buffer size.
  1259.                 //
  1260.                 cchBuf -= cchSkip;
  1261.                 //
  1262.                 // Move the kept bytes to the beginning of the buffer.
  1263.                 //
  1264.                 MoveMemory(szBuf, szBuf + cchSkip, cchBuf);
  1265.             }
  1266.         }
  1267.         else
  1268.         {
  1269.             fDoneReading = TRUE;
  1270.         }
  1271.     }
  1272.     EXITPROC(2, "DS ScanForTagA=%d", iRet);
  1273.     return iRet;
  1274. }
  1275. int CActiveDesktop::_ScanForTagW(CReadFileObj *pFileObj, int iOffsetStart, LPCWSTR pwszTag)
  1276. {
  1277.     ENTERPROC(2, "DS ScanForTag(pFileObj=%08X,iOffsetStart=%d,pszTagA=>%s<)",
  1278.     pFileObj, iOffsetStart, pwszTag);
  1279.     int iRet = -1;
  1280.     BOOL fDoneReading = FALSE;
  1281.     int iOffset;
  1282.     DWORD cchTag = lstrlenW(pwszTag);
  1283.     pFileObj->FileSeekChars(iOffsetStart, FILE_BEGIN);
  1284.     iOffset = iOffsetStart;
  1285.     DWORD cchBuf = 0;
  1286.     while (!fDoneReading)
  1287.     {
  1288.         WCHAR wszBuf[INTERNET_MAX_URL_LENGTH+1];
  1289.         //
  1290.         // Fill in the buffer.
  1291.         //
  1292.         UINT cchTryRead = ARRAYSIZE(wszBuf) - cchBuf - 1;
  1293.         UINT cchRead;
  1294.         if(SUCCEEDED(pFileObj->FileReadCharsW(&wszBuf[cchBuf], cchTryRead, &cchRead)) && cchRead)
  1295.         {
  1296.             cchBuf += cchRead;
  1297.             //
  1298.             // Terminate the string.
  1299.             //
  1300.             wszBuf[cchBuf] = L'';
  1301.             //
  1302.             // Scan for the tag.
  1303.             //
  1304.             LPWSTR pwszTagInBuf = StrStrIW(wszBuf, pwszTag);
  1305.             if (pwszTagInBuf)
  1306.             {
  1307.                 //
  1308.                 // Found the tag, compute the offset.
  1309.                 //
  1310.                 iRet = (int) (iOffset + pwszTagInBuf - wszBuf);
  1311.                 fDoneReading = TRUE;
  1312.             }
  1313.             else if (cchRead < cchTryRead)
  1314.             {
  1315.                 //
  1316.                 // Ran out of file without finding tag.
  1317.                 //
  1318.                 fDoneReading = TRUE;
  1319.             }
  1320.             else
  1321.             {
  1322.                 //
  1323.                 // Compute how many bytes we want to throw away
  1324.                 // from this buffer so we can read in more data.
  1325.                 // We don't want to throw away all the bytes because
  1326.                 // the tag we want may span two buffers.
  1327.                 //
  1328.                 DWORD cchSkip = cchBuf - cchTag;
  1329.                 //
  1330.                 // Advance the file offset.
  1331.                 //
  1332.                 iOffset += cchSkip;
  1333.                 //
  1334.                 // Reduce the buffer size.
  1335.                 //
  1336.                 cchBuf -= cchSkip;
  1337.                 //
  1338.                 // Move the kept bytes to the beginning of the buffer.
  1339.                 //
  1340.                 MoveMemory(wszBuf, wszBuf + cchSkip, cchBuf*sizeof(WCHAR));
  1341.             }
  1342.         }
  1343.         else
  1344.         {
  1345.             fDoneReading = TRUE;
  1346.         }
  1347.     }
  1348.     EXITPROC(2, "DS ScanForTag=%d", iRet);
  1349.     return iRet;
  1350. }
  1351. int CActiveDesktop::_ScanTagEntriesA(CReadFileObj *pReadFileObj, int iOffsetStart, TAGENTRYA *pte, int cte)
  1352. {
  1353.     ENTERPROC(2, "DS ScanTagEntriesA(pReadFileObj=%08X,iOffsetStart=%d,pte=%08X,cte=%d)",
  1354.                 pReadFileObj, iOffsetStart, pte, cte);
  1355.     int iRet = -1;
  1356.     int i;
  1357.     for (i=0; i<cte; i++,pte++)
  1358.     {
  1359.         iRet = _ScanForTagA(pReadFileObj, iOffsetStart, pte->pszTag);
  1360.         if (iRet != -1)
  1361.         {
  1362.             if (pte->fSkipPast)
  1363.             {
  1364.                 iRet += lstrlenA(pte->pszTag);
  1365.             }
  1366.             break;
  1367.         }
  1368.     }
  1369.     EXITPROC(2, "DS ScanTagEntriesA=%d", iRet);
  1370.     return iRet;
  1371. }
  1372. int CActiveDesktop::_ScanTagEntriesW(CReadFileObj *pReadFileObj, int iOffsetStart, TAGENTRYW *pte, int cte)
  1373. {
  1374.     ENTERPROC(2, "DS ScanTagEntriesW(pReadFileObj=%08X,iOffsetStart=%d,pte=%08X,cte=%d)",
  1375.                 pReadFileObj, iOffsetStart, pte, cte);
  1376.     int iRet = -1;
  1377.     int i;
  1378.     for (i=0; i<cte; i++,pte++)
  1379.     {
  1380.         iRet = _ScanForTagW(pReadFileObj, iOffsetStart, pte->pwszTag);
  1381.         if (iRet != -1)
  1382.         {
  1383.             if (pte->fSkipPast)
  1384.             {
  1385.                 iRet += lstrlenW(pte->pwszTag);
  1386.             }
  1387.             break;
  1388.         }
  1389.     }
  1390.     EXITPROC(2, "DS ScanTagEntriesW=%d", iRet);
  1391.     return iRet;
  1392. }
  1393. void CActiveDesktop::_ParseAnsiInputHtmlFile( LPTSTR szSelectedWallpaper, int *piOffsetBase, int *piOffsetComp)
  1394. {
  1395.     //
  1396.     // Figure out where to insert the base href tag.
  1397.     //
  1398.     int     iOffsetBase = 0, iBaseTagStart;
  1399.     BOOL    fUseBaseHref;
  1400.     LONG    lOffsetDueToBOM = 0; //Character Offset due to the Byte Order Mark.
  1401.                                  //1 for UNICODE and 0 for ANSI files.
  1402. //  98/11/11 #248047 vtan: This code looks for a <BASE HREF=...> tag.
  1403. //  It used to use a scan for "<BASE" and assume that this was the
  1404. //  desired tag. HTML allows a "<BASEFONT>" tag which was being
  1405. //  mistaken for a "<BASE HREF=...>" tag. The code now looks for the
  1406. //  same string but looks at the character following the "<BASE" to
  1407. //  see if it's a white-space character.
  1408.     fUseBaseHref = TRUE;
  1409.     _pReadFileObjHtmlBkgd->FileGetCurCharOffset(&lOffsetDueToBOM);
  1410.     iOffsetBase = (int)lOffsetDueToBOM;
  1411.     iBaseTagStart = _ScanForTagA(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, "<BASE");
  1412.                 
  1413.     if (iBaseTagStart != -1)
  1414.     {
  1415.         UINT   uiCountChars, uiTryToRead;
  1416.         char   szBaseTagBuffer[6+1];     // allow for "<BASEx" plus a NULL.
  1417.         _pReadFileObjHtmlBkgd->FileSeekChars(iBaseTagStart, FILE_BEGIN);
  1418.         uiTryToRead = ARRAYSIZE(szBaseTagBuffer) - 1;
  1419.         if(SUCCEEDED(_pReadFileObjHtmlBkgd->FileReadCharsA(szBaseTagBuffer, uiTryToRead, &uiCountChars)) && uiCountChars)
  1420.         {
  1421.             char    ch;
  1422.             ch = szBaseTagBuffer[5];
  1423.             fUseBaseHref = ((ch != ' ') &&
  1424.                             (ch != 'r') &&
  1425.                             (ch != 'n') &&      // this covers the UNIX line break scheme
  1426.                             (ch != 't'));
  1427.         }
  1428.     }
  1429.     if (fUseBaseHref)
  1430.     {
  1431.         TAGENTRYA rgteBase[] = {
  1432.                                    { "<HEAD>", TRUE, },
  1433.                                    { "<BODY", FALSE, },
  1434.                                    { "<HTML>", TRUE, },
  1435.                                };
  1436.         iOffsetBase = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, rgteBase, ARRAYSIZE(rgteBase));
  1437.         if (iOffsetBase == -1)
  1438.         {
  1439.             iOffsetBase = (int)lOffsetDueToBOM;
  1440.         }
  1441.     }
  1442.     //
  1443.     // Figure out where to insert the components.
  1444.     //
  1445.     TAGENTRYA rgteComponents[] = {
  1446.                                      { "</BODY>", FALSE, },
  1447.                                      { "</HTML>", FALSE, },
  1448.                                  };
  1449.     int iOffsetComponents = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteComponents, ARRAYSIZE(rgteComponents));
  1450.     //
  1451.     // Write out the initial HTML up to the <HEAD> tag.
  1452.     //
  1453.     _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, iOffsetBase);
  1454.     //
  1455.     // Write out the base tag.
  1456.     //
  1457.     if (fUseBaseHref)
  1458.     {
  1459.         //BASE tag must point to the base "URL". So, don't strip out the filename.
  1460.         _WriteHtmlFromIdF(IDS_BASE_TAG, szSelectedWallpaper);
  1461.     }
  1462.     // Figure out where to insert the DIV clause
  1463.     TAGENTRYA rgteBodyStart[] = {
  1464.                                     { "<BODY", FALSE, },
  1465.                                 };
  1466.     int iOffsetBodyStart = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteBodyStart, ARRAYSIZE(rgteBodyStart));
  1467.     // Write out HTML until after the <BODY ......>
  1468.     if (iOffsetBodyStart == -1)
  1469.     {   // the <BODY> tag is not found, so we need to insert it.
  1470.         // Copy over stuff until </HEAD>
  1471.         TAGENTRYA rgteHeadEnd[] = {
  1472.                                       { "</HEAD>", TRUE, },
  1473.                                   };
  1474.         int iOffsetHeadEnd = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBase, rgteHeadEnd, ARRAYSIZE(rgteHeadEnd));
  1475.         if(iOffsetHeadEnd != -1)
  1476.         {
  1477.             _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetHeadEnd);
  1478.             iOffsetBase = iOffsetHeadEnd;
  1479.         }
  1480.         _WriteHtmlFromIdF(IDS_BODY_CENTER_WP2); // "<BODY>"
  1481.         _fNeedBodyEnd = TRUE;
  1482.     }
  1483.     else
  1484.     {
  1485.         TAGENTRYA rgteBodyEnd[] = {
  1486.                                        { ">", TRUE, },
  1487.                                   };
  1488.         int iOffsetBodyEnd = _ScanTagEntriesA(_pReadFileObjHtmlBkgd, iOffsetBodyStart, rgteBodyEnd, ARRAYSIZE(rgteBodyEnd));
  1489.         if (iOffsetBodyEnd == -1)
  1490.         {   // An error in the HTML.
  1491.             iOffsetBodyEnd = iOffsetBodyStart;  // BUGBUG: We need a better recovery idea.
  1492.         }
  1493.         _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetBodyEnd);
  1494.         iOffsetBase = iOffsetBodyEnd;
  1495.     }
  1496.     *piOffsetBase = iOffsetBase;
  1497.     *piOffsetComp = iOffsetComponents;
  1498. }
  1499. void CActiveDesktop::_GenerateHtmlHeader(void)
  1500. {
  1501.     ENTERPROC(2, "DS GenerateHtmlHeader()");
  1502.     EnumMonitorsArea ema;
  1503.     GetMonitorSettings(&ema);
  1504.     RECT rcViewAreas[LV_MAX_WORKAREAS];  // WorkArea minus toolbar/tray areas
  1505.     int nViewAreas = ARRAYSIZE(rcViewAreas);
  1506.     // Get the ViewAreas
  1507.     if (!GetViewAreas(rcViewAreas, &nViewAreas))
  1508.     {
  1509.         nViewAreas = 0;
  1510.     }
  1511.     //Assume that the final Deskstat.htt that we generate is going to be in UNICODE.
  1512.     //This will change to ANSI only if the background html wallpaper is ANSI (determined later)
  1513.     _iDestFileCharset = UNICODE_HTML_CHARSET;
  1514.     
  1515.     //
  1516.     // Write out the background and color.
  1517.     //
  1518.     TCHAR szSelectedWallpaper[INTERNET_MAX_URL_LENGTH];
  1519.     // If the wallpaper does not have a directory specified (this may happen if other apps. change this value),
  1520.     // we have to figure it out.
  1521.     GetWallpaperWithPath(_szSelectedWallpaper, szSelectedWallpaper, ARRAYSIZE(szSelectedWallpaper));
  1522.     
  1523.     BOOL fValidWallpaper = GetFileAttributes(szSelectedWallpaper) != 0xFFFFFFFF;
  1524.     if (_fSingleItem || IsWallpaperPicture(szSelectedWallpaper) || !fValidWallpaper)
  1525.     {
  1526.         //
  1527.         //  Write the BOM for UNICODE
  1528.         //
  1529.         if(_hFileHtml)
  1530.         {
  1531.             DWORD cbWritten;
  1532.             
  1533.             WriteFile(_hFileHtml, (LPCSTR)&wUnicodeBOM, sizeof(wUnicodeBOM), &cbWritten, NULL);
  1534.         }
  1535.     
  1536.         // To account for the vagaries of the desktop browser (it's TopLeft starts from the TopLeft
  1537.         // of the Desktop ViewArea instead of the TopLeft of the monitor, as might be expected)
  1538.         // which happens only in the case of one active monitor systems, we add the width of the
  1539.         // tray/toolbars to the co-ordinates of the DIV section of each monitor's wallpaper.
  1540.         int iLeft, iTop;
  1541.         if(nViewAreas == 1)
  1542.         {
  1543.             iLeft = rcViewAreas[0].left - ema.rcVirtualMonitor.left;
  1544.             iTop = rcViewAreas[0].top - ema.rcVirtualMonitor.top;
  1545.         }
  1546.         else
  1547.         {
  1548.             iLeft = 0;
  1549.             iTop = 0;
  1550.         }
  1551.         //
  1552.         // Write out the standard header.
  1553.         //
  1554.         UINT i;
  1555.         for (i=IDS_COMMENT_BEGIN; i<IDS_BODY_BEGIN; i++)
  1556.         {
  1557.             _WriteHtmlFromIdF(i);
  1558.         }
  1559.         //
  1560.         // Write out the body tag, with background bitmap.
  1561.         //
  1562.         DWORD rgbDesk;
  1563.         rgbDesk = GetSysColor(COLOR_DESKTOP);
  1564.         TCHAR szBitmapFile[MAX_PATH];
  1565.         GetPerUserFileName(szBitmapFile, ARRAYSIZE(szBitmapFile), PATTERN_FILENAME);
  1566.         if (!_fSingleItem && _szSelectedWallpaper[0] && fValidWallpaper)
  1567.         {
  1568.             TCHAR szWallpaperUrl[INTERNET_MAX_URL_LENGTH];
  1569.             DWORD cch = ARRAYSIZE(szWallpaperUrl);
  1570.             UrlCreateFromPath(szSelectedWallpaper, szWallpaperUrl, &cch, URL_INTERNAL_PATH);
  1571.             switch (_wpo.dwStyle)
  1572.             {
  1573.                 case WPSTYLE_TILE:
  1574.                     //
  1575.                     // Ignore the pattern, tile the wallpaper as background.
  1576.                     //
  1577.                     _WriteHtmlFromIdF(IDS_BODY_BEGIN2, szWallpaperUrl, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1578.                     break;
  1579.                 case WPSTYLE_CENTER:
  1580.                     if (IsValidPattern(_szSelectedPattern))
  1581.                     {
  1582.                         //
  1583.                         // Tile the pattern as the main background.
  1584.                         //
  1585.                         _WriteHtmlFromIdF(IDS_BODY_BEGIN2, szBitmapFile, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1586.                         if(_fBackgroundHtml)   // We are generating the HTML for preview
  1587.                         {
  1588.                             _WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP, szWallpaperUrl);
  1589.                         }
  1590.                         else
  1591.                         {
  1592.                             //
  1593.                             // Write out a DIV section for a centered, untiled wallpaper.
  1594.                             //
  1595.                             // write it out for each monitor.
  1596.                             for(int i = 0; i < ema.iMonitors; i++)
  1597.                             {
  1598.                                 _WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP2,
  1599.                                             ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
  1600.                                             ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
  1601.                                             ema.rcMonitor[i].right - ema.rcMonitor[i].left,
  1602.                                             ema.rcMonitor[i].bottom - ema.rcMonitor[i].top,
  1603.                                             szWallpaperUrl);
  1604.                             }
  1605.                         }
  1606.                     }
  1607.                     else
  1608.                     {
  1609.                         //
  1610.                         // Write out a non-tiled, centered wallpaper as background.
  1611.                         //
  1612.                         if(_fBackgroundHtml)   // We are generating the HTML for preview
  1613.                         {
  1614.                             _WriteHtmlFromIdF(IDS_BODY_CENTER_WP, szWallpaperUrl, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1615.                         }
  1616.                         else
  1617.                         {
  1618.                             _WriteHtmlFromIdF(IDS_BODY_CENTER_WP2, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1619.                             // write it out for each monitor.
  1620.                             for(int i = 0; i < ema.iMonitors; i++)
  1621.                             {
  1622.                                 _WriteHtmlFromIdF(IDS_BODY_PATTERN_AND_WP2,
  1623.                                                     ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
  1624.                                                     ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
  1625.                                                     ema.rcMonitor[i].right - ema.rcMonitor[i].left,
  1626.                                                     ema.rcMonitor[i].bottom - ema.rcMonitor[i].top,
  1627.                                                     szWallpaperUrl);
  1628.                             }
  1629.                         }
  1630.                     }
  1631.                     break;
  1632.                 case WPSTYLE_STRETCH:
  1633.                     //
  1634.                     // Ignore the pattern, create a DIV section of the wallpaper
  1635.                     // stretched to 100% of the screen.
  1636.                     //
  1637.                     _WriteHtmlFromIdF(IDS_BODY_BEGIN2, c_szNULL, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1638.                     if(_fBackgroundHtml)   // We are generating the HTML for preview
  1639.                     {
  1640.                         _WriteHtmlFromIdF(IDS_STRETCH_WALLPAPER, szWallpaperUrl);
  1641.                     }
  1642.                     else
  1643.                     {
  1644.                         // stretch it for each monitor.
  1645.                         for(int i = 0; i < ema.iMonitors; i++)
  1646.                         {
  1647.                             _WriteHtmlFromIdF(IDS_DIV_START3, ema.rcMonitor[i].left - ema.rcVirtualMonitor.left - iLeft,
  1648.                                                 ema.rcMonitor[i].top - ema.rcVirtualMonitor.top - iTop,
  1649.                                                 ema.rcMonitor[i].right - ema.rcMonitor[i].left,
  1650.                                                 ema.rcMonitor[i].bottom - ema.rcMonitor[i].top);
  1651.                             _WriteHtmlFromIdF(IDS_STRETCH_WALLPAPER, szWallpaperUrl);
  1652.                             _WriteHtmlFromId(IDS_DIV_END);
  1653.                         }
  1654.                     }
  1655.                     break;
  1656.             }
  1657.         }
  1658.         else
  1659.         {
  1660.             //
  1661.             // Ignore the wallpaper, generate either a tiled pattern
  1662.             // or solid color background.
  1663.             //
  1664.             _WriteHtmlFromIdF(IDS_BODY_BEGIN2, !_fSingleItem && IsValidPattern(_szSelectedPattern) ? szBitmapFile : c_szNULL, GetRValue(rgbDesk), GetGValue(rgbDesk), GetBValue(rgbDesk));
  1665.         }
  1666.     }
  1667.     else
  1668.     {
  1669.         if ((_pReadFileObjHtmlBkgd = new CReadFileObj(szSelectedWallpaper)) &&
  1670.             (_pReadFileObjHtmlBkgd->_hFile != INVALID_HANDLE_VALUE))
  1671.         {
  1672.             //The final Desktop.htt will be in ANSI only if the source html file is also in ansi.
  1673.             //So, get the type from the selected wallpaper object.
  1674.             _iDestFileCharset = _pReadFileObjHtmlBkgd->_iCharset;
  1675.             //
  1676.             //  Write the BOM for UNICODE
  1677.             //
  1678.             if(_hFileHtml && (_iDestFileCharset == UNICODE_HTML_CHARSET))
  1679.             {
  1680.                 DWORD cbWritten;
  1681.             
  1682.                 WriteFile(_hFileHtml, (LPCSTR)&wUnicodeBOM, sizeof(wUnicodeBOM), &cbWritten, NULL);
  1683.             }
  1684.     
  1685.             //
  1686.             // Figure out where to insert the base href tag.
  1687.             //
  1688.             int     iOffsetBase = 0;
  1689.             int     iOffsetComponents;
  1690. //  98/11/11 #248047 vtan: This code looks for a <BASE HREF=...> tag.
  1691. //  It used to use a scan for "<BASE" and assume that this was the
  1692. //  desired tag. HTML allows a "<BASEFONT>" tag which was being
  1693. //  mistaken for a "<BASE HREF=...>" tag. The code now looks for the
  1694. //  same string but looks at the character following the "<BASE" to
  1695. //  see if it's a white-space character.
  1696.             if(_iDestFileCharset == ANSI_HTML_CHARSET)
  1697.             {
  1698.                 //The following function parses the ANSI input html file and finds various offsets
  1699.                 _ParseAnsiInputHtmlFile(szSelectedWallpaper, &iOffsetBase, &iOffsetComponents);
  1700.             }
  1701.             else
  1702.             {
  1703.                 //The following code parses the UNICODE input html wallpaper file.
  1704.                 int iBaseTagStart;
  1705.                 BOOL    fUseBaseHref;
  1706.                 LONG    lOffsetDueToBOM = 0; //Character Offset due to the Byte Order Mark.
  1707.                                          //1 for UNICODE and 0 for ANSI files.
  1708.                 fUseBaseHref = TRUE;
  1709.                 _pReadFileObjHtmlBkgd->FileGetCurCharOffset(&lOffsetDueToBOM);
  1710.                 iOffsetBase = (int)lOffsetDueToBOM;
  1711.                 iBaseTagStart = _ScanForTagW(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, L"<BASE");
  1712.                 
  1713.                 if (iBaseTagStart != -1)
  1714.                 {
  1715.                     UINT   uiCountChars, uiTryToRead;
  1716.                     WCHAR  wszBaseTagBuffer[6+1];     // allow for "<BASEx" plus a NULL.
  1717.                     _pReadFileObjHtmlBkgd->FileSeekChars(iBaseTagStart, FILE_BEGIN);
  1718.                     uiTryToRead = ARRAYSIZE(wszBaseTagBuffer) - 1;
  1719.                     if(SUCCEEDED(_pReadFileObjHtmlBkgd->FileReadCharsW(wszBaseTagBuffer, uiTryToRead, &uiCountChars)) && uiCountChars)
  1720.                     {
  1721.                         WCHAR    wc;
  1722.                         wc = wszBaseTagBuffer[5];
  1723.                         fUseBaseHref = ((wc != L' ') &&
  1724.                                         (wc != L'r') &&
  1725.                                         (wc != L'n') &&      // this covers the UNIX line break scheme
  1726.                                         (wc != L't'));
  1727.                     }
  1728.                 }
  1729.                 if (fUseBaseHref)
  1730.                 {
  1731.                     TAGENTRYW rgteBase[] = {
  1732.                                             { L"<HEAD>", TRUE, },
  1733.                                             { L"<BODY", FALSE, },
  1734.                                             { L"<HTML>", TRUE, },
  1735.                                            };
  1736.                     iOffsetBase = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, rgteBase, ARRAYSIZE(rgteBase));
  1737.                     if (iOffsetBase == -1)
  1738.                     {
  1739.                         iOffsetBase = (int)lOffsetDueToBOM;
  1740.                     }
  1741.                 }
  1742.                 //
  1743.                 // Figure out where to insert the components.
  1744.                 //
  1745.                 TAGENTRYW rgteComponents[] = {
  1746.                                                 { L"</BODY>", FALSE, },
  1747.                                                 { L"</HTML>", FALSE, },
  1748.                                              };
  1749.                 iOffsetComponents = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteComponents, ARRAYSIZE(rgteComponents));
  1750.                 //
  1751.                 // Write out the initial HTML up to the <HEAD> tag.
  1752.                 //
  1753.                 _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, (int)lOffsetDueToBOM, iOffsetBase);
  1754.                 //
  1755.                 // Write out the base tag.
  1756.                 //
  1757.                 if (fUseBaseHref)
  1758.                 {
  1759.                     //BASE tag must point to the base "URL". So, don't strip out the filename.
  1760.                     _WriteHtmlFromIdF(IDS_BASE_TAG, szSelectedWallpaper);
  1761.                 }
  1762.                 // Figure out where to insert the DIV clause
  1763.                 TAGENTRYW rgteBodyStart[] = {
  1764.                                                 { L"<BODY", FALSE, },
  1765.                                             };
  1766.                 int iOffsetBodyStart = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteBodyStart, ARRAYSIZE(rgteBodyStart));
  1767.                 // Write out HTML until after the <BODY ......>
  1768.                 if (iOffsetBodyStart == -1)
  1769.                 {   // the <BODY> tag is not found, so we need to insert it.
  1770.                     // Copy over stuff until </HEAD>
  1771.                     TAGENTRYW rgteHeadEnd[] = {
  1772.                                                 { L"</HEAD>", TRUE, },
  1773.                                               };
  1774.                     int iOffsetHeadEnd = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBase, rgteHeadEnd, ARRAYSIZE(rgteHeadEnd));
  1775.                     if(iOffsetHeadEnd != -1)
  1776.                     {
  1777.                         _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetHeadEnd);
  1778.                         iOffsetBase = iOffsetHeadEnd;
  1779.                     }
  1780.                     _WriteHtmlFromIdF(IDS_BODY_CENTER_WP2); // "<BODY>"
  1781.                     _fNeedBodyEnd = TRUE;
  1782.                 }
  1783.                 else
  1784.                 {
  1785.                     TAGENTRYW rgteBodyEnd[] = {
  1786.                                                 { L">", TRUE, },
  1787.                                               };
  1788.                     int iOffsetBodyEnd = _ScanTagEntriesW(_pReadFileObjHtmlBkgd, iOffsetBodyStart, rgteBodyEnd, ARRAYSIZE(rgteBodyEnd));
  1789.                     if (iOffsetBodyEnd == -1)
  1790.                     {   // An error in the HTML.
  1791.                         iOffsetBodyEnd = iOffsetBodyStart;  // BUGBUG: We need a better recovery idea.
  1792.                     }
  1793.                     _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetBodyEnd);
  1794.                     iOffsetBase = iOffsetBodyEnd;
  1795.                 }
  1796.             }
  1797.             // Insert the DIV clause
  1798.             if(ema.iMonitors > 1)
  1799.             {
  1800.                 int         iIndexPrimaryMonitor;
  1801.                 HMONITOR    hMonitorPrimary;
  1802.                 MONITORINFO monitorInfo;
  1803.                 // 99/03/23 #275429 vtan: We used GetViewAreas() to fill in rcViewAreas above.
  1804.                 // The code here used to assume that [0] ALWAYS referred to the primary monitor.
  1805.                 // This isn't the case if the monitor settings are changed without a restart.
  1806.                 // In order to compensate for this and always render the wallpaper into the
  1807.                 // primary monitor, a search is performed to find a (left, top) that matches
  1808.                 // one of the work areas and this is used as the primary monitor. If none can
  1809.                 // be found then default to the old algorithm.
  1810.                 hMonitorPrimary = GetPrimaryMonitor();
  1811.                 monitorInfo.cbSize = sizeof(monitorInfo);
  1812.                 TBOOL(GetMonitorInfo(hMonitorPrimary, &monitorInfo));
  1813.                 iIndexPrimaryMonitor = -1;
  1814.                 for (int i = 0; (iIndexPrimaryMonitor < 0) && (i < nViewAreas); ++i)
  1815.                 {
  1816.                     if ((monitorInfo.rcWork.left == rcViewAreas[i].left) && (monitorInfo.rcWork.top == rcViewAreas[i].top))
  1817.                     {
  1818.                         iIndexPrimaryMonitor = i;
  1819.                     }
  1820.                 }
  1821.                 if (iIndexPrimaryMonitor < 0)
  1822.                     iIndexPrimaryMonitor = 0;
  1823.                 if ((nViewAreas <= 0) || (rcViewAreas[iIndexPrimaryMonitor].right == rcViewAreas[iIndexPrimaryMonitor].left))
  1824.                 // The second case could occur on bootup
  1825.                 {
  1826.                     // Some error occured when getting the ViewAreas. Recover from the error by using the workarea.
  1827.                     // Get the workarea of the primary monitor, since HTML wallpapers are displayed only there.
  1828.                     GetMonitorWorkArea(hMonitorPrimary, &rcViewAreas[iIndexPrimaryMonitor]);
  1829.                 }
  1830.                 _WriteHtmlFromIdF(IDS_DIV_START3,
  1831.                                   rcViewAreas[iIndexPrimaryMonitor].left - ema.rcVirtualMonitor.left,
  1832.                                   rcViewAreas[iIndexPrimaryMonitor].top - ema.rcVirtualMonitor.top,
  1833.                                   rcViewAreas[iIndexPrimaryMonitor].right - rcViewAreas[iIndexPrimaryMonitor].left,
  1834.                                   rcViewAreas[iIndexPrimaryMonitor].bottom - rcViewAreas[iIndexPrimaryMonitor].top);
  1835.             }
  1836.             //
  1837.             // Write out HTML from after <HEAD> tag to just before </BODY> tag.
  1838.             //
  1839.             _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, iOffsetBase, iOffsetComponents);
  1840.             if(ema.iMonitors > 1)
  1841.             {
  1842.                 _WriteHtmlFromId(IDS_DIV_END);
  1843.             }
  1844.         }
  1845.         else
  1846.         {
  1847.             if(_pReadFileObjHtmlBkgd)
  1848.                 delete _pReadFileObjHtmlBkgd;
  1849.             _pReadFileObjHtmlBkgd = NULL;
  1850.         }
  1851.     }
  1852.     EXITPROC(2, "DS GenerateHtmlHeader!");
  1853. }
  1854. void CActiveDesktop::_WriteResizeable(COMPONENTA *pcomp)
  1855. {
  1856.     TCHAR   szResizeable[3];
  1857.     szResizeable[0] = TEXT('');
  1858.     //If Resize is set, then the comp is resizeable in both X and Y directions!
  1859.     if(pcomp->cpPos.fCanResize)
  1860.         lstrcat(szResizeable, TEXT("XY"));
  1861.     else
  1862.     {
  1863.         if(pcomp->cpPos.fCanResizeX)
  1864.             lstrcat(szResizeable, TEXT("X"));
  1865.         if(pcomp->cpPos.fCanResizeY)
  1866.             lstrcat(szResizeable, TEXT("Y"));
  1867.     }
  1868.     _WriteHtmlFromIdF(IDS_RESIZEABLE, szResizeable);
  1869. }
  1870. void CActiveDesktop::_WriteHtmlW(LPCWSTR wcBuf, UINT cchToWrite, UINT *pcchWritten)
  1871. {
  1872.     ULONG    cchWritten = 0;
  1873.     UINT     uiSize;
  1874.     
  1875.     if(_pStream)
  1876.     {
  1877.         uiSize = sizeof(WCHAR);
  1878.         _pStream->Write((LPVOID)wcBuf, cchToWrite * uiSize, &cchWritten);
  1879.     }
  1880.     else
  1881.     {
  1882.         ASSERT(_hFileHtml);
  1883.         uiSize = (_iDestFileCharset == ANSI_HTML_CHARSET) ? sizeof(char) : sizeof(WCHAR);
  1884.         WriteFile(_hFileHtml, (LPCVOID)wcBuf, cchToWrite * uiSize, &cchWritten, NULL);
  1885.     }
  1886.     *pcchWritten = (UINT)(cchWritten/uiSize);  //Convert to number of chars.
  1887. }
  1888. void CActiveDesktop::_GenerateHtmlPicture(COMPONENTA *pcomp)
  1889. {
  1890.     ENTERPROC(2, "DS GenerateHtmlPicture(pcomp=%08X)");
  1891.     //
  1892.     // Write out the image src HTML.
  1893.     //
  1894.     TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  1895.     DWORD cch=ARRAYSIZE(szUrl);
  1896.     if (FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &cch, 0)))
  1897.     {
  1898.         lstrcpy(szUrl, pcomp->szSource);
  1899.     }
  1900.     _WriteHtmlFromIdF(IDS_IMAGE_BEGIN2, pcomp->dwID, szUrl);
  1901.     //
  1902.     // Write out whether this image is resizeable or not!
  1903.     //
  1904.     _WriteResizeable(pcomp);
  1905.     //
  1906.     // Write out the URL that must be used for subscription purposes.
  1907.     //
  1908.     _WriteHtmlFromIdF(IDS_SUBSCRIBEDURL, pcomp->szSubscribedURL);
  1909.     //
  1910.     // Write out the image location HTML.
  1911.     //
  1912.     if ((pcomp->cpPos.dwWidth == COMPONENT_DEFAULT_WIDTH) &&
  1913.         (pcomp->cpPos.dwHeight == COMPONENT_DEFAULT_HEIGHT))
  1914.     {
  1915.         _WriteHtmlFromIdF(IDS_IMAGE_LOCATION, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.izIndex);
  1916.     }
  1917.     else
  1918.     {
  1919.         _WriteHtmlFromIdF(IDS_IMAGE_SIZE, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop,
  1920.                             pcomp->cpPos.dwWidth, pcomp->cpPos.dwHeight, pcomp->cpPos.izIndex);
  1921.     }
  1922.     EXITPROC(2, "DS GenerateHtmlPicture!");
  1923. }
  1924. void CActiveDesktop::_GenerateHtmlDoc(COMPONENTA *pcomp)
  1925. {
  1926.     ENTERPROC(2, "DS GenerateHtmlDoc(pcomp=%08X)");
  1927.     
  1928.     TCHAR   szUrl[INTERNET_MAX_URL_LENGTH];
  1929.     DWORD   dwSize = ARRAYSIZE(szUrl);
  1930.     LPTSTR  lpszUrl = szUrl;
  1931.     if(FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &dwSize, 0)))
  1932.         lpszUrl = pcomp->szSource;
  1933.     //
  1934.     // Write out the DIV header HTML.
  1935.     //
  1936.     _WriteHtmlFromIdF(IDS_DIV_START2, pcomp->dwID, lpszUrl);
  1937.     //
  1938.     // Write out whether this component is resizeable or not!
  1939.     //
  1940.     _WriteResizeable(pcomp);
  1941.     //
  1942.     // Write out the DIV location HTML.
  1943.     //
  1944.     _WriteHtmlFromIdF(IDS_DIV_SIZE, pcomp->cpPos.dwHeight, _fSingleItem ? 0 : pcomp->cpPos.iLeft,
  1945.         _fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.dwWidth, pcomp->cpPos.izIndex);
  1946.     //
  1947.     // Extract the doc contents directly into the HTML.
  1948.     //
  1949.     _WriteHtmlFromFile(pcomp->szSource);
  1950.     //
  1951.     // Close the DIV section.
  1952.     //
  1953.     _WriteHtmlFromId(IDS_DIV_END);
  1954.     EXITPROC(2, "DS GenerateHtmlDoc!");
  1955. }
  1956. void CActiveDesktop::_GenerateHtmlSite(COMPONENTA *pcomp)
  1957. {
  1958.     ENTERPROC(2, "DS GenerateHtmlSite(pcomp=%08X)");
  1959.     //
  1960.     // Write out the frame src HTML.
  1961.     //
  1962.     TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  1963.     DWORD cch=ARRAYSIZE(szUrl);
  1964.     if (FAILED(UrlCreateFromPath(pcomp->szSource, szUrl, &cch, 0)))
  1965.     {
  1966.         lstrcpy(szUrl, pcomp->szSource);
  1967.     }
  1968.     DWORD   currentURLLength, maximumURLLength;
  1969.     TCHAR   *pURL, formatBuffer[0x0100];
  1970. //  98/09/29 #211384 vtan: There is a limitation in wvsprintf.
  1971. //  It only allows 2048 bytes in its buffer. If the URL is
  1972. //  longer than 1024 characters less the IDS_IFRAME_BEGIN2
  1973. //  string length less the component ID less "scrolling=no"
  1974. //  if the component cannot be scrolled then the URL string
  1975. //  will not be correctly inserted into the IDS_IFRAME_BEGIN2
  1976. //  string and there will be a missing end-quote and trident
  1977. //  will fail to render desktop.htt correctly.
  1978. //  To correct against this the followING limits the length of
  1979. //  the URL to this maximum and truncates any characters
  1980. //  beyond the limit so that the IDS_IFRAME_BEGIN2 string
  1981. //  contains its end-quote and trident does not barf.
  1982. //  The above condition is a boundary condition and this
  1983. //  check is quick so that the calculations that follow do
  1984. //  not have to be executed repeatedly.
  1985.     currentURLLength = lstrlen(szUrl);
  1986.     if (currentURLLength > 768)                                 // a hard-coded limit
  1987.     {
  1988.         maximumURLLength = 1024;                                // wvsprintf limit
  1989.         LoadString(HINST_THISDLL, IDS_IFRAME_BEGIN2, formatBuffer, ARRAYSIZE(formatBuffer));
  1990.         maximumURLLength -= lstrlen(formatBuffer);              // IDS_IFRAME_BEGIN2
  1991.         maximumURLLength -= 16;                                 // pcomp->dwID
  1992.         maximumURLLength -= lstrlen(TEXT("scrolling=no"));      // pcomp->fNoScroll
  1993.         if (currentURLLength > maximumURLLength)
  1994.             szUrl[maximumURLLength] = static_cast<TCHAR>('');
  1995.     }
  1996.     _WriteHtmlFromIdF(IDS_IFRAME_BEGIN2, pcomp->dwID, szUrl, pcomp->fNoScroll ? TEXT("scrolling=no") : c_szNULL);
  1997.     //
  1998.     // Write out whether this Component is resizeable or not!
  1999.     //
  2000.     _WriteResizeable(pcomp);
  2001. //  98/09/29 #211384 vtan: See above.
  2002.     currentURLLength = lstrlen(pcomp->szSubscribedURL);
  2003.     if (currentURLLength > 768)
  2004.     {
  2005.         lstrcpy(szUrl, pcomp->szSubscribedURL);
  2006.         maximumURLLength = 1024;
  2007.         LoadString(HINST_THISDLL, IDS_SUBSCRIBEDURL, formatBuffer, ARRAYSIZE(formatBuffer));
  2008.         maximumURLLength -= lstrlen(formatBuffer);              // IDS_SUBSCRIBEDURL
  2009.         if (currentURLLength > maximumURLLength)
  2010.             szUrl[maximumURLLength] = static_cast<TCHAR>('');
  2011.         pURL = szUrl;
  2012.     }
  2013.     else
  2014.         pURL = pcomp->szSubscribedURL;
  2015.     //
  2016.     // Write out the URL that must be used for subscription purposes.
  2017.     //
  2018.     _WriteHtmlFromIdF(IDS_SUBSCRIBEDURL, pURL);
  2019.     //
  2020.     // Write out the frame location HTML.
  2021.     //
  2022.     _WriteHtmlFromIdF(IDS_IFRAME_SIZE, _fSingleItem ? 0 : pcomp->cpPos.iLeft, _fSingleItem ? 0 : pcomp->cpPos.iTop,
  2023.         pcomp->cpPos.dwWidth, pcomp->cpPos.dwHeight, pcomp->cpPos.izIndex);
  2024.     EXITPROC(2, "DS GenerateHtmlSite!");
  2025. }
  2026. void CActiveDesktop::_GenerateHtmlControl(COMPONENTA *pcomp)
  2027. {
  2028.     ENTERPROC(2, "DS GenerateHtmlControl(pcomp=%08X)");
  2029.     ASSERT(pcomp);
  2030.     
  2031.     // Did the Administrator restrict "Channel UI"?
  2032.     if (SHRestricted2W(REST_NoChannelUI, NULL, 0))
  2033.     {
  2034.         TCHAR szChannelOCGUID[GUIDSTR_MAX];
  2035.         SHStringFromGUID(CLSID_ChannelOC, szChannelOCGUID, ARRAYSIZE(szChannelOCGUID));
  2036.         if (!StrCmpNI(pcomp->szSource, &(szChannelOCGUID[1]), lstrlen(pcomp->szSource)-3))
  2037.         {
  2038.             // Yes, so we need to hide the Channel Desktop Component.
  2039.             // Return here before we generate it.
  2040.             return;
  2041.         }        
  2042.     }
  2043.     
  2044.     //
  2045.     // Write out the control HTML.
  2046.     //
  2047.     // First the control header
  2048.     _WriteHtmlFromIdF(IDS_CONTROL_1, pcomp->dwID);
  2049.     // then the size
  2050.     _WriteHtmlFromIdF(IDS_CONTROL_2, pcomp->cpPos.dwHeight, _fSingleItem ? 0 : pcomp->cpPos.iLeft,
  2051.         _fSingleItem ? 0 : pcomp->cpPos.iTop, pcomp->cpPos.dwWidth, pcomp->cpPos.izIndex);
  2052.     //
  2053.     // Write out whether this Control is resizeable or not!
  2054.     //
  2055.     _WriteResizeable(pcomp);
  2056.     // Finally the rest of the control
  2057.     _WriteHtmlFromIdF(IDS_CONTROL_3, pcomp->szSource);
  2058.     EXITPROC(2, "DS GenerateHtmlControl!");
  2059. }
  2060. void CActiveDesktop::_GenerateHtmlComponent(COMPONENTA *pcomp)
  2061. {
  2062.     ENTERPROC(2, "DS GenerateHtmlComponent(pcomp=%08X)");
  2063.     switch(pcomp->iComponentType)
  2064.     {
  2065.         case COMP_TYPE_PICTURE:
  2066.             _GenerateHtmlPicture(pcomp);
  2067.             break;
  2068.         case COMP_TYPE_HTMLDOC:
  2069.             _GenerateHtmlDoc(pcomp);
  2070.             break;
  2071.         case COMP_TYPE_WEBSITE:
  2072.             _GenerateHtmlSite(pcomp);
  2073.             break;
  2074.         case COMP_TYPE_CONTROL:
  2075.             _GenerateHtmlControl(pcomp);
  2076.             break;
  2077.     }
  2078.     EXITPROC(2, "DS GenerateHtmlComponent!");
  2079. }
  2080. void CActiveDesktop::_GenerateHtmlFooter(void)
  2081. {
  2082.     ENTERPROC(2, "DS GenerateHtmlFooter()");
  2083.     //
  2084.     // Write out the deskmovr object.
  2085.     //
  2086.     if (!_fNoDeskMovr)
  2087.     {
  2088.         TCHAR szDeskMovrFile[MAX_PATH];
  2089.         GetWindowsDirectory(szDeskMovrFile, ARRAYSIZE(szDeskMovrFile));
  2090.         lstrcat(szDeskMovrFile, DESKMOVR_FILENAME);
  2091.         _WriteHtmlFromFile(szDeskMovrFile);
  2092.     }
  2093.     //
  2094.     // Write out the concluding HTML tags.
  2095.     //
  2096.     if (_pReadFileObjHtmlBkgd)
  2097.     {
  2098.         if(_fNeedBodyEnd)
  2099.         {    // We had introduced the <BODY> tag by ourselves.
  2100.             _WriteHtmlFromId(IDS_BODY_END2);
  2101.             _fNeedBodyEnd = FALSE;
  2102.         }
  2103.         _WriteHtmlFromReadFileObj(_pReadFileObjHtmlBkgd, -1, -1);
  2104.         delete _pReadFileObjHtmlBkgd;   //Close the file and cleanup!
  2105.         _pReadFileObjHtmlBkgd = NULL;
  2106.     }
  2107.     else
  2108.     {
  2109.         _WriteHtmlFromId(IDS_BODY_END);
  2110.     }
  2111.     EXITPROC(2, "DS GenerateHtmlFooter!");
  2112. }
  2113. void CActiveDesktop::_GenerateHtml(void)
  2114. {
  2115.     ENTERPROC(2, "DS GenerateHtml()");
  2116.     TCHAR szHtmlFile[MAX_PATH];
  2117.     //
  2118.     // Compute the filename.
  2119.     //
  2120.     szHtmlFile[0] = TEXT('');
  2121.     GetPerUserFileName(szHtmlFile, ARRAYSIZE(szHtmlFile), DESKTOPHTML_FILENAME);
  2122.     //
  2123.     // Recreate the file.
  2124.     //
  2125.     _hFileHtml = CreateFile(szHtmlFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  2126.                             FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, NULL);
  2127.     if (_hFileHtml != INVALID_HANDLE_VALUE)
  2128.     {
  2129.         _GenerateHtmlHeader();
  2130.         if (_co.fEnableComponents && _hdsaComponent && DSA_GetItemCount(_hdsaComponent) && !SHRestricted(REST_NODESKCOMP))
  2131.         {
  2132.             int i;
  2133.             for (i=0; i<DSA_GetItemCount(_hdsaComponent); i++)
  2134.             {
  2135.                 COMPONENTA comp;
  2136.                 comp.dwSize = sizeof(COMPONENTA);
  2137.                 if ((DSA_GetItem(_hdsaComponent, i, &comp) != -1) && (comp.fChecked))
  2138.                 {
  2139.                     _GenerateHtmlComponent(&comp);
  2140.                 }
  2141.             }
  2142.         }
  2143.         _GenerateHtmlFooter();
  2144.         CloseHandle(_hFileHtml);
  2145.         SetDesktopFlags(COMPONENTS_DIRTY, 0);
  2146.     }
  2147.     else
  2148.     {
  2149.         // 99/05/19 #340772 vtan: If unable to open desktop.htt it's probably
  2150.         // in use by another process or task (perhaps trident is trying to
  2151.         // render it). In this case mark it dirty so that it will get recreated
  2152.         // - yet again but this time with more current data.
  2153.         SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
  2154.     }
  2155.     EXITPROC(2, "DS GenerateHtml!");
  2156. }
  2157. HRESULT CActiveDesktop::GenerateDesktopItemHtml(LPCWSTR pwszFileName, COMPONENT *pcomp, DWORD dwReserved)
  2158. {
  2159.     HRESULT hres = E_FAIL;
  2160.     ENTERPROC(2, "DS GenerateComponentHtml(pcomp=%08X)", pcomp);
  2161.     LPTSTR  pszFileName;
  2162.     //Check for the input parameters
  2163.     if(!pwszFileName || (pcomp && (pcomp->dwSize != SIZEOF(*pcomp)) && (pcomp->dwSize != SIZEOF(IE4COMPONENT))))
  2164.         return E_INVALIDARG;
  2165.     ASSERT(!dwReserved);     // These should be 0
  2166. #ifndef UNICODE
  2167.     CHAR    szFileName[MAX_PATH];
  2168.     SHUnicodeToAnsi(pwszFileName, szFileName, ARRAYSIZE(szFileName));
  2169.     pszFileName = szFileName;
  2170. #else
  2171.     pszFileName = (LPTSTR)pwszFileName;
  2172. #endif
  2173.     //
  2174.     // Create the file.
  2175.     //
  2176.     _hFileHtml = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  2177.                                 FILE_ATTRIBUTE_NORMAL, NULL);
  2178.     if (_hFileHtml != INVALID_HANDLE_VALUE)
  2179.     {
  2180.         _fNoDeskMovr = TRUE;
  2181.         _fBackgroundHtml = TRUE;
  2182.         //Check if we need to add a component
  2183.         if(pcomp)
  2184.         {
  2185.             COMPONENTA  CompA;
  2186.             CompA.dwSize = sizeof(CompA);
  2187.             WideCompToMultiComp(pcomp, &CompA);
  2188.             _fSingleItem = TRUE;
  2189.             _GenerateHtmlHeader();
  2190.             _GenerateHtmlComponent(&CompA);
  2191.             _GenerateHtmlFooter();
  2192.             _fSingleItem = FALSE;
  2193.         }
  2194.         else
  2195.         {
  2196.             //generate just the header and the footer with proper
  2197.             // wallpaper and pattern info!
  2198.             _GenerateHtmlHeader();
  2199.             _GenerateHtmlFooter();
  2200.         }
  2201.         _fBackgroundHtml = FALSE;
  2202.         _fNoDeskMovr = FALSE;
  2203.         CloseHandle(_hFileHtml);
  2204.         hres = S_OK;
  2205.     }
  2206.     _hFileHtml = NULL;
  2207.     EXITPROC(2, "DS GenerateComponentHtml=%d", hres);
  2208.     return hres;
  2209. }
  2210. //
  2211. // AddUrl
  2212. //
  2213. //
  2214. HRESULT CActiveDesktop::AddUrl(HWND hwnd, LPCWSTR pszSourceW, LPCOMPONENT pcomp, DWORD dwFlags)
  2215. {
  2216.     LPTSTR pszExt;
  2217.     HRESULT fOkay = TRUE;
  2218.     BOOL fExtIsCdf,fPathIsUrl;
  2219.     BOOL fSubscribed = FALSE;
  2220.     COMPONENT   compLocal;
  2221.     COMPONENTA  compA;
  2222.     TCHAR szSource[INTERNET_MAX_URL_LENGTH];
  2223. //  98/08/28 vtan #202777: The following if statement sanitizes parameters
  2224. //  passed to AddUrl(). The statements following the "||" are executed
  2225. //  despite the for pcomp against NULL. This causes an access violation
  2226. //  and an exception to be thrown.
  2227. #if     0
  2228.     //Check for the input parameters.
  2229.     if(!pszSourceW || (pcomp &&
  2230.        ((pcomp->dwSize != SIZEOF(*pcomp)) && (pcomp->dwSize != SIZEOF(IE4COMPONENT))) ||
  2231.        ((pcomp->dwSize == SIZEOF(*pcomp)) && !VALIDATESTATE(pcomp->dwCurItemState))))
  2232.         return E_INVALIDARG;
  2233. #else
  2234. //  The following performs the same comparison but is spread into three
  2235. //  separate comparisons. As performance is not a critical issue here
  2236. //  but correctness is this makes the tests clear and understandable.
  2237. //  The invalid conditions are described.
  2238. //  Validate input parameters. Invalid parameters are:
  2239. //      1) NULL pszSourceW
  2240. //      2) pcomp->dwSize for a COMPONENT struct but invalid pcomp->dwCurItemState
  2241. //      3) pcomp->dwSize is not for a COMPONENT struct nor for a IE4COMPONENT struct
  2242.     if (pszSourceW == NULL)
  2243.         return(E_INVALIDARG);
  2244.     if (pcomp != NULL)
  2245.     {
  2246.         if ((pcomp->dwSize == sizeof(*pcomp)) && !VALIDATESTATE(pcomp->dwCurItemState))
  2247.             return(E_INVALIDARG);
  2248.         if ((pcomp->dwSize != sizeof(*pcomp)) && (pcomp->dwSize != sizeof(IE4COMPONENT)))
  2249.             return(E_INVALIDARG);
  2250.     }
  2251. #endif
  2252.     // Catch folks that call our API's to add components and prevent them from doing
  2253.     // so if the restriction is in place.
  2254.     if (SHIsRestricted(NULL, REST_NOADDDESKCOMP))
  2255.         return E_ACCESSDENIED;
  2256.     if (!pcomp)
  2257.     {
  2258.         pcomp = &compLocal;
  2259.         pcomp->dwSize = sizeof(compLocal);
  2260.         pcomp->dwCurItemState = IS_NORMAL;
  2261.     }
  2262.     // Attempt to come up with a reasonable window handle if none is passed in.  ParseDesktopComponent
  2263.     // will fail to attempt to create a subscription if a NULL window handle is passed in.
  2264.     if (!hwnd)
  2265.         hwnd = GetLastActivePopup(GetActiveWindow());
  2266.     compA.dwSize = sizeof(compA);
  2267.     compA.dwCurItemState = (pcomp->dwSize != SIZEOF(IE4COMPONENT)) ? pcomp->dwCurItemState : IS_NORMAL;
  2268.     g_pActiveDesk = this;
  2269.     SHUnicodeToTChar(pszSourceW, szSource, ARRAYSIZE(szSource));
  2270.     pszExt = PathFindExtension(szSource);
  2271.     fExtIsCdf = lstrcmpi(pszExt, TEXT(".CDF")) == 0;
  2272.     fPathIsUrl = PathIsURL(szSource) && !UrlIsFileUrl(szSource);
  2273.     if (FindComponent(szSource))
  2274.     {
  2275.         if (dwFlags & ADDURL_SILENT)  
  2276.         {
  2277.             lstrcpy(compA.szSource, szSource);
  2278.             MultiCompToWideComp(&compA, pcomp);
  2279.             RemoveDesktopItem(pcomp, 0);
  2280.         }
  2281.         else  
  2282.         {
  2283.             // This is a long string. So,...
  2284.             TCHAR szMsg[512];
  2285.             TCHAR szMsg2[256];
  2286.             TCHAR szTitle[128];
  2287.             LoadString(HINST_THISDLL, IDS_COMP_EXISTS, szMsg, ARRAYSIZE(szMsg));
  2288.             LoadString(HINST_THISDLL, IDS_COMP_EXISTS_2, szMsg2, ARRAYSIZE(szMsg2));
  2289.             lstrcat(szMsg, szMsg2);
  2290.             LoadString(HINST_THISDLL, IDS_COMP_TITLE, szTitle, ARRAYSIZE(szTitle));
  2291.             MessageBox(hwnd, szMsg, szTitle, MB_OK);
  2292.             fOkay = FALSE;
  2293.         }
  2294.     }
  2295.     if (fOkay && CheckForExistingSubscription(szSource))
  2296.     {
  2297.         if ((dwFlags & ADDURL_SILENT) ||
  2298.             (ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_SUBSCRIBED), 
  2299.                  MAKEINTRESOURCE(IDS_COMP_TITLE), MB_YESNO) == IDYES))
  2300.         {
  2301.             DeleteFromSubscriptionList(szSource);
  2302.         }
  2303.         else
  2304.         {
  2305.             fOkay = FALSE;
  2306.         }
  2307.     }
  2308.     if (fOkay)
  2309.     {
  2310.         if (fPathIsUrl || fExtIsCdf)
  2311.         {
  2312.             WCHAR szUrlW[INTERNET_MAX_URL_LENGTH];
  2313.             SHTCharToUnicode(szSource, szUrlW, ARRAYSIZE(szUrlW));
  2314.             HRESULT hr;
  2315.             IProgressDialog * pProgressDlg = NULL;
  2316.             DECLAREWAITCURSOR;
  2317. //  98/12/16 vtan #250938: Cannot add new components that are not
  2318. //  local with ICW run to completion. Tell the user and launch ICW.
  2319.             if (!IsICWCompleted())
  2320.             {
  2321.                 if ((dwFlags & ADDURL_SILENT) == 0)
  2322.                 {
  2323.                     ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_COMP_ICW_ADD), MAKEINTRESOURCE(IDS_COMP_ICW_TITLE), MB_OK);
  2324.                     LaunchICW();
  2325.                 }
  2326.                 fOkay = FALSE;
  2327.             }
  2328.             else
  2329.             {
  2330.                 SetWaitCursor();
  2331.                 // ParseDesktopComponent can hang for a long time, we need some sort of progress
  2332.                 // UI up before we call it.
  2333.                 if (!(dwFlags & ADDURL_SILENT) && !fExtIsCdf)
  2334.                 {
  2335.                     if (pProgressDlg = CProgressDialog_CreateInstance(IDS_COMP_TITLE, IDA_ISEARCH, g_hinst))
  2336.                     {
  2337.                         WCHAR szConnectingW[80];
  2338.                         TCHAR szConnecting[80];
  2339.                         LoadString(HINST_THISDLL, IDS_CONNECTING, szConnecting, ARRAYSIZE(szConnecting));
  2340.                         SHTCharToUnicode(szConnecting, szConnectingW, ARRAYSIZE(szConnectingW));
  2341.                         pProgressDlg->SetLine(1, szConnectingW, FALSE, NULL);
  2342.                         pProgressDlg->SetLine(2, szUrlW, TRUE, NULL);
  2343.                         pProgressDlg->StartProgressDialog(hwnd, NULL, PROGDLG_AUTOTIME | PROGDLG_NOPROGRESSBAR, NULL);
  2344.                     }
  2345.                 }
  2346.                 hr = ParseDesktopComponent(hwnd, szUrlW, pcomp);