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

Windows Kernel

Development Platform:

Visual C++

  1. #include "local.h"
  2. #include "hsfolder.h"
  3. #include "../security.h"
  4. #include "../favorite.h"
  5. #include "resource.h"
  6. #include <mluisupp.h>
  7. #define DM_HSFOLDER 0
  8. STDAPI  AddToFavorites(HWND hwnd, LPCITEMIDLIST pidlCur, LPCTSTR pszTitle,
  9.                        BOOL fDisplayUI, IOleCommandTarget *pCommandTarget, IHTMLDocument2 *pDoc);
  10. STDAPI HlinkFrameNavigateNHL(DWORD grfHLNF, LPBC pbc,
  11.                            IBindStatusCallback *pibsc,
  12.                            LPCWSTR pszTargetFrame,
  13.                            LPCWSTR pszUrl,
  14.                            LPCWSTR pszLocation);
  15. INT_PTR CALLBACK CacheItem_PropDlgProc(HWND, UINT, WPARAM, LPARAM);
  16. INT_PTR CALLBACK HistItem_PropDlgProc(HWND, UINT, WPARAM, LPARAM);
  17. void MakeLegalFilenameA(LPSTR pszFilename);
  18. void MakeLegalFilenameW(LPWSTR pszFilename);
  19. #define MAX_ITEM_OPEN 10
  20. //////////////////////////////////////////////////////////////////////////////
  21. //
  22. // CHistCacheItem Object
  23. //
  24. //////////////////////////////////////////////////////////////////////////////
  25. CHistCacheItem::CHistCacheItem() 
  26. {
  27.     DllAddRef();
  28.     InitClipboardFormats();
  29.     _cRef = 1;
  30.     _dwDelCookie = DEL_COOKIE_WARN;
  31. }        
  32. CHistCacheItem::~CHistCacheItem()
  33. {
  34.     if (_pHCFolder)
  35.         _pHCFolder->Release();          // release the pointer to the sf
  36.     if (_ppcei)
  37.     {
  38.         for (UINT i = 0; i < _cItems; i++) 
  39.         {
  40.             if (_ppcei[i])
  41.                 ILFree((LPITEMIDLIST)_ppcei[i]);
  42.         }
  43.         LocalFree((HLOCAL)_ppcei);
  44.     }
  45.     
  46.     DllRelease();
  47. }
  48. HRESULT CHistCacheItem::Initalize(CHistCacheFolder *pHCFolder, HWND hwnd, UINT cidl, LPCITEMIDLIST *ppidl)
  49. {
  50.     HRESULT hres;
  51.     _ppcei = (LPCEIPIDL *)LocalAlloc(LPTR, cidl * sizeof(LPCEIPIDL));
  52.     if (_ppcei)
  53.     {
  54.         _hwndOwner = hwnd;
  55.         _cItems     = cidl;
  56.         hres = S_OK;
  57.         for (UINT i = 0; i < cidl; i++)
  58.         {
  59.             _ppcei[i] = (LPCEIPIDL)ILClone(ppidl[i]);
  60.             if (!_ppcei[i])
  61.             {
  62.                 hres = E_OUTOFMEMORY;
  63.                 break;
  64.             }
  65.         }
  66.         if (SUCCEEDED(hres))
  67.         {
  68.             _pHCFolder = pHCFolder;
  69.             _pHCFolder->AddRef();      // we're going to hold onto this pointer, so
  70.         }
  71.     }
  72.     else
  73.         hres = E_OUTOFMEMORY;
  74.     return hres;
  75. }        
  76. HRESULT CHistCacheItem_CreateInstance(CHistCacheFolder *pHCFolder, HWND hwnd,
  77.     UINT cidl, LPCITEMIDLIST *ppidl, REFIID riid, void **ppv)
  78. {
  79.     HRESULT hr;
  80.     *ppv = NULL;                 // null the out param
  81.     if (!_ValidateIDListArray(cidl, ppidl))
  82.         return E_FAIL;
  83.     CHistCacheItem *pHCItem = new CHistCacheItem;
  84.     if (pHCItem)
  85.     {
  86.         hr = pHCItem->Initalize(pHCFolder, hwnd, cidl, ppidl);
  87.         if (SUCCEEDED(hr))
  88.             hr = pHCItem->QueryInterface(riid, ppv);
  89.         pHCItem->Release();
  90.     }
  91.     else
  92.         hr = E_OUTOFMEMORY;
  93.     return hr;
  94. }
  95. //////////////////////////////////
  96. //
  97. // IUnknown Methods...
  98. //
  99. HRESULT CHistCacheItem::QueryInterface(REFIID iid, void **ppv)
  100. {
  101.     HRESULT hres;
  102.     static const QITAB qit[] = {
  103.         QITABENT(CHistCacheItem, IContextMenu),
  104.         QITABENT(CHistCacheItem, IDataObject),
  105.         QITABENT(CHistCacheItem, IExtractIconA),
  106.         QITABENT(CHistCacheItem, IExtractIconW),
  107.         QITABENT(CHistCacheItem, IQueryInfo),
  108.          { 0 },
  109.     };
  110.     hres = QISearch(this, qit, iid, ppv);
  111.     if (FAILED(hres) && iid == IID_IHistCache) 
  112.     {
  113.         *ppv = (LPVOID)this;    // for our friends
  114.         AddRef();
  115.         hres = S_OK;
  116.     }
  117.     return hres;
  118. }
  119. ULONG CHistCacheItem::AddRef()
  120. {
  121.     return InterlockedIncrement(&_cRef);
  122. }
  123. ULONG CHistCacheItem::Release()
  124. {
  125.     if (InterlockedDecrement(&_cRef))
  126.         return _cRef;
  127.     delete this;
  128.     return 0;   
  129. }
  130. //////////////////////////////////
  131. //
  132. // IQueryInfo Methods
  133. //
  134. HRESULT CHistCacheItem::GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip)
  135. {
  136.     return _pHCFolder->_GetInfoTip((LPCITEMIDLIST)_ppcei[0], dwFlags, ppwszTip);
  137. }
  138. HRESULT CHistCacheItem::GetInfoFlags(DWORD *pdwFlags)
  139. {
  140.     LPCITEMIDLIST pidl = (LPCITEMIDLIST)_ppcei[0];
  141.     LPCTSTR pszUrl = HCPidlToSourceUrl(pidl);
  142.     *pdwFlags = QIF_CACHED; 
  143.     if (pszUrl)
  144.     {
  145.         pszUrl = _StripHistoryUrlToUrl(pszUrl);
  146.         BOOL fCached = TRUE;
  147.         if (UrlHitsNet(pszUrl) && !UrlIsMappedOrInCache(pszUrl))
  148.         {
  149.             fCached = FALSE;
  150.         }
  151.             
  152.         if (!fCached)
  153.             *pdwFlags &= ~QIF_CACHED;
  154.     }
  155.     return S_OK;
  156. }
  157. //////////////////////////////////
  158. //
  159. // IExtractIconA Methods...
  160. //
  161. HRESULT CHistCacheItem::GetIconLocation(UINT uFlags, LPSTR pszIconFile, UINT ucchMax, PINT pniIcon, PUINT puFlags)
  162. {
  163.     int cbIcon;
  164.     if (_pHCFolder->_uViewType) {
  165.         switch (_pHCFolder->_uViewType) {
  166.         case VIEWPIDL_SEARCH:
  167.         case VIEWPIDL_ORDER_FREQ:
  168.         case VIEWPIDL_ORDER_TODAY:
  169.             cbIcon = IDI_HISTURL;
  170.             break;
  171.         case VIEWPIDL_ORDER_SITE:
  172.             switch(_pHCFolder->_uViewDepth) {
  173.             case 0: cbIcon = (uFlags & GIL_OPENICON) ? IDI_HISTOPEN:IDI_HISTFOLDER; break;
  174.             case 1: cbIcon = IDI_HISTURL; break;
  175.             }
  176.             break;
  177.         }
  178.     }
  179.     else {
  180.         switch (_pHCFolder->_foldertype)
  181.         {
  182.         case FOLDER_TYPE_Cache:
  183.             if (ucchMax < 2) return E_FAIL;
  184.             
  185.             *puFlags = GIL_NOTFILENAME;
  186.             pszIconFile[0] = '*';
  187.             pszIconFile[1] = '';
  188.             
  189.             // "*" as the file name means iIndex is already a system icon index.
  190.             return _pHCFolder->GetIconOf((LPCITEMIDLIST)_ppcei[0], uFlags, pniIcon);
  191.             break;
  192.             
  193.         case FOLDER_TYPE_Hist:
  194.             cbIcon = IDI_HISTWEEK;
  195.             break;
  196.         case FOLDER_TYPE_HistInterval:
  197.             cbIcon = (uFlags & GIL_OPENICON) ? IDI_HISTOPEN:IDI_HISTFOLDER;
  198.             break;
  199.         case FOLDER_TYPE_HistDomain:
  200.             cbIcon = IDI_HISTURL;
  201.             break;
  202.         default:
  203.             return E_FAIL;
  204.         }
  205.     }
  206.     *puFlags = 0;
  207.     *pniIcon = -cbIcon;
  208.     StrCpyNA(pszIconFile, "shdocvw.dll", ucchMax);
  209.     return S_OK;
  210. }
  211. HRESULT CHistCacheItem::Extract(LPCSTR pcszFile, UINT uIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT ucIconSize)
  212. {
  213.     return S_FALSE;
  214. }
  215. //////////////////////////////////
  216. //
  217. // IExtractIconW Methods...
  218. //
  219. HRESULT CHistCacheItem::GetIconLocation(UINT uFlags, LPWSTR pwzIconFile, UINT ucchMax, PINT pniIcon, PUINT puFlags)
  220. {
  221.     CHAR szIconFile[MAX_PATH];
  222.     HRESULT hr = GetIconLocation(uFlags, szIconFile, ARRAYSIZE(szIconFile), pniIcon, puFlags);
  223.     if (SUCCEEDED(hr))
  224.         AnsiToUnicode(szIconFile, pwzIconFile, ucchMax);
  225.     return hr;
  226. }
  227. HRESULT CHistCacheItem::Extract(LPCWSTR pcwzFile, UINT uIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT ucIconSize)
  228. {
  229.     CHAR szFile[MAX_PATH];
  230.     UnicodeToAnsi(pcwzFile, szFile, ARRAYSIZE(szFile));
  231.     return Extract(szFile, uIconIndex, phiconLarge, phiconSmall, ucIconSize);
  232. }
  233. //////////////////////////////////
  234. //
  235. // IContextMenu Methods
  236. //
  237. HRESULT CHistCacheItem::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst,UINT idCmdLast, UINT uFlags)
  238. {
  239.     USHORT cItems;
  240.     TraceMsg(DM_HSFOLDER, "hci - cm - QueryContextMenu() called.");
  241.     
  242.     if ((uFlags & CMF_VERBSONLY) || (uFlags & CMF_DVFILE))
  243.     {
  244.         cItems = MergePopupMenu(&hmenu, POPUP_CONTEXT_URL_VERBSONLY, 0, indexMenu, 
  245.             idCmdFirst, idCmdLast);
  246.     
  247.     }
  248.     else  // (uFlags & CMF_NORMAL)
  249.     {
  250.         UINT idResource = POPUP_CACHECONTEXT_URL;
  251.         // always use the cachecontext menu unless:
  252.         if ( ((_pHCFolder->_uViewType == VIEWPIDL_ORDER_SITE) &&
  253.               (_pHCFolder->_uViewDepth == 0))                      ||
  254.              (!IsLeaf(_pHCFolder->_foldertype)) )
  255.             idResource = POPUP_HISTORYCONTEXT_URL;
  256.         cItems = MergePopupMenu(&hmenu, idResource, 0, indexMenu, idCmdFirst, idCmdLast);
  257.         if (IsInetcplRestricted(L"History"))
  258.         {
  259.             DeleteMenu(hmenu, RSVIDM_DELCACHE + idCmdFirst, MF_BYCOMMAND);
  260.             _SHPrettyMenu(hmenu);
  261.         }
  262.     }
  263.     SetMenuDefaultItem(hmenu, indexMenu, MF_BYPOSITION);
  264.     return ResultFromShort(cItems);    // number of menu items    
  265. }
  266. LPCTSTR CHistCacheItem::_GetUrl(int nIndex)
  267. {
  268.     LPCTSTR pszUrl = NULL;
  269.     if (IsHistory(_pHCFolder->_foldertype))
  270.         pszUrl = _StripHistoryUrlToUrl(HCPidlToSourceUrl((LPCITEMIDLIST)_ppcei[nIndex]));
  271.     else
  272.         pszUrl = HCPidlToSourceUrl((LPCITEMIDLIST)_ppcei[nIndex]);
  273.     return pszUrl;
  274. }
  275. // Return value:
  276. //               TRUE - URL is Safe.
  277. //               FALSE - URL is questionable and needs to be re-zone checked w/o PUAF_NOUI.
  278. BOOL CHistCacheItem::_ZoneCheck(int nIndex, DWORD dwUrlAction)
  279. {
  280.     LPCTSTR pszUrl = _GetUrl(nIndex);
  281.     // Are we dealing with the history folder?
  282.     if (IsHistory(_pHCFolder->_foldertype))
  283.     {
  284.         // Yes, then consider anything that is not
  285.         // a FILE URL safe.
  286.         int nScheme = GetUrlScheme(pszUrl);
  287.         if (URL_SCHEME_FILE != nScheme)
  288.             return TRUE;        // It's safe because it's not a file URL.
  289.     }
  290.     if (S_OK != ZoneCheckUrl(pszUrl, dwUrlAction, PUAF_NOUI, NULL))
  291.         return FALSE;
  292.     return TRUE;
  293. }
  294. HRESULT CHistCacheItem::_AddToFavorites(int nIndex)
  295. {
  296.     HRESULT hr = S_OK;
  297.     LPITEMIDLIST pidlUrl = NULL;
  298.     TCHAR szParsedUrl[MAX_URL_STRING];
  299.     // NOTE: This URL came from the user, so we need to clean it up.
  300.     //       If the user entered "yahoo.com" or "Search Get Rich Quick",
  301.     //       it will be turned into a search URL by ParseURLFromOutsideSourceW().
  302.     DWORD cchParsedUrl = ARRAYSIZE(szParsedUrl);
  303.     if (!ParseURLFromOutsideSource(_GetUrl(nIndex), szParsedUrl, &cchParsedUrl, NULL))
  304.     {
  305.         StrCpyN(szParsedUrl, _GetUrl(nIndex), ARRAYSIZE(szParsedUrl));
  306.     } 
  307.     hr = IEParseDisplayName(CP_ACP, szParsedUrl, &pidlUrl);
  308.     if (SUCCEEDED(hr))
  309.     {
  310.         LPCTSTR pszTitle = _GetURLTitle(_ppcei[nIndex]);
  311.         if ((pszTitle == NULL) || (lstrlen(pszTitle) == 0))
  312.             pszTitle = _GetUrl(nIndex);
  313.         AddToFavorites(_hwndOwner, pidlUrl, pszTitle, TRUE, NULL, NULL);
  314.         ILFree(pidlUrl);
  315.         hr = S_OK;
  316.     }
  317.     return hr;
  318. }
  319. STDMETHODIMP CHistCacheItem::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  320. {
  321.     UINT i;
  322.     int idCmd = _GetCmdID(pici->lpVerb);
  323.     HRESULT hres = S_OK;
  324.     DWORD dwAction;
  325.     BOOL fCancelCopyAndOpen = FALSE;
  326.     BOOL fZonesUI = FALSE;
  327.     BOOL fMustFlushNotify = FALSE;
  328.     BOOL fBulkDelete;
  329.     TraceMsg(DM_HSFOLDER, "hci - cm - InvokeCommand() called.");
  330.     if (idCmd == RSVIDM_DELCACHE)
  331.     {
  332.         TCHAR szBuff[INTERNET_MAX_URL_LENGTH+MAX_PATH];
  333.         TCHAR szFormat[MAX_PATH];
  334.                 
  335.         if (IsHistory(_pHCFolder->_foldertype))
  336.         {
  337.             if (_cItems == 1)          
  338.             {
  339.                 TCHAR szTitle[MAX_URL_STRING];
  340.                 if (_pHCFolder->_foldertype != FOLDER_TYPE_Hist)
  341.                 {
  342.                     _GetURLDispName(_ppcei[0], szTitle, ARRAYSIZE(szTitle));
  343.                 }
  344.                 else
  345.                 {
  346.                     FILETIME ftStart, ftEnd;
  347.                     LPCTSTR pszIntervalName = _GetURLTitle(_ppcei[0]);
  348.                     if (SUCCEEDED(_ValueToIntervalW(pszIntervalName, &ftStart, &ftEnd)))
  349.                     {
  350.                         GetDisplayNameForTimeInterval(&ftStart, &ftEnd, szTitle, ARRAYSIZE(szTitle));
  351.                     }
  352.                 }
  353.                 MLLoadString(IDS_WARN_DELETE_HISTORYITEM, szFormat, ARRAYSIZE(szFormat));
  354.                 wnsprintf(szBuff, ARRAYSIZE(szBuff), szFormat, szTitle);
  355.             }
  356.             else
  357.             {
  358.                 MLLoadString(IDS_WARN_DELETE_MULTIHISTORY, szFormat, ARRAYSIZE(szFormat));
  359.                 wnsprintf(szBuff, ARRAYSIZE(szBuff), szFormat, _cItems);
  360.             }
  361.             if (DialogBoxParam(MLGetHinst(),
  362.                                  MAKEINTRESOURCE(DLG_HISTCACHE_WARNING),
  363.                                  pici->hwnd,
  364.                                  HistoryConfirmDeleteDlgProc,
  365.                                  (LPARAM)szBuff) != IDYES)
  366.             {
  367.                 return S_FALSE;
  368.             }
  369.             return _pHCFolder->_DeleteItems((LPCITEMIDLIST *)_ppcei, _cItems);
  370.         }
  371.     }
  372.     // ZONES SECURITY CHECK.
  373.     //
  374.     // We need to cycle through each action and Zone Check the URLs.
  375.     // We pass NOUI when zone checking the URLs because we don't want info
  376.     // displayed to the user.  We will stop when we find the first questionable
  377.     // URL.  We will then 
  378.     for (i = 0; (i < _cItems) && !fZonesUI; i++)
  379.     {
  380.         if (_ppcei[i]) 
  381.         {
  382.             switch (idCmd)
  383.             {
  384.             case RSVIDM_OPEN:
  385.                 if ((i < MAX_ITEM_OPEN) && _pHCFolder->_IsLeaf())
  386.                 {
  387.                     if (!_ZoneCheck(i, URLACTION_SHELL_VERB))
  388.                     {
  389.                         fZonesUI = TRUE;
  390.                         dwAction = URLACTION_SHELL_VERB;
  391.                     }
  392.                 }
  393.                 break;
  394.             case RSVIDM_COPY:
  395.                 if (_pHCFolder->_IsLeaf())
  396.                 {
  397.                     if (!_ZoneCheck(i, URLACTION_SHELL_MOVE_OR_COPY))
  398.                     {
  399.                         fZonesUI = TRUE;
  400.                         dwAction = URLACTION_SHELL_MOVE_OR_COPY;
  401.                     }
  402.                 }
  403.                 break;
  404.             }
  405.         }
  406.     }
  407.     if (fZonesUI)
  408.     {
  409.         LPCTSTR pszUrl = _GetUrl(i-1);  // Sub 1 because of for loop above.
  410.         if (S_OK != ZoneCheckUrl(pszUrl, dwAction, PUAF_DEFAULT|PUAF_WARN_IF_DENIED, NULL))
  411.         {
  412.             // The user cannot do this or does not want to do this.
  413.             fCancelCopyAndOpen = TRUE;
  414.         }
  415.     }
  416.     i = _cItems;
  417.     fBulkDelete = i > LOTS_OF_FILES;
  418.     // fCancelCopyAndOpen happens if the user cannot or chose not to proceed.
  419.     while (i && !fCancelCopyAndOpen)
  420.     {
  421.         i--;
  422.         if (_ppcei[i]) 
  423.         {
  424.             switch (idCmd)
  425.             {
  426.             case RSVIDM_OPEN:
  427.                 ASSERT(!_pHCFolder->_uViewType);
  428.                 if (i >= MAX_ITEM_OPEN)
  429.                 {
  430.                     hres = S_FALSE;
  431.                     goto Done;
  432.                 }
  433.                 if (!IsLeaf(_pHCFolder->_foldertype))
  434.                 {
  435.                     LPITEMIDLIST pidlOpen;
  436.                     
  437.                     hres = S_FALSE;
  438.                     pidlOpen = ILCombine(_pHCFolder->_pidl,(LPITEMIDLIST)_ppcei[i]);
  439.                     if (pidlOpen)
  440.                     {
  441.                         IShellBrowser *psb = FileCabinet_GetIShellBrowser(_hwndOwner);
  442.                         if (psb)
  443.                         {
  444.                             psb->AddRef();
  445.                             psb->BrowseObject(pidlOpen, 
  446.                                         (i==_cItems-1) ? SBSP_DEFBROWSER:SBSP_NEWBROWSER);
  447.                             psb->Release();
  448.                             hres = S_OK;
  449.                         }
  450.                         else
  451.                         {
  452.                             hres = _LaunchAppForPidl(pici->hwnd, pidlOpen);
  453.                         }
  454.                         ILFree(pidlOpen);
  455.                     }
  456.                 }
  457.                 else
  458.                 {
  459.                     if (!IsHistory(_pHCFolder->_foldertype) && 
  460.                         (CEI_CACHEENTRYTYPE(_ppcei[i]) & COOKIE_CACHE_ENTRY))
  461.                     {
  462.                         ASSERT(PathFindExtension(CEI_LOCALFILENAME(_ppcei[i])) && 
  463.                             !StrCmpI(PathFindExtension(CEI_LOCALFILENAME(_ppcei[i])),TEXT(".txt")));
  464.                         hres = _LaunchApp(pici->hwnd, CEI_LOCALFILENAME(_ppcei[i]));
  465.                     }
  466.                     else
  467.                     {
  468.                         TCHAR szDecoded[MAX_URL_STRING];
  469.                         ConditionallyDecodeUTF8(_GetUrl(i), szDecoded, ARRAYSIZE(szDecoded));
  470.                         hres = _LaunchApp(pici->hwnd, szDecoded);
  471.                     }
  472.                 }
  473.                 break;
  474.             case RSVIDM_ADDTOFAVORITES:
  475.                 hres = _AddToFavorites(i);
  476.                 goto Done;
  477.             case RSVIDM_OPEN_NEWWINDOW:
  478.                 {
  479.                     TCHAR szDecoded[MAX_URL_STRING];
  480.                     ConditionallyDecodeUTF8(_GetUrl(i), szDecoded, ARRAYSIZE(szDecoded));
  481.                     LPWSTR pwszTarget;
  482.                     
  483.                     if (SUCCEEDED((hres = SHStrDup(szDecoded, &pwszTarget)))) {
  484.                         hres = NavToUrlUsingIEW(pwszTarget, TRUE);
  485.                         CoTaskMemFree(pwszTarget);
  486.                     }
  487.                     goto Done;
  488.                 }
  489.             case RSVIDM_COPY:
  490.                 if (!_pHCFolder->_IsLeaf())
  491.                 {
  492.                     hres = E_FAIL;
  493.                 }
  494.                 else
  495.                 {
  496.                     OleSetClipboard((IDataObject *)this);
  497.                 }
  498.                 goto Done;
  499.             case RSVIDM_DELCACHE:
  500.                 ASSERT(!_pHCFolder->_uViewType);                
  501.                 if (IsHistory(_pHCFolder->_foldertype))
  502.                 {
  503.                     hres = E_FAIL;
  504.                 }
  505.                 else
  506.                 {
  507.                     // pop warning msg for cookie only once
  508.                     if ((CEI_CACHEENTRYTYPE(_ppcei[i]) & COOKIE_CACHE_ENTRY) &&     
  509.                         (_dwDelCookie == DEL_COOKIE_WARN ))
  510.                     {
  511.                         if(CachevuWarningDlg(_ppcei[i], IDS_WARN_DELETE_CACHE, pici->hwnd))
  512.                             _dwDelCookie = DEL_COOKIE_YES;
  513.                         else
  514.                             _dwDelCookie = DEL_COOKIE_NO;
  515.                     }
  516.                     if ((CEI_CACHEENTRYTYPE(_ppcei[i]) & COOKIE_CACHE_ENTRY) &&     
  517.                         (_dwDelCookie == DEL_COOKIE_NO ))
  518.                         continue;
  519.               
  520.                     if (DeleteUrlCacheEntry(HCPidlToSourceUrl((LPCITEMIDLIST)_ppcei[i])))
  521.                     {
  522.                         if (!fBulkDelete)
  523.                         {
  524.                             _GenerateEvent(SHCNE_DELETE, _pHCFolder->_pidl, (LPITEMIDLIST)(_ppcei[i]), NULL);
  525.                         }
  526.                         fMustFlushNotify = TRUE;
  527.                     }
  528.                     else 
  529.                         hres = E_FAIL;
  530.                 }
  531.                 break;
  532.             case RSVIDM_PROPERTIES:
  533.                 // NOTE: We'll probably want to split this into two cases
  534.                 // and call a function in each case
  535.                 //
  536.                 if (IsLeaf(_pHCFolder->_foldertype))
  537.                 {
  538.                     if (IsHistory(_pHCFolder->_foldertype)) {
  539.                         // this was a bug in IE4, too:
  540.                         //   the pidl is re-created so that it has the most up-to-date information
  541.                         //   possible -- this way we can avoid assuming that the NSC has cached the
  542.                         //   most up-to-date pidl (which, in most cases, it hasn't)
  543.                         LPHEIPIDL pidlTemp =
  544.                             _pHCFolder->_CreateHCacheFolderPidlFromUrl(FALSE,
  545.                                                                        HCPidlToSourceUrl((LPITEMIDLIST)_ppcei[i]));
  546.                         if (pidlTemp) {
  547.                             _CreatePropSheet(pici->hwnd, (LPCEIPIDL)pidlTemp,
  548.                                              DLG_HISTITEMPROP, HistItem_PropDlgProc);
  549.                             LocalFree(pidlTemp);
  550.                         }
  551.                     }
  552.                     else
  553.                         _CreatePropSheet(pici->hwnd, _ppcei[i], DLG_CACHEITEMPROP, CacheItem_PropDlgProc);
  554.                 }
  555.                 else
  556.                 {
  557.                     hres = E_FAIL;
  558.                 }
  559.                 goto Done;
  560.             default:
  561.                 hres = E_FAIL;
  562.                 break;
  563.             }
  564.             
  565.             ASSERT(SUCCEEDED(hres));
  566.             if (FAILED(hres))
  567.                 TraceMsg(DM_HSFOLDER, "Cachevu failed the command at: %s", HCPidlToSourceUrl((LPCITEMIDLIST)_ppcei[i]));
  568.         }
  569.     }
  570. Done:
  571.     if (fMustFlushNotify)
  572.     {
  573.         if (fBulkDelete)
  574.         {
  575.             ASSERT(!_pHCFolder->_uViewType);
  576.             _GenerateEvent(SHCNE_UPDATEDIR, _pHCFolder->_pidl, NULL, NULL);
  577.         }
  578.         SHChangeNotifyHandleEvents();
  579.     }
  580.     return hres;
  581. }
  582. STDMETHODIMP CHistCacheItem::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved,
  583.                                 LPSTR pszName, UINT cchMax)
  584. {
  585.     HRESULT hres = E_FAIL;
  586.     TraceMsg(DM_HSFOLDER, "hci - cm - GetCommandString() called.");
  587.     if ((uFlags == GCS_VERBA) || (uFlags == GCS_VERBW))
  588.     {
  589.         LPCSTR pszSrc = NULL;
  590.         switch(idCmd)
  591.         {
  592.             case RSVIDM_OPEN:
  593.                 pszSrc = c_szOpen;
  594.                 break;
  595.             case RSVIDM_COPY:
  596.                 pszSrc = c_szCopy;
  597.                 break;
  598.             case RSVIDM_DELCACHE:
  599.                 pszSrc = c_szDelcache;
  600.                 break;
  601.             case RSVIDM_PROPERTIES:
  602.                 pszSrc = c_szProperties;
  603.                 break;
  604.         }
  605.         
  606.         if (pszSrc)
  607.         {
  608.             if (uFlags == GCS_VERBA)
  609.                 StrCpyNA(pszName, pszSrc, cchMax);
  610.             else if (uFlags == GCS_VERBW) // GCS_VERB === GCS_VERBW
  611.                 SHAnsiToUnicode(pszSrc, (LPWSTR)pszName, cchMax);
  612.             else
  613.                 ASSERT(0);
  614.             hres = S_OK;
  615.         }
  616.     }
  617.     
  618.     else if (uFlags == GCS_HELPTEXTA || uFlags == GCS_HELPTEXTW)
  619.     {
  620.         switch(idCmd)
  621.         {
  622.             case RSVIDM_OPEN:
  623.             case RSVIDM_COPY:
  624.             case RSVIDM_DELCACHE:
  625.             case RSVIDM_PROPERTIES:
  626.                 if (uFlags == GCS_HELPTEXTA)
  627.                 {
  628.                     MLLoadStringA(IDS_SB_FIRST+ (UINT)idCmd, pszName, cchMax);
  629.                 }
  630.                 else
  631.                 {
  632.                     MLLoadStringW(IDS_SB_FIRST+ (UINT)idCmd, (LPWSTR)pszName, cchMax);
  633.                 }
  634.                 hres = NOERROR;
  635.                 break;
  636.             default:
  637.                 break;
  638.         }
  639.     }
  640.     return hres;
  641. }
  642. //////////////////////////////////
  643. //
  644. // IDataObject Methods...
  645. //
  646. HRESULT CHistCacheItem::GetData(LPFORMATETC pFEIn, LPSTGMEDIUM pSTM)
  647. {
  648.     HRESULT hres;
  649. #ifdef DEBUG
  650.     TCHAR szName[64];
  651.     if (!GetClipboardFormatName(pFEIn->cfFormat, szName, sizeof(szName)))
  652.         wnsprintf(szName, ARRAYSIZE(szName), TEXT("#%d"), pFEIn->cfFormat);
  653.     TraceMsg(DM_HSFOLDER, "hci - do - GetData(%s)", szName);
  654. #endif
  655.     pSTM->hGlobal = NULL;
  656.     pSTM->pUnkForRelease = NULL;
  657.     if (IsHistory(_pHCFolder->_foldertype))
  658.     {
  659.         if ((pFEIn->cfFormat == g_cfFileDescW) && (pFEIn->tymed & TYMED_HGLOBAL))
  660.             hres = _CreateFileDescriptorW(pSTM);
  661.         else if ((pFEIn->cfFormat == g_cfFileDescA) && (pFEIn->tymed & TYMED_HGLOBAL))
  662.             hres = _CreateFileDescriptorA(pSTM);
  663.         else if ((pFEIn->cfFormat == g_cfFileContents) && (pFEIn->tymed & TYMED_ISTREAM))
  664.             hres = _CreateFileContents(pSTM, pFEIn->lindex);
  665.         else if (pFEIn->cfFormat == CF_UNICODETEXT && (pFEIn->tymed & TYMED_HGLOBAL))
  666.             hres = _CreateUnicodeTEXT(pSTM);
  667.         else if (pFEIn->cfFormat == CF_TEXT && (pFEIn->tymed & TYMED_HGLOBAL))
  668.             hres = _CreateHTEXT(pSTM);
  669.         else if (pFEIn->cfFormat == g_cfURL && (pFEIn->tymed & TYMED_HGLOBAL))
  670.             hres = _CreateURL(pSTM);
  671.         else if ((pFEIn->cfFormat == g_cfPreferedEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
  672.             hres = _CreatePrefDropEffect(pSTM);
  673.    
  674.         else
  675.             hres = DATA_E_FORMATETC;
  676.     }
  677.     else
  678.     {   
  679.         if (pFEIn->cfFormat == CF_HDROP && (pFEIn->tymed & TYMED_HGLOBAL))
  680.             hres = _CreateHDROP(pSTM);
  681.         else if ((pFEIn->cfFormat == g_cfPreferedEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
  682.             hres = _CreatePrefDropEffect(pSTM);
  683.    
  684.         else
  685.             hres = DATA_E_FORMATETC;
  686.     }
  687.     
  688.     return hres;
  689. }
  690. HRESULT CHistCacheItem::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  691. {
  692.     TraceMsg(DM_HSFOLDER, "hci - do - GetDataHere() called.");
  693.     return E_NOTIMPL;
  694. }
  695. HRESULT CHistCacheItem::QueryGetData(LPFORMATETC pFEIn)
  696. {
  697. #ifdef DEBUG
  698.     TCHAR szName[64];
  699.     if (!GetClipboardFormatName(pFEIn->cfFormat, szName, sizeof(szName)))
  700.         wnsprintf(szName, ARRAYSIZE(szName), TEXT("#%d"), pFEIn->cfFormat);
  701.     TraceMsg(DM_HSFOLDER, "hci - do - QueryGetData(%s)", szName);
  702. #endif
  703.     if (IsHistory(_pHCFolder->_foldertype))
  704.     {
  705.         if (pFEIn->cfFormat == g_cfFileDescW ||
  706.             pFEIn->cfFormat == g_cfFileDescA ||
  707.             pFEIn->cfFormat == g_cfFileContents   ||
  708.             pFEIn->cfFormat == g_cfURL            ||
  709.             pFEIn->cfFormat == CF_UNICODETEXT     ||
  710.             pFEIn->cfFormat == CF_TEXT            ||
  711.             pFEIn->cfFormat == g_cfPreferedEffect)
  712.         {
  713.             TraceMsg(DM_HSFOLDER, "    format supported.");
  714.             return NOERROR;
  715.         }
  716.     }
  717.     else
  718.     {
  719.         if (pFEIn->cfFormat == CF_HDROP            || 
  720.             pFEIn->cfFormat == g_cfPreferedEffect)
  721.         {
  722.             TraceMsg(DM_HSFOLDER, "    format supported.");
  723.             return NOERROR;
  724.         }
  725.     }
  726.     
  727.     return S_FALSE;
  728. }
  729. HRESULT CHistCacheItem::GetCanonicalFormatEtc(LPFORMATETC pFEIn, LPFORMATETC pFEOut)
  730. {
  731.     TraceMsg(DM_HSFOLDER, "hci - do - GetCanonicalFormatEtc() called.");
  732.     return DATA_S_SAMEFORMATETC;
  733. }
  734. HRESULT CHistCacheItem::SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease)
  735. {
  736.     TraceMsg(DM_HSFOLDER, "hci - do - SetData() called.");
  737.     return E_NOTIMPL;
  738. }
  739. HRESULT CHistCacheItem::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC *ppEnum)
  740. {
  741.     if (IsHistory(_pHCFolder->_foldertype))
  742.     {
  743.         FORMATETC Histfmte[] = {
  744.             {g_cfFileDescW,      NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  745.             {g_cfFileDescA,      NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  746.             {g_cfFileContents,   NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM },
  747.             {g_cfURL,            NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  748.             {CF_UNICODETEXT,     NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  749.             {CF_TEXT,            NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  750.             {g_cfPreferedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  751.         };
  752.         return SHCreateStdEnumFmtEtc(ARRAYSIZE(Histfmte), Histfmte, ppEnum);
  753.     }
  754.     else
  755.     {
  756.         FORMATETC Cachefmte[] = {
  757.             {CF_HDROP,                NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  758.             {g_cfPreferedEffect,      NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  759.         };
  760.         return SHCreateStdEnumFmtEtc(ARRAYSIZE(Cachefmte), Cachefmte, ppEnum);
  761.     }
  762. }
  763. HRESULT CHistCacheItem::DAdvise(LPFORMATETC pFE, DWORD grfAdv, LPADVISESINK pAdvSink, DWORD *pdwConnection)
  764. {
  765.     return OLE_E_ADVISENOTSUPPORTED;
  766. }
  767. HRESULT CHistCacheItem::DUnadvise(DWORD dwConnection)
  768. {
  769.     return OLE_E_ADVISENOTSUPPORTED;
  770. }
  771. HRESULT CHistCacheItem::EnumDAdvise(LPENUMSTATDATA *ppEnum)
  772. {
  773.     return OLE_E_ADVISENOTSUPPORTED;
  774. }
  775. //////////////////////////////////////////////////////////////////////////////
  776. //
  777. // Helper Routines
  778. //
  779. //////////////////////////////////////////////////////////////////////////////
  780. INT_PTR CALLBACK HistItem_PropDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  781. {
  782.     LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE) GetWindowLongPtr(hDlg, DWLP_USER);
  783.     LPHEIPIDL phei = lpPropSheet ? (LPHEIPIDL)lpPropSheet->lParam : NULL;
  784.     switch(message) {
  785.         case WM_INITDIALOG:
  786.         {
  787.             SHFILEINFO sfi;
  788.             TCHAR szBuf[80];
  789.             TCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
  790.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  791.             phei = (LPHEIPIDL)((LPPROPSHEETPAGE)lParam)->lParam;
  792.             SHGetFileInfo(TEXT(".url"), 0, &sfi, SIZEOF(sfi), SHGFI_ICON |
  793.                 SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
  794.             SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_SETICON, (WPARAM)sfi.hIcon, 0);
  795.             
  796.             _GetURLTitleForDisplay((LPCEIPIDL)phei, szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  797.             SetDlgItemText(hDlg, IDD_TITLE, szDisplayUrl);
  798.             
  799.             SetDlgItemText(hDlg, IDD_FILETYPE, sfi.szTypeName);
  800.             
  801.             ConditionallyDecodeUTF8(_GetUrlForPidl((LPCITEMIDLIST)phei), szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  802.             SetDlgItemText(hDlg, IDD_INTERNET_ADDRESS, szDisplayUrl);
  803.             
  804.             FileTimeToDateTimeStringInternal(&phei->ftLastVisited, szBuf, ARRAYSIZE(szBuf), FALSE);
  805.             SetDlgItemText(hDlg, IDD_LAST_VISITED, szBuf);
  806.             // It looks like the hitcount is double what it is supposed to be
  807.             //  (ie - navigate to a site and hitcount += 2)
  808.             // For now, we'll just half the hitcount before we display it:
  809.             wnsprintf(szBuf, ARRAYSIZE(szBuf), TEXT("%d"), (phei->dwNumHits)/2) ;
  810.             SetDlgItemText(hDlg, IDD_NUMHITS, szBuf);
  811.             break;            
  812.         }
  813.         
  814.         
  815.         case WM_DESTROY:
  816.             {
  817.                 HICON hIcon = (HICON)SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_GETICON, 0, 0);
  818.                 if (hIcon)
  819.                     DestroyIcon(hIcon);
  820.             }
  821.             break;
  822.         case WM_COMMAND:
  823.         case WM_HELP:
  824.         case WM_CONTEXTMENU:
  825.             // user can't change anything, so we don't care about any messages
  826.             break;
  827.         default:
  828.             return FALSE;
  829.             
  830.     } // end of switch
  831.     
  832.     return TRUE;
  833. }
  834. INT_PTR CALLBACK CacheItem_PropDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  835. {
  836.     LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE) GetWindowLongPtr(hDlg, DWLP_USER);
  837.     LPCEIPIDL pcei = lpPropSheet ? (LPCEIPIDL)lpPropSheet->lParam : NULL;
  838.     switch(message) {
  839.         case WM_INITDIALOG: {
  840.             SHFILEINFO sfi;
  841.             TCHAR szBuf[80];
  842.             
  843.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  844.             pcei = (LPCEIPIDL)((LPPROPSHEETPAGE)lParam)->lParam;
  845.             // get the icon and file type strings
  846.             SHGetFileInfo(CEI_LOCALFILENAME(pcei), 0, &sfi, SIZEOF(sfi), SHGFI_ICON | SHGFI_TYPENAME);
  847.             SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_SETICON, (WPARAM)sfi.hIcon, 0);
  848.             // set the info strings
  849.             SetDlgItemText(hDlg, IDD_HSFURL, HCPidlToSourceUrl((LPCITEMIDLIST)pcei));
  850.             SetDlgItemText(hDlg, IDD_FILETYPE, sfi.szTypeName);
  851.             SetDlgItemText(hDlg, IDD_FILESIZE, StrFormatByteSize(pcei->cei.dwSizeLow, szBuf, ARRAYSIZE(szBuf)));
  852.             SetDlgItemText(hDlg, IDD_CACHE_NAME, PathFindFileName(CEI_LOCALFILENAME(pcei)));
  853.             FileTimeToDateTimeStringInternal(&pcei->cei.ExpireTime, szBuf, ARRAYSIZE(szBuf), FALSE);
  854.             SetDlgItemText(hDlg, IDD_EXPIRES, szBuf);
  855.             FileTimeToDateTimeStringInternal(&pcei->cei.LastModifiedTime, szBuf, ARRAYSIZE(szBuf), FALSE);
  856.             SetDlgItemText(hDlg, IDD_LAST_MODIFIED, szBuf);
  857.             FileTimeToDateTimeStringInternal(&pcei->cei.LastAccessTime, szBuf, ARRAYSIZE(szBuf), FALSE);
  858.             SetDlgItemText(hDlg, IDD_LAST_ACCESSED, szBuf);
  859.             
  860.             break;
  861.         }
  862.         case WM_DESTROY:
  863.             {
  864.                 HICON hIcon = (HICON)SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_GETICON, 0, 0);
  865.                 if (hIcon)
  866.                     DestroyIcon(hIcon);
  867.             }
  868.             break;
  869.         case WM_COMMAND:
  870.         case WM_HELP:
  871.         case WM_CONTEXTMENU:
  872.             // user can't change anything, so we don't care about any messages
  873.             break;
  874.         default:
  875.             return FALSE;
  876.             
  877.     } // end of switch
  878.     
  879.     return TRUE;
  880. }
  881. HRESULT CHistCacheItem::_CreateFileDescriptorA(LPSTGMEDIUM pSTM)
  882. {
  883.     
  884.     pSTM->tymed = TYMED_HGLOBAL;
  885.     pSTM->pUnkForRelease = NULL;
  886.     FILEGROUPDESCRIPTORA *pfgd = (FILEGROUPDESCRIPTORA*)GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTORA) + (_cItems-1) * sizeof(FILEDESCRIPTORA));
  887.     if (pfgd == NULL)
  888.     {
  889.         TraceMsg(DM_HSFOLDER, "hci -   Couldn't alloc file descriptor");
  890.         return E_OUTOFMEMORY;
  891.     }
  892.     
  893.     pfgd->cItems = _cItems;     // set the number of items
  894.     for (UINT i = 0; i < _cItems; i++)
  895.     {
  896.         FILEDESCRIPTORA *pfd = &(pfgd->fgd[i]);
  897.         UINT cchFilename;
  898.         
  899.         SHTCharToAnsi(_GetURLTitle(_ppcei[i]), pfd->cFileName, ARRAYSIZE(pfd->cFileName) );
  900.         
  901.         MakeLegalFilenameA(pfd->cFileName);
  902.         cchFilename = lstrlenA(pfd->cFileName);
  903.         SHTCharToAnsi(L".URL", pfd->cFileName+cchFilename, ARRAYSIZE(pfd->cFileName)-cchFilename);
  904.     }
  905.     pSTM->hGlobal = pfgd;
  906.     
  907.     return S_OK;
  908. }
  909.     
  910. HRESULT CHistCacheItem::_CreateFileDescriptorW(LPSTGMEDIUM pSTM)
  911. {
  912.     
  913.     pSTM->tymed = TYMED_HGLOBAL;
  914.     pSTM->pUnkForRelease = NULL;
  915.     
  916.     FILEGROUPDESCRIPTORW *pfgd = (FILEGROUPDESCRIPTORW*)GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTORW) + (_cItems-1) * sizeof(FILEDESCRIPTORW));
  917.     if (pfgd == NULL)
  918.     {
  919.         TraceMsg(DM_HSFOLDER, "hci -   Couldn't alloc file descriptor");
  920.         return E_OUTOFMEMORY;
  921.     }
  922.     
  923.     pfgd->cItems = _cItems;     // set the number of items
  924.     for (UINT i = 0; i < _cItems; i++)
  925.     {
  926.         FILEDESCRIPTORW *pfd = &(pfgd->fgd[i]);
  927.         
  928.         _GetURLTitleForDisplay(_ppcei[i], pfd->cFileName, ARRAYSIZE(pfd->cFileName));
  929.         
  930.         MakeLegalFilenameW(pfd->cFileName);
  931.         UINT cchFilename = lstrlenW(pfd->cFileName);
  932.         SHTCharToUnicode(L".URL", pfd->cFileName+cchFilename, ARRAYSIZE(pfd->cFileName)-cchFilename);
  933.     }
  934.     pSTM->hGlobal = pfgd;
  935.     
  936.     return S_OK;
  937. }
  938. // this format is explicitly ANSI, hence no TCHAR stuff
  939. HRESULT CHistCacheItem::_CreateURL(LPSTGMEDIUM pSTM)
  940. {
  941.     DWORD cchSize;
  942.     LPCTSTR pszURL = _StripHistoryUrlToUrl(HCPidlToSourceUrl((LPCITEMIDLIST)_ppcei[0]));
  943.     if (!pszURL)
  944.         return E_FAIL;
  945.     
  946.     // render the url
  947.     cchSize = lstrlen(pszURL) + 1;
  948.     pSTM->tymed = TYMED_HGLOBAL;
  949.     pSTM->pUnkForRelease = NULL;
  950.     pSTM->hGlobal = GlobalAlloc(GPTR, cchSize * sizeof(CHAR));
  951.     if (pSTM->hGlobal)
  952.     {
  953.         TCharToAnsi(pszURL, (LPSTR)pSTM->hGlobal, cchSize);
  954.         return S_OK;
  955.     }
  956.     return E_OUTOFMEMORY;
  957. }
  958. HRESULT CHistCacheItem::_CreatePrefDropEffect(LPSTGMEDIUM pSTM)
  959. {
  960.     ASSERT(!_pHCFolder->_uViewType);    
  961.     pSTM->tymed = TYMED_HGLOBAL;
  962.     pSTM->pUnkForRelease = NULL;
  963.     
  964.     pSTM->hGlobal = GlobalAlloc(GPTR, sizeof(DWORD));
  965.     if (pSTM->hGlobal)
  966.     {
  967.         *((LPDWORD)pSTM->hGlobal) = DROPEFFECT_COPY;
  968.         return S_OK;
  969.     }
  970.     return E_OUTOFMEMORY;    
  971. }
  972. HRESULT CHistCacheItem::_CreateFileContents(LPSTGMEDIUM pSTM, LONG lindex)
  973. {
  974.     HRESULT hr;
  975.     
  976.     // make sure the index is in a valid range.
  977.     ASSERT((unsigned)lindex < _cItems);
  978.     ASSERT(lindex >= 0);
  979.     // here's a partial fix for when ole sometimes passes in -1 for lindex
  980.     if (lindex == -1)
  981.     {
  982.         if (_cItems == 1)
  983.             lindex = 0;
  984.         else
  985.             return E_FAIL;
  986.     }
  987.     
  988.     pSTM->tymed = TYMED_ISTREAM;
  989.     pSTM->pUnkForRelease = NULL;
  990.     
  991.     hr = CreateStreamOnHGlobal(NULL, TRUE, &pSTM->pstm);
  992.     if (SUCCEEDED(hr))
  993.     {
  994.         LARGE_INTEGER li = {0L, 0L};
  995.         IUniformResourceLocator *purl;
  996.      hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  997.         IID_IUniformResourceLocator, (void **)&purl);
  998.         if (SUCCEEDED(hr))
  999.         {
  1000.             TCHAR szDecoded[MAX_URL_STRING];
  1001.             ConditionallyDecodeUTF8(_GetUrlForPidl((LPCITEMIDLIST)_ppcei[lindex]), 
  1002.                 szDecoded, ARRAYSIZE(szDecoded));
  1003.             hr = purl->SetURL(szDecoded, TRUE);
  1004.             if (SUCCEEDED(hr))
  1005.             {
  1006.                 IPersistStream *pps;
  1007.                 hr = purl->QueryInterface(IID_IPersistStream, (LPVOID *)&pps);
  1008.                 if (SUCCEEDED(hr))
  1009.                 {
  1010.                     hr = pps->Save(pSTM->pstm, TRUE);
  1011.                     pps->Release();
  1012.                 }
  1013.             }
  1014.             purl->Release();
  1015.         }               
  1016.         pSTM->pstm->Seek(li, STREAM_SEEK_SET, NULL);
  1017.     }
  1018.     return hr;
  1019. }
  1020. HRESULT CHistCacheItem::_CreateHTEXT(LPSTGMEDIUM pSTM)
  1021. {
  1022.     UINT i;
  1023.     UINT cbAlloc = sizeof(TCHAR);        // null terminator
  1024.     TCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
  1025.     
  1026.     for (i = 0; i < _cItems; i++)
  1027.     {
  1028.         LPCTSTR pszUrl = _GetDisplayUrlForPidl((LPCITEMIDLIST)_ppcei[i], szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  1029.         if (!pszUrl)
  1030.             return E_FAIL;
  1031.         char szAnsiUrl[MAX_URL_STRING];
  1032.         TCharToAnsi(pszUrl, szAnsiUrl, ARRAYSIZE(szAnsiUrl));
  1033.         // 2 extra for carriage return and newline
  1034.         cbAlloc += sizeof(CHAR) * (lstrlenA(szAnsiUrl) + 2);  
  1035.     }
  1036.     // render the url
  1037.     
  1038.     pSTM->tymed = TYMED_HGLOBAL;
  1039.     pSTM->pUnkForRelease = NULL;
  1040.     pSTM->hGlobal = GlobalAlloc(GPTR, cbAlloc);
  1041.     if (pSTM->hGlobal)
  1042.     {
  1043.         LPSTR  pszHTEXT = (LPSTR)pSTM->hGlobal;
  1044.         int    cchHTEXT = cbAlloc / sizeof(CHAR);
  1045.         for (i = 0; i < _cItems; i++)
  1046.         {
  1047.             if (i && cchHTEXT > 2)
  1048.             {
  1049.                 *pszHTEXT++ = 0xD;
  1050.                 *pszHTEXT++ = 0xA;
  1051.                 cchHTEXT -= 2;
  1052.             }
  1053.             LPCTSTR pszUrl = _GetDisplayUrlForPidl((LPCITEMIDLIST)_ppcei[i], szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  1054.             int     cchUrl = lstrlen(pszUrl);
  1055.             TCharToAnsi(pszUrl, pszHTEXT, cchHTEXT);
  1056.             pszHTEXT += cchUrl;
  1057.             cchHTEXT -= cchUrl;
  1058.         }
  1059.         return S_OK;
  1060.     }
  1061.     return E_OUTOFMEMORY;
  1062. }
  1063. HRESULT CHistCacheItem::_CreateUnicodeTEXT(LPSTGMEDIUM pSTM)
  1064. {
  1065.     UINT i;
  1066.     UINT cbAlloc = sizeof(WCHAR);        // null terminator
  1067.     WCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
  1068.     for (i = 0; i < _cItems; i++)
  1069.     {
  1070.         ConditionallyDecodeUTF8(_GetUrlForPidl((LPCITEMIDLIST)_ppcei[i]), 
  1071.             szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  1072.         if (!*szDisplayUrl)
  1073.             return E_FAIL;
  1074.         cbAlloc += sizeof(WCHAR) * (lstrlenW(szDisplayUrl) + 2);
  1075.     }
  1076.     // render the url
  1077.     
  1078.     pSTM->tymed = TYMED_HGLOBAL;
  1079.     pSTM->pUnkForRelease = NULL;
  1080.     pSTM->hGlobal = GlobalAlloc(GPTR, cbAlloc);
  1081.     if (pSTM->hGlobal)
  1082.     {
  1083.         LPTSTR pszHTEXT = (LPTSTR)pSTM->hGlobal;
  1084.         int    cchHTEXT = cbAlloc / sizeof(WCHAR);
  1085.         for (i = 0; i < _cItems; i++)
  1086.         {
  1087.             if (i && cchHTEXT > 2)
  1088.             {
  1089.                 *pszHTEXT++ = 0xD;
  1090.                 *pszHTEXT++ = 0xA;
  1091.                 cchHTEXT -= 2;
  1092.             }
  1093.             ConditionallyDecodeUTF8(_GetUrlForPidl((LPCITEMIDLIST)_ppcei[i]), 
  1094.                 szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  1095.             int     cchUrl = lstrlenW(szDisplayUrl);
  1096.             StrCpyN(pszHTEXT, szDisplayUrl, cchHTEXT);
  1097.             pszHTEXT += cchUrl;
  1098.             cchHTEXT -= cchUrl;
  1099.         }
  1100.         return S_OK;
  1101.     }
  1102.     return E_OUTOFMEMORY;
  1103. }
  1104. // use CEI_LOCALFILENAME to get the file name for the HDROP, but map that
  1105. // to the final file name (store in the file system) through the "FileNameMap"
  1106. // data which uses _GetURLTitle() as the final name of the file.
  1107. HRESULT CHistCacheItem::_CreateHDROP(STGMEDIUM *pmedium)
  1108. {
  1109.     ASSERT(!_pHCFolder->_uViewType);
  1110.     UINT i;
  1111.     UINT cbAlloc = sizeof(DROPFILES) + sizeof(CHAR);        // header + null terminator
  1112.     for (i = 0; i < _cItems; i++)
  1113.     {
  1114.         char szAnsiUrl[MAX_URL_STRING];
  1115.         
  1116.         SHTCharToAnsi(CEI_LOCALFILENAME(_ppcei[i]), szAnsiUrl, ARRAYSIZE(szAnsiUrl));
  1117.         cbAlloc += sizeof(CHAR) * (lstrlenA(szAnsiUrl) + 1);
  1118.     }
  1119.     pmedium->tymed = TYMED_HGLOBAL;
  1120.     pmedium->pUnkForRelease = NULL;
  1121.     pmedium->hGlobal = GlobalAlloc(GPTR, cbAlloc);
  1122.     if (pmedium->hGlobal)
  1123.     {
  1124.         LPDROPFILES pdf = (LPDROPFILES)pmedium->hGlobal;
  1125.         LPSTR pszFiles  = (LPSTR)(pdf + 1);
  1126.         int   cchFiles  = (cbAlloc - sizeof(DROPFILES) - sizeof(CHAR));
  1127.         pdf->pFiles = sizeof(DROPFILES);
  1128.         pdf->fWide = FALSE;
  1129.         for (i = 0; i < _cItems; i++)
  1130.         {
  1131.             LPTSTR pszPath = CEI_LOCALFILENAME(_ppcei[i]);
  1132.             int    cchPath = lstrlen(pszPath);
  1133.             SHTCharToAnsi(pszPath, pszFiles, cchFiles);
  1134.             pszFiles += cchPath + 1;
  1135.             cchFiles -= cchPath + 1;
  1136.             ASSERT((UINT)((LPBYTE)pszFiles - (LPBYTE)pdf) < cbAlloc);
  1137.         }
  1138.         ASSERT((LPSTR)pdf + cbAlloc - 1 == pszFiles);
  1139.         ASSERT(*pszFiles == 0); // zero init alloc
  1140.         return NOERROR;
  1141.     }
  1142.     return E_OUTOFMEMORY;
  1143. }
  1144. //
  1145. // These routines make a string into a legal filename by replacing
  1146. // all invalid characters with spaces.
  1147. //
  1148. // The list of invalid characters was obtained from the NT error
  1149. // message you get when you try to rename a file to an invalid name.
  1150. //
  1151. #ifndef UNICODE
  1152. #error The MakeLegalFilename code only works when it's part of a UNICODE build
  1153. #endif
  1154. //
  1155. // This function takes a string and makes it into a
  1156. // valid filename (by calling PathCleanupSpec).
  1157. //
  1158. // The PathCleanupSpec function wants to know what
  1159. // directory the file will live in.  But it's going
  1160. // on the clipboard, so we don't know.  We just
  1161. // guess the desktop.
  1162. //
  1163. // It only uses this path to decide if the filesystem
  1164. // supports long filenames or not, and to check for
  1165. // MAX_PATH overflow.
  1166. //
  1167. void MakeLegalFilenameW(LPWSTR pszFilename)
  1168. {
  1169.     WCHAR szDesktopPath[MAX_PATH];
  1170.     GetWindowsDirectoryW(szDesktopPath,MAX_PATH);
  1171.     PathCleanupSpec(szDesktopPath,pszFilename);
  1172. }
  1173. //
  1174. // ANSI wrapper for above function
  1175. //
  1176. void MakeLegalFilenameA(LPSTR pszFilename)
  1177. {
  1178.     WCHAR szFilenameW[MAX_PATH];
  1179.     SHAnsiToUnicode(pszFilename, szFilenameW, MAX_PATH);
  1180.     MakeLegalFilenameW(szFilenameW);
  1181.     SHUnicodeToAnsi(szFilenameW, pszFilename, MAX_PATH);
  1182. }