Leaked source code of windows server 2003
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.

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