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

Windows Kernel

Development Platform:

Visual C++

  1. /***************************************************************************/
  2. /* WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! */
  3. /***************************************************************************/
  4. /* As part of the shdocvw/browseui split, parts of this file are moving to */
  5. /* shell32/shlwapi (#ifdef POSTPOSTSPLIT).  Make sure you make your delta  */
  6. /* to the shell32/shlwapi version also!                                    */
  7. /***************************************************************************/
  8. #include "priv.h"
  9. #include "sccls.h"
  10. #include "shlobj.h"
  11. #include <fsmenu.h>
  12. #include <tchar.h>
  13. #ifndef UNIX
  14. #include <webcheck.h>
  15. #else
  16. #include <subsmgr.h>
  17. #endif
  18. #include "resource.h"
  19. #include "mshtml.h"     // for IHTMLElement
  20. #include "mlang.h"  // fo char conversion
  21. #include <advpub.h> // for IE activesetup GUID
  22. #include "winineti.h" // For name of a mutex used in IsWininetLoadedAnywhere()
  23. #include "htregmng.h"
  24. #include <ntverp.h>
  25. #include "mruex.h"
  26. #include "mttf.h"
  27. #include <platform.h>
  28. #include <mobsync.h>
  29. #include <mobsyncp.h>
  30. #include <winuser.h>
  31. #include <mluisupp.h>
  32. #include "shdocfl.h"
  33. #include <shlwapip.h>
  34. #include "../lib/brutil.cpp"
  35. STDAPI CDelegateMalloc_Create(void *pv, SIZE_T cbSize, WORD wOuter, IMalloc **ppmalloc);
  36. const VARIANT c_vaEmpty = {0};
  37. const TCHAR c_szRegKeyTypedURLs[]     = TEXT("Software\Microsoft\Internet Explorer\TypedURLs");
  38. #define DM_SESSIONCOUNT     0
  39. int     g_cxIcon = 0;
  40. int     g_cyIcon = 0;
  41. int     g_cxSmIcon = 0;
  42. int     g_cySmIcon = 0;
  43. const DISPPARAMS c_dispparamsNoArgs = {NULL, NULL, 0, 0};
  44. const LARGE_INTEGER c_li0 = { 0, 0 };
  45. const ITEMIDLIST s_idlNULL = { 0 } ;
  46. int InitColorDepth(void)
  47. {
  48.     static int s_lrFlags = 0;              // Flags passed to LoadImage
  49.     if (s_lrFlags == 0)
  50.     {
  51.         int nColorRes, nIconDepth = 0;
  52.         HKEY hkey;
  53.         // Determine the color depth so we can load the best image
  54.         // (This code was stolen from FileIconInit in shell32)
  55.         // Get the user prefered icon size (and color depth) from the
  56.         // registry.
  57.         //
  58.         if (NO_ERROR == RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_METRICS, &hkey))
  59.         {
  60.             nIconDepth = SHRegGetIntW(hkey, L"Shell Icon Bpp", nIconDepth);
  61.             RegCloseKey(hkey);
  62.         }
  63.         nColorRes = GetCurColorRes();
  64.         if (nIconDepth > nColorRes)
  65.             nIconDepth = 0;
  66.         if (nColorRes <= 8)
  67.             nIconDepth = 0; // wouldn't have worked anyway
  68.         if (nColorRes > 4 && nIconDepth <= 4)
  69.             s_lrFlags = LR_VGACOLOR;
  70.         else
  71.             s_lrFlags = LR_DEFAULTCOLOR;
  72.     }
  73.     return s_lrFlags;
  74. }
  75. HICON   g_hiconSplat = NULL;
  76. HICON   g_hiconSplatSm = NULL;      // small version
  77. void LoadCommonIcons(void)
  78. {
  79.     if (NULL == g_hiconSplat)
  80.     {
  81.         // Use LoadLibraryEx so we don't load code pages
  82.         HINSTANCE hinst = LoadLibrary(TEXT("url.dll"));
  83.         if (hinst)
  84.         {
  85.             int lrFlags = InitColorDepth();
  86.             g_hiconSplat   = (HICON)LoadImage(hinst, MAKEINTRESOURCE(IDI_URL_SPLAT), IMAGE_ICON, g_cxIcon, g_cyIcon, lrFlags);
  87.             g_hiconSplatSm = (HICON)LoadImage(hinst, MAKEINTRESOURCE(IDI_URL_SPLAT), IMAGE_ICON, g_cxSmIcon, g_cySmIcon, lrFlags);
  88.             FreeLibrary(hinst);
  89.         }
  90.     }
  91. }
  92. STDAPI_(BOOL) UrlHitsNetW(LPCWSTR pszURL)
  93. {
  94.     BOOL fResult;
  95.     // Handle the easy ones on our own and call URLMON for the others.
  96.     switch (GetUrlScheme(pszURL))
  97.     {
  98.     case URL_SCHEME_FILE:
  99.     case URL_SCHEME_RES:
  100.         fResult = FALSE;
  101.         break;
  102.     case URL_SCHEME_HTTP:
  103.     case URL_SCHEME_HTTPS:
  104.     case URL_SCHEME_FTP:
  105.     case URL_SCHEME_GOPHER:
  106.     case URL_SCHEME_TELNET:
  107.     case URL_SCHEME_WAIS:
  108.         fResult = TRUE;
  109.         break;
  110.     default:
  111.         {
  112.         DWORD fHitsNet;
  113.         DWORD dwSize;
  114.         fResult = SUCCEEDED(CoInternetQueryInfo(
  115.                             pszURL, QUERY_USES_NETWORK,
  116.                             0, &fHitsNet, sizeof(fHitsNet), &dwSize, 0)) && fHitsNet;
  117.         }
  118.     }
  119.     return fResult;
  120. }
  121. STDAPI_(BOOL) CallCoInternetQueryInfo(LPCTSTR pszURL, QUERYOPTION QueryOption)
  122. {
  123.     DWORD fRetVal;
  124.     DWORD dwSize;
  125.     return SUCCEEDED(CoInternetQueryInfo(
  126.                         pszURL, QueryOption,
  127.                         0, &fRetVal, sizeof(fRetVal), &dwSize, 0)) && fRetVal;
  128. }
  129. // see if a given URL is in the cache
  130. STDAPI_(BOOL) UrlIsInCache(LPCTSTR pszURL)
  131. {
  132.     return CallCoInternetQueryInfo(pszURL, QUERY_IS_CACHED);
  133. }
  134. // See if a give URL is actually present as an installed entry
  135. STDAPI_(BOOL) UrlIsInstalledEntry(LPCTSTR pszURL)
  136. {
  137.     return CallCoInternetQueryInfo(pszURL, QUERY_IS_INSTALLEDENTRY);
  138. }
  139. // see if a given URL is in the cache OR if it is mapped
  140. STDAPI_(BOOL) UrlIsMappedOrInCache(LPCTSTR pszURL)
  141. {
  142.     return CallCoInternetQueryInfo(pszURL, QUERY_IS_CACHED_OR_MAPPED);
  143. }
  144. BOOL IsFileUrlW(LPCWSTR pcwzUrl)
  145. {
  146.     return (GetUrlSchemeW(pcwzUrl) == URL_SCHEME_FILE);
  147. }
  148. BOOL IsFileUrl(LPCSTR psz)
  149. {
  150.     return (GetUrlSchemeA(psz) == URL_SCHEME_FILE);
  151. }
  152. BOOL PathIsFilePath(LPCWSTR lpszPath)
  153. {
  154. #ifdef UNIX
  155.     if (lpszPath[0] == TEXT('/'))
  156. #else
  157.     if ((lpszPath[0] == TEXT('\')) || (lpszPath[1] == TEXT(':')))
  158. #endif
  159.         return TRUE;
  160.     return IsFileUrlW(lpszPath);
  161. }
  162. BOOL IsSubscribableW(LPCWSTR pszUrl)
  163. {
  164.     //  BUGBUG: this should be method on the subscription mgr interface - zekel
  165.     DWORD dwScheme = GetUrlSchemeW(pszUrl);
  166.     return (dwScheme == URL_SCHEME_HTTP) || (dwScheme == URL_SCHEME_HTTPS);
  167. }
  168. BOOL IsSubscribableA(LPCSTR pszUrl)
  169. {
  170.     //  BUGBUG: this should be method on the subscription mgr interface - zekel
  171.     DWORD dwScheme = GetUrlSchemeA(pszUrl);
  172.     return (dwScheme == URL_SCHEME_HTTP) || (dwScheme == URL_SCHEME_HTTPS);
  173. }
  174. DWORD SHRandom(void)
  175. {
  176.     GUID guid;
  177.     DWORD dw;
  178.     CoCreateGuid(&guid);
  179.     HashData((LPBYTE)&guid, SIZEOF(guid), (LPBYTE)&dw, SIZEOF(dw));
  180.     return dw;
  181. }
  182. // See if we are hosted by IE (explorer.exe or iexplore.exe)
  183. BOOL IsInternetExplorerApp()
  184. {
  185.     if ((g_fBrowserOnlyProcess) ||                  // if in iexplore.exe process,
  186.         (GetModuleHandle(TEXT("EXPLORER.EXE"))))        // or explorer.exe process,
  187.     {
  188.         return TRUE;                                // then we are IE
  189.     }
  190.     return FALSE;
  191. }
  192. BOOL IsTopFrameBrowser(IServiceProvider *psp, IUnknown *punk)
  193. {
  194.     IShellBrowser *psb;
  195.     ASSERT(psp);
  196.     ASSERT(punk);
  197.     BOOL fRet = FALSE;
  198.     if(SUCCEEDED(psp->QueryService(SID_STopFrameBrowser, IID_IShellBrowser, (void **)&psb)))
  199.     {
  200.         fRet = IsSameObject(psb, punk);
  201.         psb->Release();
  202.     }
  203.     return fRet;
  204. }
  205. DWORD GetUrlSchemePidl(LPITEMIDLIST pidl)
  206. {
  207.     if (pidl && IsURLChild(pidl, TRUE))
  208.     {
  209.         TCHAR szUrl[MAX_URL_STRING];
  210.         if (SUCCEEDED(IEGetDisplayName(pidl, szUrl, SHGDN_FORPARSING)))
  211.             return GetUrlScheme(szUrl);
  212.     }
  213.     return URL_SCHEME_INVALID;
  214. }
  215. //-----------------------------------------------------------------------------
  216. #ifndef POSTPOSTSPLIT
  217. STDAPI_(BSTR) LoadBSTR(UINT uID)
  218. {
  219.     WCHAR wszBuf[MAX_PATH];
  220.     if (MLLoadStringW(uID, wszBuf, ARRAYSIZE(wszBuf)))
  221.     {
  222.         return SysAllocString(wszBuf);
  223.     }
  224.     return NULL;
  225. }
  226. #endif
  227. BOOL StringIsUTF8A(LPCSTR psz, DWORD cb)
  228. {
  229.     BOOL fRC = FALSE;
  230.     CHAR *pb;
  231.     CHAR b;
  232.     DWORD dwCnt;
  233.     DWORD dwUTF8Cnt;
  234.     if(!psz || !(*psz) || cb == 0)
  235.         return(FALSE);
  236.     pb = (CHAR*)psz;
  237.     while(cb-- && *pb)
  238.     {
  239.         if((*pb & 0xc0) == 0xc0) // bit pattern starts with 11
  240.         {
  241.             dwCnt = dwUTF8Cnt = 0;
  242.             b = *pb;
  243.             while((b & 0xc0) == 0xc0)
  244.             {
  245.                 dwCnt++;
  246.                 if((*(pb+dwCnt) & 0xc0) == 0x80)   // bits at dwCnt bytes from current offset in str aren't 10
  247.                     dwUTF8Cnt++;
  248.                 b = (b << 1) & 0xff;
  249.             }
  250.             if(dwCnt == dwUTF8Cnt)
  251.                 fRC = TRUE;       // Found UTF8 encoded chars
  252.                 
  253.             pb += ++dwCnt;
  254.         }
  255.         else
  256.         {
  257.             pb++;
  258.         }
  259.     }
  260.     return(fRC);
  261. }
  262. BOOL StringIsUTF8W(LPCWSTR pwz, DWORD cb)
  263. {
  264.     BOOL  fRC = FALSE;
  265.     WCHAR *pb;
  266.     WCHAR b;
  267.     DWORD dwCnt;
  268.     DWORD dwUTF8Cnt;
  269.     if(!pwz || !(*pwz) || cb == 0)
  270.         return(FALSE);
  271.     pb = (WCHAR*)pwz;
  272.     while(cb-- && *pb)
  273.     {
  274.         if(*pb > 255)   // Non ansi so bail
  275.             return(FALSE);
  276.             
  277.         if((*pb & 0xc0) == 0xc0) // bit pattern starts with 11
  278.         {
  279.             dwCnt = dwUTF8Cnt = 0;
  280.             b = *pb;
  281.             while((b & 0xc0) == 0xc0)
  282.             {
  283.                 dwCnt++;
  284.                 if((*(pb+dwCnt) & 0xc0) == 0x80)   // bits at dwCnt bytes from current offset in str aren't 10
  285.                     dwUTF8Cnt++;
  286.                 b = (b << 1) & 0xff;
  287.             }
  288.             if(dwCnt == dwUTF8Cnt)
  289.                 fRC = TRUE;       // Found UTF8 encoded chars
  290.                 
  291.             pb += ++dwCnt;
  292.         }
  293.         else
  294.         {
  295.             pb++;
  296.         }
  297.     }
  298.     return(fRC);
  299. }
  300. //
  301. //  StringContainsHighAnsi
  302. //
  303. //  Determine if string contains high-ANSI characters. Search is
  304. //    stopped when we hit the first high-ANSI character, when we hit the terminator
  305. //    or when we have decremented dwInLen to zero
  306. //
  307. //  Return Value:
  308. //      TRUE    - pszIn contains one or more high-ANSI characters
  309. //
  310. //      FALSE   - pszIn (or substring of length dwInLen) does not contain
  311. //                high-ANSI characters
  312. //
  313. BOOL StringContainsHighAnsiA(LPCSTR pszIn, DWORD dwInLen)
  314. {
  315.     while (dwInLen-- && *pszIn) 
  316.     {
  317.         if (*pszIn++ & 0x80)
  318.             return TRUE;
  319.     }
  320.     return FALSE;
  321. }
  322. BOOL StringContainsHighAnsiW(LPCWSTR pszIn, DWORD dwInLen)
  323. {
  324.     while (dwInLen-- && *pszIn) 
  325.     {
  326.         if (*pszIn++ & 0x80)
  327.             return TRUE;
  328.     }
  329.     return FALSE;
  330. }
  331. BOOL UTF8Enabled(VOID)
  332. {
  333.     static DWORD   dwIE = URL_ENCODING_NONE;
  334.     DWORD   dwOutLen = sizeof(DWORD);
  335.     
  336.     if(dwIE == URL_ENCODING_NONE)
  337.         UrlMkGetSessionOption(URLMON_OPTION_URL_ENCODING, &dwIE, sizeof(DWORD), &dwOutLen, NULL);
  338.     return(dwIE == URL_ENCODING_ENABLE_UTF8);
  339. }
  340. //
  341. // PrepareURLForDisplay
  342. //
  343. //     Decodes without stripping file:// prefix
  344. //
  345. #undef PrepareURLForDisplay
  346. BOOL PrepareURLForDisplayW(LPCWSTR pwz, LPWSTR pwzOut, LPDWORD pcbOut)
  347. {
  348.     if (PathIsFilePath(pwz))
  349.     {
  350.         if (IsFileUrlW(pwz))
  351.             return SUCCEEDED(PathCreateFromUrlW(pwz, pwzOut, pcbOut, 0));
  352.         StrCpyNW(pwzOut, pwz, *pcbOut);
  353.         *pcbOut = lstrlenW(pwzOut);
  354.         return TRUE;
  355.     }
  356.     
  357.     return SUCCEEDED(UrlUnescapeW((LPWSTR)pwz, pwzOut, pcbOut, 0));
  358. }
  359. //
  360. // PrepareURLForDisplayUTF8W
  361. //
  362. // pwz -          [In] UTF8 encoded string like "%e6%aa%e4%a6.doc".
  363. // pwzOut -       [Out]  UTF8 decoded string.
  364. // pcchOut -      [In/Out] Count of characters in pwzOut on input.  Number of chars copies to pwzOut on output
  365. //                         including the terminating null.
  366. // fUTF8Enabled - [In] Flag to indicated whether UTF8 is enabled.
  367. //
  368. // Returns:
  369. //    S_OK upon success.
  370. //    E_FAIL for failure.
  371. //    ERROR_BUFFER_OVERFLOW if the number of converted chars is greater than the passed in size of output buffer.
  372. //
  373. //    Note: If UTF8 is not enabled or the string does not contain UTF8 the output string will be unescaped
  374. //    and will return S_OK.
  375. //
  376. HRESULT PrepareURLForDisplayUTF8W(LPCWSTR pwz, LPWSTR pwzOut, LPDWORD pcchOut, BOOL fUTF8Enabled)
  377. {
  378.     HRESULT hr = E_FAIL;
  379.     DWORD   cch;
  380.     DWORD   cch1;
  381.     CHAR    szBuf[MAX_URL_STRING];
  382.     CHAR    *pszBuf = szBuf;
  383.     if(!pwz || !pwzOut || !pcchOut)
  384.     {
  385.         if(pcchOut)
  386.             *pcchOut = 0;
  387.         return(hr);
  388.     }
  389.         
  390.     cch = *pcchOut;
  391.     cch1 = ARRAYSIZE(szBuf);
  392.     hr = UrlUnescapeW((LPWSTR)pwz, pwzOut, pcchOut, 0);
  393.     if(SUCCEEDED(hr))
  394.     {
  395.         if (fUTF8Enabled && StringIsUTF8W(pwzOut, cch))
  396.         {
  397.             if(*pcchOut > ARRAYSIZE(szBuf)) // Internal buffer not big enough so alloc one
  398.             {
  399.                 if((pszBuf = (CHAR *)LocalAlloc(LPTR, ((*pcchOut)+1) * sizeof(CHAR))) == NULL)
  400.                 {
  401.                     *pcchOut = 0;
  402.                     return(E_OUTOFMEMORY);
  403.                 }
  404.                 cch1 = *pcchOut;
  405.             }
  406.             // Compress wide string
  407.             CHAR *pIn = (CHAR *)pwzOut;
  408.             CHAR *pOut = pszBuf;
  409.             while((*pIn != '') || (*(pIn+1) != '') && --cch1)
  410.             {
  411.                 if(*pIn != '')
  412.                 {
  413.                     *pOut = *pIn;
  414.                     pOut++;
  415.                 }
  416.                 pIn++;
  417.             }
  418.             *pOut = '';
  419.             // Convert to UTF8 wide string
  420.             if((cch1 = SHAnsiToUnicodeCP(CP_UTF8, pszBuf, pwzOut, cch)) != 0)
  421.             {
  422.                 hr = S_OK;
  423.                 *pcchOut = cch1;
  424.             }
  425.             // SHAnsiToUnicode doesn't tell us if it has truncated the convertion to fit the output buffer
  426.             RIPMSG(cch1 != cch, "PrepareUrlForDisplayUTF8: Passed in size of out buf equal to converted size; buffer might be truncated");
  427.             if((pszBuf != NULL) && (pszBuf != szBuf))
  428.                 LocalFree((CHAR *)pszBuf);
  429.         }
  430.         else
  431.         {
  432.             hr = S_OK;;
  433.         }
  434.     }
  435.     return(hr);
  436. }
  437. //
  438. // PrepareURLForExternalApp -
  439. //
  440. //   Decodes and strips, if needed, file:// prefix
  441. //
  442. //  BUGBUGCOMPAT - for IE30 compatibility reasons, we have to Unescape all Urls - zekel - 1-JUL-97
  443. //  before passing them to an APP.  this does limit their use, but
  444. //  people already depend on this behavior.  specifically MS Chat.
  445. BOOL PrepareURLForExternalApp (LPCWSTR psz, LPWSTR pszOut, LPDWORD pcchOut)
  446. {
  447.     if(IsFileUrlW(psz))
  448.         return SUCCEEDED(PathCreateFromUrl(psz, pszOut, pcchOut, 0));
  449.     else
  450.         return SUCCEEDED(UrlUnescape((LPWSTR)psz, pszOut, pcchOut, 0));
  451. }
  452. BOOL ParseURLFromOutsideSourceW (LPCWSTR psz, LPWSTR pszOut, LPDWORD pcchOut, LPBOOL pbWasSearchURL)
  453. {
  454.     // This is our hardest case.  Users and outside applications might
  455.     // type fully-escaped, partially-escaped, or unescaped URLs at us.
  456.     // We need to handle all these correctly.  This API will attempt to
  457.     // determine what sort of URL we've got, and provide us a returned URL
  458.     // that is guaranteed to be FULLY escaped.
  459.     IURLQualify(psz, UQF_DEFAULT, pszOut, pbWasSearchURL, NULL);
  460.     //
  461.     //  go ahead and canonicalize this appropriately
  462.     //
  463.     if (FAILED(UrlCanonicalize(pszOut, pszOut, pcchOut, URL_ESCAPE_SPACES_ONLY)))
  464.     {
  465.         //
  466.         //  we cant resize from here.
  467.         //  NOTE UrlCan will return E_POINTER if it is an insufficient buffer
  468.         //
  469.         TraceMsg(DM_ERROR, "sdv PUFOS:UC() failed.");
  470.         return FALSE;
  471.     }
  472.     return TRUE;
  473. } // ParseURLFromOutsideSource
  474. BOOL ParseURLFromOutsideSourceA (LPCSTR psz, LPSTR pszOut, LPDWORD pcchOut, LPBOOL pbWasSearchURL)
  475. {
  476.     SHSTRW strw;
  477.     DWORD cch ;
  478.     ASSERT(psz);
  479.     ASSERT(pszOut);
  480.     ASSERT(pcchOut && *pcchOut);
  481.     //
  482.     //  BUGBUG we arent guaranteed to have the correct cch's here - zekel - 27-jan-97
  483.     //  but for now this is adequate.
  484.     //
  485.     if(SUCCEEDED(strw.SetStr(psz)) && SUCCEEDED(strw.SetSize(cch = *pcchOut)) &&
  486.         ParseURLFromOutsideSourceW((LPCWSTR) strw, (LPWSTR) strw, pcchOut, pbWasSearchURL))
  487.     {
  488.         return SHUnicodeToAnsi((LPCWSTR)strw, pszOut, cch);
  489.     }
  490.     return FALSE;
  491. }
  492. int DPA_ILFreeCallback(void * p, void * d)
  493. {
  494.     Pidl_Set((LPITEMIDLIST*)&p, NULL);
  495.     return 1;
  496. }
  497. void _DeletePidlDPA(HDPA hdpa)
  498. {
  499.     DPA_DestroyCallback(hdpa, (PFNDPAENUMCALLBACK)DPA_ILFreeCallback, 0);
  500. }
  501. BOOL _InitComCtl32()
  502. {
  503.     static BOOL fInitialized = FALSE;
  504.     if (!fInitialized)
  505.     {
  506.         INITCOMMONCONTROLSEX icc;
  507.         icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  508.         icc.dwICC = ICC_USEREX_CLASSES | ICC_COOL_CLASSES | ICC_INTERNET_CLASSES | ICC_PAGESCROLLER_CLASS | ICC_NATIVEFNTCTL_CLASS;
  509.         fInitialized = InitCommonControlsEx(&icc);
  510.     }
  511.     return fInitialized;
  512. }
  513. #ifndef ALPHA_WARNING_IS_DUMB
  514. #pragma message("building with alpha warning enabled")
  515. void AlphaWarning(HWND hwnd)
  516. {
  517.     static BOOL fShown = FALSE;
  518.     TCHAR szTemp[265];
  519.     TCHAR szFull[2048];
  520.     szFull[0] = TEXT('');
  521.     int i = IDS_ALPHAWARNING;
  522.     if (fShown)
  523.         return;
  524.     fShown = TRUE;
  525.     while(MLLoadShellLangString (i++, szTemp, ARRAYSIZE(szTemp))) {
  526.         StrCatBuff(szFull, szTemp, ARRAYSIZE(szFull));
  527.     }
  528.     MessageBox(hwnd, szFull, TEXT("Internet Explorer"), MB_ICONINFORMATION | MB_OK);
  529. }
  530. #endif
  531. #if 0
  532. // t-neilb: Should be able to remove
  533. /*******************************************************************
  534.  NAME:       InitHistoryList
  535.  SYNOPSIS:   Reads persistent addresses from registry and puts them
  536.              into a combo box.
  537. ********************************************************************/
  538. BOOL InitHistoryList(HWND hwndCB)
  539. {
  540.     ASSERT(hwndCB); // window needs to have been created
  541.     if (!hwndCB)
  542.         return FALSE;
  543.     // open the registry key containing addresses
  544.     HKEY hKey;
  545.     DWORD result;
  546.     result = RegCreateKey(HKEY_CURRENT_USER, c_szRegKeyTypedURLs, &hKey);
  547.     if (result != ERROR_SUCCESS)
  548.         return FALSE;
  549.     ASSERT(hKey);
  550.     // read values from registry and put them in combo box
  551.     UINT nTrys;
  552.     UINT nCount = 0;
  553.     TCHAR szValueName[10];   // big enough for "url99"
  554.     TCHAR szAddress[MAX_URL_STRING+1];
  555.     DWORD dwAddress;
  556.     for (nTrys = 0; nTrys < MAX_SAVE_TYPED_URLS; nTrys++) {
  557.         // make a value name a la "url1" (1-based for historical reasons)
  558.         wnsprintf(szValueName, ARRAYSIZE(szValueName), TEXT("url%u"), nTrys+1);
  559.         dwAddress = ARRAYSIZE(szAddress);
  560.         if (RegQueryValueEx(hKey, szValueName, NULL, NULL, (LPBYTE)szAddress,
  561.                             &dwAddress) == ERROR_SUCCESS) {
  562.             if (szAddress[0]) {
  563.                 ComboBox_InsertString(hwndCB, nCount, szAddress);
  564.                 nCount++;
  565.             }
  566.         }
  567.     }
  568.     RegCloseKey(hKey);
  569.     return TRUE;
  570. }
  571. BOOL SaveHistoryList(HWND hwndCB)
  572. {
  573.     ASSERT(hwndCB); // address window needs to have been created
  574.     if (!hwndCB)
  575.         return FALSE;
  576.     // open the registry key containing addresses
  577.     HKEY hKey;
  578.     DWORD result = RegCreateKey(HKEY_CURRENT_USER, c_szRegKeyTypedURLs, &hKey);
  579.     if (result != ERROR_SUCCESS)
  580.         return FALSE;
  581.     ASSERT(hKey);
  582.     // get the number of items in combo box
  583.     int nItems = ComboBox_GetCount(hwndCB);
  584.     int nTrys;
  585.     TCHAR szValueName[10];   // big enough for "url99"
  586.     TCHAR szAddress[MAX_URL_STRING+1];
  587.     // loop through every potential saved URL in registry.
  588.     for (nTrys = 0; nTrys < MAX_SAVE_TYPED_URLS; nTrys++) {
  589.         // make a value name a la "url1" (1-based for historical reasons)
  590.         wnsprintf(szValueName,ARRAYSIZE(szValueName), TEXT("url%u"),nTrys+1);
  591.         // for every combo box item we have, get the corresponding
  592.         // text and save it in the registry
  593.         if (nTrys < nItems) {
  594.             // get text from combo box
  595.             if (ComboBox_GetLBText(hwndCB, nTrys, szAddress)) {
  596.                 // store it in registry
  597.                 RegSetValueEx(hKey,szValueName,0,REG_SZ,(LPBYTE)
  598.                               szAddress,(lstrlen(szAddress)*sizeof(TCHAR))+1);
  599.                 continue;
  600.             }
  601.         }
  602.         // if we get here, we've run out of combo box items (or
  603.         // failed to retrieve text for one of them).  Delete any
  604.         // extra items that may be lingering in the registry.
  605.         RegDeleteValue(hKey,szValueName);
  606.     }
  607.     RegCloseKey(hKey);
  608.     return TRUE;
  609. }
  610. #endif
  611. #ifndef POSTPOSTSPLIT
  612. #endif
  613. #define DM_NAV              TF_SHDNAVIGATE
  614. #define DM_ZONE             TF_SHDNAVIGATE
  615. #define DM_IEDDE            DM_TRACE
  616. #define DM_CANCELMODE       0
  617. #define DM_UIWINDOW         0
  618. #define DM_ENABLEMODELESS   0
  619. #define DM_EXPLORERMENU     0
  620. #define DM_BACKFORWARD      0
  621. #define DM_PROTOCOL         0
  622. #define DM_ITBAR            0
  623. #define DM_STARTUP          0
  624. #define DM_AUTOLIFE         0
  625. #define DM_PALETTE          0
  626. PFNSHCHANGENOTIFYREGISTER    g_pfnSHChangeNotifyRegister = NULL;
  627. PFNSHCHANGENOTIFYDEREGISTER  g_pfnSHChangeNotifyDeregister = NULL;
  628. BOOL g_fNewNotify = FALSE;   // Are we using classic mode (W95 or new mode?
  629. BOOL CALLBACK AddPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam)
  630. {
  631.     PROPSHEETHEADER * ppsh = (PROPSHEETHEADER *)lParam;
  632.     if (ppsh->nPages < MAX_PAGES)
  633.     {
  634.         ppsh->phpage[ppsh->nPages++] = hpage;
  635.         return TRUE;
  636.     }
  637.     return FALSE;
  638. }
  639. BOOL SHIsRegisteredClient(LPCTSTR pszClient)
  640. {
  641.     LONG cbSize = 0;
  642.     TCHAR szKey[80];
  643.     wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("Software\Clients\%s"), pszClient);
  644.     return (RegQueryValue(HKEY_LOCAL_MACHINE, szKey, NULL, &cbSize) == ERROR_SUCCESS) &&
  645.            (cbSize > sizeof(TCHAR));
  646. }
  647. // Exporting by ordinal is not available on UNIX.
  648. // But we have all these symbols exported because it's UNIX default.
  649. #ifdef UNIX
  650. #define GET_PRIVATE_PROC_ADDRESS(_hinst, _fname, _ord) GetProcAddress(_hinst, _fname)
  651. #else
  652. #define GET_PRIVATE_PROC_ADDRESS(_hinst, _fname, _ord) GetProcAddress(_hinst, _ord)
  653. #endif
  654. ULONG RegisterNotify(HWND hwnd, UINT nMsg, LPCITEMIDLIST pidl, DWORD dwEvents, UINT uFlags, BOOL fRecursive)
  655. {
  656.     SHChangeNotifyEntry fsne;
  657.     // See if we need to still figure out which version of SHChange Notify to call?
  658.     if  (g_pfnSHChangeNotifyDeregister == NULL)
  659.     {
  660.         HMODULE hmodShell32 = ::GetModuleHandle(TEXT("SHELL32"));
  661.         if (!hmodShell32)
  662.             return 0;   // Nothing registered...
  663.         g_pfnSHChangeNotifyRegister = (PFNSHCHANGENOTIFYREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,
  664.                                                                                           "NTSHChangeNotifyRegister",
  665.                                                                                           (LPSTR)640);
  666.         if (g_pfnSHChangeNotifyRegister && (WhichPlatform() == PLATFORM_INTEGRATED))
  667.         {
  668.             g_pfnSHChangeNotifyDeregister = (PFNSHCHANGENOTIFYDEREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,
  669.                                                                                                   "NTSHChangeNotifyDeregister",
  670.                                                                                                   (LPSTR)641);
  671.             g_fNewNotify = TRUE;
  672.         }
  673.         else
  674.         {
  675.             g_pfnSHChangeNotifyRegister = (PFNSHCHANGENOTIFYREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,
  676.                                                                                               "SHChangeNotifyRegister",
  677.                                                                                               (LPSTR)2);
  678.             g_pfnSHChangeNotifyDeregister = (PFNSHCHANGENOTIFYDEREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,
  679.                                                                                                   "SHChangeNotifyDeregister",
  680.                                                                                                   (LPSTR)4);
  681.         }
  682.         if  (g_pfnSHChangeNotifyDeregister == NULL)
  683.             return 0;   // Could not get either to work...
  684.     }
  685.     uFlags |= SHCNRF_ShellLevel | SHCNRF_InterruptLevel;
  686.     if (g_fNewNotify)
  687.         uFlags |= SHCNRF_NewDelivery;
  688.     fsne.fRecursive = fRecursive;
  689.     fsne.pidl = pidl;
  690.     return g_pfnSHChangeNotifyRegister(hwnd, uFlags, dwEvents, nMsg, 1, &fsne);
  691. }
  692. //----------------------------------------------------------------------------
  693. // Just like shells SHRestricted() only this put up a message if the restricion
  694. // is in effect.
  695. // BUGBUG: this function is identical to shell32's SHIsRestricted
  696. BOOL SHIsRestricted(HWND hwnd, RESTRICTIONS rest)
  697. {
  698.     if (SHRestricted(rest))
  699.     {
  700.         SHRestrictedMessageBox(hwnd);
  701.         return TRUE;
  702.     }
  703.     return FALSE;
  704. }
  705. BOOL SHIsRestricted2W(HWND hwnd, BROWSER_RESTRICTIONS rest, LPCWSTR pwzUrl, DWORD dwReserved)
  706. {
  707.     if (SHRestricted2W(rest, pwzUrl, dwReserved))
  708.     {
  709.         SHRestrictedMessageBox(hwnd);
  710.         return TRUE;
  711.     }
  712.     return FALSE;
  713. }
  714. BOOL bIsValidString(LPCSTR pszString, ULONG cbLen)
  715. {
  716.     if (cbLen == 0) return TRUE;
  717.     while (cbLen--)
  718.         if (*pszString++ == '') return TRUE;
  719.     return FALSE;
  720. }
  721. BOOL ViewIDFromViewMode(UINT uViewMode, SHELLVIEWID *pvid)
  722. {
  723.     switch (uViewMode)
  724.     {
  725.     case FVM_ICON:
  726.         *pvid = VID_LargeIcons;
  727.         break;
  728.     case FVM_SMALLICON:
  729.         *pvid = VID_SmallIcons;
  730.         break;
  731.     case FVM_LIST:
  732.         *pvid = VID_List;
  733.         break;
  734.     case FVM_DETAILS:
  735.         *pvid = VID_Details;
  736.         break;
  737.     default:
  738.         *pvid = VID_LargeIcons;
  739.         return(FALSE);
  740.     }
  741.     return(TRUE);
  742. }
  743. HIMAGELIST g_himlSysSmall = NULL;
  744. HIMAGELIST g_himlSysLarge = NULL;
  745. void _InitSysImageLists()
  746. {
  747.     if (!g_himlSysSmall)
  748.     {
  749.         Shell_GetImageLists(&g_himlSysLarge, &g_himlSysSmall);
  750.         ImageList_GetIconSize(g_himlSysLarge, &g_cxIcon, &g_cyIcon);
  751.         ImageList_GetIconSize(g_himlSysSmall, &g_cxSmIcon, &g_cySmIcon);
  752.     }
  753. }
  754. #define     SZAPPNAME   TEXT("Explorer")
  755. #define     SZDEFAULT   TEXT(".Default")
  756. void IEPlaySound(LPCTSTR pszSound, BOOL fSysSound)
  757. {
  758. #if !defined(UNIX)
  759.     TCHAR szKey[256];
  760.     // check the registry first
  761.     // if there's nothing registered, we blow off the play,
  762.     // but we don't set the MM_DONTLOAD flag so that if they register
  763.     // something we will play it
  764.     wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("AppEvents\Schemes\Apps\%s\%s\.current"),
  765.         (fSysSound ? SZDEFAULT : SZAPPNAME), pszSound);
  766.     TCHAR szFileName[MAX_PATH];
  767.     szFileName[0] = 0;
  768.     LONG cbSize = SIZEOF(szFileName);
  769.     // note the test for an empty string, PlaySound will play the Default Sound if we
  770.     // give it a sound it cannot find...
  771.     if ((RegQueryValue(HKEY_CURRENT_USER, szKey, szFileName, &cbSize) == ERROR_SUCCESS)
  772.         && cbSize && szFileName[0] != 0)
  773.     {
  774.         //
  775.         // Unlike SHPlaySound in shell32.dll, we get the registry value
  776.         // above and pass it to PlaySound with SND_FILENAME instead of
  777.         // SDN_APPLICATION, so that we play sound even if the application
  778.         // is not Explroer.exe (such as IExplore.exe or WebBrowserOC).
  779.         //
  780.         PlaySoundWrapW(szFileName, NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
  781.     }
  782. #endif //!UNIX
  783. }
  784. #ifndef POSTPOSTSPLIT
  785. void* DataObj_GetDataOfType(IDataObject* pdtobj, UINT cfType, STGMEDIUM *pstg)
  786. {
  787.     void * pret = NULL;
  788.     FORMATETC fmte = {cfType, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  789.     if (pdtobj->GetData(&fmte, pstg) == S_OK) {
  790.         pret = GlobalLock(pstg->hGlobal);
  791.         if (!pret)
  792.             ReleaseStgMedium(pstg);
  793.     }
  794.     return pret;
  795. }
  796. void ReleaseStgMediumHGLOBAL(STGMEDIUM *pstg)
  797. {
  798.     ASSERT(pstg->tymed == TYMED_HGLOBAL);
  799.     GlobalUnlock(pstg->hGlobal);
  800.     ReleaseStgMedium(pstg);
  801. }
  802. #endif
  803. #ifndef POSTPOSTSPLIT
  804. // Copied from shell32 (was _ILCreate), which does not export this.
  805. // The fsmenu code needs this function.
  806. STDAPI_(LPITEMIDLIST) IEILCreate(UINT cbSize)
  807. {
  808.     LPITEMIDLIST pidl = (LPITEMIDLIST)SHAlloc(cbSize);
  809.     if (pidl)
  810.         memset(pidl, 0, cbSize);      // needed for external task allicator
  811.     return pidl;
  812. }
  813. #endif
  814. DWORD CommonDragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt)
  815. {
  816.     DWORD dwEffect = DROPEFFECT_NONE;
  817.     FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  818.     if (pdtobj->QueryGetData(&fmte) == S_OK)
  819.         dwEffect = DROPEFFECT_COPY | DROPEFFECT_LINK;
  820.     else
  821.     {
  822.         InitClipboardFormats();
  823.         fmte.cfFormat = g_cfHIDA;
  824.         if (pdtobj->QueryGetData(&fmte) == S_OK)
  825.             dwEffect = DROPEFFECT_LINK;
  826.         else {
  827.             fmte.cfFormat = g_cfURL;
  828.             if (pdtobj->QueryGetData(&fmte) == S_OK)
  829.                 dwEffect = DROPEFFECT_LINK | DROPEFFECT_COPY | DROPEFFECT_MOVE;
  830.         }
  831.     }
  832.     return dwEffect;
  833. }
  834. // MapNbspToSp
  835. //
  836. // Purpose:
  837. //     Unicode character code point 0x00a0 is designated to HTML
  838. //     entity &nbsp, but some windows code pages don't have code
  839. //     point that can map from 0x00a0. In the most occasion in the
  840. //     shell, NBSP is just a space when it's rendered so we can
  841. //     replace it with 0x0020 safely.
  842. //     This function takes lpwszIn as a string that has
  843. //     non-displayable characters in it, and tries to translate
  844. //     it again after removing NBSP (00a0) from it.
  845. //     returns S_OK if this re-translation is successful.
  846. //
  847. #define nbsp 0x00a0
  848. HRESULT SHMapNbspToSp(LPCWSTR lpwszIn, LPSTR lpszOut, int cbszOut)
  849. {
  850.     BOOL fFoundNbsp = FALSE;
  851.     BOOL fNotDisplayable = TRUE; // assumes FAIL
  852.     LPWSTR pwsz, p;
  853.     if (!lpwszIn || !lpszOut || cbszOut == 0)
  854.         return E_FAIL;
  855.     ASSERT(IS_VALID_STRING_PTRW(lpwszIn, -1));
  856.     ASSERT(IS_VALID_WRITE_BUFFER(lpszOut, TCHAR, cbszOut));
  857.     int cch = lstrlenW(lpwszIn) + 1;
  858.     pwsz = (LPWSTR)LocalAlloc(LPTR, cch * sizeof(WCHAR));
  859.     if (pwsz)
  860.     {
  861.         StrCpyNW(pwsz, lpwszIn, cch);
  862.         p = pwsz;
  863.         while (*p)
  864.         {
  865.             if (*p== nbsp)
  866.             {
  867.                 *p= 0x0020; // replace with space
  868.                 if (!fFoundNbsp)
  869.                     fFoundNbsp = TRUE;
  870.             }
  871.             p++;
  872.         }
  873.         // don't call WC2MB unless we found Nbsp - for perf reason
  874.         if (fFoundNbsp)
  875.         {
  876.             int iret = WideCharToMultiByte(CP_ACP, 0, pwsz, -1, lpszOut,
  877.                                            cbszOut, NULL, &fNotDisplayable);
  878.             if (!fNotDisplayable && iret == 0)
  879.             {
  880.                 // truncated. make it dbcs safe.
  881.                 SHTruncateString(lpszOut, cbszOut);
  882.             }
  883.         }
  884.         LocalFree((LOCALHANDLE)pwsz);
  885.     }
  886.     return (fFoundNbsp && !fNotDisplayable) ? S_OK : S_FALSE;
  887. }
  888. #undef nbsp
  889. int PropBag_ReadInt4(IPropertyBag* pPropBag, LPWSTR pszKey, int iDefault)
  890. {
  891.     VARIANT var = {VT_I4};      // VT_I4 (not 0) so get coercion
  892.     HRESULT hres = pPropBag->Read(pszKey, &var, NULL);
  893.     if (hres==S_OK) {
  894.         if (var.vt==VT_I4) {
  895.             iDefault = var.lVal;
  896.         }
  897.         else {
  898.             VariantClear(&var);
  899.         }
  900.     }
  901.     return iDefault;
  902. }
  903. HRESULT _SetPreferedDropEffect(IDataObject *pdtobj, DWORD dwEffect)
  904. {
  905.     InitClipboardFormats();
  906.     HRESULT hres = E_OUTOFMEMORY;
  907.     DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
  908.     if (pdw)
  909.     {
  910.         STGMEDIUM medium;
  911.         FORMATETC fmte = {g_cfPreferedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  912.         *pdw = dwEffect;
  913.         medium.tymed = TYMED_HGLOBAL;
  914.         medium.hGlobal = pdw;
  915.         medium.pUnkForRelease = NULL;
  916.         hres = pdtobj->SetData(&fmte, &medium, TRUE);
  917.         if (FAILED(hres))
  918.             GlobalFree((HGLOBAL)pdw);
  919.     }
  920.     return hres;
  921. }
  922. #ifndef POSTPOSTSPLIT
  923. HRESULT DragDrop(HWND hwnd, IShellFolder * psfParent, LPCITEMIDLIST pidl, DWORD dwPrefEffect, DWORD *pdwEffect)
  924. {
  925.     HRESULT hres = E_FAIL;
  926.     LPCITEMIDLIST pidlChild;
  927.     if (!psfParent)
  928.         IEBindToParentFolder(pidl, &psfParent, &pidlChild);
  929.     else 
  930.     {
  931.         pidlChild = pidl;
  932.         psfParent->AddRef();
  933.     }
  934.     if (psfParent)
  935.     {
  936.         DWORD dwAttrib = DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK;
  937.         psfParent->GetAttributesOf(1, &pidlChild, &dwAttrib);
  938.         IDataObject *pdtobj;
  939.         hres = psfParent->GetUIObjectOf(NULL, 1, &pidlChild, IID_IDataObject, NULL, (void**)&pdtobj);
  940.         if (SUCCEEDED(hres))
  941.         {
  942.             DWORD dwEffect = (DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK) & dwAttrib;
  943.             if (dwPrefEffect)
  944.             {
  945.                 //win95 shell32 doesn't know about prefered drop effect, so make it the only effect
  946.                 if (IsOS(OS_WIN95) && (WhichPlatform() == PLATFORM_BROWSERONLY))
  947.                 {
  948.                     dwEffect = DROPEFFECT_LINK & dwAttrib;
  949.                 }
  950.                 else if (dwPrefEffect & dwEffect)
  951.                 {
  952.                     _SetPreferedDropEffect(pdtobj, dwPrefEffect);
  953.                 }
  954.             }
  955.             ASSERT(dwEffect);
  956.             // Win95 Browser Only - the shell32 in this process doesn't know
  957.             // ole is loaded, even though it is.
  958.             SHLoadOLE(SHELLNOTIFY_OLELOADED);
  959.             IDragSourceHelper* pDragImages;
  960.             if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, IID_IDragSourceHelper, (void**)&pDragImages)))
  961.             {
  962.                 pDragImages->InitializeFromWindow(hwnd, 0, pdtobj);
  963.                 pDragImages->Release();
  964.             }
  965.             hres = SHDoDragDrop(hwnd, pdtobj, NULL, dwEffect, &dwEffect);
  966.             if (pdwEffect)
  967.                 *pdwEffect = dwEffect;
  968.             pdtobj->Release();
  969.         }
  970.         psfParent->Release();
  971.     }
  972.     return hres;
  973. }
  974. #endif
  975. #define IEICONTYPE_GETFILEINFO              0x00000001
  976. #define IEICONTYPE_DEFAULTICON              0x00000002
  977. typedef struct tagIEICONS
  978. {
  979.     int nDefaultIcon;
  980.     int nIEIcon;
  981.     LPCTSTR szFile;
  982.     LPCTSTR szFileExt;
  983.     int nIconResourceNum;
  984.     LPCTSTR szCLSID;
  985.     DWORD dwType;
  986. } IEICONS;
  987. IEICONS g_IEIcons[] = {
  988.     {-1, -1, TEXT("MSHTML.DLL"), TEXT(".htm"), 1, NULL, IEICONTYPE_GETFILEINFO},
  989.     {-1, -1, TEXT("URL.DLL"), TEXT("http\DefaultIcon"), 0, TEXT("{FBF23B42-E3F0-101B-8488-00AA003E56F8}"), IEICONTYPE_DEFAULTICON}
  990. };
  991. //This function returns the IE icon regardless of the which browser is  default
  992. void _GenerateIEIcons(void)
  993. {
  994.     int nIndex;
  995.     for (nIndex = 0; nIndex < ARRAYSIZE(g_IEIcons); nIndex++)
  996.     {
  997.         SHFILEINFO sfi;
  998.         TCHAR szModule[MAX_PATH];
  999.         HMODULE hmod = GetModuleHandle(g_IEIcons[nIndex].szFile);
  1000.         if (hmod)
  1001.         {
  1002.             GetModuleFileName(hmod, szModule, ARRAYSIZE(szModule));
  1003.         }
  1004.         else
  1005.         {   //HACKHACK : This is a hack to get the mstml
  1006.             TCHAR   szKey[GUIDSTR_MAX * 4];
  1007.             TCHAR   szGuid[GUIDSTR_MAX];
  1008.             //The CLSID used here belongs to MS HTML Generic Page. If someone changes the guid then we
  1009.             // are  tossed.
  1010.             if (!g_IEIcons[nIndex].szCLSID)
  1011.                 SHStringFromGUID(CLSID_HTMLDocument, szGuid, GUIDSTR_MAX);
  1012.             wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("CLSID\%s\InProcServer32"), g_IEIcons[nIndex].szCLSID ? g_IEIcons[nIndex].szCLSID : szGuid);
  1013.             long cb = SIZEOF(szModule);
  1014.             RegQueryValue(HKEY_CLASSES_ROOT, szKey, szModule, &cb);
  1015.         }
  1016.         g_IEIcons[nIndex].nIEIcon = Shell_GetCachedImageIndex(szModule, g_IEIcons[nIndex].nIconResourceNum, 0);
  1017.         switch(g_IEIcons[nIndex].dwType)
  1018.         {
  1019.         case IEICONTYPE_GETFILEINFO:
  1020.             sfi.iIcon = 0;
  1021.             StrCpyN(szModule, TEXT("c:\notexist"), ARRAYSIZE(szModule));
  1022.             StrCatBuff(szModule, g_IEIcons[nIndex].szFileExt, ARRAYSIZE(szModule));
  1023.             SHGetFileInfo(szModule, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);
  1024.             g_IEIcons[nIndex].nDefaultIcon = sfi.iIcon;
  1025.             break;
  1026.         case IEICONTYPE_DEFAULTICON:
  1027.             {
  1028.                 TCHAR szPath[MAX_PATH];
  1029.                 DWORD cbSize = SIZEOF(szPath);
  1030.                 SHGetValue(HKEY_CLASSES_ROOT, g_IEIcons[nIndex].szFileExt, TEXT(""), NULL, szPath, &cbSize);
  1031.                 g_IEIcons[nIndex].nDefaultIcon = Shell_GetCachedImageIndex(szPath, PathParseIconLocation(szPath), 0);
  1032.             }
  1033.             break;
  1034.         }
  1035.     }
  1036. }
  1037. int IEMapPIDLToSystemImageListIndex(IShellFolder *psfParent, LPCITEMIDLIST pidlChild, int *piSelectedImage)
  1038. {
  1039.     int nIndex;
  1040.     int nIcon = SHMapPIDLToSystemImageListIndex(psfParent, pidlChild, piSelectedImage);
  1041.     if (-1 == g_IEIcons[0].nDefaultIcon)
  1042.         _GenerateIEIcons();
  1043.     for (nIndex = 0; nIndex < ARRAYSIZE(g_IEIcons); nIndex++)
  1044.     {
  1045.         if((nIcon == g_IEIcons[nIndex].nDefaultIcon) ||
  1046.             (piSelectedImage && *piSelectedImage == g_IEIcons[nIndex].nDefaultIcon))
  1047.         {
  1048.             nIcon = g_IEIcons[nIndex].nIEIcon;
  1049.             if (piSelectedImage)
  1050.                 *piSelectedImage = nIcon;
  1051.             break;
  1052.         }
  1053.     }
  1054.     return nIcon;
  1055. }
  1056. void IEInvalidateImageList(void)
  1057. {
  1058.     g_IEIcons[0].nDefaultIcon = -1;
  1059. }
  1060. int _GetIEHTMLImageIndex()
  1061. {
  1062.     if (-1 == g_IEIcons[0].nDefaultIcon)
  1063.         _GenerateIEIcons();
  1064.     return g_IEIcons[0].nIEIcon;
  1065. }
  1066. // Checks to see if any process at all
  1067. // has loaded wininet
  1068. static BOOL g_fWininetLoadedSomeplace = FALSE;
  1069. BOOL IsWininetLoadedAnywhere()
  1070. {
  1071.     HANDLE hMutex = NULL;
  1072.     BOOL fRet;
  1073.     if(g_fWininetLoadedSomeplace)
  1074.         return TRUE;
  1075.     //
  1076.     // Use OpenMutexA so it works on W95.
  1077.     // wininet is ansi and created this mutex with CreateMutexA
  1078.     hMutex = OpenMutexA(SYNCHRONIZE, FALSE, WININET_STARTUP_MUTEX);
  1079.     if(hMutex)
  1080.     {
  1081.         fRet = TRUE;
  1082.         g_fWininetLoadedSomeplace = TRUE;
  1083.         CloseHandle(hMutex);
  1084.     }
  1085.     else
  1086.     {
  1087.         fRet = FALSE;
  1088.     }
  1089.     return fRet;
  1090. }
  1091. //   Checks if global state is offline
  1092. BOOL SHIsGlobalOffline(void)
  1093. {
  1094.     DWORD   dwState = 0, dwSize = sizeof(DWORD);
  1095.     BOOL    fRet = FALSE;
  1096.     if(!IsWininetLoadedAnywhere())
  1097.         return FALSE;
  1098.     // Since wininet is already loaded someplace
  1099.     // We have to load wininet to check if offline
  1100.     if(InternetQueryOptionA(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState,
  1101.         &dwSize))
  1102.     {
  1103.         if(dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
  1104.             fRet = TRUE;
  1105.     }
  1106.     return fRet;
  1107. }
  1108. void SetGlobalOffline(BOOL fOffline)
  1109. {
  1110.     INTERNET_CONNECTED_INFO ci;
  1111.     memset(&ci, 0, sizeof(ci));
  1112.     if(fOffline) {
  1113.         ci.dwConnectedState = INTERNET_STATE_DISCONNECTED_BY_USER;
  1114.         ci.dwFlags = ISO_FORCE_DISCONNECTED;
  1115.     } else {
  1116.         ci.dwConnectedState = INTERNET_STATE_CONNECTED;
  1117.     }
  1118.     InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
  1119. }
  1120. // This API is documented and is called by apps outside
  1121. // the shell such as OE
  1122. #ifdef UNIX
  1123. extern "C"
  1124. #endif
  1125. void SetShellOfflineState(BOOL fPutOffline)
  1126. {
  1127.     BOOL fWasOffline = SHIsGlobalOffline();
  1128.     if(fWasOffline != fPutOffline)
  1129.     {   
  1130.         SetGlobalOffline(fPutOffline); // Set the state
  1131.         // Tell all browser windows to update their title   
  1132.         SendShellIEBroadcastMessage(WM_WININICHANGE,0,0, 1000); 
  1133.     }
  1134. }
  1135. BOOL GetHistoryFolderPath(LPTSTR pszPath, int cchPath)
  1136. {
  1137.     INTERNET_CACHE_CONFIG_INFO cci;
  1138.     DWORD cbcci = sizeof(INTERNET_CACHE_CONFIG_INFO);
  1139.     if (GetUrlCacheConfigInfo(&cci, &cbcci, CACHE_CONFIG_HISTORY_PATHS_FC))
  1140.     {
  1141.         StrCpyN(pszPath, cci.CachePaths[0].CachePath, cchPath);
  1142.         return TRUE;
  1143.     }
  1144.     return FALSE;
  1145. }
  1146. #ifndef POSTPOSTSPLIT
  1147. // in:
  1148. //      pidlRoot    root part of pidl.
  1149. //      pidl        equal to or child below pidlRoot
  1150. //      pszKey      root key to store stuff under, should match pidlRoot
  1151. //      grfMode     read/write
  1152. //
  1153. // example:
  1154. //      pidlRoot = c:winfavorites
  1155. //      pidl     = c:winfavoriteschannels
  1156. //      pszKey   = "MenuOrderFavorites"
  1157. //      result -> stream comes from HKCU...MenuOrderFavoriteschannels
  1158. //
  1159. IStream * OpenPidlOrderStream(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST pidl, LPCSTR pszKey, DWORD grfMode)
  1160. {
  1161.     LPITEMIDLIST pidlAlloc = NULL;
  1162.     TCHAR   szRegPath[MAX_URL_STRING];
  1163.     TCHAR szKey[MAXIMUM_SUB_KEY_LENGTH];
  1164.     SHAnsiToTChar(pszKey, szKey, ARRAYSIZE(szKey));
  1165.     StrCpyN(szRegPath, TEXT("Software\Microsoft\Windows\CurrentVersion\Explorer"), ARRAYSIZE(szRegPath));
  1166.     StrCatBuff(szRegPath, szKey, ARRAYSIZE(szRegPath));
  1167.     // deal with ordinal vs true pidls
  1168.     if (HIWORD(pidlRoot) == 0)
  1169.     {
  1170.         // Sundown: coercion to int since we are assuming ordinal pidl
  1171.         SHGetSpecialFolderLocation(NULL, PtrToLong(pidlRoot), &pidlAlloc);
  1172.         pidlRoot = pidlAlloc;
  1173.     }
  1174.     // build a reg key from the names of the items below the pidlRoot folder. we do
  1175.     // this because IEGetDisplayName(SFGAO_FORPARSING) has a bug for file system
  1176.     // junctions (channel contents) that returns garbage path names.
  1177.     if (pidlRoot)
  1178.     {
  1179.         LPITEMIDLIST pidlCopy = ILClone(pidl);
  1180.         if (pidlCopy)
  1181.         {
  1182.             LPCITEMIDLIST pidlTail = ILFindChild(pidlRoot, pidlCopy);
  1183.             if (pidlTail)
  1184.             {
  1185.                 LPITEMIDLIST pidlNext;
  1186.                 for (pidlNext = ILGetNext(pidlTail); pidlNext; pidlNext = ILGetNext(pidlNext))
  1187.                 {
  1188.                     WORD cbSave = pidlNext->mkid.cb;
  1189.                     pidlNext->mkid.cb = 0;
  1190.                     IShellFolder *psf;
  1191.                     LPCITEMIDLIST pidlChild;
  1192.                     // we do a full bind every time, we could skip this for sub items
  1193.                     // and bind from this point down but this code is simpler and binds
  1194.                     // aren't that bad...
  1195.                     if (SUCCEEDED(IEBindToParentFolder(pidlCopy, &psf, &pidlChild)))
  1196.                     {
  1197.                         STRRET sr;
  1198.                         if (SUCCEEDED(psf->GetDisplayNameOf(pidlChild, SHGDN_NORMAL, &sr)))
  1199.                         {
  1200.                             LPTSTR pszName;
  1201.                             if (SUCCEEDED(StrRetToStr(&sr, pidlChild, &pszName)))
  1202.                             {
  1203.                                 StrCatBuff(szRegPath, TEXT("\"), ARRAYSIZE(szRegPath));
  1204.                                 StrCatBuff(szRegPath, pszName, ARRAYSIZE(szRegPath));
  1205.                                 CoTaskMemFree(pszName);
  1206.                             }
  1207.                         }
  1208.                         psf->Release();
  1209.                     }
  1210.                     pidlNext->mkid.cb = cbSave;
  1211.                 }
  1212.             }
  1213.             ILFree(pidlCopy);
  1214.         }
  1215.         if (pidlAlloc)
  1216.             ILFree(pidlAlloc);
  1217.         return SHOpenRegStream(HKEY_CURRENT_USER, szRegPath, TEXT("Order"), grfMode);
  1218.     }
  1219.     return NULL;
  1220. }
  1221. #endif
  1222. HRESULT GetHTMLElementID(IHTMLElement *pielem, LPTSTR pszName, DWORD cchSize)
  1223. {
  1224.     // only do this persistence thing if we're in ( or completing ) an operation
  1225.     BSTR bstrID = NULL;
  1226.     HRESULT hr;
  1227.     if (!pielem)
  1228.         hr = E_INVALIDARG;
  1229.     else if (SUCCEEDED(hr = pielem->get_id(&bstrID)))
  1230.     {
  1231.         SHUnicodeToTChar(bstrID, pszName, cchSize);
  1232.         SysFreeString(bstrID);
  1233.     }
  1234.     return hr;
  1235. }
  1236. /**********************************************************************
  1237. * SHRestricted2
  1238. *
  1239. * These are new restrictions that apply to browser only and integrated
  1240. * mode.  (Since we're not changing shell32 in browser only mode, we
  1241. * need to duplicate the functionality.)
  1242. *
  1243. * BUGBUG: What window will listen to the WM_WININICHANGE
  1244. *           lParam="Policy" message and invalidate the cache?
  1245. *           Remember not to cache the per zone values.
  1246. **********************************************************************/
  1247. // The ZAW compliant policy location.
  1248. const TCHAR c_szInfodeliveryBase[] = TEXT("Software\Policies\Microsoft\Internet Explorer\Infodelivery");
  1249. const TCHAR c_szInfodeliveryKey[] = TEXT("Restrictions");
  1250. // The normal policy location.
  1251. const TCHAR c_szExplorerBase[] = TEXT("Software\Microsoft\Windows\CurrentVersion\Policies");
  1252. const TCHAR c_szExplorerKey[] = TEXT("Explorer");
  1253. // The browser policy location that SP2 used
  1254. const TCHAR c_szBrowserBase[] = TEXT("Software\Policies\Microsoft\Internet Explorer");
  1255. const TCHAR c_szBrowserKey[]  = TEXT("Restrictions");
  1256. const TCHAR c_szToolbarKey[]  = TEXT("Toolbars\Restrictions");
  1257. const SHRESTRICTIONITEMS c_rgRestrictionItems[] =
  1258. {
  1259.     // explorer restrictions
  1260.     { REST_NOTOOLBARCUSTOMIZE,      c_szExplorerKey,    TEXT("NoToolbarCustomize") },
  1261.     { REST_NOBANDCUSTOMIZE,         c_szExplorerKey,    TEXT("NoBandCustomize")    },
  1262.     { REST_SMALLICONS,              c_szExplorerKey,    TEXT("SmallIcons")        },
  1263.     { REST_LOCKICONSIZE,            c_szExplorerKey,    TEXT("LockIconSize")      },
  1264.     { REST_SPECIFYDEFAULTBUTTONS,   c_szExplorerKey,    TEXT("SpecifyDefaultButtons") },
  1265.     { REST_BTN_BACK,                c_szExplorerKey,    TEXT("Btn_Back")      },
  1266.     { REST_BTN_FORWARD,             c_szExplorerKey,    TEXT("Btn_Forward")   },
  1267.     { REST_BTN_STOPDOWNLOAD,        c_szExplorerKey,    TEXT("Btn_Stop")      },
  1268.     { REST_BTN_REFRESH,             c_szExplorerKey,    TEXT("Btn_Refresh")    },
  1269.     { REST_BTN_HOME,                c_szExplorerKey,    TEXT("Btn_Home")      },
  1270.     { REST_BTN_SEARCH,              c_szExplorerKey,    TEXT("Btn_Search")    },
  1271.     { REST_BTN_HISTORY,             c_szExplorerKey,    TEXT("Btn_History")   },
  1272.     { REST_BTN_FAVORITES,           c_szExplorerKey,    TEXT("Btn_Favorites") },
  1273.     { REST_BTN_ALLFOLDERS,          c_szExplorerKey,    TEXT("Btn_Folders")       },
  1274.     { REST_BTN_THEATER,             c_szExplorerKey,    TEXT("Btn_Fullscreen") },
  1275.     { REST_BTN_TOOLS,               c_szExplorerKey,    TEXT("Btn_Tools")     },
  1276.     { REST_BTN_MAIL,                c_szExplorerKey,    TEXT("Btn_MailNews")  },
  1277.     { REST_BTN_FONTS,               c_szExplorerKey,    TEXT("Btn_Size")      },
  1278.     { REST_BTN_PRINT,               c_szExplorerKey,    TEXT("Btn_Print")     },
  1279.     { REST_BTN_EDIT,                c_szExplorerKey,    TEXT("Btn_Edit")          },
  1280.     { REST_BTN_DISCUSSIONS,         c_szExplorerKey,    TEXT("Btn_Discussions")   },
  1281.     { REST_BTN_CUT,                 c_szExplorerKey,    TEXT("Btn_Cut")           },
  1282.     { REST_BTN_COPY,                c_szExplorerKey,    TEXT("Btn_Copy")          },
  1283.     { REST_BTN_PASTE,               c_szExplorerKey,    TEXT("Btn_Paste")         },
  1284.     { REST_BTN_ENCODING,            c_szExplorerKey,    TEXT("Btn_Encoding")          },
  1285.     { REST_NoUserAssist,            c_szExplorerKey,    TEXT("NoInstrumentation"),      },
  1286.     { REST_NoWindowsUpdate,         c_szExplorerKey,    TEXT("NoWindowsUpdate"),        },
  1287.     { REST_NoExpandedNewMenu,       c_szExplorerKey,    TEXT("NoExpandedNewMenu"),      },
  1288.     // ported from SP1
  1289.     { REST_NOFILEURL,               c_szExplorerKey,       TEXT("NoFileUrl"),          },
  1290.     // infodelivery restrictions
  1291.     { REST_NoChannelUI,             c_szInfodeliveryKey,   TEXT("NoChannelUI")        },
  1292.     { REST_NoAddingChannels,        c_szInfodeliveryKey,   TEXT("NoAddingChannels") },
  1293.     { REST_NoEditingChannels,       c_szInfodeliveryKey,   TEXT("NoEditingChannels") },
  1294.     { REST_NoRemovingChannels,      c_szInfodeliveryKey,   TEXT("NoRemovingChannels") },
  1295.     { REST_NoAddingSubscriptions,   c_szInfodeliveryKey,   TEXT("NoAddingSubscriptions") },
  1296.     { REST_NoEditingSubscriptions,  c_szInfodeliveryKey,   TEXT("NoEditingSubscriptions") },
  1297.     { REST_NoRemovingSubscriptions, c_szInfodeliveryKey,   TEXT("NoRemovingSubscriptions") },
  1298.     { REST_NoChannelLogging,        c_szInfodeliveryKey,   TEXT("NoChannelLogging")         },
  1299.     { REST_NoManualUpdates,         c_szInfodeliveryKey,   TEXT("NoManualUpdates")        },
  1300.     { REST_NoScheduledUpdates,      c_szInfodeliveryKey,   TEXT("NoScheduledUpdates")     },
  1301.     { REST_NoUnattendedDialing,     c_szInfodeliveryKey,   TEXT("NoUnattendedDialing")    },
  1302.     { REST_NoChannelContent,        c_szInfodeliveryKey,   TEXT("NoChannelContent")       },
  1303.     { REST_NoSubscriptionContent,   c_szInfodeliveryKey,   TEXT("NoSubscriptionContent")  },
  1304.     { REST_NoEditingScheduleGroups, c_szInfodeliveryKey,   TEXT("NoEditingScheduleGroups") },
  1305.     { REST_MaxChannelSize,          c_szInfodeliveryKey,   TEXT("MaxChannelSize")         },
  1306.     { REST_MaxSubscriptionSize,     c_szInfodeliveryKey,   TEXT("MaxSubscriptionSize")    },
  1307.     { REST_MaxChannelCount,         c_szInfodeliveryKey,   TEXT("MaxChannelCount")        },
  1308.     { REST_MaxSubscriptionCount,    c_szInfodeliveryKey,   TEXT("MaxSubscriptionCount")   },
  1309.     { REST_MinUpdateInterval,       c_szInfodeliveryKey,   TEXT("MinUpdateInterval")      },
  1310.     { REST_UpdateExcludeBegin,      c_szInfodeliveryKey,   TEXT("UpdateExcludeBegin")     },
  1311.     { REST_UpdateExcludeEnd,        c_szInfodeliveryKey,   TEXT("UpdateExcludeEnd")       },
  1312.     { REST_UpdateInNewProcess,      c_szInfodeliveryKey,   TEXT("UpdateInNewProcess")     },
  1313.     { REST_MaxWebcrawlLevels,       c_szInfodeliveryKey,   TEXT("MaxWebcrawlLevels")      },
  1314.     { REST_MaxChannelLevels,        c_szInfodeliveryKey,   TEXT("MaxChannelLevels")       },
  1315.     { REST_NoSubscriptionPasswords, c_szInfodeliveryKey,   TEXT("NoSubscriptionPasswords")},
  1316.     { REST_NoBrowserSaveWebComplete,c_szInfodeliveryKey,   TEXT("NoBrowserSaveWebComplete") },
  1317.     { REST_NoSearchCustomization,   c_szInfodeliveryKey,   TEXT("NoSearchCustomization"),  },
  1318.     { REST_NoSplash,                c_szInfodeliveryKey,   TEXT("NoSplash"),  },
  1319.     // browser restrictions ported from SP2
  1320.     { REST_NoFileOpen,              c_szBrowserKey,         TEXT("NoFileOpen"),             },
  1321.     { REST_NoFileNew,               c_szBrowserKey,         TEXT("NoFileNew"),              },
  1322.     { REST_NoBrowserSaveAs ,        c_szBrowserKey,         TEXT("NoBrowserSaveAs"),        },
  1323.     { REST_NoBrowserOptions,        c_szBrowserKey,         TEXT("NoBrowserOptions"),       },
  1324.     { REST_NoFavorites,             c_szBrowserKey,         TEXT("NoFavorites"),            },
  1325.     { REST_NoSelectDownloadDir,     c_szBrowserKey,         TEXT("NoSelectDownloadDir"),    },
  1326.     { REST_NoBrowserContextMenu,    c_szBrowserKey,         TEXT("NoBrowserContextMenu"),   },
  1327.     { REST_NoBrowserClose,          c_szBrowserKey,         TEXT("NoBrowserClose"),         },
  1328.     { REST_NoOpeninNewWnd,          c_szBrowserKey,         TEXT("NoOpeninNewWnd"),         },
  1329.     { REST_NoTheaterMode,           c_szBrowserKey,         TEXT("NoTheaterMode"),          },
  1330.     { REST_NoFindFiles,             c_szBrowserKey,         TEXT("NoFindFiles"),            },
  1331.     { REST_NoViewSource,            c_szBrowserKey,         TEXT("NoViewSource"),           },
  1332.     { REST_GoMenu,                  c_szBrowserKey,         TEXT("RestGoMenu"),             },
  1333.     { REST_NoToolbarOptions,        c_szToolbarKey,         TEXT("NoToolbarOptions"),       },
  1334.     { REST_AlwaysPromptWhenDownload,c_szBrowserKey,         TEXT("AlwaysPromptWhenDownload"),},
  1335.     { REST_NoHelpItem_TipOfTheDay,  c_szBrowserKey,         TEXT("NoHelpItemTipOfTheDay"),  },
  1336.     { REST_NoHelpItem_NetscapeHelp, c_szBrowserKey,         TEXT("NoHelpItemNetscapeHelp"), },
  1337.     { REST_NoHelpItem_Tutorial,     c_szBrowserKey,         TEXT("NoHelpItemTutorial"),     },
  1338.     { REST_NoHelpItem_SendFeedback, c_szBrowserKey,         TEXT("NoHelpItemSendFeedback"), },
  1339.     { REST_NoNavButtons,            c_szBrowserKey,         TEXT("NoNavButtons"),           },
  1340.     { REST_NoHelpMenu,              c_szBrowserKey,         TEXT("NoHelpMenu"),             },
  1341.     { REST_NoBrowserBars,           c_szBrowserKey,         TEXT("NoBrowserBars"),          },
  1342.     { REST_NoToolBar,               c_szToolbarKey,         TEXT("NoToolBar"),              },
  1343.     { REST_NoAddressBar,            c_szToolbarKey,         TEXT("NoAddressBar"),           },
  1344.     { REST_NoLinksBar,              c_szToolbarKey,         TEXT("NoLinksBar"),             },
  1345.     
  1346.     {0, NULL, NULL},
  1347. };
  1348. typedef struct {
  1349.     BROWSER_RESTRICTIONS rest;
  1350.     DWORD dwAction;    
  1351. } ACTIONITEM;
  1352. const ACTIONITEM c_ActionItems[] = {
  1353.     { REST_NoAddingChannels,        URLACTION_INFODELIVERY_NO_ADDING_CHANNELS },
  1354.     { REST_NoEditingChannels,       URLACTION_INFODELIVERY_NO_EDITING_CHANNELS },
  1355.     { REST_NoRemovingChannels,      URLACTION_INFODELIVERY_NO_REMOVING_CHANNELS },
  1356.     { REST_NoAddingSubscriptions,   URLACTION_INFODELIVERY_NO_ADDING_SUBSCRIPTIONS },
  1357.     { REST_NoEditingSubscriptions,  URLACTION_INFODELIVERY_NO_EDITING_SUBSCRIPTIONS },
  1358.     { REST_NoRemovingSubscriptions, URLACTION_INFODELIVERY_NO_REMOVING_SUBSCRIPTIONS },
  1359.     { REST_NoChannelLogging,        URLACTION_INFODELIVERY_NO_CHANNEL_LOGGING },
  1360. };
  1361. #define REST_WITHACTION_FIRST   REST_NoAddingChannels
  1362. #define REST_WITHACTION_LAST    REST_NoChannelLogging
  1363. #define RESTRICTIONMAX (c_rgRestrictionItems[ARRAYSIZE(c_rgRestrictionItems) - 1].rest)
  1364. DWORD g_rgRestrictionItemValues[ARRAYSIZE(c_rgRestrictionItems)];
  1365. DWORD SHRestricted2W(BROWSER_RESTRICTIONS rest, LPCWSTR pwzUrl, DWORD dwReserved)
  1366. {
  1367.     // Validate restriction and dwReserved
  1368.     if (dwReserved)
  1369.     {
  1370.         RIPMSG(0, "SHRestricted2W: Invalid dwReserved");
  1371.         return 0;
  1372.     }
  1373.     if (!(InRange(rest, REST_EXPLORER_FIRST, REST_EXPLORER_LAST))
  1374.         && !(InRange(rest, REST_INFO_FIRST, REST_INFO_LAST))
  1375.         && !(InRange(rest, REST_BROWSER_FIRST, REST_BROWSER_LAST)))
  1376.     {
  1377.         RIPMSG(0, "SHRestricted2W: Invalid browser restriction");
  1378.         return 0;
  1379.     }
  1380.     // See if the restriction is in place in the URL zone
  1381.     // BUGBUG: Should we assert on NULL URLs if the restriction is per zone?
  1382.     // It might be reasonable to query the global setting.
  1383.     if (pwzUrl && InRange(rest, REST_WITHACTION_FIRST, REST_WITHACTION_LAST))
  1384.     {
  1385.         // Compute the index into the table
  1386.         int index = rest - REST_WITHACTION_FIRST;
  1387.         ASSERT(c_ActionItems[index].dwAction);
  1388.         IInternetSecurityManager *pism = NULL;
  1389.         HRESULT hr;
  1390.         hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
  1391.                               IID_IInternetSecurityManager, (void**)&pism);
  1392.         if (SUCCEEDED(hr) && pism)
  1393.         {
  1394.             DWORD dwPolicy = 0;
  1395.             DWORD dwContext = 0;
  1396.             hr = pism->ProcessUrlAction(pwzUrl,
  1397.                                         c_ActionItems[index].dwAction,
  1398.                                         (BYTE *)&dwPolicy,
  1399.                                         sizeof(dwPolicy),
  1400.                                         (BYTE *)&dwContext,
  1401.                                         sizeof(dwContext),
  1402.                                         PUAF_NOUI,
  1403.                                         0);
  1404.             pism->Release();
  1405.             if (SUCCEEDED(hr))
  1406.             {
  1407.                 if (GetUrlPolicyPermissions(dwPolicy) == URLPOLICY_ALLOW)
  1408.                     return 0;
  1409.                 else
  1410.                     return 1;    // restrict for query and disallow
  1411.             }
  1412.         }
  1413.     }
  1414.     // The cache may be invalid. Check first! We have to use
  1415.     // a global named semaphore in case this function is called
  1416.     // from a process other than the shell process. (And we're
  1417.     // sharing the same count between shell32 and shdocvw.)
  1418.     static HANDLE hRestrictions = NULL;
  1419.     static long lRestrictionCount = -1;
  1420.     if (hRestrictions == NULL)
  1421.         hRestrictions = SHGlobalCounterCreate(GUID_Restrictions);
  1422.     long lGlobalCount = SHGlobalCounterGetValue(hRestrictions);
  1423.     if (lGlobalCount != lRestrictionCount)
  1424.     {
  1425.         memset((LPBYTE)g_rgRestrictionItemValues, (BYTE)-1, SIZEOF(g_rgRestrictionItemValues));
  1426.         lRestrictionCount = lGlobalCount;
  1427.     }
  1428.     LPCWSTR pszBaseKey;
  1429.     if (InRange(rest, REST_EXPLORER_FIRST, REST_EXPLORER_LAST))
  1430.         pszBaseKey = c_szExplorerBase;
  1431.     else
  1432.     {
  1433.         if (InRange(rest, REST_BROWSER_FIRST, REST_BROWSER_LAST))
  1434.             pszBaseKey = c_szBrowserBase;
  1435.         else 
  1436.             pszBaseKey = c_szInfodeliveryBase;
  1437.     }
  1438.     return SHRestrictionLookup(rest, pszBaseKey, c_rgRestrictionItems, g_rgRestrictionItemValues);
  1439. }
  1440. DWORD SHRestricted2A(BROWSER_RESTRICTIONS rest, LPCSTR pszUrl, DWORD dwReserved)
  1441. {
  1442.     if (pszUrl)
  1443.     {
  1444.         WCHAR wzUrl[MAX_URL_STRING];
  1445.         ASSERT(ARRAYSIZE(wzUrl) > lstrlenA(pszUrl));        // We only work for Urls of MAX_URL_STRING or shorter.
  1446.         AnsiToUnicode(pszUrl, wzUrl, ARRAYSIZE(wzUrl));
  1447.         return SHRestricted2W(rest, wzUrl, dwReserved);
  1448.     }
  1449.     else
  1450.     {
  1451.         return SHRestricted2W(rest, NULL, dwReserved);
  1452.     }
  1453. }
  1454. /**********************************************************************
  1455. *
  1456. **********************************************************************/
  1457. #define MAX_SUBSTR_SIZE     100
  1458. typedef struct tagURLSub
  1459. {
  1460.     LPCTSTR szTag;
  1461.     DWORD dwType;
  1462. } URLSUB;
  1463. const static URLSUB c_UrlSub[] = {
  1464.     {TEXT("{SUB_CLSID}"), URLSUB_CLSID},
  1465.     {TEXT("{SUB_PRD}"), URLSUB_PRD},
  1466.     {TEXT("{SUB_PVER}"), URLSUB_PVER},
  1467.     {TEXT("{SUB_OS}"), URLSUB_OS},
  1468.     {TEXT("{SUB_RFC1766}"), URLSUB_RFC1766}
  1469. };
  1470. void GetWebLocaleAsRFC1766(LPTSTR pszLocale, int cchLocale)
  1471. {
  1472.     LCID lcid;
  1473.     TCHAR szValue[MAX_PATH];
  1474.     DWORD cbVal = sizeof(szValue);
  1475.     DWORD dwType;
  1476.     ASSERT(NULL != pszLocale);
  1477.     *pszLocale = TEXT('');
  1478.     
  1479.     if ((SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_INTERNATIONAL,
  1480.                     REGSTR_VAL_ACCEPT_LANGUAGE, 
  1481.                     &dwType, szValue, &cbVal) == ERROR_SUCCESS) &&
  1482.         (REG_SZ == dwType))
  1483.     {
  1484.         TCHAR *psz = szValue;
  1485.         //  Use the first one we find so terminate at the comma or semicolon
  1486.         while (*psz && (*psz != TEXT(',')) && (*psz != TEXT(';')))
  1487.         {
  1488.             psz = CharNext(psz);
  1489.         }
  1490.         *psz = TEXT('');
  1491.         //  If it's user defined, this will fail and we will fall back
  1492.         //  to the system default.
  1493.         if (SUCCEEDED(Rfc1766ToLcid(&lcid, szValue)))
  1494.         {
  1495.             StrCpyN(pszLocale, szValue, cchLocale);
  1496.         }
  1497.     }
  1498.     if (TEXT('') == *pszLocale)
  1499.     {
  1500.         //  No entry in the registry or it's a user defined header.
  1501.         //  Either way we fall back to the system default.
  1502.         LcidToRfc1766(GetUserDefaultLCID(), pszLocale, cchLocale);
  1503.     }
  1504. }
  1505. HRESULT URLSubstitution(LPCWSTR pszUrlIn, LPWSTR pszUrlOut, DWORD cchSize, DWORD dwSubstitutions)
  1506. {
  1507.     HRESULT hr = S_OK;
  1508.     DWORD dwIndex;
  1509.     WCHAR szTempUrl[MAX_URL_STRING];
  1510.     ASSERT(cchSize <= ARRAYSIZE(szTempUrl));    // We will truncate anything longer than MAX_URL_STRING
  1511.     StrCpyNW(szTempUrl, pszUrlIn, ARRAYSIZE(szTempUrl));
  1512.     for (dwIndex = 0; dwIndex < ARRAYSIZE(c_UrlSub); dwIndex++)
  1513.     {
  1514.         while (IsFlagSet(dwSubstitutions, c_UrlSub[dwIndex].dwType))
  1515.         {
  1516.             LPWSTR pszTag = StrStr(szTempUrl, c_UrlSub[dwIndex].szTag);
  1517.             if (pszTag)
  1518.             {
  1519.                 TCHAR szCopyUrl[MAX_URL_STRING];
  1520.                 TCHAR szSubStr[MAX_SUBSTR_SIZE];  // The Substitution
  1521.                 // Copy URL Before Substitution.
  1522.                 StrCpyN(szCopyUrl, szTempUrl, (int)(pszTag-szTempUrl+1));
  1523.                 pszTag += lstrlen(c_UrlSub[dwIndex].szTag);
  1524.                 switch (c_UrlSub[dwIndex].dwType)
  1525.                 {
  1526.                 case URLSUB_CLSID:
  1527.                 {
  1528.                     //  REVIEW (tnoonan)
  1529.                     //  Should we be using the inetcpl locale settings here?
  1530.                     LCID lcid = GetUserDefaultLCID();
  1531.                     wnsprintf(szSubStr, ARRAYSIZE(szSubStr), TEXT("%#04lx"), lcid);
  1532.                 }
  1533.                     break;
  1534.                 case URLSUB_PRD:
  1535.                     MLLoadString(IDS_SUBSTR_PRD, szSubStr, ARRAYSIZE(szSubStr));
  1536.                     break;
  1537.                 case URLSUB_PVER:
  1538.                     MLLoadString(IDS_SUBSTR_PVER, szSubStr, ARRAYSIZE(szSubStr));
  1539.                     break;
  1540.                 case URLSUB_OS:
  1541.                     if (g_bRunOnMemphis)
  1542.                     {
  1543.                         StrCpyN(szSubStr, TEXT("98"), ARRAYSIZE(szSubStr));
  1544.                     }
  1545.                     else if (g_fRunningOnNT)
  1546.                     {
  1547.                         if (g_bRunOnNT5)
  1548.                             StrCpyN(szSubStr, TEXT("N5"), ARRAYSIZE(szSubStr));
  1549.                         else
  1550.                             StrCpyN(szSubStr, TEXT("N4"), ARRAYSIZE(szSubStr));
  1551.                     }
  1552.                     else
  1553.                     {
  1554.                         StrCpyN(szSubStr, TEXT("95"), ARRAYSIZE(szSubStr));
  1555.                     }
  1556.                     break;
  1557.                 case URLSUB_RFC1766:
  1558.                     GetWebLocaleAsRFC1766(szSubStr, ARRAYSIZE(szSubStr));
  1559.                     break;
  1560.                     
  1561.                 default:
  1562.                     szSubStr[0] = TEXT('');
  1563.                     ASSERT(FALSE);  // Not Impl.
  1564.                     hr = E_NOTIMPL;
  1565.                     break;
  1566.                 }
  1567.                 // Add the Substitution String to the end (will become the middle)
  1568.                 StrCatBuff(szCopyUrl, szSubStr, ARRAYSIZE(szCopyUrl));
  1569.                 // Add the rest of the URL after the substitution substring.
  1570.                 StrCatBuff(szCopyUrl, pszTag, ARRAYSIZE(szCopyUrl));
  1571.                 StrCpyN(szTempUrl, szCopyUrl, ARRAYSIZE(szTempUrl));
  1572.             }
  1573.             else
  1574.                 break;  // This will allow us to replace all the occurances of this string.
  1575.         }
  1576.     }
  1577.     StrCpyN(pszUrlOut, szTempUrl, cchSize);
  1578.     return hr;
  1579. }
  1580. // inetcpl.cpl uses this.
  1581. STDAPI URLSubRegQueryA(LPCSTR pszKey, LPCSTR pszValue, BOOL fUseHKCU,
  1582.                            LPSTR pszUrlOut, DWORD cchSizeOut, DWORD dwSubstitutions)
  1583. {
  1584.     HRESULT hr;
  1585.     TCHAR szKey[MAX_PATH];
  1586.     TCHAR szValue[MAX_PATH];
  1587.     TCHAR szUrlOut[MAX_URL_STRING];
  1588.     AnsiToTChar(pszKey, szKey, ARRAYSIZE(szKey));
  1589.     AnsiToTChar(pszValue, szValue, ARRAYSIZE(szValue));
  1590.     hr = URLSubRegQueryW(szKey, szValue, fUseHKCU, szUrlOut, ARRAYSIZE(szUrlOut), dwSubstitutions);
  1591.     TCharToAnsi(szUrlOut, pszUrlOut, cchSizeOut);
  1592.     return hr;
  1593. }
  1594. HRESULT URLSubRegQueryW(LPCWSTR pszKey, LPCWSTR pszValue, BOOL fUseHKCU,
  1595.                            LPWSTR pszUrlOut, DWORD cchSizeOut, DWORD dwSubstitutions)
  1596. {
  1597.     HRESULT hr = E_FAIL;
  1598.     WCHAR szTempUrl[MAX_URL_STRING];
  1599.     DWORD ccbSize = sizeof(szTempUrl);
  1600.     if (ERROR_SUCCESS == SHRegGetUSValueW(pszKey, pszValue, NULL, szTempUrl,
  1601.                                 &ccbSize, !fUseHKCU, NULL, NULL))
  1602.     {
  1603.         hr = URLSubstitution(szTempUrl, pszUrlOut, cchSizeOut, dwSubstitutions);
  1604.     }
  1605.     return hr;
  1606. }
  1607. // note that anyone inside shdocvw should pass hInst==NULL to
  1608. // ensure that pluggable UI works correctly. anyone outside of shdocvw
  1609. // must pass an hInst for their appropriate resource dll
  1610. HRESULT URLSubLoadString(HINSTANCE hInst, UINT idRes, LPWSTR pszUrlOut,
  1611.                          DWORD cchSizeOut, DWORD dwSubstitutions)
  1612. {
  1613.     HRESULT hr = E_FAIL;
  1614.     WCHAR   szTempUrl[MAX_URL_STRING];
  1615.     int     nStrLen;
  1616.     nStrLen = 0;
  1617.     if (hInst == NULL)
  1618.     {
  1619.         // this is for internal users who want pluggable UI to work
  1620.         nStrLen = MLLoadStringW(idRes, szTempUrl, ARRAYSIZE(szTempUrl));
  1621.     }
  1622.     else
  1623.     {
  1624.         // this is for external users who use us to load some
  1625.         // of their own resources but whom we can't change (like shell32)
  1626.         nStrLen = LoadStringWrap(hInst, idRes, szTempUrl, ARRAYSIZE(szTempUrl));
  1627.     }
  1628.     if (nStrLen > 0)
  1629.     {
  1630.         hr = URLSubstitution(szTempUrl, pszUrlOut, cchSizeOut, dwSubstitutions);
  1631.     }
  1632.     return hr;
  1633. }
  1634. /**********************************************************************
  1635.     FUNCTION: ILIsWeb
  1636.     DESCRIPTION:
  1637.         ILIsUrlChild() will find pidls that exist under "DesktopThe Internet"
  1638.     section of the Shell Name Space.  This function includes those items
  1639.     and file system items that have a "txt/html.
  1640. **********************************************************************/
  1641. BOOL ILIsWeb(LPCITEMIDLIST pidl)
  1642. {
  1643.     BOOL fIsWeb = FALSE;
  1644.     if (pidl)
  1645.     {
  1646.         if (IsURLChild(pidl, TRUE))
  1647.             fIsWeb = TRUE;
  1648.         else
  1649.         {
  1650.             TCHAR szPath[MAX_PATH];
  1651.             fIsWeb = (!ILIsRooted(pidl)
  1652.             && SUCCEEDED(SHGetPathFromIDList(pidl, szPath)) 
  1653.             && (PathIsHTMLFile(szPath) ||
  1654.                  PathIsContentType(szPath, TEXT("text/xml"))));
  1655.         }
  1656.     }
  1657.     return fIsWeb;
  1658. }
  1659. //
  1660. // in:
  1661. //      pidlTo
  1662. STDAPI CreateLinkToPidl(LPCITEMIDLIST pidlTo, LPCTSTR pszDir, LPCTSTR pszTitle, LPTSTR pszOut, int cchOut)
  1663. {
  1664.     HRESULT hres = E_FAIL;
  1665.     TCHAR szPathDest[MAX_URL_STRING];
  1666.     BOOL fCopyLnk;
  1667.     if (SHGetNewLinkInfo((LPCTSTR)pidlTo, pszDir, szPathDest, &fCopyLnk, SHGNLI_PIDL))
  1668.     {
  1669.         IShellLinkA *pslA;  // Use A version for W95.
  1670.         if (SUCCEEDED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, (void**)&pslA)))
  1671.         {
  1672.             TCHAR szPathSrc[MAX_URL_STRING];
  1673.             DWORD dwAttributes = SFGAO_FILESYSTEM | SFGAO_FOLDER;
  1674.             // get source
  1675.             BOOL fPath = SUCCEEDED(SHGetNameAndFlags(pidlTo, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, szPathSrc, ARRAYSIZE(szPathSrc), &dwAttributes));
  1676.             if (fCopyLnk) 
  1677.             {
  1678.                 if (((dwAttributes & (SFGAO_FILESYSTEM | SFGAO_FOLDER)) == SFGAO_FILESYSTEM) && CopyFile(szPathSrc, szPathDest, TRUE))
  1679.                 {
  1680.                     SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, szPathDest, NULL);
  1681.                     SHChangeNotify(SHCNE_FREESPACE, SHCNF_PATH, szPathDest, NULL);
  1682.                     hres = S_OK;
  1683.                 }
  1684.                 else
  1685.                 {
  1686.                     // load the source object that will be "copied" below (with the ::Save call)
  1687.                     SAFERELEASE(pslA);
  1688.                     hres = SHGetUIObjectFromFullPIDL(pidlTo, NULL, IID_IShellLinkA, (void **)&pslA);
  1689.                     // this pslA is released at the end of the topmost if
  1690.                     if (SUCCEEDED(hres))
  1691.                     {
  1692.                         IPersistFile *ppf;
  1693.                         hres = pslA->QueryInterface(IID_IPersistFile, (void**)&ppf);
  1694.                         if (SUCCEEDED(hres))
  1695.                         {
  1696.                             hres = ppf->Save(szPathDest, TRUE);
  1697.                             ppf->Release();
  1698.                         }
  1699.                     }
  1700.                 }
  1701.             } 
  1702.             else 
  1703.             {
  1704.                 IPersistFile *ppf;
  1705.                 pslA->SetIDList(pidlTo);
  1706.                 //
  1707.                 // make sure the working directory is set to the same
  1708.                 // directory as the app (or document).
  1709.                 //
  1710.                 // dont do this for non-FS pidls (ie control panel)
  1711.                 //
  1712.                 // what about a UNC directory? we go ahead and set
  1713.                 // it, wont work for a WIn16 app.
  1714.                 //
  1715.                 if (fPath && !PathIsDirectory(szPathSrc)) {
  1716.                     ASSERT(!PathIsRelative(szPathSrc));
  1717.                     PathRemoveFileSpec(szPathSrc);
  1718.                     // Try to get the W version.
  1719.                     IShellLinkW* pslW;
  1720.                     if (SUCCEEDED(pslA->QueryInterface(IID_IShellLinkW, (void**)&pslW)))
  1721.                     {
  1722.                         ASSERT(pslW);
  1723.                         pslW->SetWorkingDirectory(szPathSrc);
  1724.                         pslW->Release();
  1725.                     }
  1726.                     else
  1727.                     {
  1728.                         CHAR szPathSrcA[MAX_URL_STRING];
  1729.                         SHUnicodeToAnsi(szPathSrc, szPathSrcA, ARRAYSIZE(szPathSrcA));
  1730.                         pslA->SetWorkingDirectory(szPathSrcA);
  1731.                     }
  1732.                 }
  1733.                 hres = pslA->QueryInterface(IID_IPersistFile, (void **)&ppf);
  1734.                 if (SUCCEEDED(hres)) {
  1735.                     WCHAR wszPath[ARRAYSIZE(szPathDest)];
  1736.                     if (pszTitle && pszTitle[0]) {
  1737.                         PathRemoveFileSpec(szPathDest);
  1738.                         PathAppend(szPathDest, pszTitle);
  1739.                         StrCatBuff(szPathDest, TEXT(".lnk"), ARRAYSIZE(szPathDest));
  1740.                     }
  1741.                     SHTCharToUnicode(szPathDest, wszPath, ARRAYSIZE(wszPath));
  1742.                     hres = ppf->Save(wszPath, TRUE);
  1743.                     if (pszOut)
  1744.                     {
  1745.                         StrCpyN(pszOut, wszPath, cchOut);
  1746.                     }
  1747.                     ppf->Release();
  1748.                 }
  1749.             }
  1750.             pslA->Release();
  1751.         }
  1752.     }
  1753.     return hres;
  1754. }
  1755. #ifndef POSTPOSTSPLIT
  1756. int GetColorComponent(LPTSTR *ppsz)
  1757. {
  1758.     int iColor = 0;
  1759.     if (*ppsz) {
  1760.         LPTSTR pBuf = *ppsz;
  1761.         iColor = StrToInt(pBuf);
  1762.         // find the next comma
  1763.         while(pBuf && *pBuf && *pBuf!=TEXT(','))
  1764.             pBuf++;
  1765.         // if valid and not NULL...
  1766.         if (pBuf && *pBuf)
  1767.             pBuf++;         // increment
  1768.         *ppsz = pBuf;
  1769.     }
  1770.     return iColor;
  1771. }
  1772. // Read the registry for a string (REG_SZ) of comma separated RGB values
  1773. COLORREF RegGetColorRefString( HKEY hkey, LPTSTR RegValue, COLORREF Value)
  1774. {
  1775.     TCHAR SmallBuf[80];
  1776.     TCHAR *pBuf;
  1777.     DWORD cb;
  1778.     int iRed, iGreen, iBlue;
  1779.     cb = ARRAYSIZE(SmallBuf);
  1780.     if (RegQueryValueEx(hkey, RegValue, NULL, NULL, (LPBYTE)&SmallBuf, &cb)
  1781.         == ERROR_SUCCESS)
  1782.     {
  1783.         pBuf = SmallBuf;
  1784.         iRed = GetColorComponent(&pBuf);
  1785.         iGreen = GetColorComponent(&pBuf);
  1786.         iBlue = GetColorComponent(&pBuf);
  1787.         // make sure all values are valid
  1788.         iRed    %= 256;
  1789.         iGreen  %= 256;
  1790.         iBlue   %= 256;
  1791.         Value = RGB(iRed, iGreen, iBlue);
  1792.     }
  1793.     return Value;
  1794. }
  1795. #endif
  1796. #ifdef DEBUG // {
  1797. //***   SearchDW -- scan for DWORD in buffer
  1798. // ENTRY/EXIT
  1799. //  pdwBuf  buffer
  1800. //  cbBuf   size of buffer in *bytes* (*not* DWORDs)
  1801. //  dwVal   DWORD we're looking for
  1802. //  dOff    (return) byte offset in buffer; o.w. -1 if not found
  1803. //
  1804. int SearchDW(DWORD *pdwBuf, int cbBuf, DWORD dwVal)
  1805. {
  1806.     int dOff;
  1807.     for (dOff = 0; dOff < cbBuf; dOff += SIZEOF(DWORD), pdwBuf++) {
  1808.         if (*pdwBuf == dwVal)
  1809.             return dOff;
  1810.     }
  1811.     return -1;
  1812. }
  1813. #endif // }
  1814. // NOTE: These are directly copied from fsnotify.c in shell32. Please make sure
  1815. // NOTE: any changes are reflected there also.
  1816. // this is the NEW SHCNE_UPDATEIMAGE stuff, it passes renough data so that the recieving process
  1817. // has a vague chance that it can find the right index to refresh.
  1818. extern "C" void WINAPI _SHUpdateImageA( LPCSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex )
  1819. {
  1820.     WCHAR szWHash[MAX_PATH];
  1821.     MultiByteToWideChar( CP_ACP, 0, pszHashItem, -1, szWHash, MAX_PATH );
  1822.     _SHUpdateImageW( szWHash, iIndex, uFlags, iImageIndex );
  1823. }
  1824. extern "C" void WINAPI _SHUpdateImageW( LPCWSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex )
  1825. {
  1826.     SHChangeUpdateImageIDList rgPidl;
  1827.     SHChangeDWORDAsIDList rgDWord;
  1828.     int cLen = MAX_PATH - (lstrlenW( pszHashItem ) + 1);
  1829.     cLen *= sizeof( WCHAR );
  1830.     if ( cLen < 0 )
  1831.         cLen = 0;
  1832.     // make sure we send a valid index
  1833.     if ( iImageIndex == -1 )
  1834.         iImageIndex = II_DOCUMENT;
  1835.     rgPidl.dwProcessID = GetCurrentProcessId();
  1836.     rgPidl.iIconIndex = iIndex;
  1837.     rgPidl.iCurIndex = iImageIndex;
  1838.     rgPidl.uFlags = uFlags;
  1839.     StrCpyNW( rgPidl.szName, pszHashItem, MAX_PATH );
  1840.     rgPidl.cb = (USHORT)(sizeof( rgPidl ) - cLen);
  1841.     _ILNext( (LPITEMIDLIST) &rgPidl )->mkid.cb = 0;
  1842.     rgDWord.cb = (unsigned short) PtrDiff(&rgDWord.cbZero, &rgDWord);
  1843.     rgDWord.dwItem1 = (DWORD) iImageIndex;
  1844.     rgDWord.dwItem2 = 0;
  1845.     rgDWord.cbZero = 0;
  1846.     // pump it as an extended event
  1847.     SHChangeNotify( SHCNE_UPDATEIMAGE, SHCNF_IDLIST, &rgDWord, &rgPidl );
  1848. }
  1849. // ancient shell API wrapper...
  1850. extern "C" int _WorA_Shell_GetCachedImageIndex(LPCWSTR pszIconPath, int iIconIndex, UINT uIconFlags);
  1851. #ifndef POSTPOSTSPLIT
  1852. extern "C" int WINAPI _SHHandleUpdateImage( LPCITEMIDLIST pidlExtra )
  1853. {
  1854.     SHChangeUpdateImageIDList * pUs = (SHChangeUpdateImageIDList*) pidlExtra;
  1855.     if ( !pUs )
  1856.     {
  1857.         return -1;
  1858.     }
  1859.     // if in the same process, or an old style notification
  1860.     if ( pUs->dwProcessID == GetCurrentProcessId())
  1861.     {
  1862.         return (int) pUs->iCurIndex;
  1863.     }
  1864.     else
  1865.     {
  1866.         WCHAR szBuffer[MAX_PATH];
  1867.         int iIconIndex = *(int UNALIGNED *)((BYTE *)&pUs->iIconIndex);
  1868.         UINT uFlags = *(UINT UNALIGNED *)((BYTE *)&pUs->uFlags);
  1869.         ualstrcpynW( szBuffer, pUs->szName, ARRAYSIZE(szBuffer) );
  1870.         // we are in a different process, look up the hash in our index to get the right one...
  1871.         return _WorA_Shell_GetCachedImageIndex( szBuffer, iIconIndex, uFlags );
  1872.     }
  1873. }
  1874. #endif
  1875. HRESULT FormatUrlForDisplay(LPWSTR pwzURL, LPWSTR pwzFriendly, UINT cchBuf, BOOL fSeperate, DWORD dwCodePage)
  1876. {
  1877.     const   DWORD       dwMaxPathLen        = 32;
  1878.     const   DWORD       dwMaxHostLen        = 32;
  1879.     const   DWORD       dwMaxTemplateLen    = 64;
  1880.     const   DWORD       dwElipsisLen        = 3;
  1881.     const   CHAR        rgchElipsis[]       = "...";
  1882.     HRESULT hrRC = E_FAIL;
  1883.     HRESULT hr;
  1884.     if (pwzURL==NULL || pwzFriendly==NULL)
  1885.         return E_POINTER;
  1886.     *pwzFriendly = '';
  1887.     if (!*pwzURL)
  1888.         return S_OK;
  1889.     if (!cchBuf)
  1890.         return E_FAIL;
  1891.     // Wininet can't deal with code pages other than CP_ACP so convert the URL ourself and call InterCrackUrlA
  1892.     URL_COMPONENTSA urlComp;
  1893.     CHAR   rgchScheme[INTERNET_MAX_SCHEME_LENGTH];
  1894.     CHAR   rgchHostName[INTERNET_MAX_HOST_NAME_LENGTH];
  1895.     CHAR   rgchUrlPath[MAX_PATH];
  1896.     CHAR   rgchCanonicalUrl[MAX_URL_STRING];
  1897.     LPSTR  pszURL;
  1898.     DWORD  dwLen;
  1899.     if((pszURL = (LPSTR)LocalAlloc(LPTR, (cchBuf*2) * sizeof(CHAR))) != NULL)
  1900.     {
  1901.         SHUnicodeToAnsiCP(dwCodePage, pwzURL, pszURL, cchBuf);
  1902.         dwLen = ARRAYSIZE(rgchCanonicalUrl);
  1903.         hr = UrlCanonicalizeA(pszURL, rgchCanonicalUrl, &dwLen, 0);
  1904.         if (SUCCEEDED(hr))
  1905.         {
  1906.             ZeroMemory(&urlComp, sizeof(urlComp));
  1907.             urlComp.dwStructSize = sizeof(urlComp);
  1908.             urlComp.lpszHostName = rgchHostName;
  1909.             urlComp.dwHostNameLength = ARRAYSIZE(rgchHostName);
  1910.             urlComp.lpszUrlPath = rgchUrlPath;
  1911.             urlComp.dwUrlPathLength = ARRAYSIZE(rgchUrlPath);
  1912.             urlComp.lpszScheme = rgchScheme;
  1913.             urlComp.dwSchemeLength = ARRAYSIZE(rgchScheme);
  1914.             hr = InternetCrackUrlA(rgchCanonicalUrl, lstrlenA(rgchCanonicalUrl), 0, &urlComp);
  1915.             if (SUCCEEDED(hr))
  1916.             {
  1917.                 DWORD dwPathLen = lstrlenA(rgchUrlPath);
  1918.                 DWORD dwHostLen = lstrlenA(rgchHostName);
  1919.                 DWORD dwSchemeLen = lstrlenA(rgchScheme);
  1920.                 CHAR   rgchHostForDisplay[INTERNET_MAX_HOST_NAME_LENGTH];
  1921.                 CHAR   rgchPathForDisplay[MAX_PATH];
  1922.                 ZeroMemory(rgchHostForDisplay, sizeof(rgchHostForDisplay));
  1923.                 ZeroMemory(rgchPathForDisplay, sizeof(rgchPathForDisplay));
  1924.                 if (dwHostLen>dwMaxHostLen)
  1925.                 {
  1926.                     DWORD   dwOverFlow = dwHostLen - dwMaxHostLen + dwElipsisLen + 1;
  1927.                     wnsprintfA(rgchHostForDisplay, ARRAYSIZE(rgchHostForDisplay), "%s%s", rgchElipsis, rgchHostName+dwOverFlow);
  1928.                     dwHostLen = dwMaxHostLen;
  1929.                 }
  1930.                 else
  1931.                     StrCpyNA(rgchHostForDisplay, rgchHostName, ARRAYSIZE(rgchHostForDisplay));