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

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "iface.h"
  4. #include "itbar.h"
  5. #include "itbdrop.h"
  6. #include "bands.h"
  7. #include "isfband.h"
  8. #include "menubar.h"
  9. #include "resource.h"
  10. #include "menuisf.h"
  11. #include "../lib/dpastuff.h"
  12. #include "shlwapi.h"
  13. #include "cobjsafe.h"
  14. #include <iimgctx.h>
  15. #include "dbgmem.h"
  16. #include "inpobj.h"
  17. #include "uemapp.h"
  18. #include "mnfolder.h"
  19. #include "channel.h"
  20. #define DM_VERBOSE      0       // misc verbose traces
  21. #define DM_PERSIST      0
  22. #define TF_BANDDD   TF_BAND
  23. #define DM_RENAME       0
  24. #define DM_MISC         0       // miscellany
  25. #define SZ_PROPERTIESA     "properties"
  26. #define SZ_PROPERTIES      TEXT(SZ_PROPERTIESA)
  27. #define SZ_REGKEY_ADVFOLDER        TEXT("Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced")
  28. // {F47162A0-C18F-11d0-A3A5-00C04FD706EC}
  29. static const GUID TOID_ExtractImage = { 0xf47162a0, 0xc18f, 0x11d0, { 0xa3, 0xa5, 0x0, 0xc0, 0x4f, 0xd7, 0x6, 0xec } };
  30. #define SUPERCLASS CToolBand
  31. HRESULT FakeGetUIObjectOf( IShellFolder *psf, LPCITEMIDLIST pidl, UINT * prgfFlags, REFIID riid, void **ppvObj );
  32. extern UINT g_idFSNotify;
  33. HRESULT CExtractImageTask_Create( CLogoBase *plb,
  34.                                   LPEXTRACTIMAGE pExtract,
  35.                                   LPCWSTR pszCache,
  36.                                   DWORD dwItem,
  37.                                   int iIcon,
  38.                                   DWORD dwFlags,
  39.                                   LPRUNNABLETASK * ppTask );
  40. class CExtractImageTask : public IRunnableTask
  41. {
  42.     public:
  43.         STDMETHOD ( QueryInterface ) ( REFIID riid, void **ppvObj );
  44.         STDMETHOD_( ULONG, AddRef ) ();
  45.         STDMETHOD_( ULONG, Release ) ();
  46.         STDMETHOD (Run)( void );
  47.         STDMETHOD (Kill)( BOOL fWait );
  48.         STDMETHOD (Suspend)( );
  49.         STDMETHOD (Resume)( );
  50.         STDMETHOD_( ULONG, IsRunning )( void );
  51.     protected:
  52.         CExtractImageTask( HRESULT * pHr,
  53.                            CLogoBase *plb,
  54.                            IExtractImage * pImage,
  55.                            LPCWSTR pszCache,
  56.                            DWORD dwItem,
  57.                            int iIcon,
  58.                            DWORD dwFlags );
  59.         ~CExtractImageTask();
  60.         HRESULT InternalResume();
  61.     friend HRESULT CExtractImageTask_Create( CLogoBase* plb,
  62.                                                  LPEXTRACTIMAGE pExtract,
  63.                                                  LPCWSTR pszCache,
  64.                                                  DWORD dwItem,
  65.                                                  int iIcon,
  66.                                                  DWORD dwFlags,
  67.                                                  LPRUNNABLETASK * ppTask );
  68.         LONG            m_cRef;
  69.         LONG            m_lState;
  70.         LPEXTRACTIMAGE  m_pExtract;
  71.         LPRUNNABLETASK  m_pTask;
  72.         WCHAR           m_szPath[MAX_PATH];
  73.         DWORD           m_dwFlags;
  74.         DWORD           m_dwItem;
  75.         CLogoBase*      m_plb;
  76.         HBITMAP         m_hBmp;
  77.         int             m_iIcon;
  78. };
  79. //=================================================================
  80. // Implementation of CISFBand
  81. //=================================================================
  82. CISFBand::CISFBand() : CToolbarBand()
  83. {
  84.     _fCanFocus = TRUE;
  85.     _eUemLog = UEMIND_NIL;
  86.     _dwPriv = -1;
  87.     _fHasOrder = TRUE;  // ISFBand always has an order...
  88.     _fAllowDropdown = BOOLIFY(SHRegGetBoolUSValue(SZ_REGKEY_ADVFOLDER, TEXT("CascadeFolderBands"),
  89.                     FALSE,
  90.                     FALSE)); 
  91.     // Should we enable logging of arbirary events?
  92. //    _pguidUEMGroup = &UEMIID_SHELL;
  93.     ASSERT(_pguidUEMGroup == NULL);
  94.     // Assert that this class is ZERO INITed.
  95.     ASSERT(!_pbp);
  96.     ASSERT(FALSE == _fCreatedBandProxy);
  97. }
  98. CISFBand::~CISFBand()
  99. {
  100.     if(_pbp && _fCreatedBandProxy)
  101.         _pbp->SetSite(NULL);
  102.     ATOMICRELEASE(_pbp);
  103. }
  104. HRESULT CISFBand_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  105. {
  106.     // aggregation checking is handled in class factory
  107.     HRESULT hres;
  108.     CISFBand* pObj;
  109.     hres = E_OUTOFMEMORY;
  110.     pObj = new CISFBand();
  111.     if (pObj)
  112.     {
  113.         *ppunk = SAFECAST(pObj, IShellFolderBand*);
  114.         hres = S_OK;
  115.     }
  116.     return hres;
  117. }
  118. /*----------------------------------------------------------
  119. Purpose: See CISFBand::Init for an explanation on the parameters.
  120. */
  121. CISFBand* CISFBand_CreateEx(IShellFolder* psf, LPCITEMIDLIST pidl)
  122. {
  123.     CISFBand * p = NULL;
  124.     if (psf || pidl)
  125.     {
  126.         p = new CISFBand();
  127.         if (p)
  128.         {
  129.             IShellFolderBand * psfband = SAFECAST(p, IShellFolderBand *);
  130.             if (psfband && FAILED(psfband->InitializeSFB(psf, pidl)))
  131.             {
  132.                 delete p;
  133.                 p = NULL;
  134.             }
  135.         }
  136.     }
  137.     return p;
  138. }
  139. #ifdef DEBUG
  140. #define _AddRef(psz) { ++_cRef; TraceMsg(TF_SHDREF, "CDocObjectView(%x)::QI(%s) is AddRefing _cRef=%d", this, psz, _cRef); }
  141. #else
  142. #define _AddRef(psz)    ++_cRef
  143. #endif
  144. HRESULT CISFBand::QueryInterface(REFIID riid, void **ppvObj)
  145. {
  146.     static const QITAB qit[] = {
  147.         QITABENT(CISFBand, IShellFolderBand),
  148.         { 0 },
  149.     };
  150.     HRESULT hres = QISearch(this, qit, riid, ppvObj);
  151.     if (FAILED(hres))
  152.         hres = CToolBand::QueryInterface(riid, ppvObj);
  153.     if (FAILED(hres))
  154.         hres = CSFToolbar::QueryInterface(riid, ppvObj);
  155.     if (S_OK != hres)
  156.     {
  157.         // HACKHACK: this is yucko!
  158.         if (IsEqualIID(riid, CLSID_ISFBand))
  159.         {
  160.             *ppvObj = (void*)this;
  161.             _AddRef(TEXT("CLSID_ISFBand"));
  162.             return S_OK;
  163.         }
  164.     }
  165.     return hres;
  166. }
  167. #if 0
  168. LPITEMIDLIST PidlFromFolderAndSubPath(int iFolder, TCHAR *pszSubPath)
  169. {
  170.     LPITEMIDLIST pidl = NULL;
  171.     if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, iFolder, &pidl))) {
  172.         if (pszSubPath) {
  173.             TCHAR szPath[MAX_PATH];
  174.             SHGetPathFromIDList(pidl, szPath);
  175.             PathCombine(szPath, szPath, pszSubPath);
  176.             ILFree(pidl);
  177.             pidl = ILCreateFromPath(szPath);
  178.         }
  179.     }
  180.     return pidl;
  181. }
  182. #endif
  183. //***   ILIsParentCSIDL -- like ILIsParent, but accepts a CSIDL_* for pidl1
  184. // NOTES
  185. //  TODO move to shlwapi (if/when idlist.c moves there)?
  186. //
  187. STDAPI_(BOOL) ILIsParentCSIDL(int csidl1, LPCITEMIDLIST pidl2, BOOL fImmediate)
  188. {
  189.     LPITEMIDLIST pidlSpec;
  190.     BOOL fRet = FALSE;
  191.     if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidl1, &pidlSpec))) {
  192.         fRet = ILIsParent(pidlSpec, pidl2, fImmediate);
  193.         ILFree(pidlSpec);
  194.     }
  195.     return fRet;
  196. }
  197. /*----------------------------------------------------------
  198. Purpose: IShellFolderBand::InitializeSFB
  199.          - supply IShellFolder with no PIDL if you want to view some
  200.            ISF (either already instantiated from the filesystem or
  201.            some non-filesystem ISF) that you do NOT want to receive
  202.            notifies from (either from SHChangeNotify nor from
  203.            IShellChangeNotify)
  204.          - supply a PIDL with no IShellFolder for a full-blown band
  205.            looking at a shell namespace (rooted on desktop) item.
  206. */
  207. HRESULT CISFBand::InitializeSFB(IShellFolder *psf, LPCITEMIDLIST pidl)
  208. {
  209.     HRESULT hres = S_OK;
  210.     // Did they try to add the Recycle Bin? If so we need to reject it
  211.     // for consistance reasons.  We also reject the Temp. Internet Files
  212.     // for security reasons.
  213.     if (pidl && (ILIsParentCSIDL(CSIDL_BITBUCKET, pidl, FALSE) ||
  214.                 ILIsParentCSIDL(CSIDL_INTERNET_CACHE, pidl, FALSE)))
  215.     {
  216.         // this will eventually show up as IDS_CANTISFBAND
  217.         TraceMsg(DM_TRACE, "cib.isfb: recycle => E_INVALIDARG");
  218.         hres = E_INVALIDARG;
  219.     }
  220.     if (SUCCEEDED(hres))
  221.         hres = CSFToolbar::SetShellFolder(psf, pidl);
  222.     if (SUCCEEDED(hres))
  223.         _AfterLoad();
  224.     return hres;
  225. }
  226. /*----------------------------------------------------------
  227. Purpose: IShellFolderBand::SetBandInfoSFB
  228. */
  229. HRESULT CISFBand::SetBandInfoSFB(BANDINFOSFB * pbi)
  230. {
  231.     ASSERT(pbi);
  232.     if (!pbi)
  233.         return E_POINTER;
  234.     if ((pbi->dwMask & ISFB_MASK_INVALID) ||
  235.         (pbi->dwMask & ISFB_MASK_VIEWMODE) && (pbi->wViewMode & ~3))
  236.         return E_INVALIDARG;
  237.     // We don't handle ISFB_MASK_SHELLFOLDER and ISFB_MASK_IDLIST
  238.     // in Set because there's a lot of work to resync pidl, psf, and
  239.     // notifcations in the toolbar.  If somebody wants to do it,
  240.     // more power to ya.  :)
  241.     if (pbi->dwMask & (ISFB_MASK_SHELLFOLDER | ISFB_MASK_IDLIST))
  242.         return E_INVALIDARG;
  243.     if (pbi->dwMask & ISFB_MASK_STATE)
  244.     {
  245.         if (pbi->dwStateMask & ISFB_STATE_DEBOSSED)
  246.             _fDebossed = BOOLIFY(pbi->dwState & ISFB_STATE_DEBOSSED);
  247.         if (pbi->dwStateMask & ISFB_STATE_ALLOWRENAME)
  248.             _fAllowRename = BOOLIFY(pbi->dwState & ISFB_STATE_ALLOWRENAME);
  249.         if (pbi->dwStateMask & ISFB_STATE_NOSHOWTEXT)
  250.             _fNoShowText = BOOLIFY(pbi->dwState & ISFB_STATE_NOSHOWTEXT);
  251.         if (pbi->dwStateMask & ISFB_STATE_CHANNELBAR)
  252.             _fChannels = BOOLIFY(pbi->dwState & ISFB_STATE_CHANNELBAR);
  253.         /* ISFB_STATE_NOTITLE: removed 970619, use cbs::SetBandState */
  254.         if (pbi->dwStateMask & ISFB_STATE_QLINKSMODE)
  255.             _fLinksMode = BOOLIFY(pbi->dwState & ISFB_STATE_QLINKSMODE);
  256.         if (pbi->dwStateMask & ISFB_STATE_FULLOPEN)
  257.             _fFullOpen = BOOLIFY(pbi->dwState & ISFB_STATE_FULLOPEN);
  258.         if (pbi->dwStateMask & ISFB_STATE_NONAMESORT)
  259.             _fNoNameSort = BOOLIFY(pbi->dwState & ISFB_STATE_NONAMESORT);
  260.         if (pbi->dwStateMask & ISFB_STATE_BTNMINSIZE)
  261.             _fBtnMinSize = BOOLIFY(pbi->dwState & ISFB_STATE_BTNMINSIZE);
  262.     }
  263.     if (pbi->dwMask & ISFB_MASK_BKCOLOR)
  264.     {
  265.         _crBkgnd = pbi->crBkgnd;
  266.         _fHaveBkColor = TRUE;
  267.         if (EVAL(_hwndTB))
  268.             SHSetWindowBits(_hwndTB, GWL_STYLE, TBSTYLE_CUSTOMERASE, TBSTYLE_CUSTOMERASE);
  269.         ASSERT(_hwnd);
  270.         if (_hwndPager)
  271.         {
  272.             TraceMsg(TF_BAND, "cib.sbisfb: Pager_SetBkColor(_hwnd=%x crBkgnd=%x)", _hwnd, _crBkgnd);
  273.             Pager_SetBkColor(_hwnd, _crBkgnd);
  274.         }
  275.     }
  276.     // BUGBUG (kkahl): We don't support changing these once TB is created
  277.     if (pbi->dwMask & ISFB_MASK_COLORS)
  278.     {
  279.         _crBtnLt = pbi->crBtnLt;
  280.         _crBtnDk = pbi->crBtnDk;
  281.         _fHaveColors = TRUE;
  282.     }
  283.     if (pbi->dwMask & ISFB_MASK_VIEWMODE)
  284.     {
  285.         _uIconSize = (pbi->wViewMode & 3); // stored in a 2-bit field currently...
  286.         // only force no recalc if one of the recalcable fields was set
  287.         _fNoRecalcDefaults = TRUE;
  288.     }
  289.     // If the bandsite queried us before, let it know the info may have changed
  290.     if (_fInitialized)
  291.         _BandInfoChanged();
  292.     return S_OK;
  293. }
  294. /*----------------------------------------------------------
  295. Purpose: IShellFolderBand::GetBandInfoSFB
  296. */
  297. HRESULT CISFBand::GetBandInfoSFB(BANDINFOSFB * pbi)
  298. {
  299.     ASSERT(pbi);
  300.     if (!pbi)
  301.         return E_POINTER;
  302.     if (pbi->dwMask & ISFB_MASK_STATE)
  303.     {
  304.         pbi->dwState = 0;
  305.         pbi->dwStateMask = ISFB_STATE_ALL;
  306.         if (_fDebossed)
  307.             pbi->dwState |= ISFB_STATE_DEBOSSED;
  308.         if (_fAllowRename)
  309.             pbi->dwState |= ISFB_STATE_ALLOWRENAME;
  310.         if (_fNoShowText)
  311.             pbi->dwState |= ISFB_STATE_NOSHOWTEXT;
  312.         if (_fLinksMode)
  313.             pbi->dwState |= ISFB_STATE_QLINKSMODE;
  314.         if (_fFullOpen)
  315.             pbi->dwState |= ISFB_STATE_FULLOPEN;
  316.         if (_fNoNameSort)
  317.             pbi->dwState |= ISFB_STATE_NONAMESORT;
  318.         if (_fBtnMinSize)
  319.             pbi->dwState |= ISFB_STATE_BTNMINSIZE;
  320.     }
  321.     if (pbi->dwMask & ISFB_MASK_BKCOLOR)
  322.     {
  323.         pbi->crBkgnd = (_fHaveBkColor) ? _crBkgnd : CLR_DEFAULT;
  324.     }
  325.     if (pbi->dwMask & ISFB_MASK_COLORS)
  326.     {
  327.         if (_fHaveColors)
  328.         {
  329.             pbi->crBtnLt = _crBtnLt;
  330.             pbi->crBtnDk = _crBtnDk;
  331.         }
  332.         else
  333.         {
  334.             pbi->crBtnLt = CLR_DEFAULT;
  335.             pbi->crBtnDk = CLR_DEFAULT;
  336.         }
  337.     }
  338.     if (pbi->dwMask & ISFB_MASK_VIEWMODE)
  339.     {
  340.         pbi->wViewMode = _uIconSize;
  341.     }
  342.     if (pbi->dwMask & ISFB_MASK_SHELLFOLDER)
  343.     {
  344.         pbi->psf = _psf;
  345.         if (pbi->psf)
  346.             pbi->psf->AddRef();
  347.     }
  348.     if (pbi->dwMask & ISFB_MASK_IDLIST)
  349.     {
  350.         if (_pidl)
  351.             pbi->pidl = ILClone(_pidl);
  352.         else
  353.             pbi->pidl = NULL;
  354.     }
  355.     return S_OK;
  356. }
  357. // *** IInputObject methods ***
  358. HRESULT CISFBand::TranslateAcceleratorIO(LPMSG lpMsg)
  359. {
  360.     if (SendMessage(_hwnd, TB_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg))
  361.         return S_OK;
  362.     return SUPERCLASS::TranslateAcceleratorIO(lpMsg);
  363. }
  364. void CISFBand::_SetCacheMenuPopup(IMenuPopup* pmp)
  365. {
  366.     if (!SHIsSameObject(pmp, _pmpCache)) {
  367.         _ReleaseMenuPopup(&_pmpCache);
  368.         _pmpCache = pmp;
  369.         if (_pmpCache)
  370.             _pmpCache->AddRef();
  371.     }
  372. }
  373. void CISFBand::_ReleaseMenuPopup(IMenuPopup** ppmp)
  374. {
  375.     IUnknown_SetSite(*ppmp, NULL);
  376.     ATOMICRELEASE(*ppmp);
  377. }
  378. /*----------------------------------------------------------
  379. Purpose: Releases the held menu popup.
  380. */
  381. void CISFBand::_ReleaseMenu()
  382. {
  383.     if (!SHIsSameObject(_pmp, _pmpCache)) {
  384.         TraceMsg(TF_MENUBAND, "Releasing pmp %#lx", _pmp);
  385.         _ReleaseMenuPopup(&_pmp);
  386.     } else
  387.         ATOMICRELEASE(_pmp);
  388. }
  389. //***
  390. // ENTRY/EXIT
  391. //  S_OK        desktop browser
  392. //  S_FALSE     other browser (explorer, OC, etc.)
  393. //  E_xxx       not a browser at all (e.g. band asking tray)
  394. HRESULT IsDesktopBrowser(IUnknown *punkSite)
  395. {
  396.     HRESULT hr;
  397.     IServiceProvider *psp;
  398.     IUnknown *punk;
  399.     hr = E_FAIL;
  400.     if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_STopLevelBrowser, IID_IServiceProvider, (void**)&psp))) {
  401.         hr = S_FALSE;
  402.         if (SUCCEEDED(psp->QueryInterface(SID_SShellDesktop, (void**)&punk))) {
  403.             hr = S_OK;
  404.             punk->Release();
  405.         }
  406.         psp->Release();
  407.     }
  408.     TraceMsg(DM_VERBOSE, "idb: ret hrDesk=%x (0=dt 1=sh e=!brow)", hr);
  409.     return hr;
  410. }
  411. /*----------------------------------------------------------
  412. Purpose: IDockingWindow::SetSite method.
  413. */
  414. HRESULT CISFBand::SetSite(IUnknown* punkSite)
  415. {
  416.     _ReleaseMenu();
  417.     SUPERCLASS::SetSite(punkSite);
  418.     if (_punkSite)
  419.     {
  420.         if (!_hwndTB)
  421.             _CreateToolbar(_hwndParent);
  422.         IUnknown_SetOwner(_psf, SAFECAST(this, IDeskBand*));
  423.         _Initialize();  // BUGBUG always or just on 1st SetSite?
  424.     }
  425.     else
  426.         IUnknown_SetOwner(_psf, NULL);
  427.     // BUGBUG: the below is bogus - no need to throw away and recreate.
  428.     // First destroy the band proxy
  429.     // Call SetSite(NULL) only if you own
  430.     // if not, it's the parent from whom you got it via QS who will call SetSite(NULL)
  431.     if(_pbp && _fCreatedBandProxy)
  432.         _pbp->SetSite(NULL);
  433.     ATOMICRELEASE(_pbp);
  434.     _fCreatedBandProxy = FALSE;
  435.     // Need a bandproxy
  436.     QueryService_SID_IBandProxy(punkSite, IID_IBandProxy, &_pbp, NULL);
  437.     if(!_pbp)
  438.     {
  439.         // We need to create it ourselves since our parent couldn't help
  440.         ASSERT(FALSE == _fCreatedBandProxy);
  441.         HRESULT hres;
  442.         hres = CreateIBandProxyAndSetSite(punkSite, IID_IBandProxy, &_pbp, NULL);
  443.         if(_pbp)
  444.         {
  445.             ASSERT(S_OK == hres);
  446.             _fCreatedBandProxy = TRUE;
  447.         }
  448.     }
  449.     ASSERT(_pbp);
  450.     return S_OK;
  451. }
  452. void CISFBand::_Initialize()
  453. {
  454.     _fDesktop = (IsDesktopBrowser(_punkSite) == S_OK);
  455.     return;
  456. }
  457. /*----------------------------------------------------------
  458. Purpose: IDockingWindow::CloseDW method.
  459. */
  460. HRESULT CISFBand::CloseDW(DWORD dw)
  461. {
  462.     _fClosing = TRUE;
  463.     // close down the task scheduler ...
  464.     if ( _pTaskScheduler )
  465.         ATOMICRELEASE( _pTaskScheduler );
  466.     _UnregisterToolbar();
  467.     EmptyToolbar();
  468.     IUnknown_SetOwner(_psf, NULL);
  469.     _SetCacheMenuPopup(NULL);
  470.     // should get freed in EmptyToolbar();
  471.     ASSERT(!_hdpa);
  472.     return SUPERCLASS::CloseDW(dw);
  473. }
  474. /*----------------------------------------------------------
  475. Purpose: IDockingWindow::ShowDW method
  476. */
  477. HRESULT CISFBand::ShowDW(BOOL fShow)
  478. {
  479.     HRESULT hres = S_OK;
  480.     SUPERCLASS::ShowDW(fShow);
  481.     if (fShow)
  482.     {
  483.         _fShow = TRUE;
  484.         if (_fDirty)
  485.         {
  486.             _FillToolbar();
  487.         }
  488.         if (!_fDelayInit)
  489.         {
  490.             _RegisterToolbar();
  491.         }
  492.     }
  493.     else
  494.     {
  495.         _fShow = FALSE;
  496.     }
  497.     return hres;
  498. }
  499. void CISFBand::_StopDelayPainting()
  500. {
  501.     if (_fDelayPainting) {
  502.         _fDelayPainting = FALSE;
  503.         // May be called by background thread
  504.         // Use PostMessage instead of SendMessage to avoid deadlock
  505.         PostMessage(_hwndTB, WM_SETREDRAW, TRUE, 0);
  506.         if (_hwndPager)
  507.             PostMessage(_hwnd, PGM_RECALCSIZE, 0L, 0L);
  508.     }
  509. }
  510. HWND CISFBand::_CreatePager(HWND hwndParent)
  511. {
  512.     // don't create a pager for isfbands
  513.     return hwndParent;
  514. }
  515. void CISFBand::_CreateToolbar(HWND hwndParent)
  516. {
  517.     if (_fHaveBkColor)
  518.         _dwStyle |= TBSTYLE_CUSTOMERASE;
  519.     CSFToolbar::_CreateToolbar(hwndParent);
  520.     if ( _fHaveBkColor )
  521.         ToolBar_SetInsertMarkColor(_hwndTB, GetSysColor( COLOR_BTNFACE ));
  522.     ASSERT(_hwndTB);
  523.     SendMessage(_hwndTB, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_DRAWDDARROWS, TBSTYLE_EX_DRAWDDARROWS);
  524.     if(_fChannels)
  525.     {
  526.         SHSetWindowBits(_hwndTB, GWL_EXSTYLE, dwExStyleRTLMirrorWnd, 0);        
  527.     }    
  528.     _hwnd = _hwndPager ? _hwndPager : _hwndTB;
  529.     if (_fHaveColors)
  530.     {
  531.         COLORSCHEME cs;
  532.         cs.dwSize = SIZEOF(cs);
  533.         cs.clrBtnHighlight  = _crBtnLt;
  534.         cs.clrBtnShadow     = _crBtnDk;
  535.         SendMessage(_hwndTB, TB_SETCOLORSCHEME, 0, (LPARAM) &cs);
  536.     }
  537. }
  538. int CISFBand::_GetBitmap(int iCommandID, PIBDATA pibdata, BOOL fUseCache)
  539. {
  540.     int iBitmap;
  541.     if ( _uIconSize == ISFBVIEWMODE_LOGOS )
  542.     {
  543.         LPRUNNABLETASK pTask = NULL;
  544.         DWORD dwPriority = 0;
  545.         // fetch the logo instead...
  546.         ASSERT(!_fDelayPainting);
  547.        // Warning - cannot hold ptask in a member variable - it will be a circular reference
  548.         iBitmap = GetLogoIndex( iCommandID, pibdata->GetPidl(), &pTask, &dwPriority, NULL );
  549.         if (pTask)
  550.         {
  551.             AddTaskToQueue(pTask, dwPriority, (DWORD)iCommandID);
  552.             ATOMICRELEASE(pTask);
  553.         }
  554.     }
  555.     else
  556.         iBitmap = CSFToolbar::_GetBitmap(iCommandID, pibdata, fUseCache);
  557.     return iBitmap;
  558. }
  559. void CISFBand::_SetDirty(BOOL fDirty)
  560. {
  561.     CSFToolbar::_SetDirty(fDirty);
  562.     if (fDirty)
  563.         IUnknown_Exec(_punkSite, &CGID_PrivCITCommands, CITIDM_SET_DIRTYBIT, TRUE, NULL, NULL);
  564. }
  565. BOOL CISFBand::_UpdateIconSize(UINT uIconSize, BOOL fUpdateButtons)
  566. {
  567.     BOOL fChanged = (_uIconSize != uIconSize);
  568.     _uIconSize = uIconSize;
  569.     HIMAGELIST himl = NULL;
  570.     if ( uIconSize == ISFBVIEWMODE_LOGOS )
  571.     {
  572.         if ( SUCCEEDED( InitLogoView()))
  573.         {
  574.             himl = GetLogoHIML();
  575.         }
  576.         if ( himl )
  577.         {
  578.             SendMessage(_hwndTB, TB_SETIMAGELIST, 0, (LPARAM)himl);
  579.             _UpdateButtons();
  580.         }
  581.     }
  582.     if ( !himl )
  583.         fChanged |= CSFToolbar::_UpdateIconSize(uIconSize,fUpdateButtons);
  584.     return fChanged;
  585. }
  586. void CISFBand::_UpdateVerticalMode(BOOL fVertical)
  587. {
  588.     _fVertical = (fVertical != 0);
  589.     TraceMsg(TF_BAND, "ISFBand::_UpdateVerticalMode going %hs", _fVertical ? "VERTICAL" : "HORIZONTAL");
  590.     ASSERT(_hwnd);
  591.     if (_hwndPager) {
  592.         SHSetWindowBits(_hwnd, GWL_STYLE, PGS_HORZ|PGS_VERT,
  593.             _fVertical ? PGS_VERT : PGS_HORZ);
  594.     }
  595.     if (_hwndTB)
  596.     {
  597.         SHSetWindowBits(_hwndTB, GWL_STYLE, TBSTYLE_WRAPABLE | CCS_VERT,
  598.             TBSTYLE_WRAPABLE | (_fVertical ? CCS_VERT : 0));
  599.     }
  600. }
  601. HRESULT IUnknown_QueryBand(IUnknown *punk, DWORD dwBandID, IDeskBand** ppstb, DWORD* pdwState, LPWSTR pszName, int cchName)
  602. {
  603.     HRESULT hr;
  604.     IBandSite *pbs;
  605.     hr = punk->QueryInterface(IID_IBandSite, (void**)&pbs);
  606.     if (SUCCEEDED(hr)) {
  607.         hr = pbs->QueryBand(dwBandID, ppstb, pdwState, pszName, cchName);
  608.         pbs->Release();
  609.     }
  610.     return hr;
  611. }
  612. #define CISFBAND_GETBUTTONSIZE()  (_hwndTB ?  (LONG)SendMessage(_hwndTB, TB_GETBUTTONSIZE, 0, 0L) : MAKELONG(16, 16))
  613. //
  614. // _GetIdealSize
  615. //
  616. // calculates ideal height and width for band and passes back in
  617. // psize, if psize isn't NULL; return value is band's 'ideal length'
  618. // (ideal height if vertical, else ideal width)
  619. //
  620. int CISFBand::_GetIdealSize(PSIZE psize)
  621. {
  622.     SIZE size;
  623.     LONG lButtonSize = CISFBAND_GETBUTTONSIZE();
  624.     RECT rc = {0};
  625.     if (_hwndTB)
  626.         GetClientRect(_hwndTB, &rc);
  627.     if (_fVertical)
  628.     {
  629.         // set width to be max of toolbar width and toolbar button width
  630.         size.cx = max(RECTWIDTH(rc), LOWORD(lButtonSize));
  631.         // have toolbar calculate height given that width
  632.         SendMessage(_hwndTB, TB_GETIDEALSIZE, TRUE, (LPARAM)&size);
  633.     }
  634.     else
  635.     {
  636.         // set height to be max of toolbar width and toolbar button width
  637.         size.cy = max(RECTHEIGHT(rc), HIWORD(lButtonSize));
  638.         // have toolbar calculate width given that height
  639.         SendMessage(_hwndTB, TB_GETIDEALSIZE, FALSE, (LPARAM)&size);
  640.     }
  641.     // BUGBUG: I'm ripping out this check as it causes nt5 bug #225449 (disappearing chevron).
  642.     // _fDirty == TRUE doesn't mean "we're still waiting to call _FillToolbar", it just means
  643.     // "we need to persist out this order stream".  The bit gets set after a drag-and-drop
  644.     // reordering, but we don't call a matching _FillToolbar in that case.
  645. #if 0
  646.     if (_fDirty)
  647.     {
  648.         // until the TB is populated, we get back bogus data from the
  649.         // above.  so use -1 until we actually have a correct answer.
  650.         size.cx = size.cy = -1;
  651.     }
  652. #endif
  653.     if (psize)
  654.         *psize = size;
  655.     return _fVertical ? size.cy : size.cx;
  656. }
  657. /*----------------------------------------------------------
  658. Purpose: IDeskBand::GetBandInfo method
  659. */
  660. HRESULT CISFBand::GetBandInfo(DWORD dwBandID, DWORD fViewMode,
  661.                               DESKBANDINFO* pdbi)
  662. {
  663.     HRESULT hr = S_OK;
  664.     _dwBandID = dwBandID;
  665.     // We don't know the default icon size until GetBandInfo is called.
  666.     // After we set the default, we pay attention to the context menu.
  667.     //
  668.     if (!_fNoRecalcDefaults)
  669.     {
  670.         _uIconSize = (fViewMode & (DBIF_VIEWMODE_FLOATING |DBIF_VIEWMODE_VERTICAL)) ? ISFBVIEWMODE_LARGEICONS : ISFBVIEWMODE_SMALLICONS;
  671.         _fNoRecalcDefaults = TRUE;
  672.     }
  673.     if (!_fInitialized) {
  674.         _fInitialized = TRUE;
  675.         _UpdateIconSize(_uIconSize, FALSE);
  676.         _UpdateShowText(_fNoShowText);
  677.     }
  678.     // we treat floating the same as vertical
  679.     _UpdateVerticalMode(fViewMode & (DBIF_VIEWMODE_FLOATING |DBIF_VIEWMODE_VERTICAL));
  680.     LONG lButtonSize = CISFBAND_GETBUTTONSIZE();
  681.     pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT | DBIMF_USECHEVRON;
  682.     if (_fDebossed)
  683.         pdbi->dwModeFlags |= DBIMF_DEBOSSED;
  684.     pdbi->ptMinSize.x = 0;
  685.     pdbi->ptMaxSize.y = 32000; // random
  686.     pdbi->ptIntegral.y = 1;
  687.     pdbi->ptIntegral.x = 1;
  688.     if (!_fFullOpen)
  689.         _iIdealLength = _GetIdealSize((PSIZE)&pdbi->ptActual);
  690.     // CalcMinWidthHeight {
  691.     // BUGBUG need pager msg for cx/cy scroll
  692.     #define g_cxScrollbar   (GetSystemMetrics(SM_CXVSCROLL) * 3 / 4)
  693.     #define g_cyScrollbar   (GetSystemMetrics(SM_CYVSCROLL) * 3 / 4)
  694.     #define CX_TBBUTTON_MAX (16 + CX_FILENAME_AVG)  // button + name
  695.     #define CY_TBBUTTON_MAX (16)                    // button
  696.     int csBut, csButMin, clBut, clButMin, clScroll;
  697.     // set up short/long aliases
  698.     if (_fVertical) {
  699.         csBut = LOWORD(lButtonSize);
  700.         if (_fBtnMinSize)
  701.             csButMin = min(csBut, CX_TBBUTTON_MAX);
  702.         else
  703.             csButMin = 0;   // people like to shrink things way down, so let 'em
  704.         clBut = HIWORD(lButtonSize);
  705.         clButMin = clBut;
  706.         //ASSERT(min(clBut, CY_TBBUTTON_MAX) == clButMin);  // fails!
  707.         clScroll = g_cyScrollbar;
  708.     }
  709.     else {
  710.         csBut = HIWORD(lButtonSize);
  711.         csButMin = csBut;
  712.         //ASSERT(min(csBut, CY_TBBUTTON_MAX) == csButMin);  // fails!
  713.         clBut = LOWORD(lButtonSize);
  714.         clButMin = min(clBut, CX_TBBUTTON_MAX);
  715.         clScroll = g_cxScrollbar;
  716.         // nt5:176448: integral for horz
  717.         //pdbi->ptIntegral.y = csBut;   this is the cause for 287082 and 341592
  718.     }
  719.     // n.b. virt pdbi->pt.x,y is really phys y,x (i.e. phys long,short)
  720.     pdbi->ptMinSize.x = 0;
  721.     pdbi->ptMinSize.y = csButMin;
  722.     DWORD dwState = BSSF_NOTITLE;
  723.     IUnknown_QueryBand(_punkSite, dwBandID, NULL, &dwState, NULL, 0);
  724.     if (dwState & BSSF_NOTITLE) {   // _fNoTitle
  725.         int i, cBut, clTmp;
  726.         // cbut=    text    notext
  727.         // horz     1       4
  728.         // vert     1       1
  729.         cBut = 1;
  730.         if (!_fVertical && _fNoShowText) {
  731.             // special-case for QLaunch so see several buttons
  732.             cBut = 4;   // for both QLaunch and arbitrary ISF band
  733.         }
  734.         pdbi->ptMinSize.x = cBut * clButMin;
  735.         if (_hwndPager) {
  736.             // tack on extra space for pager arrows
  737.             pdbi->ptMinSize.x += 2 * clScroll;
  738.         }
  739.         i = (int)SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0);
  740.         if (i <= cBut) {
  741.             clTmp = i * clBut;
  742.             if (clTmp < pdbi->ptMinSize.x) {
  743.                 // scrollbars take as much space as button would
  744.                 // so just do the button
  745.                 pdbi->ptMinSize.x = clTmp;
  746.             }
  747.         }
  748.     }
  749.     // }
  750. #if 0 // BUGBUG don't we need this?
  751.     if (_fHaveBkColor) {
  752.         pdbi->crBkgnd = _crBkgnd;
  753.         pdbi->dwModeFlags |= DBIMF_BKCOLOR;
  754.     }
  755. #endif
  756.     hr = _GetTitleW(pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle));
  757.     if (FAILED(hr))
  758.     {
  759.         // we don't support title
  760. #ifdef DEBUG
  761.         if (pdbi->dwMask & DBIM_TITLE)
  762.             TraceMsg(DM_VERBOSE, "cisfb.gbi: patch ~DBIM_TITLE");
  763. #endif
  764.         pdbi->dwMask &= ~DBIM_TITLE;
  765.     }
  766.     return hr;
  767. }
  768. LRESULT CISFBand::_OnCustomDraw(NMCUSTOMDRAW* pnmcd)
  769. {
  770.     NMTBCUSTOMDRAW * ptbcd = (NMTBCUSTOMDRAW *)pnmcd;
  771.     LRESULT lres = CDRF_DODEFAULT;
  772.     switch (pnmcd->dwDrawStage)
  773.     {
  774.     case CDDS_PREPAINT:
  775.         // if there is a palette, then quietly select it into the DC ...
  776.         if ( _hpalHalftone && _uIconSize == ISFBVIEWMODE_LOGOS )
  777.         {
  778.             ASSERT( pnmcd->hdc );
  779.             _hpalOld = SelectPalette( pnmcd->hdc, _hpalHalftone, TRUE );
  780.             // LINTASSERT(_hpalOld || !_hpalOld);   // 0 semi-ok for SelectPalette
  781.             RealizePalette( pnmcd->hdc );
  782.         }
  783.         // make sure we get the postpaint as well so we can de-select the palette...
  784.         lres = CDRF_NOTIFYPOSTPAINT;
  785.         break;
  786.     case CDDS_POSTPAINT:
  787.         // if there is a palette, then quietly select it into the DC ...
  788.         if ( _hpalHalftone && _uIconSize == ISFBVIEWMODE_LOGOS )
  789.         {
  790.             ASSERT( pnmcd->hdc );
  791.             (void) SelectPalette( pnmcd->hdc, _hpalOld, TRUE );
  792.             // we don't need a realize here, we can keep the other palette realzied, we
  793.             // re select the old palette above, otherwise we bleed the resource....
  794.             // RealizePalette( pnmcd->hdc );
  795.         }
  796.         break;
  797.     case CDDS_PREERASE:
  798.         if (_fHaveBkColor)
  799.         {
  800.             RECT rcClient;
  801.             GetClientRect(_hwndTB, &rcClient);
  802.             SHFillRectClr(pnmcd->hdc, &rcClient, _crBkgnd);
  803.             lres = CDRF_SKIPDEFAULT;
  804.         }
  805.         break;
  806.     }
  807.     return lres;
  808. }
  809. void CISFBand::_OnDragBegin(int iItem, DWORD dwPreferedEffect)
  810. {
  811.     LPCITEMIDLIST pidl = _IDToPidl(iItem, &_iDragSource);
  812.     ToolBar_MarkButton(_hwndTB, iItem, TRUE);
  813.     DragDrop(_hwnd, _psf, pidl, dwPreferedEffect, NULL);
  814.     ToolBar_MarkButton(_hwndTB, iItem, FALSE);
  815.     _iDragSource = -1;
  816. }
  817. LRESULT CISFBand::_OnHotItemChange(NMTBHOTITEM * pnm)
  818. {
  819.     LPNMTBHOTITEM  lpnmhi = (LPNMTBHOTITEM)pnm;
  820.     LRESULT lres = 0;
  821.     if (_hwndPager && (lpnmhi->dwFlags & HICF_ARROWKEYS))
  822.     {
  823.         int iOldPos, iNewPos;
  824.         RECT rc, rcPager;
  825.         int heightPager;
  826.         int iSelected = lpnmhi->idNew;
  827.         iOldPos = (int)SendMessage(_hwnd, PGM_GETPOS, (WPARAM)0, (LPARAM)0);
  828.         iNewPos = iOldPos;
  829.         SendMessage(_hwndTB, TB_GETITEMRECT, (WPARAM)iSelected, (LPARAM)&rc);
  830.         if (rc.top < iOldPos)
  831.         {
  832.              iNewPos =rc.top;
  833.         }
  834.         GetClientRect(_hwnd, &rcPager);
  835.         heightPager = RECTHEIGHT(rcPager);
  836.         if (rc.top >= iOldPos + heightPager)
  837.         {
  838.              iNewPos += (rc.bottom - (iOldPos + heightPager)) ;
  839.         }
  840.         if (iNewPos != iOldPos)
  841.             SendMessage(_hwnd, PGM_SETPOS, (WPARAM)0, (LPARAM)iNewPos);
  842.     }
  843.     else
  844.     {
  845.         lres = CToolbarBand::_OnHotItemChange(pnm);
  846.     }
  847.     return lres;
  848. }
  849. LRESULT CISFBand::_OnNotify(LPNMHDR pnm)
  850. {
  851.     LRESULT lres = 0;
  852.     switch (pnm->code)
  853.     {
  854.     case TBN_DROPDOWN:
  855.         {
  856.             LPNMTOOLBAR pnmtb = (LPNMTOOLBAR)pnm;
  857.             lres = TBDDRET_DEFAULT;
  858.             _DropdownItem(_IDToPidl(pnmtb->iItem), pnmtb->iItem);
  859.         }
  860.         break;
  861.     default:
  862.         lres = CSFToolbar::_OnNotify(pnm);
  863.     }
  864.     return lres;
  865. }
  866. HRESULT CISFBand::_TBStyleForPidl(LPCITEMIDLIST pidl, 
  867.                                DWORD * pdwTBStyle, DWORD* pdwTBState, DWORD * pdwMIFFlags, int* piIcon)
  868. {
  869.     HRESULT hres = CSFToolbar::_TBStyleForPidl(pidl, pdwTBStyle, pdwTBState, pdwMIFFlags, piIcon);
  870.     if (_fAllowDropdown &&
  871.         !_fCascadeFolder && 
  872.         ((_GetAttributesOfPidl(pidl, SFGAO_FOLDER) & SFGAO_FOLDER) ||
  873.          IsBrowsableShellExt(pidl)))
  874.     {
  875.         *pdwTBStyle &= ~BTNS_BUTTON;
  876.         *pdwTBStyle |= BTNS_DROPDOWN;
  877.     }
  878.     return hres;
  879. }
  880. LRESULT CISFBand::_OnContextMenu(WPARAM wParam, LPARAM lParam)
  881. {
  882.     LRESULT lres;
  883.     lres = CSFToolbar::_OnContextMenu(wParam, lParam);
  884.     // todo: csidl?
  885.     TraceMsg(DM_MISC, "cib._ocm: _dwPriv=%d", _dwPriv);
  886.     UEMFireEvent(&UEMIID_SHELL, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_UICONTEXT, (_dwPriv == CSIDL_APPDATA || _dwPriv == CSIDL_FAVORITES) ? UIBL_CTXTQCUTITEM : UIBL_CTXTISFITEM);
  887.     return lres;
  888. }
  889. LRESULT CISFBand::_DefWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  890. {
  891.     switch (uMsg) {
  892.     case WM_SIZE:
  893.         // forward to toolbar
  894.         SendMessage(_hwndTB, TB_AUTOSIZE, wParam, lParam);
  895.         if (_GetIdealSize(NULL) != _iIdealLength) {
  896.             // our ideal size has changed since the last time bandsite
  897.             // asked; so tell bandsite ask us for our bandinfo again
  898.             _BandInfoChanged();
  899.         }
  900.         return 0;
  901.     }
  902.     return CSFToolbar::_DefWindowProc(hwnd, uMsg, wParam, lParam);
  903. }
  904. /*----------------------------------------------------------
  905. Purpose: Set the given IMenuPopup as the submenu to expand.  Returns
  906.          S_FALSE if the menu was modal, S_OK if it was modeless, or
  907.          failure.
  908. */
  909. HRESULT CISFBand::_SetSubMenuPopup(IMenuPopup* pmp, UINT uiCmd, LPCITEMIDLIST pidl, DWORD dwFlagsMPPF)
  910. {
  911.     HRESULT hres = E_FAIL;
  912.     _ReleaseMenu();
  913.     _pmp = pmp;
  914.     if (pmp) {
  915.         pmp->AddRef();
  916.         RECT rc;
  917.         POINT pt;
  918.         SendMessage(_hwndTB, TB_GETRECT, uiCmd, (LPARAM)&rc);
  919.         MapWindowPoints(_hwndTB, HWND_DESKTOP, (POINT*)&rc, 2);
  920.         // Align the sub menu appropriately
  921.         if (_fVertical) {
  922.             pt.x = rc.right;
  923.             pt.y = rc.top;
  924.         } else {
  925.             pt.x = rc.left;
  926.             pt.y = rc.bottom;
  927.         }
  928.         //
  929.         // Use a reflect point for the sub-menu to start
  930.         // if the window is RTL mirrored. [samera]
  931.         //
  932.         if (IS_WINDOW_RTL_MIRRORED(_hwndTB)) {
  933.             pt.x = (_fVertical) ? rc.left : rc.right;
  934.         }
  935.         // Tell the sub menu deskbar who we are, so it can
  936.         // inform us later when the user navigates out of
  937.         // its scope.
  938.         IUnknown_SetSite(_pmp, SAFECAST(this, IDeskBand*));
  939.         // This must be called after SetSite is done above
  940.         _SendInitMenuPopup(pmp, pidl);
  941.         // Show the menubar
  942.         hres = _pmp->Popup((POINTL*)&pt, (RECTL*)&rc, dwFlagsMPPF);
  943.     }
  944.     return hres;
  945. }
  946. void CISFBand::_SendInitMenuPopup(IMenuPopup * pmp, LPCITEMIDLIST pidl)
  947. {
  948. }
  949. IMenuPopup* ISFBandCreateMenuPopup(IUnknown *punk, IShellFolder* psf, LPCITEMIDLIST pidl, BANDINFOSFB * pbi, BOOL bMenuBand)
  950. {
  951.     return ISFBandCreateMenuPopup2(punk, NULL, psf, pidl, pbi, bMenuBand);
  952. }
  953. IMenuPopup* ISFBandCreateMenuPopup2(IUnknown *punk, IMenuBand* pmb, IShellFolder* psf, LPCITEMIDLIST pidl, BANDINFOSFB * pbi, BOOL bMenuBand)
  954. {
  955.     IMenuPopup* pmpParent = NULL;
  956.     VARIANTARG v = {0};
  957.     BOOL fUseCache = FALSE;
  958.     if (punk && pidl) {
  959.         fUseCache = TRUE;
  960.         IUnknown_Exec(punk, &CGID_ISFBand, ISFBID_CACHEPOPUP, 0, NULL, &v);
  961.         if (v.vt == VT_UNKNOWN && v.punkVal)
  962.             v.punkVal->QueryInterface(IID_IMenuPopup, (void **)&pmpParent);
  963.     }
  964.     IMenuPopup * pmp = CreateMenuPopup2(pmpParent, pmb, psf, pidl, pbi, bMenuBand);
  965.     if (fUseCache) {
  966.         // cache it now
  967.         // clear from the variant above to release v.punkVal of pmpParent
  968.         VariantClear(&v);
  969.         if (pmp) {
  970.             VariantInit(&v);
  971.             v.vt = VT_UNKNOWN;
  972.             v.punkVal = pmp;
  973.             pmp->AddRef();
  974.             IUnknown_Exec(punk, &CGID_ISFBand, ISFBID_CACHEPOPUP, 0, &v, NULL);
  975.             VariantClear(&v);
  976.         }
  977.     }
  978.     ATOMICRELEASE(pmpParent);
  979.     return pmp;
  980. }
  981. IMenuPopup * CISFBand::_CreateMenuPopup(
  982.     IShellFolder * psfChild,
  983.     LPCITEMIDLIST  pidlFull,
  984.     BANDINFOSFB *  pbi)
  985. {
  986.     return ISFBandCreateMenuPopup(SAFECAST(this, IOleCommandTarget*), psfChild, pidlFull, pbi, FALSE);
  987. }
  988. HRESULT CISFBand::_DropdownItem(LPCITEMIDLIST pidl, UINT idCmd)
  989. {
  990.     HRESULT hres = E_FAIL;
  991.     if (_pidl && _psf)
  992.     {
  993.         LPITEMIDLIST pidlFull = ILCombine(_pidl, pidl);
  994.         if (pidlFull)
  995.         {
  996.             IShellFolder* psf;
  997.             if (SUCCEEDED(_psf->BindToObject(pidl, NULL, IID_IShellFolder, (void **)&psf)))
  998.             {
  999.                 RECT rc;
  1000.                 SendMessage(_hwndTB, TB_GETRECT, idCmd, (LPARAM)&rc);
  1001.                 MapWindowPoints(_hwndTB, HWND_DESKTOP, (POINT*)&rc, 2);
  1002.                 ITrackShellMenu* ptsm;
  1003.                 if (SUCCEEDED(CoCreateInstance(CLSID_TrackShellMenu, NULL, CLSCTX_INPROC_SERVER,
  1004.                     IID_ITrackShellMenu, (void**)&ptsm)))
  1005.                 {
  1006.                     ptsm->Initialize(NULL, 0, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL);
  1007.                     if (SUCCEEDED(ptsm->SetShellFolder(psf, pidlFull, NULL, SMSET_TOP | SMSET_USEBKICONEXTRACTION)))
  1008.                     {
  1009.                         POINTL pt = {rc.left, rc.right};
  1010.                         hres = ptsm->Popup(_hwndTB, &pt, (RECTL*)&rc, MPPF_BOTTOM);
  1011.                     }
  1012.                     ptsm->Release();
  1013.                 }
  1014.                 psf->Release();
  1015.             }
  1016.             ILFree(pidlFull);
  1017.         }
  1018.     }
  1019.     return hres;
  1020. }
  1021. /*----------------------------------------------------------
  1022. Purpose: Try treating the pidl as a cascading menu item.
  1023. Returns: non-zero if succeeded
  1024. */
  1025. LRESULT CISFBand::_TryCascadingItem(LPCITEMIDLIST pidl, UINT uiCmd)
  1026. {
  1027.     LRESULT lRet = 0;
  1028.     // Do we cascade to another submenu?
  1029.     if ((GetKeyState(VK_CONTROL) < 0) || _fCascadeFolder)
  1030.     {
  1031.         // Is the item a browsable folder?
  1032.         if ((_GetAttributesOfPidl(pidl, SFGAO_FOLDER) & SFGAO_FOLDER) ||
  1033.             IsBrowsableShellExt(pidl))
  1034.         {
  1035.             // Yes; cascade the browsable folder as a submenu
  1036.             lRet = (S_OK == _DropdownItem(pidl, uiCmd));
  1037.         }
  1038.     }
  1039.     return lRet;
  1040. }
  1041. /*----------------------------------------------------------
  1042. Purpose: Try just invoking the pidl
  1043. Returns: non-zero if succeeded
  1044. */
  1045. LRESULT CISFBand::_TrySimpleInvoke(LPCITEMIDLIST pidl)
  1046. {
  1047.     LRESULT lRet = 0;
  1048.     if (S_OK == _pbp->IsConnected())    // Force IE
  1049.     {
  1050.         LPITEMIDLIST pidlDest;
  1051.         if (SUCCEEDED(SHGetNavigateTarget(_psf, pidl, &pidlDest, NULL)) && pidlDest &&
  1052.             ILIsWeb(pidlDest))
  1053.         {
  1054.             TCHAR szPath[MAX_PATH];
  1055.             // We want to ensure that we first give NavFrameWithFile a chance
  1056.             // since this will do the right thing if the PIDL points to a
  1057.             // shortcut.
  1058.             // If the PIDL is a shortcut, NavFrameWithFile will restore any
  1059.             // persistence information stored in the shortcut
  1060.             // if that fails - we take the default code path that simply
  1061.             // uses the PIDL
  1062.             lRet = SUCCEEDED(GetPathForItem(_psf, pidl, szPath, NULL)) &&
  1063.                    SUCCEEDED(NavFrameWithFile(szPath, (IServiceProvider *)this));
  1064.             if (!lRet)
  1065.             {
  1066.                 if (EVAL(_pbp) && (SUCCEEDED(_pbp->NavigateToPIDL(pidlDest))))
  1067.                     lRet = 1;
  1068.             }
  1069.             ILFree(pidlDest);
  1070.         }
  1071.     }
  1072.     if (!lRet)
  1073.     {
  1074.         IContextMenu *pcm = (LPCONTEXTMENU)_GetUIObjectOfPidl(pidl, IID_IContextMenu);
  1075.         if (pcm)
  1076.         {
  1077.             LPCSTR pVerb = NULL;
  1078.             UINT fFlags = 0;
  1079.             // If ALT double click, accelerator for "Properties..."
  1080.             if (GetKeyState(VK_MENU) < 0)
  1081.             {
  1082.                 pVerb = SZ_PROPERTIESA;
  1083.             }
  1084.             //
  1085.             //  SHIFT+dblclick does a Explore by default
  1086.             //
  1087.             if (GetKeyState(VK_SHIFT) < 0)
  1088.             {
  1089.                 fFlags |= CMF_EXPLORE;
  1090.             }
  1091.             IContextMenu_Invoke(pcm, _hwndTB, pVerb, fFlags);
  1092.             pcm->Release();
  1093.         }
  1094.     }
  1095.     return lRet;
  1096. }
  1097. /*----------------------------------------------------------
  1098. Purpose: Helper function to call the menubar site's IMenuPopup::OnSelect
  1099.          method.
  1100. */
  1101. HRESULT CISFBand::_SiteOnSelect(DWORD dwType)
  1102. {
  1103.     IMenuPopup * pmp;
  1104.     HRESULT hres = IUnknown_QueryService(_punkSite, SID_SMenuPopup, IID_IMenuPopup, (void **)&pmp);
  1105.     if (SUCCEEDED(hres))
  1106.     {
  1107.         pmp->OnSelect(dwType);
  1108.         pmp->Release();
  1109.     }
  1110.     return hres;
  1111. }
  1112. LRESULT CISFBand::_OnCommand(WPARAM wParam, LPARAM lParam)
  1113. {
  1114.     UINT uiCmd = GET_WM_COMMAND_ID(wParam, lParam);
  1115.     LRESULT lres = 0;
  1116.     TraceMsg(TF_BAND, "_OnCommand 0x%x", uiCmd);
  1117.     LPCITEMIDLIST pidl = _IDToPidl(uiCmd);
  1118.     if (pidl)
  1119.     {
  1120.         if (_eUemLog != UEMIND_NIL) 
  1121.         {
  1122.             // FEATURE_UASSIST should be grp,uiCmd
  1123.             UEMFireEvent(&UEMIID_SHELL, UEME_UIQCUT, UEMF_XEVENT, -1, (LPARAM)-1);
  1124.         }
  1125.         // Only do this if we are the quick links in the browser. The derived class will set this
  1126.         if (_pguidUEMGroup)
  1127.         {
  1128.             LPITEMIDLIST pidlFull = ILCombine(_pidl, pidl);
  1129.             if (pidlFull)
  1130.             {
  1131.                 UEMFireEvent(_pguidUEMGroup, UEME_RUNPIDL, UEMF_XEVENT, (WPARAM)_psf, (LPARAM)pidl);
  1132.                 SHSendChangeMenuNotify(NULL, SHCNEE_PROMOTEDITEM, 0, pidlFull);
  1133.                 ILFree(pidlFull);
  1134.             }
  1135.         }
  1136.         lres = _TryCascadingItem(pidl, uiCmd);
  1137.         if (!lres && _fChannels)
  1138.             lres = _TryChannelSurfing(pidl);
  1139.         if (!lres)
  1140.             lres = _TrySimpleInvoke(pidl);
  1141.     }
  1142.     else
  1143.     {
  1144.         MessageBeep(MB_OK);
  1145.     }
  1146.     return(lres);
  1147. }
  1148. // *** IPersistStream
  1149. //
  1150. HRESULT CISFBand::GetClassID(CLSID *pClassID)
  1151. {
  1152.     *pClassID = CLSID_ISFBand;
  1153.     return S_OK;
  1154. }
  1155. //
  1156. //  This might be a directory inside CSIDL_APPDATA that was created on
  1157. //  a Win9x machine.  Win9x doesn't do the special folder signature info,
  1158. //  so when it shows up on NT, it's just a boring directory that now points
  1159. //  to the wrong place.
  1160. //
  1161. //  So if we get a bad directory, see if it's one of these corrupted
  1162. //  Win9x pidls and if so, try to reconstitute the original CSIDL_APPDATA
  1163. //  by searching for "Application Data".
  1164. //
  1165. void CISFBand::_FixupAppDataDirectory()
  1166. {
  1167.     TCHAR szDirPath[MAX_PATH];
  1168.     //  We use PathFileExists to check for existence because it turns off
  1169.     //  hard error boxes if the target is not available (e.g., floppy not
  1170.     //  in drive)
  1171.     if (SHGetPathFromIDList(_pidl, szDirPath) &&
  1172.         !PathFileExists(szDirPath))
  1173.     {
  1174.         static TCHAR szBSAppData[] = TEXT("\Application Data");
  1175.         LPTSTR pszAppData;
  1176.         // For every instance of "Application Data", try to graft it
  1177.         // into the real CSIDL_APPDATA. If it works, run with it.
  1178.         for (pszAppData = szDirPath;
  1179.              pszAppData = StrStrI(pszAppData, szBSAppData);
  1180.              pszAppData++)
  1181.         {
  1182.             // Found a candidate.  The thing after "\Application Data"
  1183.             // had better be another backslash (in which case we step
  1184.             // over it) or the end of the string (in which case we don't).
  1185.             TCHAR szPathBuffer[MAX_PATH];
  1186.             LPTSTR pszTail = pszAppData + ARRAYSIZE(szBSAppData) - 1;
  1187.             // If we did our math right, we should be right after the
  1188.             // "a" at the end of "Application Data".
  1189.             ASSERT(pszTail[-1] == TEXT('a'));
  1190.             if (pszTail[0] == TEXT('\'))
  1191.                 pszTail++;              // Step over separator
  1192.             else if (pszTail[0] == TEXT(''))
  1193.                 { }                     // at end of string; stay there
  1194.             else
  1195.                 continue;               // we were faked out; keep looking
  1196.             if (SHGetSpecialFolderPath(NULL, szPathBuffer, CSIDL_APPDATA, FALSE))
  1197.             {
  1198.                 PathCombine(szPathBuffer, szPathBuffer, pszTail);
  1199.                 if (PathFileExists(szPathBuffer))
  1200.                 {
  1201.                     LPITEMIDLIST    pidlReal;
  1202.                     pidlReal = ILCreateFromPath(szPathBuffer);
  1203.                     if (pidlReal)
  1204.                     {
  1205.                         ILFree(_pidl);
  1206.                         _pidl = pidlReal;
  1207.                     }
  1208.                     ASSERT(_pidl);
  1209.                     break;              // found it; stop looking
  1210.                 }
  1211.             }
  1212.         }
  1213.     }
  1214. }
  1215. typedef struct tagBANDISFSTREAM {
  1216.     WORD        wVersion;   // version of this structure
  1217.     WORD        cbSize;     // size of this structure
  1218.     DWORD       dwFlags;    // BANDISF_ flags
  1219.     DWORD       dwPriv;     // special folder identifier
  1220.     WORD        wViewMode;  // small/large/logo
  1221.     WORD        wUnused;    // For DWORD alignment
  1222.     COLORREF    crBkgnd;    // band background color
  1223.     COLORREF    crBtnLt;    // band button hilite color
  1224.     COLORREF    crBtnDk;    // band button lolite color
  1225. } BANDISFSTREAM, * PBANDISFSTREAM;
  1226. #define BANDISF_VERSION 0x22
  1227. #define BANDISF_MASK_PSF         0x00000001 // TRUE if _psf is saved
  1228. #define BANDISF_BOOL_NOSHOWTEXT  0x00000002 // TRUE if _fNoShowText
  1229. #define BANDISF_BOOL_LARGEICON   0x00000004 // last used in version 0x20
  1230. #define BANDISF_MASK_PIDLASLINK  0x00000008 // TRUE if _pidl is saved as a link
  1231. #define BANDISF_UNUSED10         0x00000010 // (obsolete) was BOOL_NOTITLE
  1232. #define BANDISF_BOOL_CHANNELS    0x00000020 // TRUE if in channel mode
  1233. #define BANDISF_BOOL_ALLOWRENAME 0x00000040 // TRUE if _psf context menu should be enabled
  1234. #define BANDISF_BOOL_DEBOSSED    0x00000080 // TRUE if band should have embossed background
  1235. #define BANDISF_MASK_ORDERLIST   0x00000100 // TRUE if an order list is saved
  1236. #define BANDISF_BOOL_BKCOLOR     0x00000200 // TRUE if bk color is persisted
  1237. #define BANDISF_BOOL_FULLOPEN    0x00000400 // TRUE if band should maximize when opened
  1238. #define BANDISF_BOOL_NONAMESORT  0x00000800 // TRUE if band should _not_ sort icons by name
  1239. #define BANDISF_BOOL_BTNMINSIZE  0x00001000 // TRUE if band should report min thickness of button
  1240. #define BANDISF_BOOL_COLORS      0x00002000 // TRUE if colors are persisted
  1241. #define BANDISF_VALIDBITS        0x00003FFF
  1242. HRESULT CISFBand::Load(IStream *pstm)
  1243. {
  1244.     HRESULT hres;
  1245.     DWORD cbRead;
  1246.     BANDISFSTREAM bisfs = {0};
  1247.     // figure out what we need to load
  1248.     //
  1249.     // read first DWORD only (old stream format started with ONE dword)
  1250.     hres = pstm->Read(&bisfs, SIZEOF(DWORD), &cbRead);
  1251.     if (SUCCEEDED(hres))
  1252.     {
  1253.         if (bisfs.cbSize == 0)
  1254.         {
  1255.             // upgrade case, IE4 beta1 shipped this way
  1256.             //
  1257.             bisfs.dwFlags = *((LPDWORD)&bisfs);
  1258.             bisfs.cbSize = SIZEOF(bisfs);
  1259.             bisfs.wVersion = BANDISF_VERSION;
  1260.             bisfs.dwPriv = -1;
  1261.             bisfs.wViewMode = (bisfs.dwFlags & BANDISF_BOOL_LARGEICON) ? ISFBVIEWMODE_LARGEICONS : ISFBVIEWMODE_SMALLICONS;
  1262.         }
  1263.         else
  1264.         {
  1265.             // read rest of stream
  1266.             //
  1267.             DWORD dw = (DWORD)bisfs.cbSize;
  1268.             if (dw > SIZEOF(bisfs))
  1269.                 dw = SIZEOF(bisfs);
  1270.             dw -= SIZEOF(DWORD);
  1271.             hres = pstm->Read(&(bisfs.dwFlags), dw, &cbRead);
  1272.             if (FAILED(hres))
  1273.                 return(hres);
  1274.         }
  1275.         // HEY, DON'T BE LAME ANY MORE.  When you next touch this code,
  1276.         // I suggest you figure out what sizes of this structure have
  1277.         // been actually shipped and only upgrade those.  Also use
  1278.         // the offsetof macro so you don't have to keep calculating these
  1279.         // things...
  1280.         // old upgrade, I don't know what state is persisted at setup time!
  1281.         //
  1282.         if (bisfs.cbSize == SIZEOF(bisfs) - 3*SIZEOF(COLORREF) - SIZEOF(DWORD) - SIZEOF(DWORD))
  1283.         {
  1284.             bisfs.dwPriv = -1;
  1285.             bisfs.cbSize += SIZEOF(DWORD);
  1286.         }
  1287.         // most recent upgrade, this is NOT persisted in registry at setup time!!!
  1288.         //
  1289.         if (bisfs.cbSize == SIZEOF(bisfs) - 3*SIZEOF(COLORREF) - SIZEOF(DWORD))
  1290.         {
  1291.             bisfs.wViewMode = (bisfs.dwFlags & BANDISF_BOOL_LARGEICON) ? ISFBVIEWMODE_LARGEICONS : ISFBVIEWMODE_SMALLICONS;
  1292.             bisfs.cbSize = SIZEOF(bisfs);
  1293.         }
  1294.         // upgrade from version 0x21 + crBkgnd only to 0x22
  1295.         //
  1296.         if (bisfs.cbSize == SIZEOF(bisfs) - 2*SIZEOF(COLORREF))
  1297.         {
  1298.             bisfs.cbSize = SIZEOF(bisfs);
  1299.         }
  1300.         // upgrade from version 0x21 to 0x22
  1301.         //
  1302.         if (bisfs.cbSize == SIZEOF(bisfs) - 3*SIZEOF(COLORREF))
  1303.         {
  1304.             bisfs.cbSize = SIZEOF(bisfs);
  1305.         }
  1306.         if (!EVAL(bisfs.cbSize >= SIZEOF(bisfs)))
  1307.         {
  1308.             return(E_FAIL);
  1309.         }
  1310.         ASSERT(!(bisfs.dwFlags & ~BANDISF_VALIDBITS));
  1311.         if (bisfs.dwFlags & BANDISF_BOOL_NOSHOWTEXT)
  1312.             _fNoShowText = TRUE;
  1313.         if (bisfs.dwFlags & BANDISF_BOOL_ALLOWRENAME)
  1314.             _fAllowRename = TRUE;
  1315.         if (bisfs.dwFlags & BANDISF_BOOL_DEBOSSED)
  1316.             _fDebossed = TRUE;
  1317.         if (bisfs.dwFlags & BANDISF_BOOL_FULLOPEN)
  1318.             _fFullOpen = TRUE;
  1319.         if (bisfs.dwFlags & BANDISF_BOOL_NONAMESORT)
  1320.             _fNoNameSort = TRUE;
  1321.         if (bisfs.dwFlags & BANDISF_BOOL_BTNMINSIZE)
  1322.             _fBtnMinSize = TRUE;
  1323.         if (bisfs.dwFlags & BANDISF_BOOL_BKCOLOR)
  1324.         {
  1325.             _crBkgnd = bisfs.crBkgnd;
  1326.             _fHaveBkColor = TRUE;
  1327.         }
  1328.         if (bisfs.dwFlags & BANDISF_BOOL_COLORS)
  1329.         {
  1330.             _crBtnLt = bisfs.crBtnLt;
  1331.             _crBtnDk = bisfs.crBtnDk;
  1332.             _fHaveColors = TRUE;
  1333.         }
  1334.         _dwPriv = bisfs.dwPriv;
  1335. #if 1 // BUGBUG FEATURE_UASSIST hack this should be persisted not recalc'ed
  1336. #define UEMIsLogCsidl(dwPrivID)    ((dwPrivID) == CSIDL_APPDATA)
  1337.         if (UEMIsLogCsidl(_dwPriv)) {
  1338.             _eUemLog = UEMIND_SHELL;
  1339.         }
  1340. #endif
  1341.         _uIconSize = bisfs.wViewMode;
  1342.         _fNoRecalcDefaults = TRUE;
  1343.         if (bisfs.dwFlags & BANDISF_MASK_PIDLASLINK)
  1344.         {
  1345.             ASSERT(NULL==_pidl);
  1346.             hres = LoadPidlAsLink(_punkSite, pstm, &_pidl);
  1347.             // If we hit hits, LoadPidlAsLink() read a chuck of our data. - BryanSt
  1348.             ASSERT(SUCCEEDED(hres));
  1349. //            DEBUG_CODE(TCHAR szDbgBuffer[MAX_PATH];)
  1350. //            TraceMsg(TF_BAND|TF_GENERAL, "CISFBand::Load() _pidl=>%s<", Dbg_PidlStr(_pidl, szDbgBuffer, SIZECHARS(szDbgBuffer)));
  1351.             _FixupAppDataDirectory();
  1352.         }
  1353.                 
  1354.         if (SUCCEEDED(hres) && (bisfs.dwFlags & BANDISF_MASK_PSF))
  1355.         {
  1356.             ASSERT(NULL == _psf);
  1357.             hres = OleLoadFromStream(pstm, IID_IShellFolder, (void **)&_psf);
  1358.         }
  1359.         // map this to working info
  1360.         //
  1361.         if (SUCCEEDED(hres))
  1362.             _AfterLoad();
  1363.         // we need _psf before we can read the order list.
  1364.         if (SUCCEEDED(hres) && (bisfs.dwFlags & BANDISF_MASK_ORDERLIST))
  1365.         {
  1366.             hres = OrderList_LoadFromStream(pstm, &_hdpaOrder, _psf);
  1367.             if (SUCCEEDED(hres))
  1368.             {
  1369.                 // _fDropped "persists" along with the orderlist - if this flag
  1370.                 // is set, we assume we have a non-default ordering
  1371.                 _fDropped = TRUE;
  1372.             }
  1373.         }
  1374.     }
  1375.     return hres;
  1376. }
  1377. HRESULT SaveIsfToStream(IShellFolder *psf, IStream *pstm)
  1378. {
  1379.     IPersistStream* pps;
  1380.     HRESULT hres = psf->QueryInterface(IID_IPersistStream, (void **)&pps);
  1381.     if (SUCCEEDED(hres))
  1382.     {
  1383.         hres = OleSaveToStream(pps, pstm);
  1384.         pps->Release();
  1385.     }
  1386.     return hres;
  1387. }
  1388. HRESULT CISFBand::Save(IStream *pstm, BOOL fClearDirty)
  1389. {
  1390.     IPersistStream* pps = NULL;
  1391.     HRESULT hres;
  1392.     BANDISFSTREAM bisfs = {0};
  1393.     // figure out what we will save
  1394.     //
  1395.     if (_pidl)
  1396.         bisfs.dwFlags |= BANDISF_MASK_PIDLASLINK;
  1397.     // BUGBUG(lamadio): This case is busted. None of the IShellFolders implement IPersistStream (at least as far as
  1398.     // TJ and I can see). Qhen quick links initializes, it will set the pidlQuickLinks as the _pidl. So, in the 
  1399.     // After load, _fPSFBandDesktop gets set to TRUE. Why? I don't know. Well, then we never attempt to persist the 
  1400.     // IShellFolder and we will never fail the save. We should remove this case so we don't run into this again.
  1401.     if (_psf && !_fPSFBandDesktop)
  1402.         bisfs.dwFlags |= BANDISF_MASK_PSF;
  1403.     if (_fDropped && (_hdpa || _hdpaOrder)) // only if a drop occurred do we have non-default ordering
  1404.         bisfs.dwFlags |= BANDISF_MASK_ORDERLIST;
  1405.     if (_fNoShowText)
  1406.         bisfs.dwFlags |= BANDISF_BOOL_NOSHOWTEXT;
  1407.     if (_fAllowRename)
  1408.         bisfs.dwFlags |= BANDISF_BOOL_ALLOWRENAME;
  1409.     if (_fDebossed)
  1410.         bisfs.dwFlags |= BANDISF_BOOL_DEBOSSED;
  1411.     if (_fFullOpen)
  1412.         bisfs.dwFlags |= BANDISF_BOOL_FULLOPEN;
  1413.     if (_fNoNameSort)
  1414.         bisfs.dwFlags |= BANDISF_BOOL_NONAMESORT;
  1415.     if (_fBtnMinSize)
  1416.         bisfs.dwFlags |= BANDISF_BOOL_BTNMINSIZE;
  1417.     if (_fHaveBkColor)
  1418.     {
  1419.         bisfs.dwFlags |= BANDISF_BOOL_BKCOLOR;
  1420.         bisfs.crBkgnd = _crBkgnd;
  1421.     }
  1422.     if (_fHaveColors)
  1423.     {
  1424.         bisfs.dwFlags |= BANDISF_BOOL_COLORS;
  1425.         bisfs.crBtnLt = _crBtnLt;
  1426.         bisfs.crBtnDk = _crBtnDk;
  1427.     }
  1428.     bisfs.cbSize = SIZEOF(bisfs);
  1429.     bisfs.wVersion = BANDISF_VERSION;
  1430.     bisfs.dwPriv = _dwPriv;
  1431.     bisfs.wViewMode = _uIconSize;
  1432.     // now save it
  1433.     //
  1434.     hres = pstm->Write(&bisfs, SIZEOF(bisfs), NULL);
  1435.     if (SUCCEEDED(hres) && bisfs.dwFlags & BANDISF_MASK_PIDLASLINK)
  1436.     {
  1437.         hres = SavePidlAsLink(_punkSite, pstm, _pidl);
  1438.         // BUGBUG: We need to save a terminator.
  1439.     }
  1440.     if (SUCCEEDED(hres) && bisfs.dwFlags & BANDISF_MASK_PSF)
  1441.     {
  1442.         hres = SaveIsfToStream(_psf, pstm);
  1443.     }
  1444.     if (SUCCEEDED(hres) && (bisfs.dwFlags & BANDISF_MASK_ORDERLIST))
  1445.     {
  1446.         hres = OrderList_SaveToStream(pstm, (_hdpa ? _hdpa : _hdpaOrder), _psf);
  1447.     }
  1448.     return(hres);
  1449. }
  1450. #if 0
  1451. // IPersistPropertyBag implementation
  1452. //
  1453. HRESULT CISFBand::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
  1454. {
  1455.     ASSERT(0);  // obsolete!
  1456.     _fCascadeFolder = PropBag_ReadInt4(pPropBag, L"Cascade", FALSE);
  1457.     // n.b. old "Title" property nuked
  1458.     _uIconSize = (PropBag_ReadInt4(pPropBag, L"Large", TRUE) ? ISFBVIEWMODE_LARGEICONS : ISFBVIEWMODE_SMALLICONS);
  1459.     _fNoShowText = PropBag_ReadInt4(pPropBag, L"Text", TRUE);
  1460.     return(S_OK);
  1461. }
  1462. HRESULT CISFBand::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
  1463. {
  1464.     return(E_NOTIMPL);
  1465. }
  1466. HRESULT CISFBand::InitNew()
  1467. {
  1468.     ASSERT(0);  // obsolete!
  1469.     return(E_NOTIMPL);
  1470. }
  1471. #endif
  1472. // IContextMenu implementation
  1473. //
  1474. HRESULT CISFBand::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
  1475. {
  1476.     BOOL fChanged = FALSE;
  1477.     int idCmd = -1;
  1478.     UINT uNewMode = 0;
  1479.     if (!HIWORD(lpici->lpVerb))
  1480.         idCmd = LOWORD(lpici->lpVerb);
  1481.     switch (idCmd)
  1482.     {
  1483.     case ISFBIDM_LARGE:
  1484.         uNewMode = ISFBVIEWMODE_LARGEICONS;
  1485.         goto newViewMode;
  1486.     case ISFBIDM_SMALL:
  1487.         uNewMode = ISFBVIEWMODE_SMALLICONS;
  1488. newViewMode:
  1489.         if (uNewMode != _uIconSize)
  1490.         {
  1491.             BOOL fRefresh = FALSE;
  1492.             if (uNewMode == ISFBVIEWMODE_LOGOS || _uIconSize == ISFBVIEWMODE_LOGOS)
  1493.             {
  1494.                 // invalidate all before switching the imagelist...
  1495.                 _RememberOrder();
  1496.                 EmptyToolbar();
  1497.                 fRefresh = TRUE;
  1498.             }
  1499.             // we Logo view has now left the building...
  1500.             if ( uNewMode != ISFBVIEWMODE_LOGOS && _uIconSize == ISFBVIEWMODE_LOGOS )
  1501.             {
  1502.                 ExitLogoView();
  1503.             }
  1504.             fChanged = _UpdateIconSize(uNewMode, TRUE);
  1505.             if ( fRefresh )
  1506.             {
  1507.                 _FillToolbar();
  1508.             }
  1509.             if (fChanged)
  1510.                 _BandInfoChanged();
  1511.         }
  1512.         // fall thru
  1513.     default:
  1514.         return CSFToolbar::InvokeCommand(lpici);
  1515.     }
  1516.     return(S_OK);
  1517. }
  1518. // *** IOleCommandTarget methods ***
  1519. STDMETHODIMP CISFBand::QueryStatus(const GUID *pguidCmdGroup,
  1520.         ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  1521. {
  1522.     HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  1523.     if (pguidCmdGroup == NULL)
  1524.     {
  1525.         // nothing
  1526.     }
  1527.     else if (IsEqualGUID(CGID_ISFBand, *pguidCmdGroup))
  1528.     {
  1529.         for (UINT i = 0; i < cCmds; i++)
  1530.         {
  1531.             switch (rgCmds[i].cmdID)
  1532.             {
  1533.             case ISFBID_CACHEPOPUP:
  1534.             case ISFBID_ISITEMVISIBLE:
  1535.             case ISFBID_PRIVATEID:
  1536.                 rgCmds[i].cmdf |= OLECMDF_SUPPORTED;
  1537.                 break;
  1538.             }
  1539.         }
  1540.         hr = S_OK;
  1541.     }
  1542.     else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup))
  1543.     {
  1544.         for (UINT i = 0; i < cCmds; i++)
  1545.         {
  1546.             switch (rgCmds[i].cmdID)
  1547.             {
  1548.             case SHDVID_UEMLOG:
  1549.                 rgCmds[i].cmdf |= OLECMDF_SUPPORTED;
  1550.                 break;
  1551.             }
  1552.         }
  1553.         hr = S_OK;
  1554.     }
  1555.     return hr;
  1556. }
  1557. HRESULT CISFBand::_IsPidlVisible(LPITEMIDLIST pidl)
  1558. {
  1559.     int i;
  1560.     if (_GetButtonFromPidl(pidl, NULL, &i)) {
  1561.         RECT rc;
  1562.         GetClientRect(_hwndTB, &rc);
  1563.         if (SHIsButtonObscured(_hwndTB, &rc, i))
  1564.             return S_FALSE;
  1565.         else
  1566.             return S_OK;
  1567.     }
  1568.     return E_FAIL;
  1569. }
  1570. HRESULT CISFBand::_OrderListFromIStream(VARIANT* pvarargIn)
  1571. {
  1572.     HRESULT hres = E_FAIL;
  1573.     if (pvarargIn->vt == VT_UNKNOWN)
  1574.     {
  1575.         IStream* pstm;
  1576.         if (SUCCEEDED(pvarargIn->punkVal->QueryInterface(IID_IStream, (void**)&pstm)))
  1577.         {
  1578.             OrderList_Destroy(&_hdpaOrder);
  1579.             hres = OrderList_LoadFromStream(pstm, &_hdpaOrder, _psf);
  1580.             if (SUCCEEDED(hres))
  1581.             {
  1582.                 _SetDirty(TRUE);
  1583.                 if (_fShow)
  1584.                 {
  1585.                     _FillToolbar();
  1586.                 }
  1587.             }
  1588.             pstm->Release();
  1589.         }
  1590.     }
  1591.     return hres;
  1592. }
  1593. HRESULT CISFBand::_IStreamFromOrderList(VARIANT* pvarargOut)
  1594. {
  1595.     HRESULT hres = E_OUTOFMEMORY;
  1596.     ASSERT(pvarargOut != NULL);
  1597.     IStream* pstm = SHCreateMemStream(NULL, 0);
  1598.     if (pstm)
  1599.     {
  1600.         hres = OrderList_SaveToStream(pstm, _hdpa, _psf);
  1601.         if (SUCCEEDED(hres))
  1602.         {
  1603.             pvarargOut->vt = VT_UNKNOWN;
  1604.             pvarargOut->punkVal = pstm;
  1605.             pvarargOut->punkVal->AddRef();
  1606.         }
  1607.         pstm->Release();
  1608.     }
  1609.     return hres;
  1610. }
  1611. STDMETHODIMP CISFBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  1612.     DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  1613. {
  1614.     if (pguidCmdGroup == NULL)
  1615.     {
  1616.         // nothing
  1617.     }
  1618.     else if (IsEqualGUID(CGID_ISFBand, *pguidCmdGroup))
  1619.     {
  1620.         switch (nCmdID)
  1621.         {
  1622.         case ISFBID_CACHEPOPUP:
  1623.             if (pvarargIn && pvarargIn->vt == VT_UNKNOWN)
  1624.             {
  1625.                 IMenuPopup* pmp = NULL;
  1626.                 if (pvarargIn->punkVal)
  1627.                     pvarargIn->punkVal->QueryInterface(IID_IMenuPopup, (void **)&pmp);
  1628.                 _SetCacheMenuPopup(pmp);
  1629.                 ATOMICRELEASE(pmp);
  1630.             }
  1631.             if (pvarargOut)
  1632.             {
  1633.                 pvarargOut->vt = VT_UNKNOWN;
  1634.                 pvarargOut->punkVal = _pmpCache;
  1635.                 if (_pmpCache)
  1636.                     _pmpCache->AddRef();
  1637.             }
  1638.             return S_OK;
  1639.         case ISFBID_ISITEMVISIBLE:
  1640.             {
  1641.                 HRESULT hr = E_INVALIDARG;
  1642.                 if (pvarargIn && pvarargIn->vt == VT_INT_PTR)
  1643.                     hr = _IsPidlVisible((LPITEMIDLIST)pvarargIn->byref);
  1644.                 return hr;
  1645.             }
  1646.         case ISFBID_PRIVATEID:
  1647.             // hack hack for BSMenu to differentiate between specially created
  1648.             // isfbands. see bsmenu's _FindBand
  1649.             // if pvarargOut is set, we give back the id we have stored.
  1650.             if (pvarargOut)
  1651.             {
  1652.                 pvarargOut->vt = VT_I4;
  1653.                 pvarargOut->lVal = _dwPriv;
  1654.             }
  1655.             // if pvarargIn is set, then we take and keep this id.
  1656.             if (pvarargIn && pvarargIn->vt == VT_I4)
  1657.                 _dwPriv = pvarargIn->lVal;
  1658.             return S_OK;
  1659.         case ISFBID_GETORDERSTREAM:
  1660.             return _IStreamFromOrderList(pvarargOut);
  1661.         case ISFBID_SETORDERSTREAM:
  1662.             return _OrderListFromIStream(pvarargIn);
  1663.         }
  1664.     }
  1665.     else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup))
  1666.     {
  1667.         switch (nCmdID)
  1668.         {
  1669.         case SHDVID_UEMLOG:
  1670.             ASSERT(pvarargOut == NULL);
  1671.             // if pvarargIn is set, then we take and keep this id.
  1672.             if (pvarargIn && pvarargIn->vt == VT_I4)
  1673.             {
  1674.                 _eUemLog = pvarargIn->lVal;
  1675.                 ASSERT(_eUemLog == UEMIND_SHELL || _eUemLog == UEMIND_BROWSER);
  1676.             }
  1677.             return S_OK;
  1678.         }
  1679.     }
  1680.     else if (IsEqualGUID(CGID_DeskBand, *pguidCmdGroup))
  1681.     {
  1682.         switch (nCmdID)
  1683.         {
  1684.         case DBID_DELAYINIT:
  1685.             _fDelayInit = TRUE;
  1686.             break;
  1687.         case DBID_FINISHINIT:
  1688.             _fDelayInit = FALSE;
  1689.             _RegisterToolbar();
  1690.             break;
  1691.         }
  1692.         return S_OK;
  1693.     }
  1694.     
  1695.     return OLECMDERR_E_NOTSUPPORTED;
  1696. }
  1697. IShellFolder * CISFBand::GetSF()
  1698. {
  1699.     ASSERT( _psf );
  1700.     return _psf;
  1701. }
  1702. HWND CISFBand::GetHWND()
  1703. {
  1704.     return _hwndTB;
  1705. }
  1706. REFTASKOWNERID CISFBand::GetTOID()
  1707. {
  1708.     return TOID_ExtractImage;
  1709. }
  1710. HRESULT CISFBand::OnTranslatedChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  1711. {
  1712.     if (lEvent == SHCNE_RMDIR && _IsEqualID(pidl1))
  1713.     {
  1714.         HRESULT hres = E_FAIL;
  1715.         IBandSite *pbandSite;
  1716.         if (_punkSite)
  1717.         {
  1718.             hres = _punkSite->QueryInterface(IID_IBandSite, (void **)&pbandSite);
  1719.             if (EVAL(SUCCEEDED(hres))) 
  1720.             {
  1721.                 pbandSite->RemoveBand(_dwBandID);
  1722.                 pbandSite->Release();
  1723.             }
  1724.         }
  1725.         return hres;
  1726.     }
  1727.     else
  1728.     {
  1729.         return CSFToolbar::OnTranslatedChange(lEvent, pidl1, pidl2);
  1730.     }
  1731. }
  1732. HRESULT CISFBand::UpdateLogoCallback( DWORD dwItem, int iIcon, HBITMAP hImage, LPCWSTR pszCache, BOOL fCache )
  1733. {
  1734.     int iItem = (int)dwItem;
  1735.     HRESULT hr;
  1736.     UINT uImage;
  1737.     // catch if we are closing...
  1738.     if ( _fClosing )
  1739.         return NOERROR;
  1740.     IMAGECACHEINFO rgInfo;
  1741.     rgInfo.dwMask = ICIFLAG_NAME | ICIFLAG_LARGE | ICIFLAG_BITMAP | ICIFLAG_NOUSAGE;
  1742.     rgInfo.cbSize = sizeof( rgInfo );
  1743.     rgInfo.pszName = pszCache;
  1744.     rgInfo.hBitmapLarge = hImage;
  1745.     ASSERT(_pLogoCache);
  1746.     if (_pLogoCache)
  1747.         hr = _pLogoCache->AddImage( &rgInfo, &uImage );
  1748.     else
  1749.         hr = E_FAIL;
  1750.     // catch if we are closing...
  1751.     if ( _fClosing )
  1752.         return NOERROR;
  1753.     if ( SUCCEEDED( hr ))
  1754.     {
  1755.         // remember the icon to logo mapping....
  1756.         AddIndicesToLogoList( iIcon, uImage );
  1757.         // catch we are closing before we try and doa bloc
  1758.         PostMessage( _hwndTB, TB_CHANGEBITMAP, iItem, uImage );
  1759.     }
  1760.     // stop delay painting when the last extract image task calls back
  1761.     if (_fDelayPainting) {
  1762.         if (_pTaskScheduler && _pTaskScheduler->CountTasks(TOID_NULL) == 1) {
  1763.             _StopDelayPainting();
  1764.         }
  1765.     }
  1766.     return hr;
  1767. }
  1768. // }
  1769. HRESULT CISFBand::_GetTitleW(LPWSTR pwszTitle, DWORD cchSize)
  1770. {
  1771.     HRESULT hr = E_FAIL;
  1772.     TraceMsg(TF_BAND, "Calling baseclass CISFBand::_GetTitleW");
  1773.     if (!EVAL(pwszTitle))
  1774.         return E_INVALIDARG;
  1775.     *pwszTitle = 0;
  1776.     if (_pidl)
  1777.     {
  1778.         hr = SHGetNameAndFlagsW(_pidl, SHGDN_NORMAL, pwszTitle, cchSize, NULL);
  1779.     }
  1780.     else if (_psf && !_fPSFBandDesktop)
  1781.     {
  1782. #ifdef BUSTED
  1783.         // BUGBUG (scotth):  We cannot call GetDisplayNameOf with NULL pidl.
  1784.         //                   We must change this code so _pidl is always
  1785.         //                   valid, and key off a flag to determine whether
  1786.         //                   to receive notifies.  Remove this code once
  1787.         //                   that is done.
  1788.         STRRET strret;
  1789.         if (SUCCEEDED(_psf->GetDisplayNameOf(NULL, SHGDN_NORMAL, &strret)))
  1790.             StrRetToBufW(&strret, NULL, pwszTitle, cchSize);
  1791. #endif
  1792.     }
  1793.     return hr;
  1794. }
  1795. STDAPI NavigateToPIDL(IWebBrowser2* pwb, LPCITEMIDLIST pidl);
  1796. HRESULT FakeGetNavigateTarget(IShellFolder *psf, LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl);
  1797. LRESULT CISFBand::_TryChannelSurfing(LPCITEMIDLIST pidl)
  1798. {
  1799.     LRESULT lRet = 0;
  1800.     ASSERT(_fChannels);
  1801.     LPITEMIDLIST pidlTarget;
  1802.     HRESULT hr = SHGetNavigateTarget(_psf, pidl, &pidlTarget, NULL);
  1803.     // channel category folders hack.
  1804.     if (FAILED(hr))
  1805.         hr = FakeGetNavigateTarget(_psf, pidl, &pidlTarget);
  1806.     if (SUCCEEDED(hr))
  1807.     {
  1808.         IWebBrowser2* pwb;
  1809.         // n.b. careful! only one of GCB and C_OB up the refcnt
  1810.         _GetChannelBrowser(&pwb);
  1811.         if (SUCCEEDED(Channels_OpenBrowser(&pwb, pwb != NULL)))
  1812.         {
  1813.             VARIANT flags;
  1814.             VARIANT varURLpidl;
  1815.             lRet = 1;   // success at this point
  1816.             if (SUCCEEDED(NavigateToPIDL(pwb, pidlTarget)))
  1817.             {
  1818.                 LPITEMIDLIST pidlFull = ILCombine(_pidl, pidl);
  1819.                 if (pidlFull)
  1820.                 {
  1821.                     flags.vt = VT_I4;
  1822.                     flags.lVal = navBrowserBar;
  1823.                     if (InitVariantFromIDList(&varURLpidl, pidlFull))
  1824.                     {
  1825.                         pwb->Navigate2(&varURLpidl, &flags, PVAREMPTY, PVAREMPTY, PVAREMPTY);
  1826.                         VariantClear(&varURLpidl);
  1827.                     }
  1828.                     ILFree(pidlFull);
  1829.                 }
  1830.             }
  1831.         }
  1832.         if (pwb)
  1833.             pwb->Release();
  1834.         ILFree(pidlTarget);
  1835.     }
  1836.     return lRet;
  1837. }
  1838. //***   _GetChannelBrowser -- find appropriate browser for surfing
  1839. // DESCRIPTION
  1840. //  for the DTBrowser case, we fail (pwb=NULL, hr=S_FALSE) so that our
  1841. // caller will create a new SHBrowser (which can be put into theater mode).
  1842. // for the SHBrowser case, we find the top-level browser (so we'll navigate
  1843. // in-place).
  1844. HRESULT CISFBand::_GetChannelBrowser(IWebBrowser2 **ppwb)
  1845. {
  1846.     HRESULT hr;
  1847.     IServiceProvider *psp;
  1848.     *ppwb = NULL;   // assume failure
  1849.     if (_fDesktop) {
  1850.         ASSERT(*ppwb == NULL);
  1851.         hr = S_FALSE;
  1852.     }
  1853.     else {
  1854.         hr = IUnknown_QueryService(_punkSite, SID_STopLevelBrowser, IID_IServiceProvider, (void**)&psp);
  1855.         ASSERT(SUCCEEDED(hr));
  1856.         if (SUCCEEDED(hr)) {
  1857.             hr = psp->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (void **)ppwb);
  1858.             ASSERT(SUCCEEDED(hr));
  1859.             psp->Release();
  1860.         }
  1861.     }
  1862.     return hr;
  1863. }
  1864. HRESULT IUnknown_SetBandInfoSFB(IUnknown *punkBand, BANDINFOSFB *pbi)
  1865. {
  1866.     HRESULT hr = E_FAIL;
  1867.     IShellFolderBand *pisfBand;
  1868.     if (punkBand) {
  1869.         hr = punkBand->QueryInterface(IID_IShellFolderBand, (void **)&pisfBand);
  1870.         if (EVAL(SUCCEEDED(hr))) {
  1871.             hr = pisfBand->SetBandInfoSFB(pbi);
  1872.             pisfBand->Release();
  1873.         }
  1874.     }
  1875.     return hr;
  1876. }
  1877. ///////////////////////////////////////////////////////////////////////////////////////////
  1878. ///////////////////////////CExtractImageTask///////////////////////////////////////////////
  1879. ///////////////////////////////////////////////////////////////////////////////////////////
  1880. // Warning
  1881. //
  1882. // The CLogoBase class cannot have a ref on the returned task
  1883. // since that would be a circular reference
  1884. //
  1885. // Warning
  1886. HRESULT CExtractImageTask_Create( CLogoBase *plb,
  1887.                                   LPEXTRACTIMAGE pExtract,
  1888.                                   LPCWSTR pszCache,
  1889.                                   DWORD dwItem,
  1890.                                   int iIcon,
  1891.                                   DWORD dwFlags,
  1892.                                   LPRUNNABLETASK * ppTask )
  1893. {
  1894.     if ( !ppTask || !plb || !pExtract )
  1895.     {
  1896.         return E_INVALIDARG;
  1897.     }
  1898.     HRESULT hr = NOERROR;
  1899.     CExtractImageTask * pNewTask = new CExtractImageTask( &hr,
  1900.                                                           plb,
  1901.                                                           pExtract,
  1902.                                                           pszCache,
  1903.                                                           dwItem,
  1904.                                                           iIcon,
  1905.                                                           dwFlags );
  1906.     if ( !pNewTask )
  1907.     {
  1908.         return E_OUTOFMEMORY;
  1909.     }
  1910.     if ( FAILED( hr ))
  1911.     {
  1912.         pNewTask->Release();
  1913.         return hr;
  1914.     }
  1915.     *ppTask = SAFECAST( pNewTask, IRunnableTask *);
  1916.     return NOERROR;
  1917. }
  1918. /////////////////////////////////////////////////////////////////////////////////////////////////////
  1919. CExtractImageTask::CExtractImageTask( HRESULT * pHr, CLogoBase *plb, IExtractImage * pImage,
  1920.     LPCWSTR pszCache, DWORD dwItem, int iIcon, DWORD dwFlags )
  1921. {
  1922.     m_lState = IRTIR_TASK_NOT_RUNNING;
  1923.     m_plb = plb;
  1924.     m_plb->AddRef();
  1925.     // cannot assume the band will kill us before it dies....
  1926.     // hence we hold a reference
  1927.     StrCpyW( m_szPath, pszCache );
  1928.     m_pExtract = pImage;
  1929.     pImage->AddRef();
  1930.     m_cRef = 1;
  1931.     // use the upper bit of the flags to determine if we should always call....
  1932.     m_dwFlags = dwFlags;
  1933.     m_dwItem = dwItem;
  1934.     m_iIcon = iIcon;
  1935.     // Since the task moves from thread to thread,
  1936.     // don't charge this thread for the objects we're using
  1937.     remove_from_memlist(m_pExtract);
  1938.     remove_from_memlist(this);
  1939. }
  1940. /////////////////////////////////////////////////////////////////////////////////////////////////////
  1941. CExtractImageTask::~CExtractImageTask()
  1942. {
  1943.     ATOMICRELEASE( m_pExtract );
  1944.     ATOMICRELEASE( m_pTask );
  1945.     if ( m_hBmp && !( m_dwFlags & EITF_SAVEBITMAP ))
  1946.     {
  1947.         DeleteObject( m_hBmp );
  1948.     }
  1949.     if(m_plb)
  1950.         m_plb->Release();
  1951. }
  1952. //////////////////////////////////////////////////////////////////////////////////////////
  1953. STDMETHODIMP CExtractImageTask::QueryInterface( REFIID riid, void **ppvObj )
  1954. {
  1955.     if ( !ppvObj )
  1956.     {
  1957.         return E_INVALIDARG;
  1958.     }
  1959.     if ( IsEqualIID( riid, IID_IUnknown ))
  1960.     {
  1961.         *ppvObj = SAFECAST( this, IUnknown *);
  1962.     }
  1963.     else if ( IsEqualIID( riid, IID_IRunnableTask ))
  1964.     {
  1965.         *ppvObj = SAFECAST( this, IRunnableTask *);
  1966.     }
  1967.     else
  1968.     {
  1969.         return E_NOINTERFACE;
  1970.     }
  1971.     AddRef();
  1972.     return NOERROR;
  1973. }
  1974. //////////////////////////////////////////////////////////////////////////////////////////
  1975. STDMETHODIMP_ (ULONG)  CExtractImageTask::AddRef()
  1976. {
  1977.     InterlockedIncrement( &m_cRef );
  1978.     return m_cRef;
  1979. }
  1980. //////////////////////////////////////////////////////////////////////////////////////////
  1981. STDMETHODIMP_ (ULONG) CExtractImageTask::Release()
  1982. {
  1983.     if (InterlockedDecrement( &m_cRef ) == 0 )
  1984.     {
  1985.         delete this;
  1986.         return 0;
  1987.     }
  1988.     return m_cRef;
  1989. }
  1990. //////////////////////////////////////////////////////////////////////////////////////////
  1991. STDMETHODIMP CExtractImageTask::Run ( void )
  1992. {
  1993.     HRESULT hr = E_FAIL;
  1994.     if ( m_lState == IRTIR_TASK_RUNNING )
  1995.     {
  1996.         hr = S_FALSE;
  1997.     }
  1998.     else if ( m_lState == IRTIR_TASK_PENDING )
  1999.     {
  2000.         hr = E_FAIL;
  2001.     }
  2002.     else if ( m_lState == IRTIR_TASK_NOT_RUNNING )
  2003.     {
  2004.         LONG lRes = InterlockedExchange( & m_lState, IRTIR_TASK_RUNNING);
  2005.         if ( lRes == IRTIR_TASK_PENDING )
  2006.         {
  2007.             m_lState = IRTIR_TASK_FINISHED;
  2008.             return NOERROR;
  2009.         }
  2010.         // see if it supports IRunnableTask
  2011.         m_pExtract->QueryInterface( IID_IRunnableTask, (void **) & m_pTask );
  2012. #ifdef UNIX
  2013.         //Hey Guys : IE4.01 has an error - it returns the wrong VTABLE
  2014.         //when this QI is done. We know how our VTABLEs are laid out
  2015. #else
  2016.         // IE4.01 has an error - it returns the wrong VTABLE
  2017.         // when this QI is done.
  2018.         if((LPVOID)m_pTask == (LPVOID)m_pExtract)
  2019.         {
  2020.             m_pTask = m_pTask + 2; // This vtable is two ptrs away and is in fstree.cpp in shell32 in IE4.01
  2021.         }
  2022. #endif
  2023.         if ( m_lState == IRTIR_TASK_RUNNING )
  2024.         {
  2025.             // start the extractor....
  2026.             hr = m_pExtract->Extract( &m_hBmp );
  2027.         }
  2028.         if (( SUCCEEDED( hr ) || ( hr != E_PENDING && (m_dwFlags & EITF_ALWAYSCALL))) && m_lState == IRTIR_TASK_RUNNING )
  2029.         {
  2030.             hr = InternalResume();
  2031.         }
  2032.         if ( m_lState != IRTIR_TASK_SUSPENDED || hr != E_PENDING )
  2033.         {
  2034.             m_lState = IRTIR_TASK_FINISHED;
  2035.         }
  2036.     }
  2037.     return hr;
  2038. }
  2039. /////////////////////////////////////////////////////////////////////////////////////////////////////
  2040. STDMETHODIMP CExtractImageTask::Kill ( BOOL fWait )
  2041. {
  2042.     if ( m_lState != IRTIR_TASK_RUNNING )
  2043.     {
  2044.         return S_FALSE;
  2045.     }
  2046.     LONG lRes = InterlockedExchange( &m_lState, IRTIR_TASK_PENDING );
  2047.     if ( lRes == IRTIR_TASK_FINISHED )
  2048.     {
  2049.         m_lState = lRes;
  2050.         return NOERROR;
  2051.     }
  2052.     // does it support IRunnableTask ? Can we kill it ?
  2053.     HRESULT hr = E_NOTIMPL;
  2054.     if ( m_pTask != NULL )
  2055.     {
  2056.         hr = m_pTask->Kill( FALSE );
  2057.     }
  2058.     return hr;
  2059. }
  2060. ///////////////////////////////////////////////////////////////////////////////////////
  2061. STDMETHODIMP CExtractImageTask::Suspend( void )
  2062. {
  2063.     if ( !m_pTask )
  2064.     {
  2065.         return E_NOTIMPL;
  2066.     }
  2067.     if ( m_lState != IRTIR_TASK_RUNNING )
  2068.     {
  2069.         return E_FAIL;
  2070.     }
  2071.     LONG lRes = InterlockedExchange( &m_lState, IRTIR_TASK_SUSPENDED );
  2072.     HRESULT hr = m_pTask->Suspend();
  2073.     if ( SUCCEEDED( hr ))
  2074.     {
  2075.         lRes = (LONG) m_pTask->IsRunning();
  2076.         if ( lRes == IRTIR_TASK_SUSPENDED )
  2077.         {
  2078.             m_lState = lRes;
  2079.         }
  2080.     }
  2081.     else
  2082.     {
  2083.         m_lState = lRes;
  2084.     }
  2085.     return hr;
  2086. }
  2087. ////////////////////////////////////////////////////////////////////////////////////////
  2088. STDMETHODIMP CExtractImageTask::Resume( void )
  2089. {
  2090.     if ( !m_pTask )
  2091.     {
  2092.         return E_NOTIMPL;
  2093.     }
  2094.     if ( m_lState != IRTIR_TASK_SUSPENDED )
  2095.     {
  2096.         return E_FAIL;
  2097.     }
  2098.     m_lState = IRTIR_TASK_RUNNING;
  2099.     HRESULT hr = m_pTask->Resume();
  2100.     if ( SUCCEEDED( hr ) || ( hr != E_PENDING && ( m_dwFlags & EITF_ALWAYSCALL )))
  2101.     {
  2102.         hr = InternalResume();
  2103.     }
  2104.     return hr;
  2105. }
  2106. /////////////////////////////////////////////////////////////////////////////////////////////////////
  2107. HRESULT CExtractImageTask::InternalResume()
  2108. {
  2109.     HRESULT hr = NOERROR;
  2110.     if ( m_dwFlags & EITF_ALWAYSCALL || m_hBmp )
  2111.     {
  2112.         // call the update function
  2113.         hr = m_plb->UpdateLogoCallback( m_dwItem, m_iIcon, m_hBmp, m_szPath, TRUE );
  2114.     }
  2115.     m_lState = IRTIR_TASK_FINISHED;
  2116.     return hr;
  2117. }
  2118. /////////////////////////////////////////////////////////////////////////////////////////////////////
  2119. STDMETHODIMP_( ULONG ) CExtractImageTask:: IsRunning ( void )
  2120. {
  2121.     return m_lState;
  2122. }
  2123. ////////////////////////////////////////////////////////////////////////////////////////////////////
  2124. //////////////////////////////CLogoBase/////////////////////////////////////////////////////////////
  2125. ////////////////////////////////////////////////////////////////////////////////////////////////////
  2126. // static data...
  2127. IImageCache * CLogoBase::s_pSharedWideLogoCache = NULL;
  2128. long CLogoBase::s_lSharedWideLogosRef = 0;
  2129. HDSA CLogoBase::s_hdsaWideLogoIndices = NULL;
  2130. CRITICAL_SECTION CLogoBase::s_csSharedLogos = {0};
  2131. extern "C" void CLogoBase_Initialize( void )
  2132. {
  2133.     CLogoBase::_Initialize();
  2134. }
  2135. extern "C" void CLogoBase_Cleanup( void )
  2136. {
  2137.     CLogoBase::_Cleanup( );
  2138. }
  2139. void CLogoBase::_Initialize( void )
  2140. {
  2141.     InitializeCriticalSection( &s_csSharedLogos );
  2142. }
  2143. void CLogoBase::_Cleanup( void )
  2144. {
  2145.     DeleteCriticalSection( & s_csSharedLogos );
  2146. }
  2147. CLogoBase::CLogoBase( BOOL fWide )
  2148. {
  2149.     // are we paletized, then use the global halftone palette ....
  2150.     HDC hdcTmp = GetDC( NULL );
  2151.     if (hdcTmp)
  2152.     {
  2153.         if (GetDeviceCaps( hdcTmp, RASTERCAPS) & RC_PALETTE)
  2154.         {
  2155.             ASSERT( g_hpalHalftone );
  2156.             _hpalHalftone = g_hpalHalftone;
  2157.         }
  2158.         ReleaseDC( NULL, hdcTmp );
  2159.     }
  2160.     _fWide = fWide;
  2161. }
  2162. CLogoBase::~CLogoBase()
  2163. {
  2164.     if (_pLogoCache || _pTaskScheduler)
  2165.     {
  2166.         ExitLogoView();
  2167.     }
  2168.     // NOTE: no palette release because we are using the global Halftone palette......
  2169. }
  2170. HRESULT CLogoBase::AddRefLogoCache( void )
  2171. {
  2172.     if ( _fWide )
  2173.     {
  2174.         EnterCriticalSection( &s_csSharedLogos );
  2175.         if ( !s_lSharedWideLogosRef )
  2176.         {
  2177.             if ( !s_hdsaWideLogoIndices )
  2178.             {
  2179.                 s_hdsaWideLogoIndices = DSA_Create( sizeof( LogoIndex ), 5 );
  2180.                 if ( !s_hdsaWideLogoIndices )
  2181.                 {
  2182.                     LeaveCriticalSection( &s_csSharedLogos );
  2183.                     return E_OUTOFMEMORY;
  2184.                 }
  2185.             }
  2186.             ASSERT( s_hdsaWideLogoIndices );
  2187.             ASSERT( !s_pSharedWideLogoCache );
  2188.             // BUGBUG for now CoCreate one per view
  2189.             HRESULT hr = CoCreateInstance( CLSID_ImageListCache,
  2190.                                            NULL,
  2191.                                            CLSCTX_INPROC,
  2192.                                            IID_IImageCache,
  2193.                                            (void **) & s_pSharedWideLogoCache );
  2194.             if ( FAILED( hr ))
  2195.             {
  2196.                 LeaveCriticalSection( &s_csSharedLogos );
  2197.                 return hr;
  2198.             }
  2199.         }
  2200.         ASSERT( s_pSharedWideLogoCache );
  2201.         // bump up the ref and get a pointer to it...
  2202.         s_lSharedWideLogosRef ++;
  2203.         _pLogoCache = s_pSharedWideLogoCache;
  2204.         _pLogoCache->AddRef();
  2205.         _hdsaLogoIndices = s_hdsaWideLogoIndices;
  2206.         LeaveCriticalSection( &s_csSharedLogos );
  2207.         return NOERROR;
  2208.     }
  2209.     else
  2210.     {
  2211.         // non wide logo version we don't share because w eonly expect there ever to be one...
  2212.         _hdsaLogoIndices = DSA_Create( sizeof( LogoIndex ), 5 );
  2213.         if ( !_hdsaLogoIndices )
  2214.         {
  2215.             return E_OUTOFMEMORY;
  2216.         }
  2217.         // BUGBUG for now CoCreate one per view
  2218.         return CoCreateInstance( CLSID_ImageListCache,
  2219.                                  NULL,
  2220.                                  CLSCTX_INPROC,
  2221.                                  IID_IImageCache,
  2222.                                  (void **) & _pLogoCache );
  2223.     }
  2224. }
  2225. HRESULT CLogoBase::ReleaseLogoCache( void )
  2226. {
  2227.     if ( !_pLogoCache )
  2228.     {
  2229.         return S_FALSE;
  2230.     }
  2231.     ATOMICRELEASE(_pLogoCache);
  2232.     if ( _fWide )
  2233.     {
  2234.         EnterCriticalSection( &s_csSharedLogos );
  2235.         ASSERT( s_lSharedWideLogosRef > 0 );
  2236.         s_lSharedWideLogosRef --;
  2237.         if ( ! s_lSharedWideLogosRef )
  2238.         {
  2239.             // let go of the final ref.....
  2240.             ATOMICRELEASE(s_pSharedWideLogoCache);
  2241.             ASSERT( s_hdsaWideLogoIndices );
  2242.             DSA_Destroy( s_hdsaWideLogoIndices );
  2243.             s_hdsaWideLogoIndices = NULL;
  2244.         }
  2245.         LeaveCriticalSection( &s_csSharedLogos );
  2246.     }
  2247.     else
  2248.     {
  2249.         // free the HDSA
  2250.         DSA_Destroy( _hdsaLogoIndices );
  2251.     }
  2252.     return NOERROR;
  2253. }
  2254. HRESULT CLogoBase::InitLogoView( void )
  2255. {
  2256.     HRESULT hr = AddRefLogoCache();
  2257.     if (SUCCEEDED(hr))
  2258.     {
  2259.         hr = CoCreateInstance(CLSID_ShellTaskScheduler,
  2260.                               NULL,
  2261.                               CLSCTX_INPROC,
  2262.                               IID_IShellTaskScheduler,
  2263.                               (void **) &_pTaskScheduler);
  2264.         if (FAILED(hr))
  2265.         {
  2266.             ATOMICRELEASE(_pLogoCache);
  2267.         }
  2268.         else
  2269.         {
  2270.             _rgLogoSize.cx = ( _fWide ) ? LOGO_WIDE_WIDTH : LOGO_WIDTH ;
  2271.             _rgLogoSize.cy = LOGO_HEIGHT;
  2272.             IMAGECACHEINITINFO rgInfo;
  2273.             rgInfo.cbSize = sizeof( rgInfo );
  2274.             rgInfo.dwMask = ICIIFLAG_LARGE;
  2275.             rgInfo.iStart = 0;
  2276.             rgInfo.iGrow = 5;
  2277.             // the color depth is currently the screen resolution...
  2278.             int iColorRes = SHGetCurColorRes();
  2279.             _dwClrDepth = (DWORD) iColorRes;
  2280.             switch (iColorRes)
  2281.             {
  2282.                 case 16 :   rgInfo.dwFlags = ILC_COLOR16;
  2283.                             break;
  2284.                 case 24 :
  2285.                 case 32 :   rgInfo.dwFlags = ILC_COLOR24;
  2286.                             break;
  2287.                 default :   rgInfo.dwFlags = ILC_COLOR8;
  2288.             }
  2289.             rgInfo.rgSizeLarge = _rgLogoSize;
  2290.             if (_pLogoCache)
  2291.                 hr = _pLogoCache->GetImageList(&rgInfo);
  2292.             else
  2293.                 hr = E_UNEXPECTED;
  2294.             if (FAILED(hr))
  2295.             {
  2296.                 ATOMICRELEASE(_pLogoCache);
  2297.                 ATOMICRELEASE(_pTaskScheduler);
  2298.             }
  2299.             else
  2300.             {
  2301.                 _himlLogos = rgInfo.himlLarge;
  2302.                 // GetImageList() will return S_FALSE if it was already created...
  2303.                 if ((hr == S_OK) && (iColorRes <= 8))
  2304.                 {
  2305.                     // init the color table so that it matches The "special halftone palette"
  2306.                     HPALETTE hpal = SHCreateShellPalette(NULL);
  2307.                     PALETTEENTRY rgColours[256];
  2308.                     RGBQUAD rgDIBColours[256];
  2309.                     ASSERT( hpal );
  2310.                     int nColours = GetPaletteEntries(hpal, 0, ARRAYSIZE(rgColours), rgColours);
  2311.                     // SHGetShellPalette should always return a 256 colour palette
  2312.                     ASSERT(nColours == ARRAYSIZE(rgColours));
  2313.                     // translate from the LOGPALETTE structure to the RGBQUAD structure ...
  2314.                     for (int iColour = 0; iColour < nColours; iColour ++)
  2315.                     {
  2316.                         rgDIBColours[iColour].rgbRed = rgColours[iColour].peRed;
  2317.                         rgDIBColours[iColour].rgbBlue = rgColours[iColour].peBlue;
  2318.                         rgDIBColours[iColour].rgbGreen = rgColours[iColour].peGreen;
  2319.                         rgDIBColours[iColour].rgbReserved = 0;
  2320.                     }
  2321.                     DeletePalette(hpal);
  2322.                     ImageList_SetColorTable(_himlLogos, 0, 256, rgDIBColours);
  2323.                 }
  2324.             }
  2325.         }
  2326.     }
  2327.     return hr;
  2328. }
  2329. HRESULT CLogoBase::ExitLogoView( void )
  2330. {
  2331.     ATOMICRELEASE( _pTaskScheduler );
  2332.     // the task scheduler callbacks can reference
  2333.     // the logocache, so make sure you free the
  2334.     // logo cache AFTER the task scheduler!
  2335.     ReleaseLogoCache();
  2336.     return NOERROR;
  2337. }
  2338. int CLogoBase::GetCachedLogoIndex( DWORD dwItem, LPCITEMIDLIST pidl, LPRUNNABLETASK *ppTask, DWORD * pdwPriority, DWORD *pdwFlags )
  2339. {
  2340.     DWORD dwPassedFlags = 0;
  2341.     if ( pdwFlags )
  2342.     {
  2343.         dwPassedFlags = *pdwFlags;
  2344.         *pdwFlags = 0;
  2345.     }
  2346.     // No logo cache?
  2347.     if (!_pLogoCache)
  2348.         return 0;
  2349.     ASSERT( pidl );
  2350.     // HACK: this is used on browser only mode to tell what sort of logos we need...
  2351.     UINT rgfFlags = _fWide;
  2352.     LPEXTRACTIMAGE pImage = NULL;
  2353.     int iImage = -1;
  2354.     HRESULT hr = E_FAIL;
  2355.     // IID_IEXtractLogo and IID_IExtractImage are the same interface, by using a new guid
  2356.     // it means we can selectively decided what can logo in logo view...
  2357.     hr = FakeGetUIObjectOf( GetSF(), pidl, &rgfFlags, IID_IExtractLogo, (void **) &pImage );
  2358.     if ( SUCCEEDED( hr ))
  2359.     {
  2360.         // extract ....
  2361.         HBITMAP hImage;
  2362.         WCHAR szPath[MAX_PATH];
  2363.         DWORD dwFlags = IEIFLAG_ASYNC | IEIFLAG_ASPECT | dwPassedFlags;
  2364.         IMAGECACHEINFO rgInfo;
  2365.         UINT uIndex;
  2366.         BOOL fAsync;
  2367.         DWORD dwPriority;
  2368.         rgInfo.cbSize = sizeof( rgInfo );
  2369.         hr = pImage->GetLocation( szPath, MAX_PATH, &dwPriority, &_rgLogoSize, _dwClrDepth, &dwFlags );
  2370.         fAsync = ( hr == E_PENDING );
  2371.         if ( SUCCEEDED( hr ) || fAsync )
  2372.         {
  2373.             // mask off the flags passed to use by the flags returned from the extractor...
  2374.             if ( pdwFlags )
  2375.                 *pdwFlags = dwPassedFlags & dwFlags;
  2376.             rgInfo.dwMask = ICIFLAG_NAME;
  2377.             rgInfo.pszName = szPath;
  2378.             hr = _pLogoCache->FindImage( &rgInfo, &uIndex );
  2379.             if ( hr == S_OK )
  2380.             {
  2381.                 ATOMICRELEASE( pImage );
  2382.                 return (int) uIndex;
  2383.             }
  2384.             if ( fAsync )
  2385.             {
  2386.                 LPRUNNABLETASK pTaskTmp = NULL;
  2387.                 ASSERT( _pTaskScheduler );
  2388.                 // pass the icon index so we can find the right logo later...
  2389.                 int iIcon = SHMapPIDLToSystemImageListIndex(GetSF(), pidl, NULL);
  2390.                 hr = CExtractImageTask_Create( this,
  2391.                                                pImage,
  2392.                                                szPath,
  2393.                                                dwItem,
  2394.                                                iIcon,
  2395.                                                0,
  2396.                                                &pTaskTmp );
  2397.                 if ( SUCCEEDED( hr ))
  2398.                 {
  2399.                     if ( !ppTask )
  2400.                     {
  2401.                         hr = AddTaskToQueue( pTaskTmp, dwPriority, dwItem );
  2402.                         pTaskTmp->Release();
  2403.                     }
  2404.                     else
  2405.                     {
  2406.                         * ppTask = pTaskTmp;
  2407.                         ASSERT( pdwPriority );
  2408.                         *pdwPriority = dwPriority;
  2409.                     }
  2410.                 }
  2411.                 else if ( ppTask )
  2412.                 {
  2413.                     *ppTask = NULL;
  2414.                 }
  2415.                 // if all this failed, then we will just end up with a default
  2416.                 // logo. This is only likely to fail in low memory conditions,
  2417.                 // so that will be fine.
  2418.                 // if this SUCCEEDED we will drop through to pick up a defualt piccy for now.
  2419.             }
  2420.             else
  2421.             {
  2422.                 // otherwise extract synchronously.......
  2423.                 hr = pImage->Extract( &hImage );
  2424.                 if ( SUCCEEDED( hr ))
  2425.                 {
  2426.                     rgInfo.dwMask = ICIFLAG_NAME | ICIFLAG_LARGE | ICIFLAG_BITMAP | ICIFLAG_NOUSAGE;
  2427.                     rgInfo.hBitmapLarge = hImage;
  2428.                     hr = _pLogoCache->AddImage( &rgInfo, &uIndex );
  2429.                     DeleteObject( hImage );
  2430.                 }
  2431.                 if ( SUCCEEDED( hr ))
  2432.                 {
  2433.                     iImage = (int ) uIndex;
  2434.                 }
  2435.             }
  2436.         }
  2437.     }
  2438.     ATOMICRELEASE( pImage );
  2439.     return iImage;
  2440. }
  2441. int CLogoBase::GetLogoIndex( DWORD dwItem, LPCITEMIDLIST pidl, LPRUNNABLETASK *ppTask, DWORD * pdwPriority, DWORD *pdwFlags )
  2442. {
  2443.     int iImage = GetCachedLogoIndex(dwItem, pidl, ppTask, pdwPriority, pdwFlags );
  2444.     if ( iImage == -1 )
  2445.     {
  2446.         // always pass FALSE, we want the proper ICON, cdfview no longer hits the
  2447.         // wire for the icon so we can safely ask for the correct icon.
  2448.         iImage = GetDefaultLogo( pidl, FALSE);
  2449.     }
  2450.     return iImage;
  2451. }
  2452. HRESULT CLogoBase::AddTaskToQueue( LPRUNNABLETASK pTask, DWORD dwPriority, DWORD dwItem )
  2453. {
  2454.     ASSERT( _pTaskScheduler );
  2455.     return _pTaskScheduler->AddTask( pTask, GetTOID(), dwItem, dwPriority );
  2456. }
  2457. int CLogoBase::GetDefaultLogo( LPCITEMIDLIST pidl, BOOL fQuick )
  2458. {
  2459.     USES_CONVERSION;
  2460.     // Get icon to draw from
  2461.     int iIndex = -1;
  2462.     if ( !fQuick )
  2463.     {
  2464.         iIndex = SHMapPIDLToSystemImageListIndex(GetSF(), pidl, NULL);
  2465.     }
  2466.     if (iIndex < 0)
  2467.     {
  2468.         iIndex = II_DOCNOASSOC;
  2469.     }
  2470.     WCHAR wszText[MAX_PATH];
  2471.     wszText[0] = 0;
  2472.     STRRET strret;
  2473.     HRESULT hr = GetSF()->GetDisplayNameOf( pidl, SHGDN_NORMAL, &strret );
  2474.     if ( SUCCEEDED( hr ))
  2475.     {
  2476.         StrRetToBufW(&strret, pidl, wszText, ARRAYSIZE(wszText));
  2477.     }
  2478.     UINT uCacheIndex = (UINT) -1;
  2479.     if (_pLogoCache)    // We didn't have one in stress.
  2480.     {
  2481.         IMAGECACHEINFO rgInfo;
  2482.         rgInfo.cbSize = sizeof( rgInfo );
  2483.         rgInfo.dwMask = ICIFLAG_NAME | ICIFLAG_INDEX;
  2484.         rgInfo.pszName = wszText;
  2485.         rgInfo.iIndex = iIndex;
  2486.         hr = _pLogoCache->FindImage( &rgInfo, &uCacheIndex );
  2487.         if ( hr == S_OK )
  2488.         {
  2489.             return uCacheIndex;
  2490.         }
  2491.         HBITMAP hDef;
  2492.         hr = CreateDefaultLogo( iIndex, _rgLogoSize.cx, _rgLogoSize.cy, W2T(wszText), &hDef );
  2493.         if ( SUCCEEDED( hr ))
  2494.         {
  2495.             rgInfo.hBitmapLarge = hDef;
  2496.             rgInfo.hMaskLarge = NULL;
  2497.             rgInfo.dwMask = ICIFLAG_NAME | ICIFLAG_INDEX | ICIFLAG_BITMAP | ICIFLAG_LARGE;
  2498.             hr = _pLogoCache->AddImage( &rgInfo, &uCacheIndex );
  2499.             if ( FAILED(hr ))
  2500.             {
  2501.                 uCacheIndex = (UINT) -1;
  2502.             }
  2503.             else
  2504.             {
  2505.                 // remember the index of the logo
  2506.                 AddIndicesToLogoList( iIndex, uCacheIndex );
  2507.             }
  2508.             DeleteObject( hDef );
  2509.         }
  2510.     }
  2511.     return (int) uCacheIndex;
  2512. }
  2513. #define DXFUDGE     4
  2514. #define COLORTEXT   RGB(255,255,255)
  2515. #define COLORBK     RGB(0,0,0)
  2516. HRESULT CLogoBase::CreateDefaultLogo(int iIcon, int cxLogo, int cyLogo, LPCTSTR pszText, HBITMAP * phBmpLogo)
  2517. {
  2518.     HRESULT hr = E_OUTOFMEMORY;
  2519.     HBITMAP hbmp = NULL;
  2520.     HIMAGELIST himl;
  2521.     int cxIcon, cyIcon;
  2522.    int x, y, dx, dy;
  2523.     // get the small icons....
  2524.     Shell_GetImageLists(NULL, &himl);
  2525.     ImageList_GetIconSize(himl, &cxIcon, &cyIcon);
  2526.     // Calculate position info. We assume logos are wider than they are tall.
  2527.     //
  2528.     ASSERT(cxLogo >= cyLogo);
  2529.     // Put the icon on the left
  2530.     x = 2;
  2531.     // Center the icon vertically
  2532.     if (cyIcon <= cyLogo)
  2533.     {
  2534.         y = (cyLogo - cyIcon) / 2;
  2535.         dy = cyIcon;
  2536.         dx = cxIcon;
  2537.     }
  2538.     else
  2539.     {
  2540.         y = 0;
  2541.         dy = cyLogo;
  2542.         // keep shrinkage proportional
  2543.         dx = MulDiv(cxIcon, cyIcon, cyLogo);
  2544.     }
  2545.     // get ready to draw
  2546.     HDC hTBDC = GetDC( GetHWND());
  2547.     if ( !hTBDC )
  2548.     {
  2549.         return E_FAIL;
  2550.     }
  2551.     HDC hdc = CreateCompatibleDC( hTBDC );
  2552.     if (hdc)
  2553.     {
  2554.         RECT    rc;
  2555.         int     dx, dy, x, y;
  2556.         SIZE    size;
  2557.         hbmp = CreateCompatibleBitmap(hTBDC, cxLogo, cyLogo);
  2558.         if (hbmp)
  2559.         {
  2560.             HGDIOBJ hTmp = SelectObject(hdc, hbmp);
  2561.             HPALETTE hpalOld;
  2562.             HFONT hfont, hfontOld;
  2563.             if ( _hpalHalftone )
  2564.             {
  2565.                 hpalOld = SelectPalette( hdc, _hpalHalftone, TRUE );
  2566.                 // LINTASSERT(hpalOld || !hpalOld);     // 0 semi-ok for SelectPalette
  2567.                 RealizePalette( hdc );
  2568.             }
  2569.             SetMapMode( hdc, MM_TEXT );
  2570.             rc.left = rc.top = 0;
  2571.             rc.bottom = cyLogo;
  2572.             rc.right = cxLogo;
  2573.             SHFillRectClr(hdc, &rc, COLORBK);
  2574.             // draw the icon into the memory DC.
  2575.             ImageList_GetIconSize(himl, &dx, &dy);
  2576.             x = DXFUDGE;
  2577.             y = ((cyLogo- dy) >> 1);
  2578.             ImageList_Draw( himl, iIcon, hdc, x, y, ILD_TRANSPARENT );
  2579.             hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  2580.             if (hfont)
  2581.                 hfontOld = (HFONT)SelectObject(hdc, hfont);
  2582.             GetTextExtentPoint32(hdc, pszText, lstrlen(pszText), &size);
  2583.             x += (dx + DXFUDGE);
  2584.             y = ((cyLogo- size.cy) >> 1);
  2585.             rc.left = x;
  2586.             UINT eto = ETO_CLIPPED;
  2587.             SetTextColor(hdc, COLORTEXT);
  2588.             SetBkMode(hdc, TRANSPARENT);
  2589.             ExtTextOut(hdc, x, y, eto, &rc
  2590.                                         , pszText, lstrlen(pszText), NULL);
  2591.             SelectObject(hdc, hfontOld);
  2592.             DeleteObject(hfont);
  2593.             if ( _hpalHalftone )
  2594.             {
  2595.                 (void) SelectPalette( hdc, hpalOld, TRUE );
  2596.                 RealizePalette( hdc );
  2597.             }
  2598.             // remove the final bitmap
  2599.             SelectObject( hdc, hTmp );
  2600.             hr = S_OK;
  2601.             if (FAILED(hr))
  2602.             {
  2603.                 DeleteObject(hbmp);
  2604.                 hbmp = NULL;
  2605.             }
  2606.         }
  2607.         DeleteDC(hdc);
  2608.     }
  2609.     ReleaseDC( GetHWND(), hTBDC );
  2610.     *phBmpLogo = hbmp;
  2611.     return hr;
  2612. }
  2613. HRESULT CLogoBase::FlushLogoCache( )
  2614. {
  2615.     HRESULT hr = E_UNEXPECTED;
  2616.     if (_pLogoCache)
  2617.     {
  2618.         // forcibly clear out the logo cache so the items get refetched ...
  2619.         _pLogoCache->Flush(TRUE);
  2620.         hr = S_OK;
  2621.     }
  2622.     return hr;
  2623. }
  2624. HRESULT CLogoBase::DitherBitmap( HBITMAP hBmp, HBITMAP * phBmpNew )
  2625. {
  2626. //     if ( !phBmpNew )
  2627. //     {
  2628. //         return E_INVALIDARG;
  2629. //     }
  2630. //
  2631. //     if ( _dwClrDepth > 8)
  2632. //     {
  2633. //         *phBmpNew = hBmp;
  2634. //         return S_FALSE;
  2635. //     }
  2636. //
  2637. //     IIntDitherer * pDither;
  2638. //     HRESULT hr = CoCreateInstance( CLSID_IntDitherer,
  2639. //                                    NULL,
  2640. //                                    CLSCTX_INPROC_SERVER,
  2641. //                                    IID_IIntDitherer,
  2642. //                                    (void **) & pDither );
  2643. //     if ( FAILED( hr ))
  2644. //     {
  2645. //         return hr;
  2646. //     }
  2647. //
  2648. //     static BYTE rgb[32768];
  2649. //     static BOOL fInit = FALSE;
  2650. //
  2651. //     if ( !fInit )
  2652. //     {
  2653. //         // init the inverse color map table
  2654. //         SHGetInverseCMAP( rgb, sizeof( rgb ));
  2655. //         fInit = TRUE;
  2656. //     }
  2657. //
  2658. //     HDC hMemDc = CreateCompatibleDC( NULL );
  2659. //     if ( !hMemDc )
  2660. //     {
  2661. //         pDither->Release();
  2662. //         return E_FAIL;
  2663. //     }
  2664. //
  2665. //     HBITMAP hOld = SelectObject( hdc, hBmp );
  2666. //
  2667. //     BITMAPINFO bi;
  2668. //
  2669. //     ZeroMemory( &bi, sizeof( bi ));
  2670. //     bi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
  2671. //     bi.bmiHeader.biBitCount = 0;
  2672. //     bi.bmiHeader.biCompression = 0;
  2673. //
  2674. //     // get the header information....
  2675. //     iRet = GetDIBits( hMemDc, hBmp, 0, 0, NULL, &bi, DIB_RGB_COLORS );
  2676. //     if ( iRet != 0 )
  2677. //     {
  2678. //         LPVOID  pBuffer, pBits;
  2679. //         int iOffset = 0;
  2680. //
  2681. //         if ( bi.bmiHeader.biCompression == BI_BITFIELDS )
  2682. //         {
  2683. //             iOffset = sizeof( DWORD ) * 3;
  2684. //         }
  2685. //         else if ( bi.bmiHeader.biBitCount <= 8 )
  2686. //         {
  2687. //             if ( bi.bmiHeader.biClrUsed )
  2688. //             {
  2689. //                 iOffset = sizeof( RGBQUAD ) * bi.bmiHeader.biClrUsed;
  2690. //             }
  2691. //             else
  2692. //             {
  2693. //                 iOffset = (1 << bi.bmiHeader.biBitCount) * sizeof( RGBQUAD );
  2694. //             }
  2695. //         }
  2696. //
  2697. //         bi.bmiHeader.biHeight = iHeight;
  2698. //
  2699. //         // calc
  2700. //         pBuffer = LocalAlloc( LPTR, sizeof( BITMAPINFOHEADER ) +
  2701. //             bi.bmiHeader.biSizeImage +
  2702. //             iOffset );
  2703. //
  2704. //         // calc the size of the colour table so we put the data afterwards...
  2705. //         pBits = (( LPBYTE )pBuffer ) + sizeof( BITMAPINFOHEADER ) + iOffset;
  2706. //
  2707. //         CopyMemory( pBuffer, &bi, sizeof( BITMAPINFOHEADER ) );
  2708. //         iRet = GetDIBits( hMemDc, hBmp, 0, iHeight, pBits,
  2709. //                           ( LPBITMAPINFO )pBuffer, DIB_RGB_COLORS );
  2710. //
  2711. //
  2712. //         // we know we are going to 256 colour bitmap, so create a DIBSECTION as the destination ...
  2713. //         pDither->DitherTo8bpp(  BYTE * pDestBits, LONG nDestPitch,
  2714. //                         BYTE * pSrcBits, LONG nSrcPitch, REFGUID bfidSrc,
  2715. //                         RGBQUAD * prgbDestColors, RGBQUAD * prgbSrcColors,
  2716. //                         rgb,
  2717. //                         LONG x, LONG y, LONG cx, LONG cy,
  2718. //                         -1, -1);
  2719. //     }
  2720. //     pDither->Release();
  2721.     ASSERT( FALSE );
  2722.     return E_NOTIMPL;
  2723. }
  2724. int CLogoBase::AddIndicesToLogoList( int iIcon, UINT uIndex )
  2725. {
  2726.     int iRet = -1;
  2727.     LogoIndex * pIndex;
  2728.     LogoIndex rgNew;
  2729.     rgNew.iIcon = iIcon;
  2730.     rgNew.iLogo = (int) uIndex;
  2731.     if ( _fWide )
  2732.     {
  2733.         EnterCriticalSection( &s_csSharedLogos );
  2734.     }
  2735.     // scan to see if we have an extact match already in there...
  2736.     for ( int n = 0; n < DSA_GetItemCount( _hdsaLogoIndices ); n ++ )
  2737.     {
  2738.         pIndex = (LogoIndex *) DSA_GetItemPtr( _hdsaLogoIndices, n );
  2739.         ASSERT( pIndex );
  2740.         if ( pIndex->iLogo == (int) uIndex )
  2741.         {
  2742.             // set the icon just incase it changed...
  2743.             pIndex->iIcon = iIcon;
  2744.             iRet = n;
  2745.             break;
  2746.         }
  2747.     }
  2748.     if ( iRet == -1 )
  2749.     {
  2750.         iRet = DSA_AppendItem( _hdsaLogoIndices, &rgNew );
  2751.     }
  2752.     if ( _fWide )
  2753.     {
  2754.         LeaveCriticalSection( &s_csSharedLogos );
  2755.     }
  2756.     return iRet;
  2757. }
  2758. int CLogoBase::FindLogoFromIcon( int iIcon, int * piLastLogo )
  2759. {
  2760.     int iRet = -1;
  2761.     if ( !piLastLogo )
  2762.     {
  2763.         return -1;
  2764.     }
  2765.     LogoIndex * pIndex;
  2766.     if ( _fWide )
  2767.     {
  2768.         EnterCriticalSection( &s_csSharedLogos );
  2769.     }
  2770.     for ( int n = *piLastLogo + 1; n < DSA_GetItemCount( _hdsaLogoIndices ); n ++ )
  2771.     {
  2772.         pIndex = (LogoIndex *) DSA_GetItemPtr( _hdsaLogoIndices, n );
  2773.         ASSERT( pIndex );
  2774.         if ( pIndex->iIcon == iIcon )
  2775.         {
  2776.             *piLastLogo = n;
  2777.             iRet = pIndex->iLogo;
  2778.             break;
  2779.         }
  2780.     }
  2781.     if ( _fWide )
  2782.     {
  2783.         LeaveCriticalSection( &s_csSharedLogos );
  2784.     }
  2785.     return iRet;
  2786. }
  2787. class CImgCtxThumb :  public IExtractImage2,
  2788.                       public IRunnableTask,
  2789.                       public IPersistFile
  2790. {
  2791.     public:
  2792.         CImgCtxThumb();
  2793.         ~CImgCtxThumb();
  2794.         STDMETHOD( QueryInterface ) ( REFIID riid, void **ppvObj );
  2795.         STDMETHOD_( ULONG, AddRef ) ( void );
  2796.         STDMETHOD_( ULONG, Release ) ( void );
  2797.         // IExtractImage
  2798.         STDMETHOD (GetLocation) ( LPWSTR pszPathBuffer,
  2799.                                   DWORD cch,
  2800.                                   DWORD * pdwPriority,
  2801.                                   const SIZE * prgSize,
  2802.                                   DWORD dwRecClrDepth,
  2803.                                   DWORD *pdwFlags );
  2804.         STDMETHOD (Extract)( HBITMAP * phBmpThumbnail);
  2805.         STDMETHOD (GetDateStamp) ( FILETIME * pftTimeStamp );
  2806.         // IPersistFile
  2807.         STDMETHOD (GetClassID )(CLSID *pClassID);
  2808.         STDMETHOD (IsDirty )();
  2809.         STDMETHOD (Load )( LPCOLESTR pszFileName, DWORD dwMode);
  2810.         STDMETHOD (Save )( LPCOLESTR pszFileName, BOOL fRemember);
  2811.         STDMETHOD (SaveCompleted )( LPCOLESTR pszFileName);
  2812.         STDMETHOD (GetCurFile )( LPOLESTR *ppszFileName);
  2813.         STDMETHOD (Run)();
  2814.         STDMETHOD (Kill)( BOOL fWait );
  2815.         STDMETHOD (Suspend)();
  2816.         STDMETHOD (Resume)();
  2817.         STDMETHOD_(ULONG, IsRunning)();
  2818.         STDMETHOD ( InternalResume )();
  2819.    protected:
  2820.         friend void CALLBACK OnImgCtxChange( VOID * pvImgCtx, VOID * pv );
  2821.         void CImgCtxThumb::CalcAspectScaledRect( const SIZE * prgSize,
  2822.                                                  RECT * pRect );
  2823.         void CImgCtxThumb::CalculateAspectRatio( const SIZE * prgSize,
  2824.                                                  RECT * pRect );
  2825.         long m_cRef;
  2826.         BITBOOL m_fAsync : 1;
  2827.         BITBOOL m_fOrigSize : 1;
  2828.         WCHAR m_szPath[MAX_PATH * 4 + 7];
  2829.         HANDLE m_hEvent;
  2830.         SIZE m_rgSize;
  2831.         DWORD m_dwRecClrDepth;
  2832.         IImgCtx * m_pImg;
  2833.         LONG m_lState;
  2834.         HBITMAP * m_phBmp;
  2835. };
  2836. ///////////////////////////////////////////////////////////////////////////////////////////
  2837. ////////////////////////CImgCtxThumb///////////////////////////////////////////////////////
  2838. ///////////////////////////////////////////////////////////////////////////////////////////
  2839. STDAPI CImgCtxThumb_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  2840. {
  2841.     *ppunk = NULL;
  2842.     CImgCtxThumb * pExtract = new CImgCtxThumb();
  2843.     if (pExtract != NULL)
  2844.     {
  2845. #ifdef DEBUG
  2846.         // remove the pImage object, otherwise we will get bogus memory leaks...
  2847.         // this object is used by an object from shell32 which doesn't track and transfer the
  2848.         // memory...
  2849.         remove_from_memlist( pExtract );
  2850. #endif
  2851.         *ppunk = SAFECAST(pExtract, IPersistFile *);
  2852.         return S_OK;
  2853.     }
  2854.     return E_OUTOFMEMORY;
  2855. }
  2856. CImgCtxThumb::CImgCtxThumb( )
  2857. {
  2858.     m_fAsync = FALSE;
  2859.     StrCpyW( m_szPath, L"file://");
  2860.     m_cRef = 1;
  2861.     DllAddRef();
  2862. }
  2863. ///////////////////////////////////////////////////////////////////////////////////////////
  2864. CImgCtxThumb::~CImgCtxThumb()
  2865. {
  2866.     ATOMICRELEASE( m_pImg );
  2867.     if ( m_hEvent )
  2868.     {
  2869.         CloseHandle( m_hEvent );
  2870.     }
  2871.     DllRelease();
  2872. }
  2873. ///////////////////////////////////////////////////////////////////////////////////////////
  2874. STDMETHODIMP CImgCtxThumb::QueryInterface( REFIID riid, void **ppvObj )
  2875. {
  2876.     static const QITAB qit[] = {
  2877.         QITABENTMULTI( CImgCtxThumb, IExtractImage, IExtractImage2),
  2878.         QITABENT(CImgCtxThumb, IExtractImage2),
  2879.         QITABENT(CImgCtxThumb, IRunnableTask),
  2880.         QITABENT(CImgCtxThumb, IPersistFile),
  2881.         { 0 },
  2882.     };
  2883.     HRESULT hres = QISearch(this, qit, riid, ppvObj);
  2884.     if ( ppvObj == NULL )
  2885.     {
  2886.         return E_INVALIDARG;
  2887.     }
  2888.     return hres;
  2889. }
  2890. ///////////////////////////////////////////////////////////////////////////////////////////
  2891. STDMETHODIMP_(ULONG) CImgCtxThumb::AddRef()
  2892. {
  2893.     InterlockedIncrement( &m_cRef );
  2894.     return m_cRef;
  2895. }
  2896. ///////////////////////////////////////////////////////////////////////////////////////////
  2897. STDMETHODIMP_(ULONG) CImgCtxThumb::Release()
  2898. {
  2899.     if ( InterlockedDecrement( &m_cRef ))
  2900.         return m_cRef;
  2901.     delete this;
  2902.     return 0;
  2903. }
  2904. ///////////////////////////////////////////////////////////////////////////////////////////
  2905. STDMETHODIMP CImgCtxThumb::GetLocation ( LPWSTR pszPathBuffer,
  2906.                                          DWORD cch,
  2907.                                          DWORD * pdwPriority,
  2908.                                          const SIZE * prgSize,
  2909.                                          DWORD dwRecClrDepth,
  2910.                                          DWORD *pdwFlags )
  2911. {
  2912.     if ( !pdwFlags || !pszPathBuffer || !prgSize )
  2913.     {
  2914.         return E_INVALIDARG;
  2915.     }
  2916.     m_rgSize = *prgSize;
  2917.     m_dwRecClrDepth = dwRecClrDepth;
  2918.     HRESULT hr = NOERROR;
  2919.     if ( *pdwFlags & IEIFLAG_ASYNC )
  2920.     {
  2921.         if ( !pdwPriority )
  2922.         {
  2923.             return E_INVALIDARG;
  2924.         }
  2925.         hr = E_PENDING;
  2926.         // lower than normal priority
  2927.         *pdwPriority = 0x01000000;
  2928.         m_fAsync = TRUE;
  2929.     }
  2930.     m_fOrigSize = BOOLIFY( *pdwFlags & IEIFLAG_ORIGSIZE );
  2931.     *pdwFlags = IEIFLAG_CACHE;
  2932.     PathCreateFromUrlW( m_szPath, pszPathBuffer, &cch, URL_UNESCAPE );
  2933.     return hr;
  2934. }
  2935. ///////////////////////////////////////////////////////////////////////////////////////////
  2936. void CALLBACK OnImgCtxChange( void * pvImgCtx, VOID * pv )
  2937. {
  2938.     CImgCtxThumb * pThis = (CImgCtxThumb *) pv;
  2939.     ASSERT( pThis );
  2940.     ASSERT( pThis->m_hEvent );
  2941.     // we only asked to know about complete anyway....
  2942.     SetEvent( pThis->m_hEvent );
  2943. }
  2944. ////////////////////////////////////////////////////////////////////////////////////
  2945. // This function makes no assumption about whether the thumbnail is square, so
  2946. // it calculates the scaling ratio for both dimensions and the uses that as
  2947. // the scaling to maintain the aspect ratio.
  2948. void CImgCtxThumb::CalcAspectScaledRect( const SIZE * prgSize, RECT * pRect )
  2949. {
  2950.     ASSERT( pRect->left == 0 );
  2951.     ASSERT( pRect->top == 0 );
  2952.     int iWidth = pRect->right;
  2953.     int iHeight = pRect->bottom;
  2954.     int iXRatio = (iWidth * 1000) / prgSize->cx;
  2955.     int iYRatio = (iHeight * 1000) / prgSize->cy;
  2956.     if ( iXRatio > iYRatio )
  2957.     {
  2958.         pRect->right = prgSize->cx;
  2959.         // work out the blank space and split it evenly between the top and the bottom...
  2960.         int iNewHeight = (( iHeight * 1000 ) / iXRatio);
  2961.         if ( iNewHeight == 0 )
  2962.         {
  2963.             iNewHeight = 1;
  2964.         }
  2965.         int iRemainder = prgSize->cy - iNewHeight;
  2966.         pRect->top = iRemainder / 2;
  2967.         pRect->bottom = iNewHeight + pRect->top;
  2968.     }
  2969.     else
  2970.     {
  2971.         pRect->bottom = prgSize->cy;
  2972.         // work out the blank space and split it evenly between the left and the right...
  2973.         int iNewWidth = (( iWidth * 1000 ) / iYRatio);
  2974.         if ( iNewWidth == 0 )
  2975.         {
  2976.             iNewWidth = 1;
  2977.         }
  2978.         int iRemainder = prgSize->cx - iNewWidth;
  2979.         pRect->left = iRemainder / 2;
  2980.         pRect->right = iNewWidth + pRect->left;
  2981.     }
  2982. }
  2983. void CImgCtxThumb::CalculateAspectRatio( const SIZE * prgSize, RECT * pRect )
  2984. {
  2985.     int iHeight = abs( pRect->bottom - pRect->top );
  2986.     int iWidth = abs( pRect->right - pRect->left );
  2987.     // check if the initial bitmap is larger than the size of the thumbnail.
  2988.     if ( iWidth > prgSize->cx || iHeight > prgSize->cy )
  2989.     {
  2990.         pRect->left = 0;
  2991.         pRect->top = 0;
  2992.         pRect->right = iWidth;
  2993.         pRect->bottom = iHeight;
  2994.         CalcAspectScaledRect( prgSize, pRect );
  2995.     }
  2996.     else
  2997.     {
  2998.         // if the bitmap was smaller than the thumbnail, just center it.
  2999.         pRect->left = ( prgSize->cx - iWidth ) / 2;
  3000.         pRect->top = ( prgSize->cy- iHeight ) / 2;
  3001.         pRect->right = pRect->left + iWidth;
  3002.         pRect->bottom = pRect->top + iHeight;
  3003.     }
  3004. }
  3005. ///////////////////////////////////////////////////////////////////////////////////////////
  3006. STDMETHODIMP CImgCtxThumb::Extract ( HBITMAP * phBmpThumbnail)
  3007. {
  3008.     m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  3009.     if ( !m_hEvent )
  3010.     {
  3011.         return E_OUTOFMEMORY;
  3012.     }
  3013.     m_phBmp = phBmpThumbnail;
  3014.     return InternalResume();
  3015. }
  3016. /////////////////////////////////////////////////////////////////////////////////////
  3017. STDMETHODIMP CImgCtxThumb::GetDateStamp ( FILETIME * pftTimeStamp )
  3018. {
  3019.     ASSERT( pftTimeStamp );
  3020.     HANDLE hFind;
  3021.     WIN32_FIND_DATAW rgData;
  3022.     WCHAR szBuffer[MAX_PATH];
  3023.     DWORD dwSize = ARRAYSIZE( szBuffer );
  3024.     PathCreateFromUrlW( m_szPath, szBuffer, &dwSize, URL_UNESCAPE );
  3025.     hFind = FindFirstFileW( szBuffer, &rgData );
  3026.     if (INVALID_HANDLE_VALUE != hFind)
  3027.     {
  3028.         *pftTimeStamp = rgData.ftLastWriteTime;
  3029.         FindClose( hFind );
  3030.         return S_OK;
  3031.     }
  3032.     return E_FAIL;
  3033. }
  3034. //////////////////////////////////////////////////////////////////////////////////////
  3035. STDMETHODIMP CImgCtxThumb::GetClassID(CLSID *pClassID)
  3036. {
  3037.     return E_NOTIMPL;
  3038. }
  3039. //////////////////////////////////////////////////////////////////////////////////////
  3040. STDMETHODIMP CImgCtxThumb::IsDirty()
  3041. {
  3042.     return E_NOTIMPL;
  3043. }
  3044. //////////////////////////////////////////////////////////////////////////////////////
  3045. STDMETHODIMP CImgCtxThumb::Load( LPCOLESTR pszFileName, DWORD dwMode)
  3046. {
  3047.     if ( !pszFileName )
  3048.     {
  3049.         return E_INVALIDARG;
  3050.     }
  3051.     if ( lstrlenW( pszFileName ) > ARRAYSIZE( m_szPath ) - 6 )
  3052.     {
  3053.         return E_FAIL;
  3054.     }
  3055.     DWORD dwAttrs = GetFileAttributesWrapW( pszFileName );
  3056.     if (( dwAttrs != (DWORD) -1) && (dwAttrs & FILE_ATTRIBUTE_OFFLINE ))
  3057.     {
  3058.         return E_FAIL;
  3059.     }
  3060.     
  3061.     DWORD dwSize = ARRAYSIZE( m_szPath );
  3062.     UrlCreateFromPathW( pszFileName, m_szPath, &dwSize, URL_ESCAPE_UNSAFE );
  3063.     return NOERROR;
  3064. }
  3065. //////////////////////////////////////////////////////////////////////////////////////
  3066. STDMETHODIMP CImgCtxThumb::Save( LPCOLESTR pszFileName, BOOL fRemember)
  3067. {
  3068.     return E_NOTIMPL;
  3069. }
  3070. //////////////////////////////////////////////////////////////////////////////////////
  3071. STDMETHODIMP CImgCtxThumb::SaveCompleted( LPCOLESTR pszFileName)
  3072. {
  3073.     return E_NOTIMPL;
  3074. }
  3075. //////////////////////////////////////////////////////////////////////////////////////
  3076. STDMETHODIMP CImgCtxThumb::GetCurFile( LPOLESTR *ppszFileName)
  3077. {
  3078.     return E_NOTIMPL;
  3079. }
  3080. ///////////////////////////////////////////////////////////////////////////////////////////
  3081. STDMETHODIMP CImgCtxThumb::Run()
  3082. {
  3083.     return E_NOTIMPL;
  3084. }
  3085. ///////////////////////////////////////////////////////////////////////////////////////////
  3086. STDMETHODIMP CImgCtxThumb::Kill( BOOL fUnused)
  3087. {
  3088.     LONG lRes = InterlockedExchange( & m_lState, IRTIR_TASK_PENDING );
  3089.     if ( lRes != IRTIR_TASK_RUNNING )
  3090.     {
  3091.         m_lState = lRes;
  3092.     }
  3093.     if ( m_hEvent )
  3094.     {
  3095.         SetEvent( m_hEvent );
  3096.     }
  3097.     return NOERROR;
  3098. }
  3099. ///////////////////////////////////////////////////////////////////////////////////////////
  3100. STDMETHODIMP CImgCtxThumb::Resume()
  3101. {
  3102.     if ( m_lState != IRTIR_TASK_SUSPENDED )
  3103.     {
  3104.         return S_FALSE;
  3105.     }
  3106.     return InternalResume();
  3107. }
  3108. ///////////////////////////////////////////////////////////////////////////////////////////
  3109. STDMETHODIMP CImgCtxThumb::Suspend()
  3110. {
  3111.     LONG lRes = InterlockedExchange( & m_lState, IRTIR_TASK_SUSPENDED );
  3112.     if ( lRes != IRTIR_TASK_RUNNING )
  3113.     {
  3114.         m_lState = lRes;
  3115.     }
  3116.     if ( m_hEvent )
  3117.     {
  3118.         SetEvent( m_hEvent );
  3119.     }
  3120.     return NOERROR;
  3121. }
  3122. ///////////////////////////////////////////////////////////////////////////////////////////
  3123. STDMETHODIMP_(ULONG) CImgCtxThumb::IsRunning()
  3124. {
  3125.     return m_lState;
  3126. }
  3127. //////////////////////////////////////////////////////////////////////////////////////
  3128. STDMETHODIMP CImgCtxThumb::InternalResume()
  3129. {
  3130.     if ( m_phBmp == NULL )
  3131.     {
  3132.         return E_UNEXPECTED;
  3133.     }
  3134.     m_lState = IRTIR_TASK_RUNNING;
  3135.     HRESULT hr = NOERROR;
  3136.     if ( !m_pImg )
  3137.     {
  3138.         hr = CoCreateInstance(CLSID_IImgCtx, NULL, CLSCTX_INPROC_SERVER,
  3139.                           IID_IImgCtx, (LPVOID*)&m_pImg);
  3140.         ASSERT( SUCCEEDED( hr ));
  3141.         if (SUCCEEDED(hr))
  3142.         {
  3143.             ASSERT(m_pImg);
  3144.             hr = m_pImg->Load(m_szPath, DWN_RAWIMAGE | m_dwRecClrDepth);
  3145.             if ( SUCCEEDED( hr ))
  3146.             {
  3147.                 hr = m_pImg->SetCallback( OnImgCtxChange, this );
  3148.             }
  3149.             if ( SUCCEEDED( hr ))
  3150.             {
  3151.                 hr = m_pImg->SelectChanges( IMGCHG_COMPLETE, 0, TRUE);
  3152.             }
  3153.             if ( FAILED( hr ))
  3154.             {
  3155.                 ATOMICRELEASE( m_pImg );
  3156.                 m_lState = IRTIR_TASK_FINISHED;
  3157.                 return hr;
  3158.             }
  3159.         }
  3160.         else
  3161.         {
  3162.             m_lState = IRTIR_TASK_FINISHED;
  3163.             return hr;
  3164.         }
  3165.     }
  3166.     ULONG fState;
  3167.     SIZE  rgSize;
  3168.     m_pImg->GetStateInfo(&fState, &rgSize, TRUE);
  3169.     if ( !( fState & IMGLOAD_COMPLETE ))
  3170.     {
  3171.         do
  3172.         {
  3173.             DWORD dwRet = MsgWaitForMultipleObjects( 1,
  3174.                                                      &m_hEvent,
  3175.                                                      FALSE,
  3176.                                                      INFINITE,
  3177.                                                      QS_ALLINPUT );
  3178.             if ( dwRet != WAIT_OBJECT_0 )
  3179.             {
  3180.                 // check the event anyway, msgs get checked first, so
  3181.                 // it could take a while for this to get fired otherwise..
  3182.                 dwRet = WaitForSingleObject( m_hEvent, 0 );
  3183.             }
  3184.             if ( dwRet == WAIT_OBJECT_0 )
  3185.             {
  3186.                 break;
  3187.             }
  3188.             MSG msg;
  3189.             // empty the message queue...
  3190.             while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
  3191.             {
  3192.             if (( msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST ) ||
  3193.                 ( msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST  && msg.message != WM_MOUSEMOVE ))
  3194.             {
  3195.                 continue;
  3196.             }
  3197.                 TranslateMessage( &msg );
  3198.                 DispatchMessage( &msg );
  3199.             }
  3200.         } while (TRUE);
  3201.         // check why we broke out...
  3202.         if ( m_lState == IRTIR_TASK_PENDING )
  3203.         {
  3204.             m_lState = IRTIR_TASK_FINISHED;
  3205.             m_pImg->Disconnect();
  3206.             ATOMICRELEASE( m_pImg );
  3207.             return E_FAIL;
  3208.         }
  3209.         if ( m_lState == IRTIR_TASK_SUSPENDED )
  3210.             return E_PENDING;
  3211.         m_pImg->GetStateInfo(&fState, &rgSize, TRUE);
  3212.     }
  3213.     hr = (fState & IMGLOAD_ERROR) ? E_FAIL : S_OK;
  3214.     if ( SUCCEEDED( hr ))
  3215.     {
  3216.         HWND hwnd = GetDesktopWindow();
  3217.         HDC hdc = GetDC( hwnd );
  3218.         // LINTASSERT(hdc || !hdc);     // 0 semi-ok
  3219.         LPVOID lpBits;
  3220.         HDC hdcBmp = CreateCompatibleDC( hdc );
  3221.         if ( hdcBmp && hdc )
  3222.         {
  3223.             struct {
  3224.                 BITMAPINFOHEADER bi;
  3225.                 DWORD            ct[256];
  3226.             } dib;
  3227.             dib.bi.biSize            = sizeof(BITMAPINFOHEADER);
  3228.             //
  3229.             // On NT5 we go directly to the thumbnail with StretchBlt
  3230.             // on other OS's we make a full size copy and pass the bits
  3231.             // to ScaleSharpen2().
  3232.             //
  3233.             if ( IsOS ( OS_NT5 ) )
  3234.             {
  3235.                 dib.bi.biWidth       = m_rgSize.cx;
  3236.                 dib.bi.biHeight      = m_rgSize.cy;
  3237.             }
  3238.             else
  3239.             {
  3240.                 dib.bi.biWidth       = rgSize.cx;
  3241.                 dib.bi.biHeight      = rgSize.cy;
  3242.             }
  3243.             dib.bi.biPlanes          = 1;
  3244.             dib.bi.biBitCount        = (WORD) m_dwRecClrDepth;
  3245.             dib.bi.biCompression     = BI_RGB;
  3246.             dib.bi.biSizeImage       = 0;
  3247.             dib.bi.biXPelsPerMeter   = 0;
  3248.             dib.bi.biYPelsPerMeter   = 0;
  3249.             dib.bi.biClrUsed         = ( m_dwRecClrDepth <= 8 ) ? (1 << m_dwRecClrDepth) : 0;
  3250.             dib.bi.biClrImportant    = 0;
  3251.             HPALETTE hpal = NULL;
  3252.             HPALETTE hpalOld = NULL;
  3253.             if ( m_dwRecClrDepth <= 8 )
  3254.             {
  3255.                 if ( m_dwRecClrDepth == 8 )
  3256.                 {
  3257.                     // need to get the right palette....
  3258.                     hr = m_pImg->GetPalette( & hpal );
  3259.                 }
  3260.                 else
  3261.                 {
  3262.                     hpal = (HPALETTE) GetStockObject( DEFAULT_PALETTE );
  3263.                 }
  3264.                 if ( SUCCEEDED( hr ) && hpal )
  3265.                 {
  3266.                     hpalOld = SelectPalette( hdcBmp, hpal, TRUE );
  3267.                     // LINTASSERT(hpalOld || !hpalOld); // 0 semi-ok for SelectPalette
  3268.                     RealizePalette( hdcBmp );
  3269.                     int n = GetPaletteEntries(hpal, 0, 256, (LPPALETTEENTRY)&dib.ct[0]);
  3270.                     ASSERT( n == (int) dib.bi.biClrUsed );
  3271.                     for (int i = 0; i < (int)dib.bi.biClrUsed; i ++)
  3272.                         dib.ct[i] = RGB(GetBValue(dib.ct[i]),GetGValue(dib.ct[i]),GetRValue(dib.ct[i]));
  3273.                 }
  3274.             }
  3275.             HBITMAP hBmp = CreateDIBSection(hdcBmp, (LPBITMAPINFO)&dib, DIB_RGB_COLORS, &lpBits, NULL, 0);
  3276.             if ( hBmp != NULL )
  3277.             {
  3278.                 HGDIOBJ hOld = SelectObject( hdcBmp, hBmp );
  3279.                 //
  3280.                 // On NT5 Go directly to the Thumbnail with StretchBlt()
  3281.                 //
  3282.                 if ( IsOS ( OS_NT5 ) )
  3283.                 {
  3284.                     // Compute output size of thumbnail
  3285.                     RECT rectThumbnail;
  3286.                     rectThumbnail.left   = 0;
  3287.                     rectThumbnail.top    = 0;
  3288.                     
  3289.                     rectThumbnail.right  = m_rgSize.cx;
  3290.                     rectThumbnail.bottom = m_rgSize.cy;
  3291.                     
  3292.                     FillRect( hdcBmp, &rectThumbnail, (HBRUSH) (COLOR_WINDOW+1));
  3293.                     rectThumbnail.right  = rgSize.cx;
  3294.                     rectThumbnail.bottom = rgSize.cy;
  3295.                     CalculateAspectRatio (&m_rgSize, &rectThumbnail);
  3296.                     // Call DanielC for the StretchBlt
  3297.                     SetStretchBltMode (hdcBmp, HALFTONE);
  3298.                     // Create the thumbnail
  3299.                     m_pImg->StretchBlt( hdcBmp,
  3300.                                         rectThumbnail.left,
  3301.                                         rectThumbnail.top,
  3302.                                         rectThumbnail.right - rectThumbnail.left,
  3303.                                         rectThumbnail.bottom - rectThumbnail.top,
  3304.                                         0, 0,
  3305.                                         rgSize.cx,
  3306.                                         rgSize.cy,
  3307.                                         SRCCOPY);
  3308.                     SelectObject( hdcBmp, hOld );
  3309.                     *m_phBmp = hBmp;
  3310.                 }
  3311.                 else
  3312.                 {
  3313.                     //
  3314.                     // On systems other than NT5 make a full size copy of
  3315.                     // the bits and pass the copy to ScaleSharpen2().
  3316.                     //
  3317.                     RECT rectThumbnail;
  3318.                     rectThumbnail.left   = 0;
  3319.                     rectThumbnail.top    = 0;
  3320.                     
  3321.                     rectThumbnail.right  = rgSize.cx;
  3322.                     rectThumbnail.bottom = rgSize.cy;
  3323.                     
  3324.                     FillRect( hdcBmp, &rectThumbnail, (HBRUSH) (COLOR_WINDOW+1));
  3325.                     m_pImg->StretchBlt( hdcBmp,
  3326.                                         0, 0,
  3327.                                         rgSize.cx,
  3328.                                         rgSize.cy,
  3329.                                         0, 0,
  3330.                                         rgSize.cx,
  3331.                                         rgSize.cy,
  3332.                                         SRCCOPY);
  3333.                     SelectObject( hdcBmp, hOld );
  3334.                     if ( m_rgSize.cx == rgSize.cx && m_rgSize.cy == rgSize.cy )
  3335.                     {
  3336.                         *m_phBmp = hBmp;
  3337.                     }
  3338.                     else
  3339.                     {
  3340.                         SIZEL rgCur;
  3341.                         rgCur.cx = rgSize.cx;
  3342.                         rgCur.cy = rgSize.cy;
  3343.                         IScaleAndSharpenImage2 * pScale;
  3344.                         hr = CoCreateInstance( CLSID_ThumbnailScaler,
  3345.                                                NULL,
  3346.                                                CLSCTX_INPROC_SERVER,
  3347.                                                IID_IScaleAndSharpenImage2,
  3348.                                                (LPVOID *) &pScale );
  3349.                         if ( SUCCEEDED( hr ))
  3350.                         {
  3351.                             hr = pScale->ScaleSharpen2((BITMAPINFO *) &dib,
  3352.                                                         lpBits,
  3353.                                                         m_phBmp,
  3354.                                                         &m_rgSize,
  3355.                                                         m_dwRecClrDepth,
  3356.                                                         hpal,
  3357.                                                         20, m_fOrigSize );
  3358.                             pScale->Release();
  3359.                         }
  3360.                         DeleteObject( hBmp );
  3361.                     }
  3362.                 }
  3363.             }
  3364.             if ( SUCCEEDED( hr ) && hpal && m_dwRecClrDepth <= 8)
  3365.             {
  3366.                 (void) SelectPalette( hdcBmp, hpalOld, TRUE );
  3367.                 RealizePalette( hdcBmp );
  3368.             }
  3369.             if ( m_dwRecClrDepth < 8 )
  3370.             {
  3371.                 // we used a stock 16 colour palette
  3372.                 DeletePalette( hpal );
  3373.             }
  3374.         }
  3375.         if ( hdc )
  3376.         {
  3377.             ReleaseDC( hwnd, hdc );
  3378.         }
  3379.         if ( hdcBmp )
  3380.         {
  3381.             DeleteDC( hdcBmp );
  3382.         }
  3383.     }
  3384.     m_pImg->Disconnect();
  3385.     ATOMICRELEASE( m_pImg );
  3386.     
  3387.     m_lState = IRTIR_TASK_FINISHED;
  3388.     return hr;
  3389. }