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

Windows Kernel

Development Platform:

Visual C++

  1. #include "shellprv.h"
  2. #include "favorite.h"
  3. #include "ids.h"
  4. #include "views.h"
  5. #include "prop.h"           // COL_DATA
  6. // 
  7. // Columns
  8. //
  9. typedef enum
  10. {
  11.     ICOL_FAV_LASTVISIT = 0,
  12.     ICOL_FAV_LASTMOD,
  13.     ICOL_FAV_NUMVISITS,
  14.     ICOL_FAV_SPLAT,
  15. };
  16. const COL_DATA c_fav_cols[] = {
  17.     {ICOL_FAV_LASTVISIT,    IDS_FAV_COL_LAST_VISIT,     18, LVCFMT_LEFT,    &SCID_LASTVISITED},
  18.     {ICOL_FAV_LASTMOD,      IDS_FAV_COL_LAST_MOD,       18, LVCFMT_LEFT,    &SCID_LASTMODIFIED},
  19.     {ICOL_FAV_NUMVISITS,    IDS_FAV_COL_COUNT_VISIT,    10, LVCFMT_RIGHT,   &SCID_VISITCOUNT},
  20.     {ICOL_FAV_SPLAT,        IDS_FAV_COL_SPLAT,          25, LVCFMT_LEFT,    &SCID_STATUS}
  21. };
  22. //==========================================================================================
  23. // Class Definitions
  24. //==========================================================================================
  25. class CFavFolderViewCB;
  26. typedef struct _FavExtra
  27. {
  28.     LPITEMIDLIST pidl;      // The pidl the information belongs to
  29.     IPropertyStorage * ppropstgSite;
  30.     FILETIME     ftVisit;   // The last time we visited the site...
  31. } FAVEXTRA, * PFAVEXTRA;
  32. #define FavExtra_IsValidSite(pfe)   ((pfe) && (pfe->ppropstgSite))
  33. typedef struct  _FavDSA
  34. {
  35.     HWND        hwnd;       // the main hwnd for a view...
  36.     CFavFolderViewCB *pffvcb;   // Pointer to callback.
  37. } FAVDSA, *PFAVDSA;
  38. //
  39. // Definition of the IEnumSFVViews wrapper class
  40. //
  41. // Note this will delegate calls to the real UEnumSFVViews and will
  42. // add the thumbnail view on the end of the list
  43. HRESULT CFavViewEnum_Create( IEnumSFVViews * pDefEnum, IEnumSFVViews ** ppEnum );
  44. class CFavViewEnum : public IEnumSFVViews
  45. {
  46.     public:
  47.         // *** IUnknown methods ***
  48.         STDMETHOD(QueryInterface) (REFIID riid, void ** ppv);
  49.         STDMETHOD_(ULONG,AddRef) (THIS);
  50.         STDMETHOD_(ULONG,Release) (THIS);
  51.         // *** IEnumSFVViews methods ***
  52.         STDMETHOD(Next)(ULONG celt, SFVVIEWSDATA **ppData, ULONG *pceltFetched);
  53.         STDMETHOD(Skip)(ULONG celt);
  54.         STDMETHOD(Reset)();
  55.         STDMETHOD(Clone)(IEnumSFVViews **ppenum);
  56.         
  57.     protected:
  58.         CFavViewEnum( IEnumSFVViews * pEnum );
  59.         ~CFavViewEnum();
  60.         friend HRESULT CFavViewEnum_Create( IEnumSFVViews * pDefEnum, IEnumSFVViews ** ppEnum );
  61.         LONG m_cRef;
  62.         IEnumSFVViews * m_pesfvv;
  63.         int m_iAddView;
  64. };
  65. //
  66. // Definition of the Favorites class
  67. //
  68. //  Note this extension only works on Nashville shells, because it
  69. //  requires the fstree's new support for aggregation in IShellFolder.
  70. class CFavorites : public IShellFolder,
  71.                    public IPersistFolder2
  72. {
  73. public:
  74.     CFavorites();
  75.     ~CFavorites();
  76.     // IUnknown methods
  77.     
  78.     virtual STDMETHODIMP  QueryInterface(REFIID riid, void **ppv);
  79.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  80.     virtual STDMETHODIMP_(ULONG) Release(void);
  81.     
  82.     // IShellFolder methods
  83.     virtual STDMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  84.     virtual STDMETHODIMP EnumObjects(HWND hwndOwner, DWORD grfFlags, IEnumIDList ** ppenumIDList);
  85.     virtual STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  86.     virtual STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void ** ppv);
  87.     virtual STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  88.     virtual STDMETHODIMP CreateViewObject (HWND hwndOwner, REFIID riid, void **ppv);
  89.     virtual STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG * rgfInOut);
  90.     virtual STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, void **ppv);
  91.     virtual STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  92.     virtual STDMETHODIMP SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags, LPITEMIDLIST * ppidlOut);
  93.     // IPersist
  94.     virtual STDMETHODIMP GetClassID(LPCLSID lpClassID);
  95.     // IPersistFolder
  96.     virtual STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  97.     // IPersistFolder2
  98.     virtual STDMETHODIMP GetCurFolder(LPITEMIDLIST *pidl);
  99.     // This is Gross, but there is no clean way for example for the
  100.     // IContextMenu to Get to the IShellView or the callback... So add a
  101.     // register/unregister site and search function to get to it...
  102.     STDMETHODIMP_(BOOL) RegisterFolderViewCB(HWND, CFavFolderViewCB *);
  103.     STDMETHODIMP_(BOOL) UnRegisterFolderViewCB(HWND);
  104.     STDMETHODIMP_(CFavFolderViewCB *) QueryFolderViewCBFromHwnd(HWND);
  105.     // implemented here so we can get at it from both IShellDetails and from the view callback...
  106.     STDMETHOD(GetDetailsOf)(IShellDetails * psd, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails);
  107. protected:
  108.     friend class CFavFolderViewCB;
  109.     friend class CFavFolderContextMenu;
  110.     friend class CFavoritesDetails;
  111.     LONG            m_cRef;
  112.     LPITEMIDLIST    m_pidl;
  113.     IUnknown *      m_punkFSFolder;      // The inside unknown...
  114.     IShellFolder *  m_psfFSFolder;       // The underlying shell folder...
  115.     HDPA            m_hdpaExtra;         // The extra stuff
  116.     HDSA            m_hdsaFolderViewCBs; //
  117.     int             m_iFirstAddedCol;    // BUGBUG: per view data in the folder
  118.     
  119. private:
  120.     // Other methods
  121.     STDMETHODIMP_(PFAVEXTRA) GetPointerToExtraData(LPCITEMIDLIST);
  122.     STDMETHODIMP_(DWORD)    GetVisitCount(LPCITEMIDLIST);
  123.     STDMETHODIMP            GetSplatInfo(LPCITEMIDLIST);
  124.     STDMETHODIMP            GetStringProp(LPCITEMIDLIST pidl, PROPID propid, LPTSTR pszBuf, DWORD cchBuf);
  125.     STDMETHODIMP            GetFileTimePropStr(LPCITEMIDLIST pidl, PROPID propid, LPTSTR pszBuf, DWORD cchBuf);
  126.     STDMETHODIMP            GetFileTimeProp(LPCITEMIDLIST pidl, PROPID propid, LPFILETIME pft);
  127.     // Other Helper functions.
  128.     STDMETHODIMP_(void)     ClearCachedData(void);
  129.     STDMETHODIMP            OpenPropertyStorage(LPCITEMIDLIST pidl, PFAVEXTRA pfe);
  130. };
  131. HRESULT CFavoritesDetails_CreateInstance(CFavorites * pFav, IShellDetails ** ppv);
  132. // IshellDetails Favorties objects...
  133. class CFavoritesDetails : public IShellDetails
  134. {
  135.     public:
  136.         CFavoritesDetails( CFavorites * pFav, HRESULT * pHr );
  137.         
  138.         // *** IUnknown methods ***
  139.         STDMETHOD(QueryInterface)(REFIID riid, void ** ppv);
  140.         STDMETHOD_(ULONG,AddRef)();
  141.         STDMETHOD_(ULONG,Release)();
  142.         // IshellDetails
  143.         STDMETHOD(GetDetailsOf)(LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails);
  144.         STDMETHOD(ColumnClick)(UINT iColumn);
  145.     protected:
  146.         ~CFavoritesDetails();
  147.         IShellDetails * m_psdFolder;
  148.         CFavorites * m_pFav;
  149.         LONG m_cRef;
  150. };
  151. //
  152. // Definition of Favorites folder view callback
  153. //
  154. class CFavFolderViewCB : public IShellFolderViewCB
  155. {
  156. public:
  157.     friend class CFavFolderContextMenu;
  158.     CFavFolderViewCB(CFavorites *, IShellFolderView *);
  159.     ~CFavFolderViewCB();
  160.     STDMETHODIMP_(void) SetMainCB(IShellFolderViewCB *psfvcb);
  161.     // IUnknown methods
  162.     virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  163.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  164.     virtual STDMETHODIMP_(ULONG) Release(void);
  165.     
  166.     // IShellFolderViewCB methods
  167.     virtual STDMETHODIMP MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam);
  168. protected:
  169.     // Helper methods
  170.     STDMETHODIMP GetViews( SHELLVIEWID * pDefID, IEnumSFVViews ** ppEnum );
  171.     STDMETHODIMP GetDetailsOf(int iCol, DETAILSINFO * pdi);
  172.     STDMETHODIMP_(void) HandleMergeMenu(UINT, QCMINFO*);
  173.     LONG                m_cRef;
  174.     CFavorites *        m_pFav;
  175.     IShellFolderView *  m_psfv;
  176.     IShellFolderViewCB *m_psfvcb;   // The one we are trying to subclass
  177.     HWND                m_hwndMain;  // The main Window
  178.     UINT                m_idCmdFirstAdded;  // First Added command to main menu
  179.     IShellDetails     * m_psdFolder;
  180. };
  181. //
  182. // Definition of Favorites context menu handler class
  183. //
  184. class CFavFolderContextMenu : public IContextMenu3, IObjectWithSite
  185. {
  186. public:
  187.     // IUnknown
  188.     virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  189.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  190.     virtual STDMETHODIMP_(ULONG) Release(void);
  191.     
  192.     // IContextMenu
  193.     virtual STDMETHODIMP QueryContextMenu (HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast,  UINT uFlags);
  194.     virtual STDMETHODIMP InvokeCommand (LPCMINVOKECOMMANDINFO lpici);
  195.     virtual STDMETHODIMP GetCommandString (UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax);
  196.     // IContextMenu2
  197.     virtual STDMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
  198.     // IContextMenu3
  199.     virtual STDMETHODIMP HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
  200.     // IObjectWithSite
  201.     virtual STDMETHODIMP SetSite(IUnknown*);
  202.     virtual STDMETHODIMP GetSite(REFIID, void**);
  203.     friend HRESULT CFavFolderContextMenu_CreateInstance(CFavorites *pFav, HWND hwnd, REFIID riid, void **);
  204. private:
  205.     CFavFolderContextMenu(CFavorites *, HWND, HRESULT *);
  206.     ~CFavFolderContextMenu();
  207.     LONG            m_cRef;
  208.     HWND            m_hwndOwner;
  209.     CFavorites *    m_pFav;
  210.     IContextMenu2 * m_pcmInner;
  211.     UINT            m_idCmdFirst;
  212. };
  213. STDAPI CFavorites_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  214. {
  215.     HRESULT hres;
  216.     CFavorites* ptfld = new CFavorites();
  217.     if (ptfld) 
  218.     {
  219.         hres = ptfld->QueryInterface(riid, ppv);
  220.         ptfld->Release();
  221.     }
  222.     else
  223.     {
  224.         *ppv = NULL;
  225.         hres = E_OUTOFMEMORY;
  226.     }
  227.     return hres;
  228. }
  229. /*----------------------------------------------------------
  230. Purpose: Helper function to read a single propvariant from
  231.          the given property storage
  232. Returns: 
  233. Cond:    --
  234. */
  235. HRESULT ReadProp(IPropertyStorage * ppropstg, PROPID propid, PROPVARIANT *ppropvar)
  236. {
  237.     PROPSPEC prspec;
  238.     prspec.ulKind = PRSPEC_PROPID;
  239.     prspec.propid = propid;
  240.     return ppropstg->ReadMultiple(1, &prspec, ppropvar);
  241. }
  242. //==========================================================================================
  243. // CFavorites Implemention
  244. //==========================================================================================
  245. CFavorites::CFavorites(void) : m_cRef(1)
  246. {
  247.     DllAddRef();
  248.     m_pidl = NULL;
  249.     m_psfFSFolder = NULL;
  250.     m_punkFSFolder = NULL;
  251.     m_hdpaExtra = NULL;  // Create when we need it...
  252.     m_hdsaFolderViewCBs = NULL; // Created when needed...
  253.     m_iFirstAddedCol = -1;
  254. }
  255. CFavorites::~CFavorites(void)
  256. {
  257.     TraceMsg(TF_FAV_FULL, "CFavorites::~CFavorites called");
  258.     AddRef();    // Make sure it does not cycle back to us...
  259.     if (m_pidl)
  260.         ILFree(m_pidl);
  261.     if (m_punkFSFolder)
  262.         m_punkFSFolder->Release();
  263.     ClearCachedData();
  264.     if (m_hdsaFolderViewCBs)
  265.         DSA_Destroy(m_hdsaFolderViewCBs);
  266.     DllRelease();
  267. }
  268. STDMETHODIMP CFavorites::OpenPropertyStorage(LPCITEMIDLIST pidl, PFAVEXTRA pfe)
  269. {
  270.     IPropertySetStorage * ppropsetstg;
  271.     HRESULT hres = BindToStorage(pidl, NULL, IID_IPropertySetStorage,  (void **)&ppropsetstg);
  272.     if (SUCCEEDED(hres))
  273.     {
  274.         hres = ppropsetstg->Open(FMTID_InternetSite, STGM_READ, &pfe->ppropstgSite);
  275.         ppropsetstg->Release();
  276.     }
  277.     return hres;
  278. }
  279. STDMETHODIMP CFavorites::QueryInterface(REFIID riid, void **ppv)
  280. {
  281.     static const QITAB qit[] = {
  282.         QITABENT(CFavorites, IShellFolder), // IID_IShellFolder
  283.         QITABENT(CFavorites, IPersistFolder),   // IID_IPersistFolder
  284.         QITABENTMULTI(CFavorites, IPersist, IPersistFolder),    // IID_IPersistFolder
  285.         QITABENTMULTI(CFavorites, IPersist, IPersistFolder2),   // IID_IPersistFolder2
  286.         { 0 },
  287.     };
  288.     HRESULT hres = QISearch(this, qit, riid, ppv);
  289.     if (FAILED(hres) && m_punkFSFolder)
  290.         hres = m_punkFSFolder->QueryInterface(riid, ppv);
  291.     return hres;
  292. }
  293. STDMETHODIMP_(ULONG) CFavorites::AddRef(void)
  294. {
  295.     return InterlockedIncrement(&m_cRef);
  296. }
  297. STDMETHODIMP_(ULONG) CFavorites::Release()
  298. {
  299.     if (InterlockedDecrement(&m_cRef))
  300.         return m_cRef;
  301.     delete this;
  302.     return 0;
  303. }
  304. STDMETHODIMP CFavorites::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
  305. {
  306.     return m_psfFSFolder->ParseDisplayName(hwnd, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
  307. }
  308. STDMETHODIMP CFavorites::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenum)
  309. {
  310.     return m_psfFSFolder->EnumObjects(hwnd, grfFlags, ppenum);
  311. }
  312. STDMETHODIMP CFavorites::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  313. {
  314.     // Lets try to pick off Binds to IShellFolder and if it is a directory
  315.     // use our implementation...
  316.     HRESULT hr = m_psfFSFolder->BindToObject(pidl, pbc, riid, ppv);
  317.     if (SUCCEEDED(hr))
  318.     {
  319.         //
  320.         // make sure that all FS Folders are wrapped by us
  321.         // but only FS folders are wrapped.  all files or junctions
  322.         // should defer to the psfInner here.
  323.         //
  324.             
  325.         CLSID clsid;
  326.         if (SUCCEEDED(IUnknown_GetClassID((IUnknown *)*ppv, &clsid))
  327.         &&  IsEqualGUID(CLSID_ShellFSFolder, clsid))
  328.         {
  329.             IPersistFolder *ppf;
  330.             ((IUnknown *)*ppv)->Release();
  331.             *ppv = NULL;
  332.             
  333.             hr = CFavorites_CreateInstance(NULL, IID_IPersistFolder, (void **)&ppf);
  334.             if (SUCCEEDED(hr))
  335.             {   
  336.                 LPITEMIDLIST pidlFull;
  337.                 hr = SHILCombine(m_pidl, pidl, &pidlFull);
  338.                 if (SUCCEEDED(hr))
  339.                 {
  340.                     hr = ppf->Initialize(pidlFull);
  341.                     ILFree(pidlFull);
  342.                     if (SUCCEEDED(hr))
  343.                         hr= ppf->QueryInterface(riid, ppv);
  344.                 }
  345.                 ppf->Release();
  346.             }
  347.         }
  348.     }
  349.     return hr;
  350. }
  351. STDMETHODIMP CFavorites::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  352. {
  353.     return m_psfFSFolder->BindToStorage(pidl, pbc, riid, ppv);
  354. }
  355. #define ComparisonResult(a, b) 
  356.     ((a) < (b) ? ResultFromShort(-1) : 
  357.      (a) > (b) ? ResultFromShort(+1) : 
  358.                  ResultFromShort( 0))
  359. STDMETHODIMP CFavorites::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  360. {
  361.     PROPID pid;
  362.     if (m_iFirstAddedCol >= 0)
  363.     {
  364.         switch ((lParam & SHCIDS_COLUMNMASK) - m_iFirstAddedCol)
  365.         {
  366.         case ICOL_FAV_NUMVISITS:
  367.             {
  368.                 DWORD dwNumVisits1 = this->GetVisitCount(pidl1);
  369.                 DWORD dwNumVisits2 = this->GetVisitCount(pidl2);
  370.                 // macro, don't inline this
  371.                 HRESULT hres = ComparisonResult(dwNumVisits1, dwNumVisits2);
  372.                 if (hres)
  373.                     return hres;
  374.                 goto DefaultSort;
  375.             }
  376.             break;
  377.         case ICOL_FAV_LASTVISIT:
  378.             pid = PID_INTSITE_LASTVISIT;
  379.             goto FinishFileTime;
  380.         case ICOL_FAV_LASTMOD:
  381.             pid = PID_INTSITE_LASTMOD;
  382.         FinishFileTime:
  383.             {
  384.                 FILETIME ft1, ft2;
  385.                 if (SUCCEEDED(this->GetFileTimeProp(pidl1, pid, &ft1)) &&
  386.                     SUCCEEDED(this->GetFileTimeProp(pidl2, pid, &ft2)))
  387.                 {
  388.                     HRESULT hres = CompareFileTime(&ft1, &ft2);
  389.                     if (hres)
  390.                         return hres;
  391.                 }
  392.                 goto DefaultSort;
  393.             }
  394.         case ICOL_FAV_SPLAT:
  395.             {
  396.                 HRESULT hres1 = this->GetSplatInfo(pidl1);
  397.                 HRESULT hres2 = this->GetSplatInfo(pidl1);
  398.                 if (hres1 != hres2)
  399.                     return ComparisonResult(hres1, hres2);
  400.                 goto DefaultSort;
  401.             }
  402.         default:
  403.             // Some column we aren't in charge of - let the superclass do it
  404.             break;
  405.         }
  406.     }
  407. DefaultSort:
  408.     return m_psfFSFolder->CompareIDs(lParam, pidl1, pidl2);
  409. }
  410. #undef ComparisonResult
  411. STDMETHODIMP CFavorites::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  412. {
  413.     // override the implemention to allow us to add in our own columns...
  414.     if (IsEqualIID(riid, IID_IShellView))
  415.     {
  416.         HRESULT hres = m_psfFSFolder->CreateViewObject(hwnd, riid, ppv);
  417.         if (SUCCEEDED(hres))
  418.         {
  419.             IShellFolderView *psfv;
  420.             if (SUCCEEDED(((IUnknown *)*ppv)->QueryInterface(IID_IShellFolderView, (void **)&psfv)))
  421.             {
  422.                 IShellFolderViewCB *psfvcbWrap;
  423.                 CFavFolderViewCB *psfvcb = new CFavFolderViewCB(this, psfv);
  424.                 if (psfvcb)
  425.                 {
  426.                     if (SUCCEEDED(psfv->SetCallback(psfvcb, &psfvcbWrap)))
  427.                     {
  428.                         psfvcb->SetMainCB(psfvcbWrap);
  429.                         psfvcbWrap->Release();
  430.                     }
  431.                     psfvcb->Release();  // Release ownership
  432.                 }
  433.                 psfv->Release();
  434.             }
  435.         }
  436.         return hres;
  437.     }
  438.     else if (IsEqualIID(riid, IID_IContextMenu))
  439.     {
  440.         return CFavFolderContextMenu_CreateInstance(this, hwnd, riid, ppv);
  441.     }
  442.     else if (IsEqualIID(riid, IID_IShellDetails))
  443.     {
  444.         return CFavoritesDetails_CreateInstance(this, (IShellDetails **)ppv); 
  445.     }
  446.     return m_psfFSFolder->CreateViewObject(hwnd, riid, ppv);
  447. }
  448. STDMETHODIMP CFavorites::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut)
  449. {
  450.     return m_psfFSFolder->GetAttributesOf(cidl, apidl, rgfInOut);
  451. }
  452. STDMETHODIMP CFavorites::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl, 
  453.                                        REFIID riid, UINT * prgfInOut, void **ppv)
  454. {
  455.     return m_psfFSFolder->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  456. }
  457. STDMETHODIMP CFavorites::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  458. {
  459.     return m_psfFSFolder->GetDisplayNameOf(pidl, uFlags, lpName);
  460. }
  461. STDMETHODIMP CFavorites::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpszName, 
  462.                                    DWORD uFlags, LPITEMIDLIST *ppidlOut)
  463. {
  464.     return m_psfFSFolder->SetNameOf(hwndOwner, pidl, lpszName, uFlags, ppidlOut);
  465. }
  466. STDMETHODIMP CFavorites::GetClassID(IN LPCLSID lpClassID)
  467. {
  468.     *lpClassID = CLSID_FavoritesFolder;
  469.     return S_OK;
  470. }
  471. STDMETHODIMP CFavorites::Initialize(IN LPCITEMIDLIST pidl)
  472. {
  473.     m_pidl = ILClone(pidl);
  474.     if (!m_pidl)
  475.         return E_OUTOFMEMORY;
  476.     // Ok we need to get The Shell Folder for the underlying File system Folder...
  477.     IUnknown *punk;
  478.     HRESULT hres = QueryInterface(IID_IUnknown, (void **)&punk);
  479.     if (SUCCEEDED(hres))
  480.     {
  481.         hres = SHCoCreateInstance(NULL, &CLSID_ShellFSFolder, punk,
  482.                                   IID_IUnknown, (void **)&m_punkFSFolder);
  483.         punk->Release();
  484.     }
  485.     if (SUCCEEDED(hres))
  486.     {
  487.         hres = m_punkFSFolder->QueryInterface(IID_IShellFolder, (void **)&m_psfFSFolder);
  488.         if (SUCCEEDED(hres))
  489.         {
  490.             m_psfFSFolder->Release();    // We need to balance back out...
  491.         }
  492.         
  493.         IPersistFolder *pipf;
  494.         hres = m_punkFSFolder->QueryInterface(IID_IPersistFolder, (void **)&pipf);
  495.         if (SUCCEEDED(hres))
  496.         {
  497.             hres = pipf->Initialize(pidl);
  498.             pipf->Release();
  499.         }
  500.     }
  501.     TraceMsg(TF_FAV_FULL, "CFavorites::Initialize End");
  502.     return hres;
  503. }
  504. STDMETHODIMP CFavorites::GetCurFolder(LPITEMIDLIST *ppidl)
  505. {
  506.     return GetCurFolderImpl(m_pidl, ppidl);
  507. }
  508. int CALLBACK FavExtra_CompareIDs(void * pv1, void * pv2, LPARAM lParam)
  509. {
  510.     IShellFolder *psf = (IShellFolder *)lParam;
  511.     PFAVEXTRA pfehdr1 = (PFAVEXTRA)pv1;
  512.     PFAVEXTRA pfehdr2 = (PFAVEXTRA)pv2;
  513.     HRESULT hres = psf->CompareIDs(0, pfehdr1->pidl, pfehdr2->pidl);
  514.     ASSERT(SUCCEEDED(hres));
  515.     return (short)SCODE_CODE(hres);   // (the short cast is important!)
  516. }
  517. STDMETHODIMP_(BOOL) CFavorites::RegisterFolderViewCB(HWND hwnd, CFavFolderViewCB *pffvcb)
  518. {
  519.     BOOL bRet = TRUE;
  520.     FAVDSA favdsa;
  521.     TraceMsg(TF_FAV_FULL, "CFavorites::RegisterFolderViewCB h:%x p:%x", hwnd, pffvcb);
  522.     if (!m_hdsaFolderViewCBs)
  523.     {
  524.         m_hdsaFolderViewCBs = DSA_Create(sizeof(FAVDSA), 4);
  525.         if (!m_hdsaFolderViewCBs)
  526.             bRet = FALSE;
  527.     }
  528.     if (bRet)
  529.     {
  530.         // Check for any duplicates
  531.         int i = DSA_GetItemCount(m_hdsaFolderViewCBs);
  532.         while (--i >= 0)
  533.         {
  534.             PFAVDSA pfavdsa = (PFAVDSA)DSA_GetItemPtr(m_hdsaFolderViewCBs, i);
  535.             if ((pfavdsa->hwnd == hwnd) || (pfavdsa->pffvcb == pffvcb))
  536.             {
  537.                 // Make sure we have one to one...
  538.                 pfavdsa->hwnd = hwnd;
  539.                 pfavdsa->pffvcb = pffvcb;
  540.                 break;
  541.             }
  542.         }
  543.         if (0 > i)
  544.         {
  545.             favdsa.hwnd = hwnd;
  546.             favdsa.pffvcb = pffvcb;
  547.             bRet = (0 <= DSA_AppendItem(m_hdsaFolderViewCBs, &favdsa));
  548.         }
  549.     }
  550.     return bRet;
  551. }
  552. STDMETHODIMP_(BOOL) CFavorites::UnRegisterFolderViewCB(HWND hwnd)
  553. {
  554.     TraceMsg(TF_FAV_FULL, "CFavorites::UnRegisterFolderViewCB h:%x", hwnd);
  555.     if (!m_hdsaFolderViewCBs)
  556.         return FALSE;
  557.     int i = DSA_GetItemCount(m_hdsaFolderViewCBs);
  558.     while (--i >= 0)
  559.     {
  560.         PFAVDSA pfavdsa = (PFAVDSA)DSA_GetItemPtr(m_hdsaFolderViewCBs, i);
  561.         if (pfavdsa->hwnd == hwnd)
  562.         {
  563.             DSA_DeleteItem(m_hdsaFolderViewCBs, i);
  564.             return TRUE;
  565.         }
  566.     }
  567.     return FALSE;
  568. }
  569. STDMETHODIMP_(CFavFolderViewCB *) CFavorites::QueryFolderViewCBFromHwnd(HWND hwnd)
  570. {
  571.     TraceMsg(TF_FAV_FULL, "CFavorites::QueryFolderViewCBFromHwnd h:%x", hwnd);
  572.     if (!m_hdsaFolderViewCBs)
  573.         return NULL;
  574.     int i = DSA_GetItemCount(m_hdsaFolderViewCBs);
  575.     while (--i >= 0)
  576.     {
  577.         PFAVDSA pfavdsa = (PFAVDSA)DSA_GetItemPtr(m_hdsaFolderViewCBs, i);
  578.         if (pfavdsa->hwnd == hwnd)
  579.         {
  580.             pfavdsa->pffvcb->AddRef();  // Increment the usage count just in case...
  581.             return pfavdsa->pffvcb;
  582.         }
  583.     }
  584.     return NULL;
  585. }
  586. /*----------------------------------------------------------
  587. Purpose: This function returns the pointer to a cached structure
  588.          which contains extra data for the given pidl.
  589. Returns: 
  590. Cond:    --
  591. */
  592. STDMETHODIMP_(PFAVEXTRA) CFavorites::GetPointerToExtraData(LPCITEMIDLIST pidl)
  593. {
  594.     PFAVEXTRA pfe = NULL;
  595.     // Allocate the cache if necessary
  596.     if (!m_hdpaExtra)
  597.         m_hdpaExtra = DPA_Create(8);
  598.     if (m_hdpaExtra)
  599.     {
  600.         FAVEXTRA fe = {(LPITEMIDLIST)pidl, 0};
  601.         int idpa = DPA_Search(m_hdpaExtra, &fe, 0, FavExtra_CompareIDs, (LPARAM)m_psfFSFolder, DPAS_SORTED);
  602.         // Is this pidl's data cached already? 
  603.         if (-1 != idpa)
  604.         {
  605.             // Yes
  606.             pfe = (PFAVEXTRA)DPA_FastGetPtr(m_hdpaExtra, idpa);
  607.             TraceMsg(TF_FAV_CACHE, "GET #%d=%08X (%08X %08X)", idpa, pfe, pfe->pidl, pfe->ppropstgSite);
  608.         }
  609.         else
  610.         {
  611.             STRRET strret;
  612.             TCHAR szPath[MAX_PATH];
  613.             if (SUCCEEDED(m_psfFSFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret)) &&
  614.                 SUCCEEDED(StrRetToBuf(&strret, pidl, szPath, SIZECHARS(szPath))))
  615.             {
  616.                 WIN32_FIND_DATA finddata;
  617.                 HANDLE hfind = FindFirstFile(szPath, &finddata);
  618.                 if (INVALID_HANDLE_VALUE != hfind)
  619.                 {
  620.                     FindClose(hfind);
  621.                     pfe = (PFAVEXTRA)LocalAlloc(LPTR, SIZEOF(*pfe));
  622.                     if (pfe)
  623.                     {
  624.                         pfe->pidl = ILClone(pidl);
  625.                         pfe->ftVisit = finddata.ftLastAccessTime;
  626.                         if (pidl)
  627.                             OpenPropertyStorage(pidl, pfe);
  628.                         // Cache it
  629.                         DPA_SortedInsertPtr(m_hdpaExtra, pfe, 0, FavExtra_CompareIDs, (LPARAM)m_psfFSFolder, DPAS_INSERTBEFORE, pfe);
  630.                         TraceMsg(TF_FAV_CACHE, "ADD #%d=%08X (%08X %08X)", DPA_GetPtrCount(m_hdpaExtra)-1, pfe, pfe->pidl, pfe->ppropstgSite);
  631.                     }
  632.                 }
  633.             }
  634.         }
  635.     }
  636.     return pfe;
  637. }
  638. /*----------------------------------------------------------
  639. Purpose: Return the visit count
  640. Returns: 
  641. Cond:    --
  642. */
  643. STDMETHODIMP_(DWORD) CFavorites::GetVisitCount(LPCITEMIDLIST pidl)
  644. {
  645.     DWORD dwRet = 0;
  646.     PFAVEXTRA pfe = GetPointerToExtraData(pidl);
  647.     PROPVARIANT propvar;
  648.     if (FavExtra_IsValidSite(pfe) && 
  649.         SUCCEEDED(ReadProp(pfe->ppropstgSite, PID_INTSITE_VISITCOUNT, &propvar)))
  650.     {
  651.         if ( VT_UI4 == propvar.vt )
  652.             dwRet = propvar.ulVal;
  653.         PropVariantClear( &propvar );
  654.     }
  655.     return dwRet;
  656. }
  657. /*----------------------------------------------------------
  658. Purpose: Return the info for the Splat(expected to be a string
  659.          value) and copy its value to the supplied buffer.
  660. Returns:
  661.     S_OK if we should splat.
  662.     S_FALSE if we should not splat.
  663.     E_FAIL if we're screwed.
  664. Cond:    --
  665. */
  666. STDMETHODIMP CFavorites::GetSplatInfo(LPCITEMIDLIST pidl)
  667. {
  668.     HRESULT hres = E_FAIL;
  669.     PROPVARIANT propvar;
  670.     PFAVEXTRA pfe = GetPointerToExtraData(pidl);
  671.     if (FavExtra_IsValidSite(pfe) &&
  672.         SUCCEEDED(ReadProp(pfe->ppropstgSite, PID_INTSITE_FLAGS, &propvar)))
  673.     {
  674.         if ((VT_UI4 == propvar.vt) && (propvar.ulVal & PIDISF_RECENTLYCHANGED))
  675.         {
  676.             hres = S_OK;    // recently changed
  677.         }
  678.         else
  679.         {
  680.             hres = S_FALSE; // not recently changed
  681.         }
  682.         PropVariantClear( &propvar );
  683.     }
  684.     return hres;
  685. }
  686. /*----------------------------------------------------------
  687. Purpose: Return the specified property (expected to be a string
  688.          value) and copy its value to the supplied buffer.
  689. Returns: 
  690. Cond:    --
  691. */
  692. STDMETHODIMP CFavorites::GetStringProp(LPCITEMIDLIST pidl, PROPID propid, LPTSTR pszBuf, DWORD cchBuf)
  693. {
  694.     HRESULT hres = E_FAIL;
  695.     PFAVEXTRA pfe = GetPointerToExtraData(pidl);
  696.     PROPVARIANT propvar;
  697.     ASSERT(pszBuf);
  698.     ASSERT(0 < cchBuf);
  699.     *pszBuf = 0;
  700.     if (FavExtra_IsValidSite(pfe))
  701.     {
  702.         hres = ReadProp(pfe->ppropstgSite, propid, &propvar);
  703.         if (SUCCEEDED(hres))
  704.         {
  705.             if (VT_LPWSTR == propvar.vt)
  706.                 SHUnicodeToTChar(propvar.pwszVal, pszBuf, cchBuf);
  707.             else if (VT_LPSTR == propvar.vt)
  708.                 SHAnsiToTChar(propvar.pszVal, pszBuf, cchBuf);
  709.             PropVariantClear(&propvar);
  710.         }
  711.     }
  712.     return hres;
  713. }
  714. /*----------------------------------------------------------
  715. Purpose: Return the specified property (expected to be a filetime
  716.          value) and copy a displayable version to the supplied buffer.
  717. Returns: 
  718. Cond:    --
  719. */
  720. STDMETHODIMP CFavorites::GetFileTimeProp(LPCITEMIDLIST pidl, PROPID propid, FILETIME * pft)
  721. {
  722.     HRESULT hres = E_FAIL;
  723.     PFAVEXTRA pfe = GetPointerToExtraData(pidl);
  724.     PROPVARIANT propvar;
  725.     pft->dwLowDateTime = 0;
  726.     pft->dwHighDateTime = 0;
  727.     if (FavExtra_IsValidSite(pfe))
  728.     {
  729.         hres = ReadProp(pfe->ppropstgSite, propid, &propvar);
  730.         if (SUCCEEDED(hres))
  731.         {
  732.             if (VT_FILETIME == propvar.vt)
  733.             {
  734.                 *pft = propvar.filetime;
  735.             }
  736.             
  737.             PropVariantClear(&propvar);
  738.         }
  739.     }
  740.     return hres;
  741. }
  742. /*----------------------------------------------------------
  743. Purpose: Destroy the cache of extra data items
  744. Returns: 
  745. Cond:    --
  746. */
  747. STDMETHODIMP_(void) 
  748. CFavorites::ClearCachedData(void)
  749. {
  750.     TraceMsg(TF_FAV_CACHE, "CLEAR start");
  751.     if (m_hdpaExtra)
  752.     {
  753.         int idpa = DPA_GetPtrCount(m_hdpaExtra);
  754.         PFAVEXTRA pfe;
  755.         TraceMsg(TF_FAV_CACHE, "CLEAR count = %d", idpa);
  756.         while (--idpa >= 0)
  757.         {
  758.             pfe = (PFAVEXTRA)DPA_FastGetPtr(m_hdpaExtra, idpa);
  759.             ASSERT(pfe);
  760.             TraceMsg(TF_FAV_CACHE, "CLEAR GET #%d=%08X (%08X %08X)", idpa, pfe, pfe->pidl, pfe->ppropstgSite);
  761.             if (pfe->pidl)
  762.                 ILFree(pfe->pidl);
  763.             if (pfe->ppropstgSite)
  764.                 pfe->ppropstgSite->Release();
  765.             LocalFree(pfe);
  766.         }
  767.         DPA_Destroy(m_hdpaExtra);
  768.         m_hdpaExtra = NULL;
  769.     }
  770.     TraceMsg(TF_FAV_CACHE, "CLEAR end");
  771. }
  772. //==========================================================================================
  773. // CFavFolderViewCB Implemention
  774. //==========================================================================================
  775. /*----------------------------------------------------------
  776. Purpose: Helper to add to the view menu
  777. Returns: 
  778. Cond:    --
  779. */
  780. UINT 
  781. _AddArrangeMenuItems(
  782.     HMENU hmenu, 
  783.     int id)
  784. {
  785.     MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_SUBMENU};
  786.     if (!GetMenuItemInfo(hmenu, SFVIDM_MENU_ARRANGE, FALSE, &mii))
  787.         return 0;
  788.     TCHAR   szTemp[128];    // Should not be any menu items bigger than this...
  789.     // So lets add our own ones in
  790.     int i;
  791.     HMENU hSubMenu = mii.hSubMenu;
  792.     for (i=0;;i++)
  793.     {
  794.         mii.fMask = MIIM_TYPE | MIIM_ID;
  795.         mii.cch = 0;    // ????
  796.         if (!GetMenuItemInfo(hSubMenu, i, TRUE, &mii) ||
  797.                 (mii.fType == MFT_SEPARATOR))
  798.             break;
  799.     }
  800.     // Will need to loop for all columns added, but for now one will
  801.     // do...
  802.     TraceMsg(TF_FAV_FULL, "CFavFolderContextMenu::HandleMergeMenu Add Ours starting at %d", id);
  803.     LoadString(g_hinst, IDS_FAV_COL_SORT_BY_LAST_VISIT,
  804.             szTemp, ARRAYSIZE(szTemp));
  805.     InsertMenu(hSubMenu, i, MF_BYPOSITION, id, szTemp);
  806.     return 1;
  807. }
  808. CFavFolderViewCB::CFavFolderViewCB(CFavorites *pFav, IShellFolderView * psfv) : m_cRef(1)
  809. {
  810.     m_pFav = pFav;
  811.     m_pFav->AddRef();
  812.     m_psfv = psfv;
  813.     m_psfvcb = NULL;
  814.     m_hwndMain = NULL;
  815. }
  816. CFavFolderViewCB::~CFavFolderViewCB(void)
  817. {
  818.     m_pFav->UnRegisterFolderViewCB(m_hwndMain);
  819.     m_pFav->Release();
  820.     if ( m_psfvcb )
  821.         m_psfvcb->Release();
  822.         
  823.     if ( m_psdFolder )
  824.         m_psdFolder->Release();
  825. }
  826. STDMETHODIMP_(void) CFavFolderViewCB::SetMainCB(IN IShellFolderViewCB *psfvcb)
  827. {
  828.     if (m_psfvcb)
  829.         m_psfvcb->Release();
  830.     m_psfvcb = psfvcb;
  831.     if (m_psfvcb)
  832.         m_psfvcb->AddRef();
  833. }
  834. STDMETHODIMP CFavFolderViewCB::QueryInterface(REFIID riid, void **ppv)
  835. {
  836.     static const QITAB qit[] = {
  837.         QITABENT(CFavFolderViewCB, IShellFolderViewCB), // IID_IShellFolderViewCB
  838.         { 0 },
  839.     };
  840.     return QISearch(this, qit, riid, ppv);
  841. }
  842. STDMETHODIMP_(ULONG) CFavFolderViewCB::AddRef(void)
  843. {
  844.     return InterlockedIncrement(&m_cRef);
  845. }
  846. STDMETHODIMP_(ULONG) CFavFolderViewCB::Release(void)
  847. {
  848.     if (InterlockedDecrement(&m_cRef))
  849.         return m_cRef;
  850.     delete this;
  851.     return 0;
  852. }
  853. STDMETHODIMP CFavFolderViewCB::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
  854. {
  855.     HRESULT hres;
  856.     if (m_psfvcb)
  857.     {
  858.         switch (uMsg)
  859.         {
  860.         case SFVM_MERGEMENU:
  861.         {
  862.             QCMINFO *pqcmi = (QCMINFO*)lParam;
  863.             UINT idCmdFirst = pqcmi->idCmdFirst;
  864.             hres = m_psfvcb->MessageSFVCB(uMsg, wParam, lParam);
  865.             if (SUCCEEDED(hres))
  866.             {
  867.                 HandleMergeMenu(idCmdFirst, pqcmi);
  868.             }
  869.             return hres;
  870.         }
  871.         case SFVM_INVOKECOMMAND:
  872.             TraceMsg(TF_FAV_FULL, "CFavFolderViewCB::MessageSFVCB Invoke C:%x", wParam);
  873.             if (wParam == m_idCmdFirstAdded)
  874.             {
  875.                 m_psfv->Rearrange(m_pFav->m_iFirstAddedCol);
  876.                 return NOERROR;
  877.             }
  878.             break;
  879.         case SFVM_HWNDMAIN:
  880.             m_hwndMain = (HWND)lParam;
  881.             m_pFav->RegisterFolderViewCB(m_hwndMain, this);
  882.             break;
  883.         case SFVM_REFRESH:
  884.             // post refresh....
  885.             if ( (BOOL) wParam == FALSE )
  886.                 m_pFav->ClearCachedData();
  887.             break;
  888.         case SFVM_GETVIEWS:
  889.             // get the views supported
  890.             return GetViews( (SHELLVIEWID *) wParam, (IEnumSFVViews **) lParam );
  891.         }
  892.         hres = m_psfvcb->MessageSFVCB(uMsg, wParam, lParam);
  893.     }
  894.     else
  895.         hres = E_NOTIMPL;
  896.     return hres;
  897. }
  898. STDMETHODIMP CFavFolderViewCB::GetDetailsOf(int iCol, DETAILSINFO * pdi)
  899. {
  900.     SHELLDETAILS rgDetails;
  901.     HRESULT hr = NOERROR;
  902.     if ( ! m_psdFolder )
  903.     {
  904.         // cache the IShellDetails ...
  905.         hr = m_pFav->m_psfFSFolder->CreateViewObject( NULL, IID_IShellDetails, (void **) & m_psdFolder );
  906.         if ( FAILED( hr ))
  907.         {
  908.             return hr;
  909.         }
  910.     }
  911.     
  912.     hr = m_pFav->GetDetailsOf(m_psdFolder, pdi->pidl, iCol, &rgDetails);
  913.     if ( SUCCEEDED( hr ))
  914.     {
  915.         pdi->fmt = rgDetails.fmt;
  916.         pdi->cxChar = rgDetails.cxChar;
  917.         pdi->str = rgDetails.str;
  918.     }
  919.     return hr;
  920. }
  921. STDMETHODIMP_(void) CFavFolderViewCB::HandleMergeMenu(UINT idCmdFirstIn, QCMINFO * pqcmi)
  922. {
  923.     TraceMsg(TF_FAV_FULL, "CFavorites::HandleMergeMenu h:%x im=%x F:%x L:%x",
  924.             pqcmi->hmenu, pqcmi->indexMenu, pqcmi->idCmdFirst, pqcmi->idCmdLast);
  925.     UINT cCmdAdded = _AddArrangeMenuItems(pqcmi->hmenu, pqcmi->idCmdFirst);
  926.     if (cCmdAdded)
  927.     {
  928.         m_idCmdFirstAdded =  pqcmi->idCmdFirst - idCmdFirstIn;
  929.         pqcmi->idCmdFirst += cCmdAdded;
  930.     }
  931. }
  932. STDMETHODIMP CFavFolderViewCB::GetViews( SHELLVIEWID * pDefID, IEnumSFVViews ** ppEnum )
  933. {
  934.     if ( !ppEnum || !pDefID )
  935.     {
  936.         return E_INVALIDARG;
  937.     }
  938.     
  939.     HRESULT hr = m_psfvcb->MessageSFVCB( SFVM_GETVIEWS, (WPARAM) pDefID, (LPARAM) ppEnum );
  940.     
  941.     IEnumSFVViews * pStdEnum = *ppEnum;
  942.     
  943.     // create the wrapper and use it....
  944.     HRESULT hr2 = CFavViewEnum_Create( *ppEnum, ppEnum );
  945.     if ( SUCCEEDED( hr2 ) && pStdEnum )
  946.     {
  947.         // we have a new one, so release the ref on the old one (the wrapper
  948.         // also has a ref)
  949.         pStdEnum->Release();
  950.     }
  951.     if ( SUCCEEDED( hr ) && FAILED( hr2 ))
  952.     {
  953.         *ppEnum = pStdEnum;
  954.     }
  955.     if ( FAILED( hr ) && SUCCEEDED( hr2 ))
  956.     {
  957.         hr = hr2;
  958.     }
  959.     return hr;
  960. }
  961. CFavFolderContextMenu::CFavFolderContextMenu(CFavorites *pFav, HWND hwnd, HRESULT *phres) : m_cRef ( 1 )
  962. {
  963.     IContextMenu *pcmToWrap;
  964.     *phres = pFav->m_psfFSFolder->CreateViewObject(hwnd, IID_IContextMenu, (void **)&pcmToWrap);
  965.     if (SUCCEEDED(*phres))
  966.     {
  967.         m_hwndOwner = hwnd;
  968.         m_pFav = pFav;
  969.         m_pFav->AddRef();
  970.         *phres = pcmToWrap->QueryInterface(IID_IContextMenu2, (void **)&m_pcmInner);
  971.         m_idCmdFirst =  0;
  972.         pcmToWrap->Release();
  973.     }
  974. }
  975. HRESULT CFavFolderContextMenu_CreateInstance(CFavorites *pFav, HWND hwnd, REFIID riid, void **ppv)
  976. {
  977.     *ppv = NULL;
  978.     HRESULT hres;
  979.     CFavFolderContextMenu *pMenu = new CFavFolderContextMenu(pFav, hwnd, &hres);
  980.     if (pMenu)
  981.     {
  982.         if (SUCCEEDED(hres))
  983.             hres = pMenu->QueryInterface(riid, ppv);
  984.         pMenu->Release();
  985.     }
  986.     else
  987.         hres = E_OUTOFMEMORY;
  988.     return hres;
  989. }
  990. CFavFolderContextMenu::~CFavFolderContextMenu(void)
  991. {
  992.     if (m_pFav)
  993.         m_pFav->Release();
  994.     if (m_pcmInner)
  995.         m_pcmInner->Release();
  996. }
  997. STDMETHODIMP CFavFolderContextMenu::QueryInterface(REFIID riid, void **ppv)
  998. {
  999.     static const QITAB qit[] = {
  1000.         QITABENT(CFavFolderContextMenu, IObjectWithSite),   // IID_IObjectWithSite
  1001.         QITABENT(CFavFolderContextMenu, IContextMenu),  // IID_IContextMenu
  1002.         QITABENTMULTI(CFavFolderContextMenu, IContextMenu, IContextMenu2),  // IID_IContextMenu2
  1003.         QITABENTMULTI(CFavFolderContextMenu, IContextMenu2, IContextMenu3),  // IID_IContextMenu3
  1004.         { 0 },
  1005.     };
  1006.     return QISearch(this, qit, riid, ppv);
  1007. }
  1008. STDMETHODIMP_(ULONG) CFavFolderContextMenu::AddRef(void)
  1009. {
  1010.     return InterlockedIncrement(&m_cRef);
  1011. }
  1012. STDMETHODIMP_(ULONG) CFavFolderContextMenu::Release(void)
  1013. {
  1014.     if (InterlockedDecrement(&m_cRef))
  1015.         return m_cRef;
  1016.     delete this;
  1017.     return 0;
  1018. }
  1019. STDMETHODIMP CFavFolderContextMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst,
  1020.                                                      UINT idCmdLast,  UINT uFlags)
  1021. {
  1022.     HRESULT hres = m_pcmInner->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
  1023.     if (SUCCEEDED(hres))
  1024.     {
  1025.         UINT cCmdAdded;
  1026.         idCmdFirst += (SHORT)hres;
  1027.         m_idCmdFirst =  (SHORT)hres;
  1028.         cCmdAdded = _AddArrangeMenuItems(hmenu, idCmdFirst);
  1029.         return ResultFromShort((SHORT)hres + cCmdAdded);
  1030.     }
  1031.     return hres;
  1032. }
  1033. STDMETHODIMP CFavFolderContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
  1034. {
  1035.     TraceMsg(TF_FAV_FULL, "CFavFolderContextMenu::InvokeCommand called %x", lpici->lpVerb);
  1036.     if (IS_INTRESOURCE(lpici->lpVerb))
  1037.     {
  1038.         UINT idCmd = LOWORD(lpici->lpVerb);
  1039.         if (idCmd == m_idCmdFirst)
  1040.         {
  1041.             // It is ours...
  1042.             TraceMsg(TF_FAV_FULL, "CFavFolderContextMenu::InvokeCommand SortByLastVisit");
  1043.             CFavFolderViewCB *pffvcb = m_pFav->QueryFolderViewCBFromHwnd(m_hwndOwner);
  1044.             if (pffvcb)
  1045.             {
  1046.                 // Maybe should do this cleaner...
  1047.                 pffvcb->m_psfv->Rearrange(m_pFav->m_iFirstAddedCol);
  1048.                 pffvcb->Release();  // release our usage of it...
  1049.             }
  1050.         }
  1051.     }
  1052.     return m_pcmInner->InvokeCommand(lpici);
  1053. }
  1054. STDMETHODIMP CFavFolderContextMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT * pwReserved, LPSTR pszName, UINT cchMax)
  1055. {
  1056.     return m_pcmInner->GetCommandString(idCmd, uType, pwReserved, pszName, cchMax);
  1057. }
  1058. STDMETHODIMP CFavFolderContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1059. {
  1060.     return m_pcmInner->HandleMenuMsg(uMsg, wParam, lParam);
  1061. }
  1062. STDMETHODIMP CFavFolderContextMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  1063. {
  1064.     IContextMenu3 *pcm3;
  1065.     HRESULT hres = m_pcmInner->QueryInterface(IID_IContextMenu3, (void **)&pcm3);
  1066.     if (SUCCEEDED(hres))
  1067.     {
  1068.         hres = pcm3->HandleMenuMsg2(uMsg, wParam, lParam, plres);
  1069.         pcm3->Release();
  1070.     }
  1071.     return hres;
  1072. }
  1073. HRESULT CFavFolderContextMenu::SetSite(IUnknown* pUnk)
  1074. {
  1075.     return IUnknown_SetSite(m_pcmInner, pUnk);
  1076. }
  1077. HRESULT CFavFolderContextMenu::GetSite(REFIID riid, void**ppv)
  1078. {
  1079.     return IUnknown_GetSite(m_pcmInner, riid, ppv);
  1080. }
  1081. HRESULT CFavViewEnum_Create( IEnumSFVViews * pDefEnum, IEnumSFVViews ** ppEnum )
  1082. {
  1083.     CFavViewEnum * pViewEnum = new CFavViewEnum( pDefEnum );
  1084.     if ( !pViewEnum )
  1085.     {
  1086.         return E_OUTOFMEMORY;
  1087.     }
  1088.     *ppEnum = SAFECAST(pViewEnum, IEnumSFVViews *);
  1089.     return NOERROR;
  1090. }
  1091. CFavViewEnum::CFavViewEnum(IEnumSFVViews * pEnum) : m_cRef(1)
  1092. {
  1093.     m_pesfvv = pEnum;
  1094.     if ( pEnum )
  1095.         pEnum->AddRef();
  1096.     m_iAddView = 0;
  1097. }
  1098. CFavViewEnum::~CFavViewEnum()
  1099. {
  1100.     if ( m_pesfvv )
  1101.         m_pesfvv->Release();
  1102. }
  1103. STDMETHODIMP CFavViewEnum::QueryInterface (REFIID riid, void ** ppv)
  1104. {
  1105.     static const QITAB qit[] = {
  1106.         QITABENT(CFavViewEnum, IEnumSFVViews),  // IID_IEnumSFVViews
  1107.         { 0 },
  1108.     };
  1109.     return QISearch(this, qit, riid, ppv);
  1110. }
  1111. STDMETHODIMP_(ULONG) CFavViewEnum::AddRef()
  1112. {
  1113.     return InterlockedIncrement(&m_cRef);
  1114. }
  1115. STDMETHODIMP_(ULONG) CFavViewEnum::Release()
  1116. {
  1117.     if (InterlockedDecrement(&m_cRef))
  1118.         return m_cRef;
  1119.     delete this;
  1120.     return 0;
  1121. }
  1122. STDMETHODIMP CFavViewEnum::Next(ULONG celt, SFVVIEWSDATA **ppData, ULONG *pceltFetched)
  1123. {
  1124.     ULONG celtFetched = 0;
  1125.     
  1126.     if ( !celt || !ppData || (celt > 1 && !pceltFetched ))
  1127.     {
  1128.         return E_INVALIDARG;
  1129.     }
  1130.     if ( !m_iAddView )
  1131.     {
  1132.         // return the Thumbnail view first 
  1133.         ppData[0] = (SFVVIEWSDATA *) SHAlloc(sizeof(SFVVIEWSDATA));
  1134.         if ( !ppData[0] )
  1135.         {
  1136.             return E_OUTOFMEMORY;
  1137.         }
  1138.         ppData[0]->idView = CLSID_ThumbnailViewExt;
  1139.         ppData[0]->idExtShellView = CLSID_ThumbnailViewExt;
  1140.         ppData[0]->dwFlags = SFVF_TREATASNORMAL | SFVF_NOWEBVIEWFOLDERCONTENTS;
  1141.         ppData[0]->lParam = 0x00000011;
  1142.         ppData[0]->wszMoniker[0] = 0;
  1143.         celtFetched ++;
  1144.         m_iAddView ++;
  1145.     }
  1146.     ULONG celtAditional = 0;
  1147.     HRESULT hr = S_FALSE;
  1148.     
  1149.     if ( celt - celtFetched > 0 && m_pesfvv )
  1150.     {
  1151.         hr = m_pesfvv->Next( celt - celtFetched,
  1152.                              ppData + celtFetched,
  1153.                              & celtAditional );
  1154.         celtFetched += celtAditional;
  1155.     }
  1156.     if (SUCCEEDED( hr ))
  1157.     {
  1158.         if ( celtFetched == celt )
  1159.         {
  1160.             hr = S_OK;
  1161.         }
  1162.     }
  1163.     else if ( celtFetched )
  1164.     {
  1165.         hr = S_FALSE;
  1166.     }
  1167.     if ( pceltFetched )
  1168.     {
  1169.         *pceltFetched = celtFetched;
  1170.     }
  1171.     
  1172.     return hr;
  1173. }
  1174. STDMETHODIMP CFavViewEnum::Skip(ULONG celt)
  1175. {
  1176.     if ( celt && !m_iAddView )
  1177.     {
  1178.         m_iAddView ++;
  1179.         celt --;
  1180.     }
  1181.     if ( celt && m_pesfvv )
  1182.     {
  1183.         return m_pesfvv->Skip( celt );
  1184.     }
  1185.     return (celt ? S_FALSE : S_OK );
  1186. }
  1187. STDMETHODIMP CFavViewEnum::Reset()
  1188. {
  1189.     m_iAddView = 0;
  1190.     if ( m_pesfvv )
  1191.     {
  1192.         m_pesfvv->Reset();
  1193.     }
  1194.     return NOERROR;
  1195. }
  1196. STDMETHODIMP CFavViewEnum::Clone(IEnumSFVViews **ppenum)
  1197. {
  1198.     IEnumSFVViews * pNewEnum = NULL;
  1199.     HRESULT hr = NOERROR;
  1200.     if ( m_pesfvv )
  1201.     {
  1202.         hr = m_pesfvv->Clone( & pNewEnum );
  1203.         if ( FAILED( hr ))
  1204.         {
  1205.             return hr;
  1206.         }
  1207.     }
  1208.     
  1209.     hr = CFavViewEnum_Create( pNewEnum, ppenum );
  1210.     if ( FAILED( hr ) && pNewEnum )
  1211.     {
  1212.         pNewEnum->Release();
  1213.     }
  1214.     return hr;
  1215. }
  1216. HRESULT CFavoritesDetails_CreateInstance(CFavorites * pFav, IShellDetails **ppv)
  1217. {
  1218.     HRESULT hr;
  1219.     CFavoritesDetails * pDetails = new CFavoritesDetails( pFav, &hr );
  1220.     if (pDetails)
  1221.     {
  1222.         if (SUCCEEDED(hr))
  1223.             *ppv = SAFECAST(pDetails, IShellDetails *);
  1224.     }
  1225.     else
  1226.         hr = E_OUTOFMEMORY;
  1227.     return hr;
  1228. }
  1229. CFavoritesDetails::CFavoritesDetails( CFavorites * pFav, HRESULT * pHr) : m_cRef ( 1 )
  1230. {
  1231.     *pHr = pFav->m_psfFSFolder->CreateViewObject( NULL, IID_IShellDetails, (void **) &m_psdFolder );
  1232.     if (SUCCEEDED(*pHr))
  1233.     {
  1234.         // hold a ref to the favorites object.
  1235.         // we use the punk above to hold the ref...
  1236.         m_pFav = pFav;
  1237.         m_pFav->AddRef();
  1238.         pFav->m_iFirstAddedCol = -1;    // BUGBUG: per view data in the folder!
  1239.     }
  1240. }
  1241. CFavoritesDetails::~CFavoritesDetails()
  1242. {
  1243.     if ( m_psdFolder )
  1244.         m_psdFolder->Release();
  1245.     if ( m_pFav )
  1246.         m_pFav->Release();
  1247. }
  1248. STDMETHODIMP CFavoritesDetails::QueryInterface(REFIID riid, void **ppv)
  1249. {
  1250.     static const QITAB qit[] = {
  1251.         QITABENT(CFavoritesDetails, IShellDetails), // IID_IShellDetails
  1252.         { 0 },
  1253.     };
  1254.     return QISearch(this, qit, riid, ppv);
  1255. }
  1256. STDMETHODIMP_( ULONG ) CFavoritesDetails::AddRef ()
  1257. {
  1258.     return InterlockedIncrement(&m_cRef);
  1259. }
  1260. STDMETHODIMP_( ULONG ) CFavoritesDetails::Release ()
  1261. {
  1262.     if (InterlockedDecrement(&m_cRef))
  1263.         return m_cRef;
  1264.     delete this;
  1265.     return 0;
  1266. }
  1267. STDMETHODIMP CFavoritesDetails::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
  1268. {
  1269.     return m_pFav->GetDetailsOf( m_psdFolder, pidl, iColumn, pDetails );
  1270. }
  1271. STDMETHODIMP CFavorites::GetDetailsOf(IShellDetails *psd, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
  1272. {
  1273.     TCHAR szTmp[MAX_PATH];
  1274.     PROPID pid;
  1275.     FILETIME ft;
  1276.     // either we are an added column, or we don't know the added columns number
  1277.     if (((int) iColumn) < m_iFirstAddedCol || m_iFirstAddedCol == -1 )
  1278.     {
  1279.         HRESULT hres = psd->GetDetailsOf(pidl, iColumn, pDetails);
  1280.         if ( SUCCEEDED( hres ) || m_iFirstAddedCol != -1)
  1281.             return hres;
  1282.         m_iFirstAddedCol = iColumn;
  1283.     }
  1284.         
  1285.     iColumn -= m_iFirstAddedCol;
  1286.     
  1287.     /// empty string
  1288.     szTmp[0] = 0;
  1289.     
  1290.     if (iColumn >= ARRAYSIZE(c_fav_cols))
  1291.         return E_FAIL;   // Some error code.
  1292.     if (!pidl)
  1293.     {
  1294.         LoadString(g_hinst, c_fav_cols[iColumn].ids, szTmp, SIZECHARS(szTmp));
  1295.         pDetails->fmt = c_fav_cols[iColumn].iFmt;
  1296.         pDetails->cxChar = c_fav_cols[iColumn].cchCol;
  1297.     }
  1298.     else
  1299.     {
  1300.         // Need to fill in the details
  1301.         switch (iColumn)
  1302.         {
  1303.         case ICOL_FAV_NUMVISITS:
  1304.             {
  1305.                 DWORD dwNumVisits = this->GetVisitCount(pidl);
  1306.                 if (dwNumVisits)
  1307.                     wsprintf(szTmp, TEXT("%u"), dwNumVisits);
  1308.             }
  1309.             break;
  1310.         case ICOL_FAV_LASTVISIT:
  1311.             pid = PID_INTSITE_LASTVISIT;
  1312.             goto FinishFileTime;
  1313.         case ICOL_FAV_LASTMOD:
  1314.             pid = PID_INTSITE_LASTMOD;
  1315.         FinishFileTime:
  1316.             if (SUCCEEDED(this->GetFileTimeProp(pidl, pid, &ft)))
  1317.                 SHFormatDateTime(&ft, NULL, szTmp, SIZECHARS(szTmp));
  1318.             break;
  1319.         case ICOL_FAV_SPLAT:
  1320.             if (this->GetSplatInfo(pidl) == S_OK)
  1321.                 LoadString(g_hinst, IDS_FAV_SPLAT, szTmp, SIZECHARS(szTmp));
  1322.             break;
  1323.         default:
  1324.             return E_FAIL;
  1325.         }
  1326.     }
  1327.     return StringToStrRet(szTmp, &pDetails->str);
  1328. }
  1329. STDMETHODIMP CFavoritesDetails::ColumnClick(UINT iColumn)
  1330. {
  1331.     return S_FALSE;     // do default
  1332. }
  1333. STDAPI Favorites_Install(BOOL bInstall)
  1334. {
  1335.     TCHAR szPath[MAX_PATH];
  1336.     // get the path to the favorites folder. Create it if it is missing and we
  1337.     // are installing, otherwise don't bother.
  1338.     if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, bInstall))
  1339.     {
  1340.         if (bInstall)
  1341.         {
  1342.             // BUGBUG kenwic 060399 #342156 We must nuke the ExtShellFolderView section to recover from an IE4 bug FIXED kenwic 060399
  1343.             SHFOLDERCUSTOMSETTINGS fcs = {sizeof(fcs), FCSM_CLSID | FCSM_VIEWID, 0};
  1344.             fcs.pclsid = (CLSID *)&CLSID_FavoritesFolder;   // const -> non const
  1345.             fcs.pvid = NULL;
  1346.             SHGetSetFolderCustomSettings(&fcs, szPath, FCS_FORCEWRITE);
  1347.         }
  1348.         else
  1349.         {
  1350.             PathUnmakeSystemFolder(szPath);
  1351.         }
  1352.     }
  1353.     return NOERROR; 
  1354. }