Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3131 lines
84 KiB

  1. #include "shellprv.h"
  2. #include "common.h"
  3. #include <varutil.h>
  4. #include "bands.h"
  5. #include "isfband.h"
  6. #include "resource.h"
  7. #include "dpastuff.h"
  8. #include "shlwapi.h"
  9. #include "cobjsafe.h"
  10. #include "uemapp.h"
  11. #include "mnfolder.h"
  12. #include "legacy.h"
  13. #include "util.h"
  14. #include "isfmenu.h"
  15. #define DM_VERBOSE 0 // misc verbose traces
  16. #define DM_PERSIST 0
  17. #define TF_BANDDD TF_BAND
  18. #define DM_RENAME 0
  19. #define DM_MISC 0 // miscellany
  20. #define SZ_PROPERTIESA "properties"
  21. #define SZ_PROPERTIES TEXT(SZ_PROPERTIESA)
  22. #define SZ_REGKEY_ADVFOLDER TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced")
  23. // {F47162A0-C18F-11d0-A3A5-00C04FD706EC}
  24. static const GUID TOID_ExtractImage = { 0xf47162a0, 0xc18f, 0x11d0, { 0xa3, 0xa5, 0x0, 0xc0, 0x4f, 0xd7, 0x6, 0xec } };
  25. #define SUPERCLASS CToolBand
  26. extern UINT g_idFSNotify;
  27. HRESULT CLogoExtractImageTask_Create(CLogoBase *plb,
  28. IExtractImage *pExtract,
  29. LPCWSTR pszCache,
  30. DWORD dwItem,
  31. int iIcon,
  32. DWORD dwFlags,
  33. IRunnableTask ** ppTask);
  34. class CLogoExtractImageTask : public IRunnableTask
  35. {
  36. public:
  37. STDMETHOD (QueryInterface) (REFIID riid, void **ppvObj);
  38. STDMETHOD_(ULONG, AddRef) ();
  39. STDMETHOD_(ULONG, Release) ();
  40. STDMETHOD (Run)(void);
  41. STDMETHOD (Kill)(BOOL fWait);
  42. STDMETHOD (Suspend)();
  43. STDMETHOD (Resume)();
  44. STDMETHOD_(ULONG, IsRunning)(void);
  45. protected:
  46. CLogoExtractImageTask(HRESULT * pHr,
  47. CLogoBase *plb,
  48. IExtractImage * pImage,
  49. LPCWSTR pszCache,
  50. DWORD dwItem,
  51. int iIcon,
  52. DWORD dwFlags);
  53. ~CLogoExtractImageTask();
  54. HRESULT InternalResume();
  55. friend HRESULT CLogoExtractImageTask_Create(CLogoBase* plb,
  56. IExtractImage *pExtract,
  57. LPCWSTR pszCache,
  58. DWORD dwItem,
  59. int iIcon,
  60. DWORD dwFlags,
  61. IRunnableTask ** ppTask);
  62. LONG m_cRef;
  63. LONG m_lState;
  64. IExtractImage * m_pExtract;
  65. IRunnableTask * m_pTask;
  66. WCHAR m_szPath[MAX_PATH];
  67. DWORD m_dwFlags;
  68. DWORD m_dwItem;
  69. CLogoBase* m_plb;
  70. HBITMAP m_hBmp;
  71. int m_iIcon;
  72. };
  73. //=================================================================
  74. // Implementation of CISFBand
  75. //=================================================================
  76. CISFBand::CISFBand() : CToolbarBand()
  77. {
  78. _fCanFocus = TRUE;
  79. _eUemLog = UEMIND_NIL;
  80. _dwPriv = -1;
  81. _fHasOrder = TRUE; // ISFBand always has an order...
  82. _fAllowDropdown = BOOLIFY(SHRegGetBoolUSValue(SZ_REGKEY_ADVFOLDER, TEXT("CascadeFolderBands"),
  83. FALSE,
  84. FALSE));
  85. // Should we enable logging of arbirary events?
  86. // _pguidUEMGroup = &UEMIID_SHELL;
  87. ASSERT(_pguidUEMGroup == NULL);
  88. // Assert that this class is ZERO INITed.
  89. ASSERT(!_pbp);
  90. ASSERT(FALSE == _fCreatedBandProxy);
  91. }
  92. CISFBand::~CISFBand()
  93. {
  94. if (_pbp && _fCreatedBandProxy)
  95. _pbp->SetSite(NULL);
  96. ATOMICRELEASE(_pbp);
  97. }
  98. // aggregation checking is handled in class factory
  99. HRESULT CISFBand_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppv)
  100. {
  101. // aggregation checking is handled in class factory
  102. HRESULT hr = E_OUTOFMEMORY;
  103. CISFBand *pObj = new CISFBand();
  104. if (pObj)
  105. {
  106. hr = pObj->QueryInterface(riid, ppv);
  107. pObj->Release();
  108. }
  109. return hr;
  110. }
  111. /*----------------------------------------------------------
  112. Purpose: See CISFBand::Init for an explanation on the parameters.
  113. */
  114. HRESULT CISFBand_CreateEx(IShellFolder* psf, LPCITEMIDLIST pidl, REFIID riid, void **ppv)
  115. {
  116. *ppv = NULL;
  117. HRESULT hr = E_FAIL;
  118. if (psf || pidl)
  119. {
  120. IShellFolderBand *psfb;
  121. hr = CoCreateInstance(CLSID_ISFBand, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellFolderBand, &psfb));
  122. if (SUCCEEDED(hr))
  123. {
  124. hr = psfb->InitializeSFB(psf, pidl);
  125. if (SUCCEEDED(hr))
  126. {
  127. hr = psfb->QueryInterface(riid, ppv);
  128. }
  129. psfb->Release();
  130. }
  131. }
  132. return hr;
  133. }
  134. #ifdef DEBUG
  135. #define _AddRef(psz) { ++_cRef; TraceMsg(TF_SHDREF, "CDocObjectView(%x)::QI(%s) is AddRefing _cRef=%d", this, psz, _cRef); }
  136. #else
  137. #define _AddRef(psz) ++_cRef
  138. #endif
  139. HRESULT CISFBand::QueryInterface(REFIID riid, void **ppvObj)
  140. {
  141. static const QITAB qit[] = {
  142. QITABENT(CISFBand, IShellFolderBand),
  143. QITABENT(CISFBand, IFolderBandPriv),
  144. { 0 },
  145. };
  146. HRESULT hr = QISearch(this, qit, riid, ppvObj);
  147. if (FAILED(hr))
  148. hr = CToolBand::QueryInterface(riid, ppvObj);
  149. if (FAILED(hr))
  150. hr = CSFToolbar::QueryInterface(riid, ppvObj);
  151. if (S_OK != hr)
  152. {
  153. // HACKHACK: this is yucko!
  154. if (IsEqualIID(riid, CLSID_ISFBand))
  155. {
  156. *ppvObj = (void*)this;
  157. _AddRef(TEXT("CLSID_ISFBand"));
  158. return S_OK;
  159. }
  160. }
  161. return hr;
  162. }
  163. //*** ILIsParentCSIDL -- like ILIsParent, but accepts a CSIDL_* for pidl1
  164. // NOTES
  165. // TODO move to shlwapi (if/when idlist.c moves there)?
  166. STDAPI_(BOOL) ILIsParentCSIDL(int csidl1, LPCITEMIDLIST pidl2, BOOL fImmediate)
  167. {
  168. LPITEMIDLIST pidlSpec;
  169. BOOL fRet = FALSE;
  170. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidl1, &pidlSpec)))
  171. {
  172. fRet = ILIsParent(pidlSpec, pidl2, fImmediate);
  173. ILFree(pidlSpec);
  174. }
  175. return fRet;
  176. }
  177. /*----------------------------------------------------------
  178. Purpose: IShellFolderBand::InitializeSFB
  179. - supply IShellFolder with no PIDL if you want to view some
  180. ISF (either already instantiated from the filesystem or
  181. some non-filesystem ISF) that you do NOT want to receive
  182. notifies from (either from SHChangeNotify nor from
  183. IShellChangeNotify)
  184. - supply a PIDL with no IShellFolder for a full-blown band
  185. looking at a shell namespace (rooted on desktop) item.
  186. */
  187. HRESULT CISFBand::InitializeSFB(IShellFolder *psf, LPCITEMIDLIST pidl)
  188. {
  189. HRESULT hr = S_OK;
  190. // Did they try to add the Recycle Bin? If so we need to reject it
  191. // for consistance reasons. We also reject the Temp. Internet Files
  192. // for security reasons.
  193. if (pidl && (ILIsParentCSIDL(CSIDL_BITBUCKET, pidl, FALSE) ||
  194. ILIsParentCSIDL(CSIDL_INTERNET_CACHE, pidl, FALSE)))
  195. {
  196. // this will eventually show up as IDS_CANTISFBAND
  197. TraceMsg(DM_TRACE, "cib.isfb: recycle => E_INVALIDARG");
  198. hr = E_INVALIDARG;
  199. }
  200. if (SUCCEEDED(hr))
  201. hr = CSFToolbar::SetShellFolder(psf, pidl);
  202. if (SUCCEEDED(hr))
  203. hr = _AfterLoad();
  204. return hr;
  205. }
  206. /*----------------------------------------------------------
  207. Purpose: IShellFolderBand::SetBandInfoSFB
  208. */
  209. HRESULT CISFBand::SetBandInfoSFB(BANDINFOSFB * pbi)
  210. {
  211. ASSERT(pbi);
  212. if (!pbi)
  213. return E_POINTER;
  214. if ((pbi->dwMask & ISFB_MASK_INVALID) ||
  215. (pbi->dwMask & ISFB_MASK_VIEWMODE) && (pbi->wViewMode & ~3))
  216. return E_INVALIDARG;
  217. // We don't handle ISFB_MASK_SHELLFOLDER and ISFB_MASK_IDLIST
  218. // in Set because there's a lot of work to resync pidl, psf, and
  219. // notifcations in the toolbar. If somebody wants to do it,
  220. // more power to ya. :)
  221. if (pbi->dwMask & (ISFB_MASK_SHELLFOLDER | ISFB_MASK_IDLIST))
  222. return E_INVALIDARG;
  223. if (pbi->dwMask & ISFB_MASK_STATE)
  224. {
  225. if (pbi->dwStateMask & ISFB_STATE_DEBOSSED)
  226. _fDebossed = BOOLIFY(pbi->dwState & ISFB_STATE_DEBOSSED);
  227. if (pbi->dwStateMask & ISFB_STATE_ALLOWRENAME)
  228. _fAllowRename = BOOLIFY(pbi->dwState & ISFB_STATE_ALLOWRENAME);
  229. if (pbi->dwStateMask & ISFB_STATE_NOSHOWTEXT)
  230. _fNoShowText = BOOLIFY(pbi->dwState & ISFB_STATE_NOSHOWTEXT);
  231. if (pbi->dwStateMask & ISFB_STATE_CHANNELBAR)
  232. _fChannels = BOOLIFY(pbi->dwState & ISFB_STATE_CHANNELBAR);
  233. /* ISFB_STATE_NOTITLE: removed 970619, use cbs::SetBandState */
  234. if (pbi->dwStateMask & ISFB_STATE_QLINKSMODE)
  235. _fLinksMode = BOOLIFY(pbi->dwState & ISFB_STATE_QLINKSMODE);
  236. if (pbi->dwStateMask & ISFB_STATE_FULLOPEN)
  237. _fFullOpen = BOOLIFY(pbi->dwState & ISFB_STATE_FULLOPEN);
  238. if (pbi->dwStateMask & ISFB_STATE_NONAMESORT)
  239. _fNoNameSort = BOOLIFY(pbi->dwState & ISFB_STATE_NONAMESORT);
  240. if (pbi->dwStateMask & ISFB_STATE_BTNMINSIZE)
  241. _fBtnMinSize = BOOLIFY(pbi->dwState & ISFB_STATE_BTNMINSIZE);
  242. }
  243. if (pbi->dwMask & ISFB_MASK_BKCOLOR)
  244. {
  245. _crBkgnd = pbi->crBkgnd;
  246. _fHaveBkColor = TRUE;
  247. if (EVAL(_hwndTB))
  248. SHSetWindowBits(_hwndTB, GWL_STYLE, TBSTYLE_CUSTOMERASE, TBSTYLE_CUSTOMERASE);
  249. ASSERT(_hwnd);
  250. if (_hwndPager)
  251. {
  252. TraceMsg(TF_BAND, "cib.sbisfb: Pager_SetBkColor(_hwnd=%x crBkgnd=%x)", _hwnd, _crBkgnd);
  253. Pager_SetBkColor(_hwnd, _crBkgnd);
  254. }
  255. }
  256. // We don't support changing these once TB is created, So?
  257. if (pbi->dwMask & ISFB_MASK_COLORS)
  258. {
  259. _crBtnLt = pbi->crBtnLt;
  260. _crBtnDk = pbi->crBtnDk;
  261. _fHaveColors = TRUE;
  262. }
  263. if (pbi->dwMask & ISFB_MASK_VIEWMODE)
  264. {
  265. _uIconSize = (pbi->wViewMode & 3); // stored in a 2-bit field currently...
  266. // only force no recalc if one of the recalcable fields was set
  267. _fNoRecalcDefaults = TRUE;
  268. }
  269. // If the bandsite queried us before, let it know the info may have changed
  270. if (_fInitialized)
  271. _BandInfoChanged();
  272. return S_OK;
  273. }
  274. /*----------------------------------------------------------
  275. Purpose: IShellFolderBand::GetBandInfoSFB
  276. */
  277. HRESULT CISFBand::GetBandInfoSFB(BANDINFOSFB * pbi)
  278. {
  279. ASSERT(pbi);
  280. if (!pbi)
  281. return E_POINTER;
  282. if (pbi->dwMask & ISFB_MASK_STATE)
  283. {
  284. pbi->dwState = 0;
  285. pbi->dwStateMask = ISFB_STATE_ALL;
  286. if (_fDebossed)
  287. pbi->dwState |= ISFB_STATE_DEBOSSED;
  288. if (_fAllowRename)
  289. pbi->dwState |= ISFB_STATE_ALLOWRENAME;
  290. if (_fNoShowText)
  291. pbi->dwState |= ISFB_STATE_NOSHOWTEXT;
  292. if (_fLinksMode)
  293. pbi->dwState |= ISFB_STATE_QLINKSMODE;
  294. if (_fFullOpen)
  295. pbi->dwState |= ISFB_STATE_FULLOPEN;
  296. if (_fNoNameSort)
  297. pbi->dwState |= ISFB_STATE_NONAMESORT;
  298. if (_fBtnMinSize)
  299. pbi->dwState |= ISFB_STATE_BTNMINSIZE;
  300. }
  301. if (pbi->dwMask & ISFB_MASK_BKCOLOR)
  302. {
  303. pbi->crBkgnd = (_fHaveBkColor) ? _crBkgnd : CLR_DEFAULT;
  304. }
  305. if (pbi->dwMask & ISFB_MASK_COLORS)
  306. {
  307. if (_fHaveColors)
  308. {
  309. pbi->crBtnLt = _crBtnLt;
  310. pbi->crBtnDk = _crBtnDk;
  311. }
  312. else
  313. {
  314. pbi->crBtnLt = CLR_DEFAULT;
  315. pbi->crBtnDk = CLR_DEFAULT;
  316. }
  317. }
  318. if (pbi->dwMask & ISFB_MASK_VIEWMODE)
  319. {
  320. pbi->wViewMode = _uIconSize;
  321. }
  322. if (pbi->dwMask & ISFB_MASK_SHELLFOLDER)
  323. {
  324. pbi->psf = _psf;
  325. if (pbi->psf)
  326. pbi->psf->AddRef();
  327. }
  328. if (pbi->dwMask & ISFB_MASK_IDLIST)
  329. {
  330. if (_pidl)
  331. pbi->pidl = ILClone(_pidl);
  332. else
  333. pbi->pidl = NULL;
  334. }
  335. return S_OK;
  336. }
  337. // *** IInputObject methods ***
  338. HRESULT CISFBand::TranslateAcceleratorIO(LPMSG lpMsg)
  339. {
  340. if (SendMessage(_hwnd, TB_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg))
  341. return S_OK;
  342. return SUPERCLASS::TranslateAcceleratorIO(lpMsg);
  343. }
  344. void CISFBand::_SetCacheMenuPopup(IMenuPopup* pmp)
  345. {
  346. if (!SHIsSameObject(pmp, _pmpCache))
  347. {
  348. _ReleaseMenuPopup(&_pmpCache);
  349. _pmpCache = pmp;
  350. if (_pmpCache)
  351. _pmpCache->AddRef();
  352. }
  353. }
  354. void CISFBand::_ReleaseMenuPopup(IMenuPopup** ppmp)
  355. {
  356. IUnknown_SetSite(*ppmp, NULL);
  357. ATOMICRELEASE(*ppmp);
  358. }
  359. /*----------------------------------------------------------
  360. Purpose: Releases the held menu popup.
  361. */
  362. void CISFBand::_ReleaseMenu()
  363. {
  364. if (!SHIsSameObject(_pmp, _pmpCache))
  365. {
  366. TraceMsg(TF_MENUBAND, "Releasing pmp %#lx", _pmp);
  367. _ReleaseMenuPopup(&_pmp);
  368. } else
  369. ATOMICRELEASE(_pmp);
  370. }
  371. //***
  372. // ENTRY/EXIT
  373. // S_OK desktop browser
  374. // S_FALSE other browser (explorer, OC, etc.)
  375. // E_xxx not a browser at all (e.g. band asking tray)
  376. HRESULT MBIsDesktopBrowser(IUnknown *punkSite)
  377. {
  378. HRESULT hr;
  379. IServiceProvider *psp;
  380. IUnknown *punk;
  381. hr = E_FAIL;
  382. if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IServiceProvider, &psp))))
  383. {
  384. hr = S_FALSE;
  385. if (SUCCEEDED(psp->QueryInterface(SID_SShellDesktop, (void**)&punk)))
  386. {
  387. hr = S_OK;
  388. punk->Release();
  389. }
  390. psp->Release();
  391. }
  392. TraceMsg(DM_VERBOSE, "idb: ret hrDesk=%x (0=dt 1=sh e=!brow)", hr);
  393. return hr;
  394. }
  395. /*----------------------------------------------------------
  396. Purpose: IDockingWindow::SetSite method.
  397. */
  398. HRESULT CISFBand::SetSite(IUnknown* punkSite)
  399. {
  400. _ReleaseMenu();
  401. SUPERCLASS::SetSite(punkSite);
  402. if (_punkSite)
  403. {
  404. if (!_hwndTB)
  405. _CreateToolbar(_hwndParent);
  406. IUnknown_SetOwner(_psf, SAFECAST(this, IDeskBand*));
  407. _Initialize();
  408. }
  409. else
  410. IUnknown_SetOwner(_psf, NULL);
  411. // First destroy the band proxy
  412. // Call SetSite(NULL) only if you own
  413. // if not, it's the parent from whom you got it via QS who will call SetSite(NULL)
  414. if (_pbp && _fCreatedBandProxy)
  415. _pbp->SetSite(NULL);
  416. ATOMICRELEASE(_pbp);
  417. _fCreatedBandProxy = FALSE;
  418. // Need a bandproxy
  419. QueryService_SID_IBandProxy(punkSite, IID_IBandProxy, &_pbp, NULL);
  420. if (!_pbp)
  421. {
  422. // We need to create it ourselves since our parent couldn't help
  423. ASSERT(FALSE == _fCreatedBandProxy);
  424. HRESULT hr = CreateIBandProxyAndSetSite(punkSite, IID_IBandProxy, &_pbp, NULL);
  425. if (_pbp)
  426. {
  427. ASSERT(S_OK == hr);
  428. _fCreatedBandProxy = TRUE;
  429. }
  430. }
  431. return S_OK;
  432. }
  433. void CISFBand::_Initialize()
  434. {
  435. _fDesktop = (MBIsDesktopBrowser(_punkSite) == S_OK);
  436. return;
  437. }
  438. /*----------------------------------------------------------
  439. Purpose: IDockingWindow::CloseDW method.
  440. */
  441. HRESULT CISFBand::CloseDW(DWORD dw)
  442. {
  443. _fClosing = TRUE;
  444. // close down the task scheduler ...
  445. if (_pTaskScheduler)
  446. ATOMICRELEASE(_pTaskScheduler);
  447. _UnregisterToolbar();
  448. EmptyToolbar();
  449. IUnknown_SetOwner(_psf, NULL);
  450. _SetCacheMenuPopup(NULL);
  451. // should get freed in EmptyToolbar();
  452. ASSERT(!_hdpa);
  453. return SUPERCLASS::CloseDW(dw);
  454. }
  455. /*----------------------------------------------------------
  456. Purpose: IDockingWindow::ShowDW method
  457. */
  458. HRESULT CISFBand::ShowDW(BOOL fShow)
  459. {
  460. HRESULT hr = S_OK;
  461. SUPERCLASS::ShowDW(fShow);
  462. if (fShow)
  463. {
  464. _fShow = TRUE;
  465. if (_fDirty)
  466. {
  467. _FillToolbar();
  468. }
  469. if (!_fDelayInit)
  470. {
  471. _RegisterToolbar();
  472. }
  473. }
  474. else
  475. {
  476. _fShow = FALSE;
  477. }
  478. return hr;
  479. }
  480. void CISFBand::_StopDelayPainting()
  481. {
  482. if (_fDelayPainting)
  483. {
  484. _fDelayPainting = FALSE;
  485. // May be called by background thread
  486. // Use PostMessage instead of SendMessage to avoid deadlock
  487. PostMessage(_hwndTB, WM_SETREDRAW, TRUE, 0);
  488. if (_hwndPager)
  489. PostMessage(_hwnd, PGM_RECALCSIZE, 0L, 0L);
  490. }
  491. }
  492. HWND CISFBand::_CreatePager(HWND hwndParent)
  493. {
  494. // don't create a pager for isfbands
  495. return hwndParent;
  496. }
  497. HRESULT CISFBand::_CreateToolbar(HWND hwndParent)
  498. {
  499. if (_fHaveBkColor)
  500. _dwStyle |= TBSTYLE_CUSTOMERASE;
  501. HRESULT hr = CSFToolbar::_CreateToolbar(hwndParent);
  502. if (SUCCEEDED(hr))
  503. {
  504. ASSERT(_hwndTB);
  505. if (_fHaveBkColor)
  506. ToolBar_SetInsertMarkColor(_hwndTB, GetSysColor(COLOR_BTNFACE));
  507. SendMessage(_hwndTB, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_DRAWDDARROWS, TBSTYLE_EX_DRAWDDARROWS);
  508. if (_fChannels)
  509. {
  510. SHSetWindowBits(_hwndTB, GWL_EXSTYLE, dwExStyleRTLMirrorWnd, 0);
  511. }
  512. _hwnd = _hwndPager ? _hwndPager : _hwndTB;
  513. if (_fHaveColors)
  514. {
  515. COLORSCHEME cs;
  516. cs.dwSize = sizeof(cs);
  517. cs.clrBtnHighlight = _crBtnLt;
  518. cs.clrBtnShadow = _crBtnDk;
  519. SendMessage(_hwndTB, TB_SETCOLORSCHEME, 0, (LPARAM) &cs);
  520. }
  521. }
  522. return hr;
  523. }
  524. int CISFBand::_GetBitmap(int iCommandID, PIBDATA pibdata, BOOL fUseCache)
  525. {
  526. int iBitmap;
  527. if (_uIconSize == ISFBVIEWMODE_LOGOS)
  528. {
  529. IRunnableTask *pTask = NULL;
  530. DWORD dwPriority = 0;
  531. // fetch the logo instead...
  532. ASSERT(!_fDelayPainting);
  533. // Warning - cannot hold ptask in a member variable - it will be a circular reference
  534. iBitmap = GetLogoIndex(iCommandID, pibdata->GetPidl(), &pTask, &dwPriority, NULL);
  535. if (pTask)
  536. {
  537. AddTaskToQueue(pTask, dwPriority, (DWORD)iCommandID);
  538. ATOMICRELEASE(pTask);
  539. }
  540. }
  541. else
  542. iBitmap = CSFToolbar::_GetBitmap(iCommandID, pibdata, fUseCache);
  543. return iBitmap;
  544. }
  545. void CISFBand::_SetDirty(BOOL fDirty)
  546. {
  547. CSFToolbar::_SetDirty(fDirty);
  548. if (fDirty)
  549. IUnknown_Exec(_punkSite, &CGID_PrivCITCommands, CITIDM_SET_DIRTYBIT, TRUE, NULL, NULL);
  550. }
  551. BOOL CISFBand::_UpdateIconSize(UINT uIconSize, BOOL fUpdateButtons)
  552. {
  553. BOOL fChanged = (_uIconSize != uIconSize);
  554. _uIconSize = uIconSize;
  555. HIMAGELIST himl = NULL;
  556. if (uIconSize == ISFBVIEWMODE_LOGOS)
  557. {
  558. if (SUCCEEDED(InitLogoView()))
  559. {
  560. himl = GetLogoHIML();
  561. }
  562. if (himl)
  563. {
  564. SendMessage(_hwndTB, TB_SETIMAGELIST, 0, (LPARAM)himl);
  565. _UpdateButtons();
  566. }
  567. }
  568. if (!himl)
  569. fChanged |= CSFToolbar::_UpdateIconSize(uIconSize,fUpdateButtons);
  570. return fChanged;
  571. }
  572. void CISFBand::_UpdateVerticalMode(BOOL fVertical)
  573. {
  574. _fVertical = (fVertical != 0);
  575. TraceMsg(TF_BAND, "ISFBand::_UpdateVerticalMode going %hs", _fVertical ? "VERTICAL" : "HORIZONTAL");
  576. ASSERT(_hwnd);
  577. if (_hwndPager)
  578. {
  579. SHSetWindowBits(_hwnd, GWL_STYLE, PGS_HORZ|PGS_VERT,
  580. _fVertical ? PGS_VERT : PGS_HORZ);
  581. }
  582. if (_hwndTB)
  583. {
  584. SHSetWindowBits(_hwndTB, GWL_STYLE, TBSTYLE_WRAPABLE | CCS_VERT,
  585. TBSTYLE_WRAPABLE | (_fVertical ? CCS_VERT : 0));
  586. }
  587. }
  588. HRESULT IUnknown_QueryBand(IUnknown *punk, DWORD dwBandID, IDeskBand** ppstb, DWORD* pdwState, LPWSTR pszName, int cchName)
  589. {
  590. HRESULT hr;
  591. IBandSite *pbs;
  592. hr = punk->QueryInterface(IID_PPV_ARG(IBandSite, &pbs));
  593. if (SUCCEEDED(hr))
  594. {
  595. hr = pbs->QueryBand(dwBandID, ppstb, pdwState, pszName, cchName);
  596. pbs->Release();
  597. }
  598. return hr;
  599. }
  600. #define CISFBAND_GETBUTTONSIZE() (_hwndTB ? (LONG)SendMessage(_hwndTB, TB_GETBUTTONSIZE, 0, 0L) : MAKELONG(16, 16))
  601. // _GetIdealSize
  602. // calculates ideal height and width for band and passes back in
  603. // psize, if psize isn't NULL; return value is band's 'ideal length'
  604. // (ideal height if vertical, else ideal width)
  605. int CISFBand::_GetIdealSize(PSIZE psize)
  606. {
  607. SIZE size;
  608. LONG lButtonSize = CISFBAND_GETBUTTONSIZE();
  609. RECT rc = {0};
  610. if (psize)
  611. {
  612. rc.right = psize->cx;
  613. rc.bottom = psize->cy;
  614. }
  615. else if (_hwndTB)
  616. {
  617. GetClientRect(_hwndTB, &rc);
  618. }
  619. if (_fVertical)
  620. {
  621. // set width to be max of toolbar width and toolbar button width
  622. size.cx = max(RECTWIDTH(rc), LOWORD(lButtonSize));
  623. // have toolbar calculate height given that width
  624. SendMessage(_hwndTB, TB_GETIDEALSIZE, TRUE, (LPARAM)&size);
  625. }
  626. else
  627. {
  628. // set height to be max of toolbar width and toolbar button width
  629. size.cy = max(RECTHEIGHT(rc), HIWORD(lButtonSize));
  630. // have toolbar calculate width given that height
  631. SendMessage(_hwndTB, TB_GETIDEALSIZE, FALSE, (LPARAM)&size);
  632. }
  633. if (psize)
  634. {
  635. *psize = size;
  636. }
  637. return _fVertical ? size.cy : size.cx;
  638. }
  639. /*----------------------------------------------------------
  640. Purpose: IDeskBand::GetBandInfo method
  641. */
  642. HRESULT CISFBand::GetBandInfo(DWORD dwBandID, DWORD fViewMode,
  643. DESKBANDINFO* pdbi)
  644. {
  645. HRESULT hr = S_OK;
  646. WCHAR szQLPath[MAX_PATH] = L"";
  647. if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szQLPath)))
  648. {
  649. WCHAR szSubDir[MAX_PATH];
  650. LoadString(g_hinst, IDS_QLAUNCHAPPDATAPATH, szSubDir, ARRAYSIZE(szSubDir));
  651. PathCombine(szQLPath, szQLPath, szSubDir);
  652. }
  653. _dwBandID = dwBandID;
  654. // We don't know the default icon size until GetBandInfo is called.
  655. // After we set the default, we pay attention to the context menu.
  656. if (!_fNoRecalcDefaults)
  657. {
  658. _uIconSize = (fViewMode & (DBIF_VIEWMODE_FLOATING |DBIF_VIEWMODE_VERTICAL)) ? ISFBVIEWMODE_LARGEICONS : ISFBVIEWMODE_SMALLICONS;
  659. _fNoRecalcDefaults = TRUE;
  660. }
  661. if (!_fInitialized)
  662. {
  663. _fInitialized = TRUE;
  664. _UpdateIconSize(_uIconSize, FALSE);
  665. _UpdateShowText(_fNoShowText);
  666. }
  667. // we treat floating the same as vertical
  668. _UpdateVerticalMode(fViewMode & (DBIF_VIEWMODE_FLOATING |DBIF_VIEWMODE_VERTICAL));
  669. LONG lButtonSize = CISFBAND_GETBUTTONSIZE();
  670. pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT | DBIMF_USECHEVRON;
  671. if (_fDebossed)
  672. pdbi->dwModeFlags |= DBIMF_DEBOSSED;
  673. pdbi->ptMinSize.x = 0;
  674. pdbi->ptMaxSize.y = 32000; // random
  675. pdbi->ptIntegral.y = (fViewMode & DBIF_VIEWMODE_VERTICAL) ? 1 : HIWORD(lButtonSize);
  676. pdbi->ptIntegral.x = 1;
  677. if (!_fFullOpen)
  678. _iIdealLength = _GetIdealSize((PSIZE)&pdbi->ptActual);
  679. // CalcMinWidthHeight {
  680. #define g_cxScrollbar (GetSystemMetrics(SM_CXVSCROLL) * 3 / 4)
  681. #define g_cyScrollbar (GetSystemMetrics(SM_CYVSCROLL) * 3 / 4)
  682. #define CX_TBBUTTON_MAX (16 + CX_FILENAME_AVG) // button + name
  683. #define CY_TBBUTTON_MAX (16) // button
  684. int csBut, csButMin, clBut, clButMin, clScroll;
  685. // set up short/long aliases
  686. if (_fVertical)
  687. {
  688. csBut = LOWORD(lButtonSize);
  689. if (_fBtnMinSize)
  690. csButMin = min(csBut, CX_TBBUTTON_MAX);
  691. else
  692. csButMin = 0; // people like to shrink things way down, so let 'em
  693. clBut = HIWORD(lButtonSize);
  694. clButMin = clBut;
  695. //ASSERT(min(clBut, CY_TBBUTTON_MAX) == clButMin); // fails!
  696. clScroll = g_cyScrollbar;
  697. }
  698. else
  699. {
  700. csBut = HIWORD(lButtonSize);
  701. csButMin = csBut;
  702. //ASSERT(min(csBut, CY_TBBUTTON_MAX) == csButMin); // fails!
  703. clBut = LOWORD(lButtonSize);
  704. clButMin = min(clBut, CX_TBBUTTON_MAX);
  705. clScroll = g_cxScrollbar;
  706. // nt5:176448: integral for horz
  707. //pdbi->ptIntegral.y = csBut; this is the cause for 287082 and 341592
  708. }
  709. // n.b. virt pdbi->pt.x,y is really phys y,x (i.e. phys long,short)
  710. pdbi->ptMinSize.x = 0;
  711. pdbi->ptMinSize.y = csButMin;
  712. DWORD dwState = BSSF_NOTITLE;
  713. BANDINFOSFB bi;
  714. TCHAR szBandPath[MAX_PATH];
  715. bi.dwMask = ISFB_MASK_IDLIST;
  716. GetBandInfoSFB(&bi);
  717. SHGetPathFromIDList(bi.pidl, szBandPath);
  718. if ((lstrcmp(szBandPath, szQLPath) == 0) && (!_fIgnoreAddToFront))
  719. {
  720. pdbi->dwModeFlags |= DBIMF_ADDTOFRONT;
  721. }
  722. ILFree(bi.pidl);
  723. IUnknown_QueryBand(_punkSite, dwBandID, NULL, &dwState, NULL, 0);
  724. if (dwState & BSSF_NOTITLE) // _fNoTitle
  725. {
  726. int i, cBut, clTmp;
  727. // cbut= text notext
  728. // horz 1 4
  729. // vert 1 1
  730. cBut = 1;
  731. if (!_fVertical && _fNoShowText)
  732. {
  733. // special-case for QLaunch so see several buttons
  734. cBut = 3; // for both QLaunch and arbitrary ISF band
  735. }
  736. pdbi->ptMinSize.x = cBut * clButMin;
  737. if (_hwndPager)
  738. {
  739. // tack on extra space for pager arrows
  740. pdbi->ptMinSize.x += 2 * clScroll;
  741. }
  742. i = (int)SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0);
  743. if (i <= cBut)
  744. {
  745. clTmp = i * clBut;
  746. if (clTmp < pdbi->ptMinSize.x)
  747. {
  748. // scrollbars take as much space as button would
  749. // so just do the button
  750. pdbi->ptMinSize.x = clTmp;
  751. }
  752. }
  753. }
  754. // }
  755. hr = _GetTitleW(pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle));
  756. if (SUCCEEDED(hr))
  757. {
  758. // set window text to give accessibility apps something to read
  759. SetWindowText(_hwndTB, pdbi->wszTitle);
  760. }
  761. else
  762. {
  763. // we don't support title
  764. #ifdef DEBUG
  765. if (pdbi->dwMask & DBIM_TITLE)
  766. TraceMsg(DM_VERBOSE, "cisfb.gbi: patch ~DBIM_TITLE");
  767. #endif
  768. pdbi->dwMask &= ~DBIM_TITLE;
  769. }
  770. return hr;
  771. }
  772. LRESULT CISFBand::_OnCustomDraw(NMCUSTOMDRAW* pnmcd)
  773. {
  774. NMTBCUSTOMDRAW * ptbcd = (NMTBCUSTOMDRAW *)pnmcd;
  775. LRESULT lres = CDRF_DODEFAULT;
  776. switch (pnmcd->dwDrawStage)
  777. {
  778. case CDDS_PREPAINT:
  779. // if there is a palette, then quietly select it into the DC ...
  780. if (_hpalHalftone && _uIconSize == ISFBVIEWMODE_LOGOS)
  781. {
  782. ASSERT(pnmcd->hdc);
  783. _hpalOld = SelectPalette(pnmcd->hdc, _hpalHalftone, TRUE);
  784. // LINTASSERT(_hpalOld || !_hpalOld); // 0 semi-ok for SelectPalette
  785. RealizePalette(pnmcd->hdc);
  786. }
  787. // make sure we get the postpaint as well so we can de-select the palette...
  788. lres = CDRF_NOTIFYPOSTPAINT;
  789. break;
  790. case CDDS_POSTPAINT:
  791. // if there is a palette, then quietly select it into the DC ...
  792. if (_hpalHalftone && _uIconSize == ISFBVIEWMODE_LOGOS)
  793. {
  794. ASSERT(pnmcd->hdc);
  795. (void) SelectPalette(pnmcd->hdc, _hpalOld, TRUE);
  796. // we don't need a realize here, we can keep the other palette realzied, we
  797. // re select the old palette above, otherwise we bleed the resource....
  798. // RealizePalette(pnmcd->hdc);
  799. }
  800. break;
  801. case CDDS_PREERASE:
  802. if (_fHaveBkColor)
  803. {
  804. RECT rcClient;
  805. GetClientRect(_hwndTB, &rcClient);
  806. SHFillRectClr(pnmcd->hdc, &rcClient, _crBkgnd);
  807. lres = CDRF_SKIPDEFAULT;
  808. }
  809. break;
  810. }
  811. return lres;
  812. }
  813. void CISFBand::_OnDragBegin(int iItem, DWORD dwPreferredEffect)
  814. {
  815. LPCITEMIDLIST pidl = _IDToPidl(iItem, &_iDragSource);
  816. ToolBar_MarkButton(_hwndTB, iItem, TRUE);
  817. if (pidl)
  818. DragDrop(_hwnd, _psf, pidl, dwPreferredEffect, NULL);
  819. ToolBar_MarkButton(_hwndTB, iItem, FALSE);
  820. _iDragSource = -1;
  821. }
  822. LRESULT CISFBand::_OnHotItemChange(NMTBHOTITEM * pnm)
  823. {
  824. LPNMTBHOTITEM lpnmhi = (LPNMTBHOTITEM)pnm;
  825. LRESULT lres = 0;
  826. if (_hwndPager && (lpnmhi->dwFlags & HICF_ARROWKEYS))
  827. {
  828. int iOldPos, iNewPos;
  829. RECT rc, rcPager;
  830. int heightPager;
  831. int iSelected = lpnmhi->idNew;
  832. iOldPos = (int)SendMessage(_hwnd, PGM_GETPOS, (WPARAM)0, (LPARAM)0);
  833. iNewPos = iOldPos;
  834. SendMessage(_hwndTB, TB_GETITEMRECT, (WPARAM)iSelected, (LPARAM)&rc);
  835. if (rc.top < iOldPos)
  836. {
  837. iNewPos =rc.top;
  838. }
  839. GetClientRect(_hwnd, &rcPager);
  840. heightPager = RECTHEIGHT(rcPager);
  841. if (rc.top >= iOldPos + heightPager)
  842. {
  843. iNewPos += (rc.bottom - (iOldPos + heightPager)) ;
  844. }
  845. if (iNewPos != iOldPos)
  846. SendMessage(_hwnd, PGM_SETPOS, (WPARAM)0, (LPARAM)iNewPos);
  847. }
  848. else
  849. {
  850. lres = CToolbarBand::_OnHotItemChange(pnm);
  851. }
  852. return lres;
  853. }
  854. LRESULT CISFBand::_OnNotify(LPNMHDR pnm)
  855. {
  856. LRESULT lres = 0;
  857. switch (pnm->code)
  858. {
  859. case TBN_DROPDOWN:
  860. {
  861. LPNMTOOLBAR pnmtb = (LPNMTOOLBAR)pnm;
  862. lres = TBDDRET_DEFAULT;
  863. _DropdownItem(_IDToPidl(pnmtb->iItem), pnmtb->iItem);
  864. }
  865. break;
  866. case NM_THEMECHANGED:
  867. {
  868. SendMessage(_hwndTB, TB_SETBUTTONSIZE, 0, 0);
  869. SendMessage(_hwndTB, TB_SETBUTTONWIDTH, 0, MAKELONG(0, 0));
  870. _fInitialized = FALSE;
  871. _BandInfoChanged();
  872. }
  873. break;
  874. default:
  875. lres = CSFToolbar::_OnNotify(pnm);
  876. }
  877. return lres;
  878. }
  879. HRESULT CISFBand::_TBStyleForPidl(LPCITEMIDLIST pidl,
  880. DWORD * pdwTBStyle, DWORD* pdwTBState, DWORD * pdwMIFFlags, int* piIcon)
  881. {
  882. HRESULT hr = CSFToolbar::_TBStyleForPidl(pidl, pdwTBStyle, pdwTBState, pdwMIFFlags, piIcon);
  883. if (_fAllowDropdown &&
  884. !_fCascadeFolder &&
  885. ((_GetAttributesOfPidl(pidl, SFGAO_FOLDER) & SFGAO_FOLDER) ||
  886. IsBrowsableShellExt(pidl)))
  887. {
  888. *pdwTBStyle &= ~BTNS_BUTTON;
  889. *pdwTBStyle |= BTNS_DROPDOWN;
  890. }
  891. return hr;
  892. }
  893. HMENU CISFBand::_GetContextMenu()
  894. {
  895. HMENU hmenu = CSFToolbar::_GetContextMenu();
  896. if (hmenu)
  897. {
  898. //
  899. // nuke the menu items which might resize us (show text,
  900. // view menu) if bandsite is in locked mode
  901. //
  902. IBandSite* pbs;
  903. if (_punkSite && SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IBandSite, &pbs))))
  904. {
  905. BANDSITEINFO bsi = {0};
  906. bsi.dwMask = BSIM_STYLE;
  907. pbs->GetBandSiteInfo(&bsi);
  908. if (bsi.dwStyle & BSIS_LOCKED)
  909. {
  910. DeleteMenu(hmenu, 0, MF_BYPOSITION); // View menu
  911. DeleteMenu(hmenu, ISFBIDM_SHOWTEXT, MF_BYCOMMAND); // show text
  912. }
  913. pbs->Release();
  914. }
  915. }
  916. return hmenu;
  917. }
  918. LRESULT CISFBand::_OnContextMenu(WPARAM wParam, LPARAM lParam)
  919. {
  920. LRESULT lres;
  921. lres = CSFToolbar::_OnContextMenu(wParam, lParam);
  922. // todo: csidl?
  923. TraceMsg(DM_MISC, "cib._ocm: _dwPriv=%d", _dwPriv);
  924. UEMFireEvent(&UEMIID_SHELL, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_UICONTEXT, (_dwPriv == CSIDL_APPDATA || _dwPriv == CSIDL_FAVORITES) ? UIBL_CTXTQCUTITEM : UIBL_CTXTISFITEM);
  925. return lres;
  926. }
  927. LRESULT CISFBand::_DefWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  928. {
  929. switch (uMsg)
  930. {
  931. case WM_SIZE:
  932. // forward to toolbar
  933. SendMessage(_hwndTB, TB_AUTOSIZE, wParam, lParam);
  934. if (_GetIdealSize(NULL) != _iIdealLength)
  935. {
  936. // our ideal size has changed since the last time bandsite
  937. // asked; so tell bandsite ask us for our bandinfo again
  938. _BandInfoChanged();
  939. }
  940. return 0;
  941. }
  942. return CSFToolbar::_DefWindowProc(hwnd, uMsg, wParam, lParam);
  943. }
  944. /*----------------------------------------------------------
  945. Purpose: Set the given IMenuPopup as the submenu to expand. Returns
  946. S_FALSE if the menu was modal, S_OK if it was modeless, or
  947. failure.
  948. */
  949. HRESULT CISFBand::_SetSubMenuPopup(IMenuPopup* pmp, UINT uiCmd, LPCITEMIDLIST pidl, DWORD dwFlagsMPPF)
  950. {
  951. HRESULT hr = E_FAIL;
  952. _ReleaseMenu();
  953. _pmp = pmp;
  954. if (pmp)
  955. {
  956. pmp->AddRef();
  957. RECT rc;
  958. POINT pt;
  959. SendMessage(_hwndTB, TB_GETRECT, uiCmd, (LPARAM)&rc);
  960. MapWindowPoints(_hwndTB, HWND_DESKTOP, (POINT*)&rc, 2);
  961. // Align the sub menu appropriately
  962. if (_fVertical)
  963. {
  964. pt.x = rc.right;
  965. pt.y = rc.top;
  966. }
  967. else
  968. {
  969. pt.x = rc.left;
  970. pt.y = rc.bottom;
  971. }
  972. // Use a reflect point for the sub-menu to start
  973. // if the window is RTL mirrored. [samera]
  974. if (IS_WINDOW_RTL_MIRRORED(_hwndTB))
  975. {
  976. pt.x = (_fVertical) ? rc.left : rc.right;
  977. }
  978. // Tell the sub menu deskbar who we are, so it can
  979. // inform us later when the user navigates out of
  980. // its scope.
  981. IUnknown_SetSite(_pmp, SAFECAST(this, IDeskBand*));
  982. // This must be called after SetSite is done above
  983. _SendInitMenuPopup(pmp, pidl);
  984. // Show the menubar
  985. hr = _pmp->Popup((POINTL*)&pt, (RECTL*)&rc, dwFlagsMPPF);
  986. }
  987. return hr;
  988. }
  989. void CISFBand::_SendInitMenuPopup(IMenuPopup * pmp, LPCITEMIDLIST pidl)
  990. {
  991. }
  992. HRESULT CISFBand::_DropdownItem(LPCITEMIDLIST pidl, UINT idCmd)
  993. {
  994. HRESULT hr = E_FAIL;
  995. if (_pidl && _psf)
  996. {
  997. LPITEMIDLIST pidlFull = ILCombine(_pidl, pidl);
  998. if (pidlFull)
  999. {
  1000. IShellFolder* psf;
  1001. if (SUCCEEDED(_psf->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psf))))
  1002. {
  1003. RECT rc;
  1004. SendMessage(_hwndTB, TB_GETRECT, idCmd, (LPARAM)&rc);
  1005. MapWindowPoints(_hwndTB, HWND_DESKTOP, (POINT*)&rc, 2);
  1006. ITrackShellMenu* ptsm;
  1007. if (SUCCEEDED(CoCreateInstance(CLSID_TrackShellMenu, NULL, CLSCTX_INPROC_SERVER,
  1008. IID_PPV_ARG(ITrackShellMenu, &ptsm))))
  1009. {
  1010. CISFMenuCallback *pISFMcb = new CISFMenuCallback();
  1011. if(pISFMcb)
  1012. {
  1013. ptsm->Initialize(pISFMcb, 0, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL | SMINIT_NOSETSITE );
  1014. pISFMcb->SetSite(_punkSite);
  1015. }
  1016. else
  1017. ptsm->Initialize(NULL, 0, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL);
  1018. if (SUCCEEDED(ptsm->SetShellFolder(psf, pidlFull, NULL, SMSET_TOP | SMSET_USEBKICONEXTRACTION)))
  1019. {
  1020. POINTL pt = {rc.left, rc.right};
  1021. hr = ptsm->Popup(_hwndTB, &pt, (RECTL*)&rc, MPPF_BOTTOM);
  1022. }
  1023. if(pISFMcb)
  1024. pISFMcb->Release();
  1025. ptsm->Release();
  1026. }
  1027. psf->Release();
  1028. }
  1029. ILFree(pidlFull);
  1030. }
  1031. }
  1032. return hr;
  1033. }
  1034. /*----------------------------------------------------------
  1035. Purpose: Try treating the pidl as a cascading menu item.
  1036. Returns: non-zero if succeeded
  1037. */
  1038. LRESULT CISFBand::_TryCascadingItem(LPCITEMIDLIST pidl, UINT uiCmd)
  1039. {
  1040. LRESULT lRet = 0;
  1041. // Do we cascade to another submenu?
  1042. if ((GetKeyState(VK_CONTROL) < 0) || _fCascadeFolder)
  1043. {
  1044. // Is the item a browsable folder?
  1045. if ((_GetAttributesOfPidl(pidl, SFGAO_FOLDER) & SFGAO_FOLDER) ||
  1046. IsBrowsableShellExt(pidl))
  1047. {
  1048. // Yes; cascade the browsable folder as a submenu
  1049. lRet = (S_OK == _DropdownItem(pidl, uiCmd));
  1050. }
  1051. }
  1052. return lRet;
  1053. }
  1054. /*----------------------------------------------------------
  1055. Purpose: Try just invoking the pidl
  1056. Returns: non-zero if succeeded
  1057. */
  1058. LRESULT CISFBand::_TrySimpleInvoke(LPCITEMIDLIST pidl)
  1059. {
  1060. LRESULT lRet = 0;
  1061. if (S_OK == _pbp->IsConnected()) // Force IE
  1062. {
  1063. LPITEMIDLIST pidlDest;
  1064. if (SUCCEEDED(SHGetNavigateTarget(_psf, pidl, &pidlDest, NULL)) && pidlDest &&
  1065. ILIsWeb(pidlDest))
  1066. {
  1067. TCHAR szPath[MAX_PATH];
  1068. // We want to ensure that we first give NavFrameWithFile a chance
  1069. // since this will do the right thing if the PIDL points to a
  1070. // shortcut.
  1071. // If the PIDL is a shortcut, NavFrameWithFile will restore any
  1072. // persistence information stored in the shortcut
  1073. // if that fails - we take the default code path that simply
  1074. // uses the PIDL
  1075. lRet = SUCCEEDED(GetPathForItem(_psf, pidl, szPath, NULL)) &&
  1076. SUCCEEDED(NavFrameWithFile(szPath, (IServiceProvider *)this));
  1077. if (!lRet)
  1078. {
  1079. if (EVAL(_pbp) && (SUCCEEDED(_pbp->NavigateToPIDL(pidlDest))))
  1080. lRet = 1;
  1081. }
  1082. ILFree(pidlDest);
  1083. }
  1084. }
  1085. if (!lRet)
  1086. {
  1087. IContextMenu *pcm = (LPCONTEXTMENU)_GetUIObjectOfPidl(pidl, IID_IContextMenu);
  1088. if (pcm)
  1089. {
  1090. LPCSTR pVerb = NULL;
  1091. UINT fFlags = 0;
  1092. // If ALT double click, accelerator for "Properties..."
  1093. if (GetKeyState(VK_MENU) < 0)
  1094. {
  1095. pVerb = SZ_PROPERTIESA;
  1096. }
  1097. // SHIFT+dblclick does a Explore by default
  1098. if (GetKeyState(VK_SHIFT) < 0)
  1099. {
  1100. fFlags |= CMF_EXPLORE;
  1101. }
  1102. IContextMenu_Invoke(pcm, _hwndTB, pVerb, fFlags);
  1103. pcm->Release();
  1104. }
  1105. }
  1106. return lRet;
  1107. }
  1108. /*----------------------------------------------------------
  1109. Purpose: Helper function to call the menubar site's IMenuPopup::OnSelect
  1110. method.
  1111. */
  1112. HRESULT CISFBand::_SiteOnSelect(DWORD dwType)
  1113. {
  1114. IMenuPopup * pmp;
  1115. HRESULT hr = IUnknown_QueryService(_punkSite, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp));
  1116. if (SUCCEEDED(hr))
  1117. {
  1118. pmp->OnSelect(dwType);
  1119. pmp->Release();
  1120. }
  1121. return hr;
  1122. }
  1123. LRESULT CISFBand::_OnCommand(WPARAM wParam, LPARAM lParam)
  1124. {
  1125. UINT uiCmd = GET_WM_COMMAND_ID(wParam, lParam);
  1126. LRESULT lres = 0;
  1127. TraceMsg(TF_BAND, "_OnCommand 0x%x", uiCmd);
  1128. LPCITEMIDLIST pidl = _IDToPidl(uiCmd);
  1129. if (pidl)
  1130. {
  1131. if (_eUemLog != UEMIND_NIL)
  1132. {
  1133. // FEATURE_UASSIST should be grp,uiCmd
  1134. UEMFireEvent(&UEMIID_SHELL, UEME_UIQCUT, UEMF_XEVENT, -1, (LPARAM)-1);
  1135. }
  1136. // Only do this if we are the quick links in the browser. The derived class will set this
  1137. if (_pguidUEMGroup)
  1138. {
  1139. LPITEMIDLIST pidlFull = ILCombine(_pidl, pidl);
  1140. if (pidlFull)
  1141. {
  1142. UEMFireEvent(_pguidUEMGroup, UEME_RUNPIDL, UEMF_XEVENT, (WPARAM)_psf, (LPARAM)pidl);
  1143. SHSendChangeMenuNotify(NULL, SHCNEE_PROMOTEDITEM, 0, pidlFull);
  1144. ILFree(pidlFull);
  1145. }
  1146. }
  1147. lres = _TryCascadingItem(pidl, uiCmd);
  1148. if (!lres && _fChannels)
  1149. lres = _TryChannelSurfing(pidl);
  1150. if (!lres)
  1151. lres = _TrySimpleInvoke(pidl);
  1152. }
  1153. else
  1154. {
  1155. MessageBeep(MB_OK);
  1156. }
  1157. return(lres);
  1158. }
  1159. // *** IPersistStream
  1160. HRESULT CISFBand::GetClassID(CLSID *pClassID)
  1161. {
  1162. *pClassID = CLSID_ISFBand;
  1163. return S_OK;
  1164. }
  1165. // This might be a directory inside CSIDL_APPDATA that was created on
  1166. // a Win9x machine. Win9x doesn't do the special folder signature info,
  1167. // so when it shows up on NT, it's just a boring directory that now points
  1168. // to the wrong place.
  1169. // So if we get a bad directory, see if it's one of these corrupted
  1170. // Win9x pidls and if so, try to reconstitute the original CSIDL_APPDATA
  1171. // by searching for "Application Data".
  1172. void CISFBand::_FixupAppDataDirectory()
  1173. {
  1174. TCHAR szDirPath[MAX_PATH];
  1175. // We use PathFileExists to check for existence because it turns off
  1176. // hard error boxes if the target is not available (e.g., floppy not
  1177. // in drive)
  1178. if (SHGetPathFromIDList(_pidl, szDirPath) &&
  1179. !PathFileExists(szDirPath))
  1180. {
  1181. static TCHAR szBSAppData[] = TEXT("\\Application Data");
  1182. LPTSTR pszAppData;
  1183. // For every instance of "Application Data", try to graft it
  1184. // into the real CSIDL_APPDATA. If it works, run with it.
  1185. for (pszAppData = szDirPath;
  1186. pszAppData = StrStrI(pszAppData, szBSAppData);
  1187. pszAppData++)
  1188. {
  1189. // Found a candidate. The thing after "\\Application Data"
  1190. // had better be another backslash (in which case we step
  1191. // over it) or the end of the string (in which case we don't).
  1192. TCHAR szPathBuffer[MAX_PATH];
  1193. LPTSTR pszTail = pszAppData + ARRAYSIZE(szBSAppData) - 1;
  1194. // If we did our math right, we should be right after the
  1195. // "a" at the end of "Application Data".
  1196. ASSERT(pszTail[-1] == TEXT('a'));
  1197. if (pszTail[0] == TEXT('\\'))
  1198. pszTail++; // Step over separator
  1199. else if (pszTail[0] == TEXT('\0'))
  1200. { } // at end of string; stay there
  1201. else
  1202. continue; // we were faked out; keep looking
  1203. if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, szPathBuffer)))
  1204. {
  1205. PathCombine(szPathBuffer, szPathBuffer, pszTail);
  1206. if (PathFileExists(szPathBuffer))
  1207. {
  1208. LPITEMIDLIST pidlReal;
  1209. pidlReal = ILCreateFromPath(szPathBuffer);
  1210. if (pidlReal)
  1211. {
  1212. ILFree(_pidl);
  1213. _pidl = pidlReal;
  1214. }
  1215. ASSERT(_pidl);
  1216. break; // found it; stop looking
  1217. }
  1218. }
  1219. }
  1220. }
  1221. }
  1222. typedef struct tagBANDISFSTREAM {
  1223. WORD wVersion; // version of this structure
  1224. WORD cbSize; // size of this structure
  1225. DWORD dwFlags; // BANDISF_ flags
  1226. DWORD dwPriv; // special folder identifier
  1227. WORD wViewMode; // small/large/logo
  1228. WORD wUnused; // For DWORD alignment
  1229. COLORREF crBkgnd; // band background color
  1230. COLORREF crBtnLt; // band button hilite color
  1231. COLORREF crBtnDk; // band button lolite color
  1232. } BANDISFSTREAM, * PBANDISFSTREAM;
  1233. #define BANDISF_VERSION 0x22
  1234. #define BANDISF_MASK_PSF 0x00000001 // TRUE if _psf is saved
  1235. #define BANDISF_BOOL_NOSHOWTEXT 0x00000002 // TRUE if _fNoShowText
  1236. #define BANDISF_BOOL_LARGEICON 0x00000004 // last used in version 0x20
  1237. #define BANDISF_MASK_PIDLASLINK 0x00000008 // TRUE if _pidl is saved as a link
  1238. #define BANDISF_UNUSED10 0x00000010 // (obsolete) was BOOL_NOTITLE
  1239. #define BANDISF_BOOL_CHANNELS 0x00000020 // TRUE if in channel mode
  1240. #define BANDISF_BOOL_ALLOWRENAME 0x00000040 // TRUE if _psf context menu should be enabled
  1241. #define BANDISF_BOOL_DEBOSSED 0x00000080 // TRUE if band should have embossed background
  1242. #define BANDISF_MASK_ORDERLIST 0x00000100 // TRUE if an order list is saved
  1243. #define BANDISF_BOOL_BKCOLOR 0x00000200 // TRUE if bk color is persisted
  1244. #define BANDISF_BOOL_FULLOPEN 0x00000400 // TRUE if band should maximize when opened
  1245. #define BANDISF_BOOL_NONAMESORT 0x00000800 // TRUE if band should _not_ sort icons by name
  1246. #define BANDISF_BOOL_BTNMINSIZE 0x00001000 // TRUE if band should report min thickness of button
  1247. #define BANDISF_BOOL_COLORS 0x00002000 // TRUE if colors are persisted
  1248. #define BANDISF_VALIDBITS 0x00003FFF
  1249. HRESULT CISFBand::Load(IStream *pstm)
  1250. {
  1251. HRESULT hr;
  1252. DWORD cbRead;
  1253. BANDISFSTREAM bisfs = {0};
  1254. // figure out what we need to load
  1255. // read first DWORD only (old stream format started with ONE dword)
  1256. hr = pstm->Read(&bisfs, sizeof(DWORD), &cbRead);
  1257. _fIgnoreAddToFront = TRUE;
  1258. if (SUCCEEDED(hr))
  1259. {
  1260. if (bisfs.cbSize == 0)
  1261. {
  1262. // upgrade case, IE4 beta1 shipped this way
  1263. bisfs.dwFlags = *((LPDWORD)&bisfs);
  1264. bisfs.cbSize = sizeof(bisfs);
  1265. bisfs.wVersion = BANDISF_VERSION;
  1266. bisfs.dwPriv = -1;
  1267. bisfs.wViewMode = (bisfs.dwFlags & BANDISF_BOOL_LARGEICON) ? ISFBVIEWMODE_LARGEICONS : ISFBVIEWMODE_SMALLICONS;
  1268. }
  1269. else
  1270. {
  1271. // read rest of stream
  1272. DWORD dw = (DWORD)bisfs.cbSize;
  1273. if (dw > sizeof(bisfs))
  1274. dw = sizeof(bisfs);
  1275. dw -= sizeof(DWORD);
  1276. hr = pstm->Read(&(bisfs.dwFlags), dw, &cbRead);
  1277. if (FAILED(hr))
  1278. return(hr);
  1279. }
  1280. // HEY, DON'T BE LAME ANY MORE. When you next touch this code,
  1281. // I suggest you figure out what sizes of this structure have
  1282. // been actually shipped and only upgrade those. Also use
  1283. // the offsetof macro so you don't have to keep calculating these
  1284. // things...
  1285. // old upgrade, I don't know what state is persisted at setup time!
  1286. if (bisfs.cbSize == sizeof(bisfs) - 3*sizeof(COLORREF) - sizeof(DWORD) - sizeof(DWORD))
  1287. {
  1288. bisfs.dwPriv = -1;
  1289. bisfs.cbSize += sizeof(DWORD);
  1290. }
  1291. // most recent upgrade, this is NOT persisted in registry at setup time!!!
  1292. if (bisfs.cbSize == sizeof(bisfs) - 3*sizeof(COLORREF) - sizeof(DWORD))
  1293. {
  1294. bisfs.wViewMode = (bisfs.dwFlags & BANDISF_BOOL_LARGEICON) ? ISFBVIEWMODE_LARGEICONS : ISFBVIEWMODE_SMALLICONS;
  1295. bisfs.cbSize = sizeof(bisfs);
  1296. }
  1297. // upgrade from version 0x21 + crBkgnd only to 0x22
  1298. if (bisfs.cbSize == sizeof(bisfs) - 2*sizeof(COLORREF))
  1299. {
  1300. bisfs.cbSize = sizeof(bisfs);
  1301. }
  1302. // upgrade from version 0x21 to 0x22
  1303. if (bisfs.cbSize == sizeof(bisfs) - 3*sizeof(COLORREF))
  1304. {
  1305. bisfs.cbSize = sizeof(bisfs);
  1306. }
  1307. if (!EVAL(bisfs.cbSize >= sizeof(bisfs)))
  1308. {
  1309. return(E_FAIL);
  1310. }
  1311. ASSERT(!(bisfs.dwFlags & ~BANDISF_VALIDBITS));
  1312. if (bisfs.dwFlags & BANDISF_BOOL_NOSHOWTEXT)
  1313. _fNoShowText = TRUE;
  1314. if (bisfs.dwFlags & BANDISF_BOOL_ALLOWRENAME)
  1315. _fAllowRename = TRUE;
  1316. if (bisfs.dwFlags & BANDISF_BOOL_DEBOSSED)
  1317. _fDebossed = TRUE;
  1318. if (bisfs.dwFlags & BANDISF_BOOL_FULLOPEN)
  1319. _fFullOpen = TRUE;
  1320. if (bisfs.dwFlags & BANDISF_BOOL_NONAMESORT)
  1321. _fNoNameSort = TRUE;
  1322. if (bisfs.dwFlags & BANDISF_BOOL_BTNMINSIZE)
  1323. _fBtnMinSize = TRUE;
  1324. if (bisfs.dwFlags & BANDISF_BOOL_BKCOLOR)
  1325. {
  1326. _crBkgnd = bisfs.crBkgnd;
  1327. _fHaveBkColor = TRUE;
  1328. }
  1329. if (bisfs.dwFlags & BANDISF_BOOL_COLORS)
  1330. {
  1331. _crBtnLt = bisfs.crBtnLt;
  1332. _crBtnDk = bisfs.crBtnDk;
  1333. _fHaveColors = TRUE;
  1334. }
  1335. _dwPriv = bisfs.dwPriv;
  1336. if (_dwPriv == CSIDL_APPDATA)
  1337. {
  1338. _eUemLog = UEMIND_SHELL;
  1339. }
  1340. _uIconSize = bisfs.wViewMode;
  1341. _fNoRecalcDefaults = TRUE;
  1342. if (bisfs.dwFlags & BANDISF_MASK_PIDLASLINK)
  1343. {
  1344. ASSERT(NULL==_pidl);
  1345. hr = LoadPidlAsLink(_punkSite, pstm, &_pidl);
  1346. // If we hit hits, LoadPidlAsLink() read a chuck of our data. - BryanSt
  1347. ASSERT(SUCCEEDED(hr));
  1348. // DEBUG_CODE(TCHAR szDbgBuffer[MAX_PATH];)
  1349. // TraceMsg(TF_BAND|TF_GENERAL, "CISFBand::Load() _pidl=>%s<", Dbg_PidlStr(_pidl, szDbgBuffer, SIZECHARS(szDbgBuffer)));
  1350. _FixupAppDataDirectory();
  1351. }
  1352. if (SUCCEEDED(hr) && (bisfs.dwFlags & BANDISF_MASK_PSF))
  1353. {
  1354. ASSERT(NULL == _psf);
  1355. hr = OleLoadFromStream(pstm, IID_PPV_ARG(IShellFolder, &_psf));
  1356. }
  1357. // map this to working info
  1358. if (SUCCEEDED(hr))
  1359. hr = _AfterLoad();
  1360. // we need _psf before we can read the order list.
  1361. if (SUCCEEDED(hr) && (bisfs.dwFlags & BANDISF_MASK_ORDERLIST))
  1362. {
  1363. hr = OrderList_LoadFromStream(pstm, &_hdpaOrder, _psf);
  1364. if (SUCCEEDED(hr))
  1365. {
  1366. // _fDropped "persists" along with the orderlist - if this flag
  1367. // is set, we assume we have a non-default ordering
  1368. _fDropped = TRUE;
  1369. }
  1370. }
  1371. }
  1372. return hr;
  1373. }
  1374. HRESULT SaveIsfToStream(IShellFolder *psf, IStream *pstm)
  1375. {
  1376. IPersistStream* pps;
  1377. HRESULT hr = psf->QueryInterface(IID_PPV_ARG(IPersistStream, &pps));
  1378. if (SUCCEEDED(hr))
  1379. {
  1380. hr = OleSaveToStream(pps, pstm);
  1381. pps->Release();
  1382. }
  1383. return hr;
  1384. }
  1385. HRESULT CISFBand::Save(IStream *pstm, BOOL fClearDirty)
  1386. {
  1387. IPersistStream* pps = NULL;
  1388. BANDISFSTREAM bisfs = {0};
  1389. // figure out what we will save
  1390. if (_pidl)
  1391. bisfs.dwFlags |= BANDISF_MASK_PIDLASLINK;
  1392. if (_psf && !_fPSFBandDesktop)
  1393. bisfs.dwFlags |= BANDISF_MASK_PSF;
  1394. if (_fDropped && (_hdpa || _hdpaOrder)) // only if a drop occurred do we have non-default ordering
  1395. bisfs.dwFlags |= BANDISF_MASK_ORDERLIST;
  1396. if (_fNoShowText)
  1397. bisfs.dwFlags |= BANDISF_BOOL_NOSHOWTEXT;
  1398. if (_fAllowRename)
  1399. bisfs.dwFlags |= BANDISF_BOOL_ALLOWRENAME;
  1400. if (_fDebossed)
  1401. bisfs.dwFlags |= BANDISF_BOOL_DEBOSSED;
  1402. if (_fFullOpen)
  1403. bisfs.dwFlags |= BANDISF_BOOL_FULLOPEN;
  1404. if (_fNoNameSort)
  1405. bisfs.dwFlags |= BANDISF_BOOL_NONAMESORT;
  1406. if (_fBtnMinSize)
  1407. bisfs.dwFlags |= BANDISF_BOOL_BTNMINSIZE;
  1408. if (_fHaveBkColor)
  1409. {
  1410. bisfs.dwFlags |= BANDISF_BOOL_BKCOLOR;
  1411. bisfs.crBkgnd = _crBkgnd;
  1412. }
  1413. if (_fHaveColors)
  1414. {
  1415. bisfs.dwFlags |= BANDISF_BOOL_COLORS;
  1416. bisfs.crBtnLt = _crBtnLt;
  1417. bisfs.crBtnDk = _crBtnDk;
  1418. }
  1419. bisfs.cbSize = sizeof(bisfs);
  1420. bisfs.wVersion = BANDISF_VERSION;
  1421. bisfs.dwPriv = _dwPriv;
  1422. bisfs.wViewMode = _uIconSize;
  1423. // now save it
  1424. HRESULT hr = pstm->Write(&bisfs, sizeof(bisfs), NULL);
  1425. if (SUCCEEDED(hr) && bisfs.dwFlags & BANDISF_MASK_PIDLASLINK)
  1426. {
  1427. hr = SavePidlAsLink(_punkSite, pstm, _pidl);
  1428. }
  1429. if (SUCCEEDED(hr) && bisfs.dwFlags & BANDISF_MASK_PSF)
  1430. {
  1431. hr = SaveIsfToStream(_psf, pstm);
  1432. }
  1433. if (SUCCEEDED(hr) && (bisfs.dwFlags & BANDISF_MASK_ORDERLIST))
  1434. {
  1435. hr = OrderList_SaveToStream(pstm, (_hdpa ? _hdpa : _hdpaOrder), _psf);
  1436. }
  1437. return hr;
  1438. }
  1439. // IContextMenu implementation
  1440. HRESULT CISFBand::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
  1441. {
  1442. BOOL fChanged = FALSE;
  1443. int idCmd = -1;
  1444. UINT uNewMode = 0;
  1445. if (!HIWORD(lpici->lpVerb))
  1446. idCmd = LOWORD(lpici->lpVerb);
  1447. switch (idCmd)
  1448. {
  1449. case ISFBIDM_LARGE:
  1450. uNewMode = ISFBVIEWMODE_LARGEICONS;
  1451. goto newViewMode;
  1452. case ISFBIDM_SMALL:
  1453. uNewMode = ISFBVIEWMODE_SMALLICONS;
  1454. newViewMode:
  1455. if (uNewMode != _uIconSize)
  1456. {
  1457. BOOL fRefresh = FALSE;
  1458. if (uNewMode == ISFBVIEWMODE_LOGOS || _uIconSize == ISFBVIEWMODE_LOGOS)
  1459. {
  1460. // invalidate all before switching the imagelist...
  1461. _RememberOrder();
  1462. EmptyToolbar();
  1463. fRefresh = TRUE;
  1464. }
  1465. // we Logo view has now left the building...
  1466. if (uNewMode != ISFBVIEWMODE_LOGOS && _uIconSize == ISFBVIEWMODE_LOGOS)
  1467. {
  1468. ExitLogoView();
  1469. }
  1470. fChanged = _UpdateIconSize(uNewMode, TRUE);
  1471. if (fRefresh)
  1472. {
  1473. _FillToolbar();
  1474. }
  1475. if (fChanged)
  1476. _BandInfoChanged();
  1477. }
  1478. // fall thru
  1479. default:
  1480. return CSFToolbar::InvokeCommand(lpici);
  1481. }
  1482. return(S_OK);
  1483. }
  1484. // *** IOleCommandTarget methods ***
  1485. STDMETHODIMP CISFBand::QueryStatus(const GUID *pguidCmdGroup,
  1486. ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  1487. {
  1488. HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  1489. if (pguidCmdGroup == NULL)
  1490. {
  1491. // nothing
  1492. }
  1493. else if (IsEqualGUID(CGID_ISFBand, *pguidCmdGroup))
  1494. {
  1495. for (UINT i = 0; i < cCmds; i++)
  1496. {
  1497. switch (rgCmds[i].cmdID)
  1498. {
  1499. case ISFBID_CACHEPOPUP:
  1500. case ISFBID_ISITEMVISIBLE:
  1501. case ISFBID_PRIVATEID:
  1502. rgCmds[i].cmdf |= OLECMDF_SUPPORTED;
  1503. break;
  1504. }
  1505. }
  1506. hr = S_OK;
  1507. }
  1508. else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup))
  1509. {
  1510. for (UINT i = 0; i < cCmds; i++)
  1511. {
  1512. switch (rgCmds[i].cmdID)
  1513. {
  1514. case SHDVID_UEMLOG:
  1515. rgCmds[i].cmdf |= OLECMDF_SUPPORTED;
  1516. break;
  1517. }
  1518. }
  1519. hr = S_OK;
  1520. }
  1521. return hr;
  1522. }
  1523. HRESULT CISFBand::_IsPidlVisible(LPITEMIDLIST pidl)
  1524. {
  1525. int i;
  1526. HRESULT hr = _GetButtonFromPidl(pidl, NULL, &i, NULL);
  1527. if (SUCCEEDED(hr))
  1528. {
  1529. RECT rc;
  1530. GetClientRect(_hwndTB, &rc);
  1531. if (SHIsButtonObscured(_hwndTB, &rc, i))
  1532. hr = S_FALSE;
  1533. else
  1534. hr = S_OK;
  1535. }
  1536. return hr;
  1537. }
  1538. HRESULT CISFBand::_OrderListFromIStream(VARIANT* pvarargIn)
  1539. {
  1540. HRESULT hr = E_FAIL;
  1541. if (pvarargIn->vt == VT_UNKNOWN)
  1542. {
  1543. IStream* pstm;
  1544. if (SUCCEEDED(pvarargIn->punkVal->QueryInterface(IID_PPV_ARG(IStream, &pstm))))
  1545. {
  1546. OrderList_Destroy(&_hdpaOrder);
  1547. hr = OrderList_LoadFromStream(pstm, &_hdpaOrder, _psf);
  1548. if (SUCCEEDED(hr))
  1549. {
  1550. _SetDirty(TRUE);
  1551. // flush out since our orderlist changed -- filltoolbar will just
  1552. // do a diff and that won't do anything on a simple reordering.
  1553. EmptyToolbar();
  1554. if (_fShow)
  1555. {
  1556. _FillToolbar();
  1557. }
  1558. }
  1559. pstm->Release();
  1560. }
  1561. }
  1562. return hr;
  1563. }
  1564. HRESULT CISFBand::_IStreamFromOrderList(VARIANT* pvarargOut)
  1565. {
  1566. HRESULT hr = E_OUTOFMEMORY;
  1567. ASSERT(pvarargOut != NULL);
  1568. IStream* pstm = SHCreateMemStream(NULL, 0);
  1569. if (pstm)
  1570. {
  1571. hr = OrderList_SaveToStream(pstm, _hdpa, _psf);
  1572. if (SUCCEEDED(hr))
  1573. {
  1574. pvarargOut->vt = VT_UNKNOWN;
  1575. pvarargOut->punkVal = pstm;
  1576. pvarargOut->punkVal->AddRef();
  1577. }
  1578. pstm->Release();
  1579. }
  1580. return hr;
  1581. }
  1582. STDMETHODIMP CISFBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  1583. DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  1584. {
  1585. if (pguidCmdGroup == NULL)
  1586. {
  1587. // nothing
  1588. }
  1589. else if (IsEqualGUID(CGID_ISFBand, *pguidCmdGroup))
  1590. {
  1591. switch (nCmdID)
  1592. {
  1593. case ISFBID_CACHEPOPUP:
  1594. if (pvarargIn && pvarargIn->vt == VT_UNKNOWN)
  1595. {
  1596. IMenuPopup* pmp = NULL;
  1597. if (pvarargIn->punkVal)
  1598. pvarargIn->punkVal->QueryInterface(IID_PPV_ARG(IMenuPopup, &pmp));
  1599. _SetCacheMenuPopup(pmp);
  1600. ATOMICRELEASE(pmp);
  1601. }
  1602. if (pvarargOut)
  1603. {
  1604. pvarargOut->vt = VT_UNKNOWN;
  1605. pvarargOut->punkVal = _pmpCache;
  1606. if (_pmpCache)
  1607. _pmpCache->AddRef();
  1608. }
  1609. return S_OK;
  1610. case ISFBID_ISITEMVISIBLE:
  1611. {
  1612. HRESULT hr = E_INVALIDARG;
  1613. if (pvarargIn && pvarargIn->vt == VT_INT_PTR)
  1614. hr = _IsPidlVisible((LPITEMIDLIST)pvarargIn->byref);
  1615. return hr;
  1616. }
  1617. case ISFBID_PRIVATEID:
  1618. // hack hack for BSMenu to differentiate between specially created
  1619. // isfbands. see bsmenu's _FindBand
  1620. // if pvarargOut is set, we give back the id we have stored.
  1621. if (pvarargOut)
  1622. {
  1623. pvarargOut->vt = VT_I4;
  1624. pvarargOut->lVal = _dwPriv;
  1625. }
  1626. // if pvarargIn is set, then we take and keep this id.
  1627. if (pvarargIn && pvarargIn->vt == VT_I4)
  1628. _dwPriv = pvarargIn->lVal;
  1629. return S_OK;
  1630. case ISFBID_GETORDERSTREAM:
  1631. return _IStreamFromOrderList(pvarargOut);
  1632. case ISFBID_SETORDERSTREAM:
  1633. return _OrderListFromIStream(pvarargIn);
  1634. }
  1635. }
  1636. else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup))
  1637. {
  1638. switch (nCmdID)
  1639. {
  1640. case SHDVID_UEMLOG:
  1641. ASSERT(pvarargOut == NULL);
  1642. // if pvarargIn is set, then we take and keep this id.
  1643. if (pvarargIn && pvarargIn->vt == VT_I4)
  1644. {
  1645. _eUemLog = pvarargIn->lVal;
  1646. ASSERT(_eUemLog == UEMIND_SHELL || _eUemLog == UEMIND_BROWSER);
  1647. }
  1648. return S_OK;
  1649. }
  1650. }
  1651. else if (IsEqualGUID(CGID_DeskBand, *pguidCmdGroup))
  1652. {
  1653. switch (nCmdID)
  1654. {
  1655. case DBID_DELAYINIT:
  1656. _fDelayInit = TRUE;
  1657. break;
  1658. case DBID_FINISHINIT:
  1659. _fDelayInit = FALSE;
  1660. _RegisterToolbar();
  1661. break;
  1662. case DBID_SETWINDOWTHEME:
  1663. if (pvarargIn && pvarargIn->vt == VT_BSTR)
  1664. {
  1665. if (_hwndTB)
  1666. {
  1667. SendMessage(_hwndTB, TB_SETWINDOWTHEME, 0, (LPARAM)pvarargIn->bstrVal);
  1668. _BandInfoChanged();
  1669. }
  1670. }
  1671. }
  1672. return S_OK;
  1673. }
  1674. return OLECMDERR_E_NOTSUPPORTED;
  1675. }
  1676. IShellFolder * CISFBand::GetSF()
  1677. {
  1678. ASSERT(_psf);
  1679. return _psf;
  1680. }
  1681. HWND CISFBand::GetHWND()
  1682. {
  1683. return _hwndTB;
  1684. }
  1685. REFTASKOWNERID CISFBand::GetTOID()
  1686. {
  1687. return TOID_ExtractImage;
  1688. }
  1689. HRESULT CISFBand::OnTranslatedChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  1690. {
  1691. if (lEvent == SHCNE_RMDIR && _IsEqualID(pidl1))
  1692. {
  1693. HRESULT hr = E_FAIL;
  1694. IBandSite *pbandSite;
  1695. if (_punkSite)
  1696. {
  1697. hr = _punkSite->QueryInterface(IID_PPV_ARG(IBandSite, &pbandSite));
  1698. if (EVAL(SUCCEEDED(hr)))
  1699. {
  1700. pbandSite->RemoveBand(_dwBandID);
  1701. pbandSite->Release();
  1702. }
  1703. }
  1704. return hr;
  1705. }
  1706. else
  1707. {
  1708. return CSFToolbar::OnTranslatedChange(lEvent, pidl1, pidl2);
  1709. }
  1710. }
  1711. HRESULT CISFBand::UpdateLogoCallback(DWORD dwItem, int iIcon, HBITMAP hImage, LPCWSTR pszCache, BOOL fCache)
  1712. {
  1713. int iItem = (int)dwItem;
  1714. HRESULT hr;
  1715. UINT uImage;
  1716. // catch if we are closing...
  1717. if (_fClosing)
  1718. return S_OK;
  1719. IMAGECACHEINFO rgInfo;
  1720. rgInfo.dwMask = ICIFLAG_NAME | ICIFLAG_LARGE | ICIFLAG_BITMAP | ICIFLAG_NOUSAGE;
  1721. rgInfo.cbSize = sizeof(rgInfo);
  1722. rgInfo.pszName = pszCache;
  1723. rgInfo.hBitmapLarge = hImage;
  1724. ASSERT(_pLogoCache);
  1725. if (_pLogoCache)
  1726. hr = _pLogoCache->AddImage(&rgInfo, &uImage);
  1727. else
  1728. hr = E_FAIL;
  1729. // catch if we are closing...
  1730. if (_fClosing)
  1731. return S_OK;
  1732. if (SUCCEEDED(hr))
  1733. {
  1734. // remember the icon to logo mapping....
  1735. AddIndicesToLogoList(iIcon, uImage);
  1736. // catch we are closing before we try and doa bloc
  1737. PostMessage(_hwndTB, TB_CHANGEBITMAP, iItem, uImage);
  1738. }
  1739. // stop delay painting when the last extract image task calls back
  1740. if (_fDelayPainting)
  1741. {
  1742. if (_pTaskScheduler && _pTaskScheduler->CountTasks(TOID_NULL) == 1)
  1743. {
  1744. _StopDelayPainting();
  1745. }
  1746. }
  1747. return hr;
  1748. }
  1749. // }
  1750. HRESULT CISFBand::_GetTitleW(LPWSTR pwszTitle, DWORD cchSize)
  1751. {
  1752. HRESULT hr = E_FAIL;
  1753. TraceMsg(TF_BAND, "Calling baseclass CISFBand::_GetTitleW");
  1754. if (!EVAL(pwszTitle))
  1755. return E_INVALIDARG;
  1756. *pwszTitle = 0;
  1757. if (_pidl)
  1758. {
  1759. hr = SHGetNameAndFlagsW(_pidl, SHGDN_NORMAL, pwszTitle, cchSize, NULL);
  1760. }
  1761. return hr;
  1762. }
  1763. STDAPI NavigateToPIDL(IWebBrowser2* pwb, LPCITEMIDLIST pidl);
  1764. LRESULT CISFBand::_TryChannelSurfing(LPCITEMIDLIST pidl)
  1765. {
  1766. LRESULT lRet = 0;
  1767. ASSERT(_fChannels);
  1768. LPITEMIDLIST pidlTarget;
  1769. HRESULT hr = SHGetNavigateTarget(_psf, pidl, &pidlTarget, NULL);
  1770. if (SUCCEEDED(hr))
  1771. {
  1772. IWebBrowser2* pwb;
  1773. // n.b. careful! only one of GCB and C_OB up the refcnt
  1774. _GetChannelBrowser(&pwb);
  1775. if (SUCCEEDED(Channels_OpenBrowser(&pwb, pwb != NULL)))
  1776. {
  1777. lRet = 1; // success at this point
  1778. if (SUCCEEDED(NavigateToPIDL(pwb, pidlTarget)))
  1779. {
  1780. LPITEMIDLIST pidlFull = ILCombine(_pidl, pidl);
  1781. if (pidlFull)
  1782. {
  1783. VARIANT varURLpidl, flags;
  1784. flags.vt = VT_I4;
  1785. flags.lVal = navBrowserBar;
  1786. if (SUCCEEDED(InitVariantFromIDList(&varURLpidl, pidlFull)))
  1787. {
  1788. pwb->Navigate2(&varURLpidl, &flags, PVAREMPTY, PVAREMPTY, PVAREMPTY);
  1789. VariantClear(&varURLpidl);
  1790. }
  1791. ILFree(pidlFull);
  1792. }
  1793. }
  1794. }
  1795. if (pwb)
  1796. pwb->Release();
  1797. ILFree(pidlTarget);
  1798. }
  1799. return lRet;
  1800. }
  1801. //*** _GetChannelBrowser -- find appropriate browser for surfing
  1802. // DESCRIPTION
  1803. // for the DTBrowser case, we fail (pwb=NULL, hr=S_FALSE) so that our
  1804. // caller will create a new SHBrowser (which can be put into theater mode).
  1805. // for the SHBrowser case, we find the top-level browser (so we'll navigate
  1806. // in-place).
  1807. HRESULT CISFBand::_GetChannelBrowser(IWebBrowser2 **ppwb)
  1808. {
  1809. HRESULT hr;
  1810. *ppwb = NULL; // assume failure
  1811. if (_fDesktop)
  1812. {
  1813. ASSERT(*ppwb == NULL);
  1814. hr = S_FALSE;
  1815. }
  1816. else
  1817. {
  1818. hr = IUnknown_QueryServiceForWebBrowserApp(_punkSite, IID_PPV_ARG(IWebBrowser2, ppwb));
  1819. }
  1820. return hr;
  1821. }
  1822. HRESULT IUnknown_SetBandInfoSFB(IUnknown *punkBand, BANDINFOSFB *pbi)
  1823. {
  1824. HRESULT hr = E_FAIL;
  1825. if (punkBand)
  1826. {
  1827. IShellFolderBand *pisfBand;
  1828. hr = punkBand->QueryInterface(IID_PPV_ARG(IShellFolderBand, &pisfBand));
  1829. if (EVAL(SUCCEEDED(hr)))
  1830. {
  1831. hr = pisfBand->SetBandInfoSFB(pbi);
  1832. pisfBand->Release();
  1833. }
  1834. }
  1835. return hr;
  1836. }
  1837. ///////////////////////////CLogoExtractImageTask///////////////////////////////////////////////
  1838. // Warning
  1839. // The CLogoBase class cannot have a ref on the returned task
  1840. // since that would be a circular reference
  1841. // Warning
  1842. HRESULT CLogoExtractImageTask_Create(CLogoBase *plb,
  1843. IExtractImage *pExtract,
  1844. LPCWSTR pszCache,
  1845. DWORD dwItem,
  1846. int iIcon,
  1847. DWORD dwFlags,
  1848. IRunnableTask ** ppTask)
  1849. {
  1850. if (!ppTask || !plb || !pExtract)
  1851. {
  1852. return E_INVALIDARG;
  1853. }
  1854. HRESULT hr;
  1855. CLogoExtractImageTask * pNewTask = new CLogoExtractImageTask(&hr, plb, pExtract, pszCache, dwItem, iIcon, dwFlags);
  1856. if (pNewTask)
  1857. {
  1858. *ppTask = SAFECAST(pNewTask, IRunnableTask *);
  1859. hr = S_OK;
  1860. }
  1861. else
  1862. {
  1863. hr = E_OUTOFMEMORY;
  1864. }
  1865. return hr;
  1866. }
  1867. CLogoExtractImageTask::CLogoExtractImageTask(HRESULT * pHr, CLogoBase *plb, IExtractImage * pImage,
  1868. LPCWSTR pszCache, DWORD dwItem, int iIcon, DWORD dwFlags)
  1869. {
  1870. m_lState = IRTIR_TASK_NOT_RUNNING;
  1871. m_plb = plb;
  1872. m_plb->AddRef();
  1873. // cannot assume the band will kill us before it dies....
  1874. // hence we hold a reference
  1875. StrCpyW(m_szPath, pszCache);
  1876. m_pExtract = pImage;
  1877. pImage->AddRef();
  1878. m_cRef = 1;
  1879. // use the upper bit of the flags to determine if we should always call....
  1880. m_dwFlags = dwFlags;
  1881. m_dwItem = dwItem;
  1882. m_iIcon = iIcon;
  1883. // Since the task moves from thread to thread,
  1884. // don't charge this thread for the objects we're using
  1885. }
  1886. CLogoExtractImageTask::~CLogoExtractImageTask()
  1887. {
  1888. ATOMICRELEASE(m_pExtract);
  1889. ATOMICRELEASE(m_pTask);
  1890. if (m_hBmp && !(m_dwFlags & EITF_SAVEBITMAP))
  1891. {
  1892. DeleteObject(m_hBmp);
  1893. }
  1894. if (m_plb)
  1895. m_plb->Release();
  1896. }
  1897. STDMETHODIMP CLogoExtractImageTask::QueryInterface(REFIID riid, void **ppv)
  1898. {
  1899. static const QITAB qit[] = {
  1900. QITABENT(CLogoExtractImageTask, IRunnableTask),
  1901. { 0 },
  1902. };
  1903. return QISearch(this, qit, riid, ppv);
  1904. }
  1905. STDMETHODIMP_ (ULONG) CLogoExtractImageTask::AddRef()
  1906. {
  1907. return InterlockedIncrement(&m_cRef);
  1908. }
  1909. STDMETHODIMP_ (ULONG) CLogoExtractImageTask::Release()
  1910. {
  1911. if (InterlockedDecrement(&m_cRef) == 0)
  1912. {
  1913. delete this;
  1914. return 0;
  1915. }
  1916. return m_cRef;
  1917. }
  1918. STDMETHODIMP CLogoExtractImageTask::Run(void)
  1919. {
  1920. HRESULT hr = E_FAIL;
  1921. if (m_lState == IRTIR_TASK_RUNNING)
  1922. {
  1923. hr = S_FALSE;
  1924. }
  1925. else if (m_lState == IRTIR_TASK_PENDING)
  1926. {
  1927. hr = E_FAIL;
  1928. }
  1929. else if (m_lState == IRTIR_TASK_NOT_RUNNING)
  1930. {
  1931. LONG lRes = InterlockedExchange(& m_lState, IRTIR_TASK_RUNNING);
  1932. if (lRes == IRTIR_TASK_PENDING)
  1933. {
  1934. m_lState = IRTIR_TASK_FINISHED;
  1935. return S_OK;
  1936. }
  1937. // see if it supports IRunnableTask
  1938. m_pExtract->QueryInterface(IID_PPV_ARG(IRunnableTask, &m_pTask));
  1939. // IE4.01 has an error - it returns the wrong VTABLE
  1940. // when this QI is done.
  1941. if ((void *)m_pTask == (void *)m_pExtract)
  1942. {
  1943. m_pTask = m_pTask + 2; // This vtable is two ptrs away and is in fstree.cpp in shell32 in IE4.01
  1944. }
  1945. if (m_lState == IRTIR_TASK_RUNNING)
  1946. {
  1947. // start the extractor....
  1948. hr = m_pExtract->Extract(&m_hBmp);
  1949. }
  1950. if ((SUCCEEDED(hr) || (hr != E_PENDING && (m_dwFlags & EITF_ALWAYSCALL))) && m_lState == IRTIR_TASK_RUNNING)
  1951. {
  1952. hr = InternalResume();
  1953. }
  1954. if (m_lState != IRTIR_TASK_SUSPENDED || hr != E_PENDING)
  1955. {
  1956. m_lState = IRTIR_TASK_FINISHED;
  1957. }
  1958. }
  1959. return hr;
  1960. }
  1961. STDMETHODIMP CLogoExtractImageTask::Kill(BOOL fWait)
  1962. {
  1963. if (m_lState != IRTIR_TASK_RUNNING)
  1964. {
  1965. return S_FALSE;
  1966. }
  1967. LONG lRes = InterlockedExchange(&m_lState, IRTIR_TASK_PENDING);
  1968. if (lRes == IRTIR_TASK_FINISHED)
  1969. {
  1970. m_lState = lRes;
  1971. return S_OK;
  1972. }
  1973. // does it support IRunnableTask ? Can we kill it ?
  1974. HRESULT hr = E_NOTIMPL;
  1975. if (m_pTask != NULL)
  1976. {
  1977. hr = m_pTask->Kill(FALSE);
  1978. }
  1979. return hr;
  1980. }
  1981. STDMETHODIMP CLogoExtractImageTask::Suspend(void)
  1982. {
  1983. if (!m_pTask)
  1984. {
  1985. return E_NOTIMPL;
  1986. }
  1987. if (m_lState != IRTIR_TASK_RUNNING)
  1988. {
  1989. return E_FAIL;
  1990. }
  1991. LONG lRes = InterlockedExchange(&m_lState, IRTIR_TASK_SUSPENDED);
  1992. HRESULT hr = m_pTask->Suspend();
  1993. if (SUCCEEDED(hr))
  1994. {
  1995. lRes = (LONG) m_pTask->IsRunning();
  1996. if (lRes == IRTIR_TASK_SUSPENDED)
  1997. {
  1998. m_lState = lRes;
  1999. }
  2000. }
  2001. else
  2002. {
  2003. m_lState = lRes;
  2004. }
  2005. return hr;
  2006. }
  2007. STDMETHODIMP CLogoExtractImageTask::Resume(void)
  2008. {
  2009. if (!m_pTask)
  2010. {
  2011. return E_NOTIMPL;
  2012. }
  2013. if (m_lState != IRTIR_TASK_SUSPENDED)
  2014. {
  2015. return E_FAIL;
  2016. }
  2017. m_lState = IRTIR_TASK_RUNNING;
  2018. HRESULT hr = m_pTask->Resume();
  2019. if (SUCCEEDED(hr) || (hr != E_PENDING && (m_dwFlags & EITF_ALWAYSCALL)))
  2020. {
  2021. hr = InternalResume();
  2022. }
  2023. return hr;
  2024. }
  2025. HRESULT CLogoExtractImageTask::InternalResume()
  2026. {
  2027. HRESULT hr = S_OK;
  2028. if (m_dwFlags & EITF_ALWAYSCALL || m_hBmp)
  2029. {
  2030. // call the update function
  2031. hr = m_plb->UpdateLogoCallback(m_dwItem, m_iIcon, m_hBmp, m_szPath, TRUE);
  2032. }
  2033. m_lState = IRTIR_TASK_FINISHED;
  2034. return hr;
  2035. }
  2036. STDMETHODIMP_(ULONG) CLogoExtractImageTask:: IsRunning(void)
  2037. {
  2038. return m_lState;
  2039. }
  2040. // static data...
  2041. IImageCache * CLogoBase::s_pSharedWideLogoCache = NULL;
  2042. long CLogoBase::s_lSharedWideLogosRef = 0;
  2043. HDSA CLogoBase::s_hdsaWideLogoIndices = NULL;
  2044. CRITICAL_SECTION CLogoBase::s_csSharedLogos = {0};
  2045. extern "C" void CLogoBase_Initialize(void)
  2046. {
  2047. CLogoBase::_Initialize();
  2048. }
  2049. extern "C" void CLogoBase_Cleanup(void)
  2050. {
  2051. CLogoBase::_Cleanup();
  2052. }
  2053. void CLogoBase::_Initialize(void)
  2054. {
  2055. InitializeCriticalSection(&s_csSharedLogos);
  2056. }
  2057. void CLogoBase::_Cleanup(void)
  2058. {
  2059. DeleteCriticalSection(& s_csSharedLogos);
  2060. }
  2061. CLogoBase::CLogoBase(BOOL fWide)
  2062. {
  2063. // are we paletized, then use the global halftone palette ....
  2064. HDC hdcTmp = GetDC(NULL);
  2065. if (hdcTmp)
  2066. {
  2067. if (GetDeviceCaps(hdcTmp, RASTERCAPS) & RC_PALETTE)
  2068. {
  2069. // we're allocating in the constructor, but so what
  2070. // nobody calls this code anyway, i was going to delete it all but that bug got punted
  2071. _hpalHalftone = SHCreateShellPalette(NULL);
  2072. }
  2073. ReleaseDC(NULL, hdcTmp);
  2074. }
  2075. _fWide = fWide;
  2076. }
  2077. CLogoBase::~CLogoBase()
  2078. {
  2079. if (_pLogoCache || _pTaskScheduler)
  2080. {
  2081. ExitLogoView();
  2082. }
  2083. if (_hpalHalftone)
  2084. {
  2085. DeletePalette(_hpalHalftone);
  2086. }
  2087. }
  2088. HRESULT CLogoBase::AddRefLogoCache(void)
  2089. {
  2090. if (_fWide)
  2091. {
  2092. EnterCriticalSection(&s_csSharedLogos);
  2093. if (!s_lSharedWideLogosRef)
  2094. {
  2095. if (!s_hdsaWideLogoIndices)
  2096. {
  2097. s_hdsaWideLogoIndices = DSA_Create(sizeof(LogoIndex), 5);
  2098. if (!s_hdsaWideLogoIndices)
  2099. {
  2100. LeaveCriticalSection(&s_csSharedLogos);
  2101. return E_OUTOFMEMORY;
  2102. }
  2103. }
  2104. ASSERT(s_hdsaWideLogoIndices);
  2105. ASSERT(!s_pSharedWideLogoCache);
  2106. HRESULT hr = CoCreateInstance(CLSID_ImageListCache, NULL, CLSCTX_INPROC,
  2107. IID_PPV_ARG(IImageCache, &s_pSharedWideLogoCache));
  2108. if (FAILED(hr))
  2109. {
  2110. LeaveCriticalSection(&s_csSharedLogos);
  2111. return hr;
  2112. }
  2113. }
  2114. ASSERT(s_pSharedWideLogoCache);
  2115. // bump up the ref and get a pointer to it...
  2116. s_lSharedWideLogosRef ++;
  2117. _pLogoCache = s_pSharedWideLogoCache;
  2118. _pLogoCache->AddRef();
  2119. _hdsaLogoIndices = s_hdsaWideLogoIndices;
  2120. LeaveCriticalSection(&s_csSharedLogos);
  2121. return S_OK;
  2122. }
  2123. else
  2124. {
  2125. // non wide logo version we don't share because w eonly expect there ever to be one...
  2126. _hdsaLogoIndices = DSA_Create(sizeof(LogoIndex), 5);
  2127. if (!_hdsaLogoIndices)
  2128. {
  2129. return E_OUTOFMEMORY;
  2130. }
  2131. return CoCreateInstance(CLSID_ImageListCache, NULL, CLSCTX_INPROC, IID_PPV_ARG(IImageCache, &_pLogoCache));
  2132. }
  2133. }
  2134. HRESULT CLogoBase::ReleaseLogoCache(void)
  2135. {
  2136. if (!_pLogoCache)
  2137. {
  2138. return S_FALSE;
  2139. }
  2140. ATOMICRELEASE(_pLogoCache);
  2141. if (_fWide)
  2142. {
  2143. EnterCriticalSection(&s_csSharedLogos);
  2144. ASSERT(s_lSharedWideLogosRef > 0);
  2145. s_lSharedWideLogosRef --;
  2146. if (! s_lSharedWideLogosRef)
  2147. {
  2148. // let go of the final ref.....
  2149. ATOMICRELEASE(s_pSharedWideLogoCache);
  2150. ASSERT(s_hdsaWideLogoIndices);
  2151. DSA_Destroy(s_hdsaWideLogoIndices);
  2152. s_hdsaWideLogoIndices = NULL;
  2153. }
  2154. LeaveCriticalSection(&s_csSharedLogos);
  2155. }
  2156. else
  2157. {
  2158. // free the HDSA
  2159. DSA_Destroy(_hdsaLogoIndices);
  2160. }
  2161. return S_OK;
  2162. }
  2163. HRESULT CLogoBase::InitLogoView(void)
  2164. {
  2165. HRESULT hr = AddRefLogoCache();
  2166. if (SUCCEEDED(hr))
  2167. {
  2168. hr = CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC,
  2169. IID_PPV_ARG(IShellTaskScheduler, &_pTaskScheduler));
  2170. if (FAILED(hr))
  2171. {
  2172. ATOMICRELEASE(_pLogoCache);
  2173. }
  2174. else
  2175. {
  2176. _rgLogoSize.cx = (_fWide) ? LOGO_WIDE_WIDTH : LOGO_WIDTH ;
  2177. _rgLogoSize.cy = LOGO_HEIGHT;
  2178. IMAGECACHEINITINFO rgInfo;
  2179. rgInfo.cbSize = sizeof(rgInfo);
  2180. rgInfo.dwMask = ICIIFLAG_LARGE;
  2181. rgInfo.iStart = 0;
  2182. rgInfo.iGrow = 5;
  2183. // the color depth is currently the screen resolution...
  2184. int iColorRes = SHGetCurColorRes();
  2185. _dwClrDepth = (DWORD) iColorRes;
  2186. switch (iColorRes)
  2187. {
  2188. case 16 : rgInfo.dwFlags = ILC_COLOR16;
  2189. break;
  2190. case 24 :
  2191. case 32 : rgInfo.dwFlags = ILC_COLOR24;
  2192. break;
  2193. default : rgInfo.dwFlags = ILC_COLOR8;
  2194. }
  2195. rgInfo.rgSizeLarge = _rgLogoSize;
  2196. if (_pLogoCache)
  2197. hr = _pLogoCache->GetImageList(&rgInfo);
  2198. else
  2199. hr = E_UNEXPECTED;
  2200. if (FAILED(hr))
  2201. {
  2202. ATOMICRELEASE(_pLogoCache);
  2203. ATOMICRELEASE(_pTaskScheduler);
  2204. }
  2205. else
  2206. {
  2207. _himlLogos = rgInfo.himlLarge;
  2208. // GetImageList() will return S_FALSE if it was already created...
  2209. if ((hr == S_OK) && (iColorRes <= 8))
  2210. {
  2211. // init the color table so that it matches The "special halftone palette"
  2212. HPALETTE hpal = SHCreateShellPalette(NULL);
  2213. PALETTEENTRY rgColours[256];
  2214. RGBQUAD rgDIBColours[256];
  2215. ASSERT(hpal);
  2216. int nColours = GetPaletteEntries(hpal, 0, ARRAYSIZE(rgColours), rgColours);
  2217. // SHGetShellPalette should always return a 256 colour palette
  2218. ASSERT(nColours == ARRAYSIZE(rgColours));
  2219. // translate from the LOGPALETTE structure to the RGBQUAD structure ...
  2220. for (int iColour = 0; iColour < nColours; iColour ++)
  2221. {
  2222. rgDIBColours[iColour].rgbRed = rgColours[iColour].peRed;
  2223. rgDIBColours[iColour].rgbBlue = rgColours[iColour].peBlue;
  2224. rgDIBColours[iColour].rgbGreen = rgColours[iColour].peGreen;
  2225. rgDIBColours[iColour].rgbReserved = 0;
  2226. }
  2227. DeletePalette(hpal);
  2228. ImageList_SetColorTable(_himlLogos, 0, 256, rgDIBColours);
  2229. }
  2230. }
  2231. }
  2232. }
  2233. return hr;
  2234. }
  2235. HRESULT CLogoBase::ExitLogoView(void)
  2236. {
  2237. ATOMICRELEASE(_pTaskScheduler);
  2238. // the task scheduler callbacks can reference
  2239. // the logocache, so make sure you free the
  2240. // logo cache AFTER the task scheduler!
  2241. ReleaseLogoCache();
  2242. return S_OK;
  2243. }
  2244. int CLogoBase::GetCachedLogoIndex(DWORD dwItem, LPCITEMIDLIST pidl, IRunnableTask **ppTask, DWORD * pdwPriority, DWORD *pdwFlags)
  2245. {
  2246. DWORD dwPassedFlags = 0;
  2247. if (pdwFlags)
  2248. {
  2249. dwPassedFlags = *pdwFlags;
  2250. *pdwFlags = 0;
  2251. }
  2252. // No logo cache?
  2253. if (!_pLogoCache)
  2254. return 0;
  2255. ASSERT(pidl);
  2256. // HACK: this is used on browser only mode to tell what sort of logos we need...
  2257. IExtractImage *pImage = NULL;
  2258. int iImage = -1;
  2259. HRESULT hr = E_FAIL;
  2260. // IID_IEXtractLogo and IID_IExtractImage are the same interface, by using a new guid
  2261. // it means we can selectively decided what can logo in logo view...
  2262. hr = GetSF()->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IExtractImage, NULL, &pImage));
  2263. if (SUCCEEDED(hr))
  2264. {
  2265. // extract ....
  2266. HBITMAP hImage;
  2267. WCHAR szPath[MAX_PATH];
  2268. DWORD dwFlags = IEIFLAG_ASYNC | IEIFLAG_ASPECT | dwPassedFlags;
  2269. IMAGECACHEINFO rgInfo;
  2270. UINT uIndex;
  2271. BOOL fAsync;
  2272. DWORD dwPriority;
  2273. rgInfo.cbSize = sizeof(rgInfo);
  2274. hr = pImage->GetLocation(szPath, MAX_PATH, &dwPriority, &_rgLogoSize, _dwClrDepth, &dwFlags);
  2275. fAsync = (hr == E_PENDING);
  2276. if (SUCCEEDED(hr) || fAsync)
  2277. {
  2278. // mask off the flags passed to use by the flags returned from the extractor...
  2279. if (pdwFlags)
  2280. *pdwFlags = dwPassedFlags & dwFlags;
  2281. rgInfo.dwMask = ICIFLAG_NAME;
  2282. rgInfo.pszName = szPath;
  2283. hr = _pLogoCache->FindImage(&rgInfo, &uIndex);
  2284. if (hr == S_OK)
  2285. {
  2286. ATOMICRELEASE(pImage);
  2287. return (int) uIndex;
  2288. }
  2289. if (fAsync)
  2290. {
  2291. IRunnableTask *pTaskTmp = NULL;
  2292. ASSERT(_pTaskScheduler);
  2293. // pass the icon index so we can find the right logo later...
  2294. int iIcon = SHMapPIDLToSystemImageListIndex(GetSF(), pidl, NULL);
  2295. hr = CLogoExtractImageTask_Create(this,
  2296. pImage,
  2297. szPath,
  2298. dwItem,
  2299. iIcon,
  2300. 0,
  2301. &pTaskTmp);
  2302. if (SUCCEEDED(hr))
  2303. {
  2304. if (!ppTask)
  2305. {
  2306. hr = AddTaskToQueue(pTaskTmp, dwPriority, dwItem);
  2307. pTaskTmp->Release();
  2308. }
  2309. else
  2310. {
  2311. * ppTask = pTaskTmp;
  2312. ASSERT(pdwPriority);
  2313. *pdwPriority = dwPriority;
  2314. }
  2315. }
  2316. else if (ppTask)
  2317. {
  2318. *ppTask = NULL;
  2319. }
  2320. // if all this failed, then we will just end up with a default
  2321. // logo. This is only likely to fail in low memory conditions,
  2322. // so that will be fine.
  2323. // if this SUCCEEDED we will drop through to pick up a defualt piccy for now.
  2324. }
  2325. else
  2326. {
  2327. // otherwise extract synchronously.......
  2328. hr = pImage->Extract(&hImage);
  2329. if (SUCCEEDED(hr))
  2330. {
  2331. rgInfo.dwMask = ICIFLAG_NAME | ICIFLAG_LARGE | ICIFLAG_BITMAP | ICIFLAG_NOUSAGE;
  2332. rgInfo.hBitmapLarge = hImage;
  2333. hr = _pLogoCache->AddImage(&rgInfo, &uIndex);
  2334. DeleteObject(hImage);
  2335. }
  2336. if (SUCCEEDED(hr))
  2337. {
  2338. iImage = (int) uIndex;
  2339. }
  2340. }
  2341. }
  2342. }
  2343. ATOMICRELEASE(pImage);
  2344. return iImage;
  2345. }
  2346. int CLogoBase::GetLogoIndex(DWORD dwItem, LPCITEMIDLIST pidl, IRunnableTask **ppTask, DWORD * pdwPriority, DWORD *pdwFlags)
  2347. {
  2348. int iImage = GetCachedLogoIndex(dwItem, pidl, ppTask, pdwPriority, pdwFlags);
  2349. if (iImage == -1)
  2350. {
  2351. // always pass FALSE, we want the proper ICON, cdfview no longer hits the
  2352. // wire for the icon so we can safely ask for the correct icon.
  2353. iImage = GetDefaultLogo(pidl, FALSE);
  2354. }
  2355. return iImage;
  2356. }
  2357. HRESULT CLogoBase::AddTaskToQueue(IRunnableTask *pTask, DWORD dwPriority, DWORD dwItem)
  2358. {
  2359. ASSERT(_pTaskScheduler);
  2360. return _pTaskScheduler->AddTask(pTask, GetTOID(), dwItem, dwPriority);
  2361. }
  2362. int CLogoBase::GetDefaultLogo(LPCITEMIDLIST pidl, BOOL fQuick)
  2363. {
  2364. USES_CONVERSION;
  2365. // Get icon to draw from
  2366. int iIndex = -1;
  2367. if (!fQuick)
  2368. {
  2369. iIndex = SHMapPIDLToSystemImageListIndex(GetSF(), pidl, NULL);
  2370. }
  2371. if (iIndex < 0)
  2372. {
  2373. iIndex = II_DOCNOASSOC;
  2374. }
  2375. WCHAR wszText[MAX_PATH];
  2376. wszText[0] = 0;
  2377. STRRET strret;
  2378. HRESULT hr = GetSF()->GetDisplayNameOf(pidl, SHGDN_NORMAL, &strret);
  2379. if (SUCCEEDED(hr))
  2380. {
  2381. StrRetToBufW(&strret, pidl, wszText, ARRAYSIZE(wszText));
  2382. }
  2383. UINT uCacheIndex = (UINT) -1;
  2384. if (_pLogoCache) // We didn't have one in stress.
  2385. {
  2386. IMAGECACHEINFO rgInfo;
  2387. rgInfo.cbSize = sizeof(rgInfo);
  2388. rgInfo.dwMask = ICIFLAG_NAME | ICIFLAG_INDEX;
  2389. rgInfo.pszName = wszText;
  2390. rgInfo.iIndex = iIndex;
  2391. hr = _pLogoCache->FindImage(&rgInfo, &uCacheIndex);
  2392. if (hr == S_OK)
  2393. {
  2394. return uCacheIndex;
  2395. }
  2396. HBITMAP hDef;
  2397. hr = CreateDefaultLogo(iIndex, _rgLogoSize.cx, _rgLogoSize.cy, W2T(wszText), &hDef);
  2398. if (SUCCEEDED(hr))
  2399. {
  2400. rgInfo.hBitmapLarge = hDef;
  2401. rgInfo.hMaskLarge = NULL;
  2402. rgInfo.dwMask = ICIFLAG_NAME | ICIFLAG_INDEX | ICIFLAG_BITMAP | ICIFLAG_LARGE;
  2403. hr = _pLogoCache->AddImage(&rgInfo, &uCacheIndex);
  2404. if (FAILED(hr))
  2405. {
  2406. uCacheIndex = (UINT) -1;
  2407. }
  2408. else
  2409. {
  2410. // remember the index of the logo
  2411. AddIndicesToLogoList(iIndex, uCacheIndex);
  2412. }
  2413. DeleteObject(hDef);
  2414. }
  2415. }
  2416. return (int) uCacheIndex;
  2417. }
  2418. #define DXFUDGE 4
  2419. #define COLORTEXT RGB(255,255,255)
  2420. #define COLORBK RGB(0,0,0)
  2421. HRESULT CLogoBase::CreateDefaultLogo(int iIcon, int cxLogo, int cyLogo, LPCTSTR pszText, HBITMAP * phBmpLogo)
  2422. {
  2423. HRESULT hr = E_OUTOFMEMORY;
  2424. HBITMAP hbmp = NULL;
  2425. HIMAGELIST himl;
  2426. int cxIcon, cyIcon;
  2427. int x, y, dx, dy;
  2428. // get the small icons....
  2429. Shell_GetImageLists(NULL, &himl);
  2430. ImageList_GetIconSize(himl, &cxIcon, &cyIcon);
  2431. // Calculate position info. We assume logos are wider than they are tall.
  2432. ASSERT(cxLogo >= cyLogo);
  2433. // Put the icon on the left
  2434. x = 2;
  2435. // Center the icon vertically
  2436. if (cyIcon <= cyLogo)
  2437. {
  2438. y = (cyLogo - cyIcon) / 2;
  2439. dy = cyIcon;
  2440. dx = cxIcon;
  2441. }
  2442. else
  2443. {
  2444. y = 0;
  2445. dy = cyLogo;
  2446. // keep shrinkage proportional
  2447. dx = MulDiv(cxIcon, cyIcon, cyLogo);
  2448. }
  2449. // get ready to draw
  2450. HDC hTBDC = GetDC(GetHWND());
  2451. if (!hTBDC)
  2452. {
  2453. return E_FAIL;
  2454. }
  2455. HDC hdc = CreateCompatibleDC(hTBDC);
  2456. if (hdc)
  2457. {
  2458. RECT rc;
  2459. int dx, dy, x, y;
  2460. SIZE size;
  2461. hbmp = CreateCompatibleBitmap(hTBDC, cxLogo, cyLogo);
  2462. if (hbmp)
  2463. {
  2464. HGDIOBJ hTmp = SelectObject(hdc, hbmp);
  2465. HPALETTE hpalOld;
  2466. HFONT hfont, hfontOld;
  2467. if (_hpalHalftone)
  2468. {
  2469. hpalOld = SelectPalette(hdc, _hpalHalftone, TRUE);
  2470. // LINTASSERT(hpalOld || !hpalOld); // 0 semi-ok for SelectPalette
  2471. RealizePalette(hdc);
  2472. }
  2473. SetMapMode(hdc, MM_TEXT);
  2474. rc.left = rc.top = 0;
  2475. rc.bottom = cyLogo;
  2476. rc.right = cxLogo;
  2477. SHFillRectClr(hdc, &rc, COLORBK);
  2478. // draw the icon into the memory DC.
  2479. ImageList_GetIconSize(himl, &dx, &dy);
  2480. x = DXFUDGE;
  2481. y = ((cyLogo- dy) >> 1);
  2482. ImageList_Draw(himl, iIcon, hdc, x, y, ILD_TRANSPARENT);
  2483. hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  2484. hfontOld = hfont ? (HFONT)SelectObject(hdc, hfont) : NULL;
  2485. GetTextExtentPoint32(hdc, pszText, lstrlen(pszText), &size);
  2486. x += (dx + DXFUDGE);
  2487. y = ((cyLogo- size.cy) >> 1);
  2488. rc.left = x;
  2489. UINT eto = ETO_CLIPPED;
  2490. SetTextColor(hdc, COLORTEXT);
  2491. SetBkMode(hdc, TRANSPARENT);
  2492. ExtTextOut(hdc, x, y, eto, &rc
  2493. , pszText, lstrlen(pszText), NULL);
  2494. if (hfontOld)
  2495. SelectObject(hdc, hfontOld);
  2496. if (hfont)
  2497. DeleteObject(hfont);
  2498. if (_hpalHalftone)
  2499. {
  2500. (void) SelectPalette(hdc, hpalOld, TRUE);
  2501. RealizePalette(hdc);
  2502. }
  2503. // remove the final bitmap
  2504. SelectObject(hdc, hTmp);
  2505. hr = S_OK;
  2506. if (FAILED(hr))
  2507. {
  2508. DeleteObject(hbmp);
  2509. hbmp = NULL;
  2510. }
  2511. }
  2512. DeleteDC(hdc);
  2513. }
  2514. ReleaseDC(GetHWND(), hTBDC);
  2515. *phBmpLogo = hbmp;
  2516. return hr;
  2517. }
  2518. HRESULT CLogoBase::FlushLogoCache()
  2519. {
  2520. HRESULT hr = E_UNEXPECTED;
  2521. if (_pLogoCache)
  2522. {
  2523. // forcibly clear out the logo cache so the items get refetched ...
  2524. _pLogoCache->Flush(TRUE);
  2525. hr = S_OK;
  2526. }
  2527. return hr;
  2528. }
  2529. HRESULT CLogoBase::DitherBitmap(HBITMAP hBmp, HBITMAP * phBmpNew)
  2530. {
  2531. ASSERT(FALSE);
  2532. return E_NOTIMPL;
  2533. }
  2534. int CLogoBase::AddIndicesToLogoList(int iIcon, UINT uIndex)
  2535. {
  2536. int iRet = -1;
  2537. LogoIndex * pIndex;
  2538. LogoIndex rgNew;
  2539. rgNew.iIcon = iIcon;
  2540. rgNew.iLogo = (int) uIndex;
  2541. if (_fWide)
  2542. {
  2543. EnterCriticalSection(&s_csSharedLogos);
  2544. }
  2545. // scan to see if we have an extact match already in there...
  2546. for (int n = 0; n < DSA_GetItemCount(_hdsaLogoIndices); n ++)
  2547. {
  2548. pIndex = (LogoIndex *) DSA_GetItemPtr(_hdsaLogoIndices, n);
  2549. ASSERT(pIndex);
  2550. if (pIndex->iLogo == (int) uIndex)
  2551. {
  2552. // set the icon just incase it changed...
  2553. pIndex->iIcon = iIcon;
  2554. iRet = n;
  2555. break;
  2556. }
  2557. }
  2558. if (iRet == -1)
  2559. {
  2560. iRet = DSA_AppendItem(_hdsaLogoIndices, &rgNew);
  2561. }
  2562. if (_fWide)
  2563. {
  2564. LeaveCriticalSection(&s_csSharedLogos);
  2565. }
  2566. return iRet;
  2567. }
  2568. int CLogoBase::FindLogoFromIcon(int iIcon, int * piLastLogo)
  2569. {
  2570. int iRet = -1;
  2571. if (!piLastLogo)
  2572. {
  2573. return -1;
  2574. }
  2575. LogoIndex * pIndex;
  2576. if (_fWide)
  2577. {
  2578. EnterCriticalSection(&s_csSharedLogos);
  2579. }
  2580. for (int n = *piLastLogo + 1; n < DSA_GetItemCount(_hdsaLogoIndices); n ++)
  2581. {
  2582. pIndex = (LogoIndex *) DSA_GetItemPtr(_hdsaLogoIndices, n);
  2583. ASSERT(pIndex);
  2584. if (pIndex->iIcon == iIcon)
  2585. {
  2586. *piLastLogo = n;
  2587. iRet = pIndex->iLogo;
  2588. break;
  2589. }
  2590. }
  2591. if (_fWide)
  2592. {
  2593. LeaveCriticalSection(&s_csSharedLogos);
  2594. }
  2595. return iRet;
  2596. }