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.

878 lines
23 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "bands.h"
  4. #include "bsmenu.h"
  5. #include "isfband.h"
  6. #include "legacy.h"
  7. #include "resource.h"
  8. #include "uemapp.h"
  9. #include "enumband.h"
  10. #include "mluisupp.h"
  11. static const CLSID g_clsidNull = {0};
  12. #define DPA_SafeGetPtrCount(hdpa) (hdpa ? DPA_GetPtrCount(hdpa) : 0)
  13. HRESULT CBandSiteMenu_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  14. {
  15. // aggregation checking is handled in class factory
  16. CBandSiteMenu *p = new CBandSiteMenu();
  17. if (p)
  18. {
  19. *ppunk = SAFECAST(p, IShellService*);
  20. return S_OK;
  21. }
  22. return E_OUTOFMEMORY;
  23. }
  24. CBandSiteMenu::CBandSiteMenu() : _cRef(1)
  25. {
  26. DllAddRef();
  27. }
  28. CBandSiteMenu::~CBandSiteMenu()
  29. {
  30. DPA_DestroyCallback(_hdpaBandClasses, _DPA_FreeBandClassInfo, 0);
  31. _hdpaBandClasses = NULL;
  32. SetOwner(NULL);
  33. DllRelease();
  34. }
  35. int CBandSiteMenu::_DPA_FreeBandClassInfo(LPVOID p, LPVOID d)
  36. {
  37. BANDCLASSINFO *pbci = (BANDCLASSINFO*)p;
  38. // req'd
  39. ASSERT(pbci->pszName || (*(int *)&pbci->clsid == 0));
  40. if (pbci->pszName)
  41. LocalFree(pbci->pszName);
  42. // optional
  43. if (pbci->pszIcon != NULL)
  44. LocalFree(pbci->pszIcon);
  45. if (pbci->pszMenu != NULL)
  46. LocalFree(pbci->pszMenu);
  47. if (pbci->pszHelp != NULL)
  48. LocalFree(pbci->pszHelp);
  49. if (pbci->pszMenuPUI != NULL)
  50. LocalFree(pbci->pszMenuPUI);
  51. if (pbci->pszHelpPUI != NULL)
  52. LocalFree(pbci->pszHelpPUI);
  53. LocalFree(pbci);
  54. return 1;
  55. }
  56. ULONG CBandSiteMenu::AddRef()
  57. {
  58. _cRef++;
  59. return _cRef;
  60. }
  61. ULONG CBandSiteMenu::Release()
  62. {
  63. ASSERT(_cRef > 0);
  64. _cRef--;
  65. if (_cRef > 0)
  66. return _cRef;
  67. delete this;
  68. return 0;
  69. }
  70. HRESULT CBandSiteMenu::SetOwner(IUnknown* punk)
  71. {
  72. ATOMICRELEASE(_pbs);
  73. if (punk)
  74. {
  75. punk->QueryInterface(IID_IBandSite, (LPVOID*)&_pbs);
  76. }
  77. return S_OK;
  78. }
  79. HRESULT CBandSiteMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
  80. {
  81. return HandleMenuMsg2(uMsg, wParam, lParam, NULL);
  82. }
  83. UINT CBandSiteMenu::_IDToInternal(UINT uID)
  84. {
  85. if (uID != -1)
  86. {
  87. uID -= _idCmdFirst;
  88. }
  89. return uID;
  90. }
  91. UINT CBandSiteMenu::_IDToExternal(UINT uID)
  92. {
  93. if (uID != -1)
  94. {
  95. uID += _idCmdFirst;
  96. }
  97. return uID;
  98. }
  99. LRESULT CBandSiteMenu::_OnInitMenuPopup(HMENU hmenu, UINT uPos)
  100. {
  101. //
  102. // Is this is the "Toolbars >" submenu (which we populate
  103. // lazily), and has it not yet been populated?
  104. //
  105. UINT uID = GetMenuItemID(hmenu, 0);
  106. uID = _IDToInternal(uID);
  107. if (uID == DBIDM_DESKTOPBAND)
  108. {
  109. // Yes
  110. _PopulateSubmenu(hmenu);
  111. }
  112. return 0;
  113. }
  114. HRESULT CBandSiteMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  115. {
  116. LRESULT lres = 0;
  117. switch (uMsg)
  118. {
  119. case WM_INITMENUPOPUP:
  120. lres = _OnInitMenuPopup((HMENU)wParam, LOWORD(lParam));
  121. break;
  122. }
  123. if (plres)
  124. *plres = lres;
  125. return S_OK;
  126. }
  127. HRESULT CBandSiteMenu::QueryInterface(REFIID riid, LPVOID * ppvObj)
  128. {
  129. static const QITAB qit[] =
  130. {
  131. QITABENT(CBandSiteMenu, IContextMenu3),
  132. QITABENTMULTI(CBandSiteMenu, IContextMenu2, IContextMenu3),
  133. QITABENTMULTI(CBandSiteMenu, IContextMenu, IContextMenu3),
  134. QITABENT(CBandSiteMenu, IShellService),
  135. { 0 },
  136. };
  137. HRESULT hres = QISearch(this, qit, riid, ppvObj);
  138. if (FAILED(hres))
  139. {
  140. if (IsEqualIID(riid, CLSID_BandSiteMenu))
  141. {
  142. *ppvObj = (void *) this;
  143. AddRef();
  144. return S_OK;
  145. }
  146. }
  147. return hres;
  148. }
  149. #define MAX_BANDS 50
  150. void CBandSiteMenu::_PopulateSubmenu(HMENU hmenuSub)
  151. {
  152. // the start id is the last of the fixed bands.
  153. // when we do the Shell_MergeMenus below, it will be incremented by idCmdFirst
  154. ASSERT(hmenuSub);
  155. CATID catid = CATID_DeskBand;
  156. if (_hdpaBandClasses)
  157. {
  158. DPA_DestroyCallback(_hdpaBandClasses, _DPA_FreeBandClassInfo, 0);
  159. _hdpaBandClasses = NULL;
  160. }
  161. LoadFromComCat(&catid);
  162. // Kick off an asynchronous update of the comcat cache
  163. SHWriteClassesOfCategories(1, &catid, 0, NULL, TRUE, FALSE, NULL);
  164. _idCmdEnumFirst = CreateMergeMenu(hmenuSub, MAX_BANDS, 0, _IDToExternal(DBIDM_NEWBANDFIXEDLAST), 0, FALSE);
  165. _AddEnumMenu(hmenuSub, GetMenuItemCount(hmenuSub) - 2); // -2 to go before "New Toolbar" and separator
  166. int iIndex = GetMenuItemCount(hmenuSub);
  167. if (SHRestricted(REST_NOCLOSE_DRAGDROPBAND) || SHRestricted(REST_CLASSICSHELL))
  168. {
  169. // We also need to disable turning On or Off the Bands.
  170. // In classic mode, don't allow them either.
  171. int nIter;
  172. for (nIter = 0; nIter < iIndex; nIter++)
  173. EnableMenuItem(hmenuSub, nIter, MF_BYPOSITION | MF_GRAYED);
  174. }
  175. if (SHRestricted(REST_CLASSICSHELL))
  176. {
  177. // Disable New Toolbar menu also.
  178. EnableMenuItem(hmenuSub, DBIDM_NEWFOLDERBAND, MF_BYCOMMAND | MF_GRAYED);
  179. }
  180. }
  181. HRESULT CBandSiteMenu::QueryContextMenu(HMENU hmenu,
  182. UINT indexMenu,
  183. UINT idCmdFirst,
  184. UINT idCmdLast,
  185. UINT uFlags)
  186. {
  187. if (!_pbs)
  188. return E_FAIL;
  189. if (SHRestricted(REST_NOTOOLBARSONTASKBAR))
  190. {
  191. return E_FAIL;
  192. }
  193. HMENU hmenuSrc = LoadMenuPopup_PrivateNoMungeW(MENU_DESKBARAPP);
  194. if (hmenuSrc)
  195. {
  196. _idCmdFirst = idCmdFirst;
  197. Shell_MergeMenus(hmenu, hmenuSrc, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
  198. DestroyMenu(hmenuSrc);
  199. if (_SHIsMenuSeparator(hmenu, indexMenu))
  200. {
  201. //
  202. // Adjust indexMenu to point to the spot where the Toolbars
  203. // submenu was actually inserted.
  204. //
  205. indexMenu++;
  206. }
  207. if (!(uFlags & CMF_ICM3))
  208. {
  209. //
  210. // Caller doesn't speak ICM3, so won't give us a chance to
  211. // populate submenu on WM_INITMENUPOPUP. Thus we need to
  212. // populate it now.
  213. //
  214. HMENU hmenuSub = GetSubMenu(hmenu, indexMenu);
  215. if (hmenuSub)
  216. _PopulateSubmenu(hmenuSub);
  217. }
  218. #ifdef DEBUG
  219. else
  220. {
  221. //
  222. // _OnInitMenuPopup assumes DBIDM_DESKTOPBAND is the first item
  223. // in the "Toolbars >" submenu. If that assumption breaks (and
  224. // you see this ASSERT rip), be sure to fix up the code there.
  225. //
  226. HMENU hmenuSub = GetSubMenu(hmenu, indexMenu);
  227. ASSERT(GetMenuItemID(hmenuSub, 0) == _IDToExternal(DBIDM_DESKTOPBAND));
  228. }
  229. #endif
  230. //
  231. // Assert that our caller gave us enough room to accomodate
  232. // the worst-case count.
  233. //
  234. ASSERT((idCmdFirst + DBIDM_NEWBANDFIXEDLAST + MAX_BANDS) < idCmdLast);
  235. return idCmdFirst + DBIDM_NEWBANDFIXEDLAST + MAX_BANDS;
  236. }
  237. return E_FAIL;
  238. }
  239. BOOL CBandSiteMenu::_CheckUnique(IDeskBand* pdb, HMENU hmenu)
  240. {
  241. // check to see if this band is unique. (not already added by comcat list or
  242. // hard coded list
  243. // if it is unique, return TRUE.
  244. // if it's not, check the other menu item
  245. CLSID clsid;
  246. DWORD dwPrivID;
  247. BOOL fRet = TRUE;
  248. UINT idCmd = (UINT)-1;
  249. if (SUCCEEDED(_GetBandIdentifiers(pdb, &clsid, &dwPrivID)))
  250. {
  251. // check the comcat list
  252. if (dwPrivID == (DWORD)-1)
  253. {
  254. for (int i = 0; i < DPA_SafeGetPtrCount(_hdpaBandClasses) ; i++)
  255. {
  256. BANDCLASSINFO *pbci = (BANDCLASSINFO*)DPA_GetPtr(_hdpaBandClasses, i);
  257. if (IsEqualGUID(clsid, pbci->clsid))
  258. {
  259. idCmd = i + DBIDM_NEWBANDFIXEDLAST;
  260. goto FoundIt;
  261. }
  262. }
  263. }
  264. else if (IsEqualGUID(clsid, CLSID_ISFBand))
  265. {
  266. // check our hardcoded list
  267. switch (dwPrivID)
  268. {
  269. case CSIDL_DESKTOP:
  270. idCmd = DBIDM_DESKTOPBAND;
  271. break;
  272. case CSIDL_APPDATA:
  273. idCmd = DBIDM_LAUNCHBAND;
  274. break;
  275. }
  276. }
  277. }
  278. FoundIt:
  279. if (idCmd != (UINT)-1)
  280. {
  281. // we found a menu for this already.... if it wasn't already checked,
  282. // check it now and it will represent us
  283. if (!(GetMenuState(hmenu, _IDToExternal(idCmd), MF_BYCOMMAND) & MF_CHECKED))
  284. {
  285. CheckMenuItem(hmenu, _IDToExternal(idCmd), MF_BYCOMMAND | MF_CHECKED);
  286. fRet = FALSE;
  287. }
  288. }
  289. return fRet;
  290. }
  291. void CBandSiteMenu::_AddEnumMenu(HMENU hmenu, int iInsert)
  292. {
  293. DWORD dwID;
  294. int iMax = MAX_BANDS - (_IDToInternal(_idCmdEnumFirst) - DBIDM_NEWBANDFIXEDLAST);
  295. for (int i = 0; i < iMax && SUCCEEDED(_pbs->EnumBands(i, &dwID)); i++)
  296. {
  297. HRESULT hr;
  298. WCHAR szName[80];
  299. DWORD dwFlags = MF_BYPOSITION;
  300. DWORD dwState;
  301. IDeskBand *pdb;
  302. hr = _pbs->QueryBand(dwID, &pdb, &dwState, szName, ARRAYSIZE(szName));
  303. if (EVAL(SUCCEEDED(hr)))
  304. {
  305. if (_CheckUnique(pdb, hmenu))
  306. {
  307. if (dwState & BSSF_VISIBLE)
  308. dwFlags |= MF_CHECKED;
  309. if (!(dwState & BSSF_UNDELETEABLE))
  310. {
  311. InsertMenu(hmenu, iInsert, dwFlags, _idCmdEnumFirst + i, szName);
  312. iInsert++;
  313. }
  314. }
  315. }
  316. if (pdb)
  317. pdb->Release();
  318. }
  319. }
  320. HRESULT CBandSiteMenu::_GetBandIdentifiers(IUnknown *punk, CLSID* pclsid, DWORD* pdwPrivID)
  321. {
  322. HRESULT hr = E_FAIL;
  323. IPersist* pp;
  324. if (SUCCEEDED(punk->QueryInterface(IID_IPersist, (LPVOID*)&pp)))
  325. {
  326. pp->GetClassID(pclsid);
  327. VARIANTARG v = {0};
  328. *pdwPrivID = (DWORD) -1;
  329. if (SUCCEEDED(IUnknown_Exec(punk, &CGID_ISFBand, ISFBID_PRIVATEID, 0, NULL, &v)))
  330. {
  331. if (v.vt == VT_I4)
  332. {
  333. *pdwPrivID = (DWORD)v.lVal;
  334. }
  335. }
  336. hr = S_OK;
  337. pp->Release();
  338. }
  339. return hr;
  340. }
  341. // we use IPersist to find the class id of bands.
  342. // we have a few special case bands (such as Quick Launch and Desktop) that are
  343. // the same band, but pointing to different objects.
  344. HRESULT CBandSiteMenu::_FindBand(const CLSID* pclsid, DWORD dwPrivID, DWORD* pdwBandID)
  345. {
  346. int i = 0;
  347. BOOL fFound = FALSE;
  348. HRESULT hr = E_FAIL;
  349. DWORD dwBandID = -1;
  350. while (hr == E_FAIL && SUCCEEDED(_pbs->EnumBands(i, &dwBandID)))
  351. {
  352. IDeskBand* pdb;
  353. if (SUCCEEDED(_pbs->QueryBand(dwBandID, &pdb, NULL, NULL, 0)))
  354. {
  355. CLSID clsid;
  356. DWORD dwPrivData;
  357. if (SUCCEEDED(_GetBandIdentifiers(pdb, &clsid, &dwPrivData)))
  358. {
  359. // special case for differentiating between all of the isfbands
  360. // find out if the private id this holds is the same as what we're asking for
  361. if (IsEqualIID(clsid, *pclsid) && (dwPrivData == dwPrivID))
  362. {
  363. hr = S_OK;
  364. }
  365. }
  366. pdb->Release();
  367. }
  368. i++;
  369. }
  370. if (pdwBandID)
  371. *pdwBandID = dwBandID;
  372. return hr;
  373. }
  374. HRESULT CBandSiteMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  375. {
  376. int idCmd;
  377. if (!_pbs)
  378. return E_FAIL;
  379. if (!HIWORD(pici->lpVerb))
  380. idCmd = LOWORD(pici->lpVerb);
  381. else
  382. return E_FAIL;
  383. //
  384. // N.B.: Caller has mapped idCmd to internal for us
  385. //
  386. int idCmdEnumFirstInt = _IDToInternal(_idCmdEnumFirst);
  387. if (idCmd >= idCmdEnumFirstInt)
  388. {
  389. // these are the bands that they're turning on and off
  390. DWORD dwID;
  391. if (SUCCEEDED(_pbs->EnumBands(idCmd - idCmdEnumFirstInt, &dwID)))
  392. {
  393. _pbs->RemoveBand(dwID);
  394. }
  395. }
  396. else
  397. {
  398. // these are our merged menus from MENU_DESKBARAPP
  399. switch (idCmd)
  400. {
  401. case DBIDM_NEWFOLDERBAND:
  402. _BrowseForNewFolderBand();
  403. break;
  404. case DBIDM_DESKTOPBAND:
  405. _ToggleSpecialFolderBand(CSIDL_DESKTOP, NULL, FALSE);
  406. break;
  407. case DBIDM_LAUNCHBAND:
  408. {
  409. TCHAR szSubDir[MAX_PATH];
  410. MLLoadString(IDS_QLAUNCHAPPDATAPATH, szSubDir, ARRAYSIZE(szSubDir));
  411. // Microsoft\\Internet Explorer\\Quick Launch
  412. _ToggleSpecialFolderBand(CSIDL_APPDATA, szSubDir, TRUE);
  413. break;
  414. }
  415. default:
  416. ASSERT(idCmd >= DBIDM_NEWBANDFIXEDLAST);
  417. _ToggleComcatBand(idCmd - DBIDM_NEWBANDFIXEDLAST);
  418. break;
  419. }
  420. }
  421. return S_OK;
  422. }
  423. HRESULT CBandSiteMenu::_BandClassEnum(REFCATID rcatid, REFCLSID rclsid, LPARAM lParam)
  424. {
  425. TCHAR szName[128],
  426. szRegName[128],
  427. szClass[GUIDSTR_MAX];
  428. DWORD cbName;
  429. HDPA hdpa = (HDPA)lParam;
  430. ASSERT(NULL != hdpa);
  431. // IE4 introduced this band, suppress it since we cut support for it in IE6
  432. if (IsEqualCLSID(CLSID_ChannelBand, rclsid))
  433. {
  434. return S_OK;
  435. }
  436. BANDCLASSINFO *pbci = (BANDCLASSINFO*)LocalAlloc(LPTR, sizeof(*pbci));
  437. if (NULL == pbci)
  438. {
  439. return E_OUTOFMEMORY;
  440. }
  441. pbci->clsid = rclsid;
  442. pbci->catid = rcatid;
  443. // now that we have the clsid,
  444. // look in the registry for the display name
  445. SHStringFromGUID(pbci->clsid, szClass, ARRAYSIZE(szClass));
  446. wnsprintf(szRegName, ARRAYSIZE(szRegName), TEXT("CLSID\\%s"), szClass);
  447. cbName = ARRAYSIZE(szName);
  448. if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, szRegName, NULL, NULL, szName, &cbName))
  449. {
  450. HKEY hkey;
  451. pbci->pszName = StrDup(szName);
  452. if (NULL == pbci->pszName)
  453. {
  454. return E_OUTOFMEMORY;
  455. }
  456. if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, szRegName, &hkey))
  457. {
  458. const struct regstrs rstab[] =
  459. {
  460. { TEXT("DefaultIcon"), FIELD_OFFSET(BANDCLASSINFO, pszIcon) },
  461. { TEXT("MenuText") , FIELD_OFFSET(BANDCLASSINFO, pszMenu) },
  462. { TEXT("HelpText") , FIELD_OFFSET(BANDCLASSINFO, pszHelp) },
  463. { TEXT("MenuTextPUI"), FIELD_OFFSET(BANDCLASSINFO, pszMenuPUI) },
  464. { TEXT("HelpTextPUI"), FIELD_OFFSET(BANDCLASSINFO, pszHelpPUI) },
  465. { 0, 0 },
  466. };
  467. // szBuf big enough for "path,-32767" or for status text
  468. TCHAR szBuf[MAX_PATH+7];
  469. Reg_GetStrs(hkey, rstab, szBuf, (int)ARRAYSIZE(szBuf), (LPVOID)pbci);
  470. RegCloseKey(hkey);
  471. }
  472. DPA_AppendPtr(hdpa, pbci);
  473. }
  474. return S_OK;
  475. }
  476. //***
  477. // Collect band class info from registry...
  478. int CBandSiteMenu::LoadFromComCat(const CATID *pcatid )
  479. {
  480. if (NULL == _hdpaBandClasses)
  481. {
  482. _hdpaBandClasses = DPA_Create(4);
  483. }
  484. if (NULL != _hdpaBandClasses && NULL != pcatid)
  485. {
  486. SHEnumClassesImplementingCATID(*pcatid, CBandSiteMenu::_BandClassEnum, (LPARAM)_hdpaBandClasses);
  487. }
  488. return DPA_SafeGetPtrCount(_hdpaBandClasses);
  489. }
  490. int CBandSiteMenu::CreateMergeMenu(HMENU hmenu, UINT cMax, UINT iPosition, UINT idCmdFirst, UINT iStart, BOOL fMungeAllowed)
  491. {
  492. int j = 0;
  493. int iMax = DPA_SafeGetPtrCount(_hdpaBandClasses);
  494. for (int i = iStart; i < iMax; i++)
  495. {
  496. if ((UINT)j >= cMax)
  497. {
  498. TraceMsg(DM_WARNING, "cbsm.cmm: cMax=%u menu overflow, truncated", cMax);
  499. break;
  500. }
  501. BANDCLASSINFO *pbci = (BANDCLASSINFO*)DPA_GetPtr(_hdpaBandClasses, i);
  502. DWORD dwFlags = IsEqualCLSID(g_clsidNull,pbci->clsid) ? MF_BYPOSITION|MF_SEPARATOR : MF_BYPOSITION;
  503. LPTSTR pszMenuText = pbci->pszMenuPUI ? pbci->pszMenuPUI : (pbci->pszMenu ? pbci->pszMenu : pbci->pszName) ;
  504. if (pszMenuText && *pszMenuText)
  505. {
  506. BOOL fInsert;
  507. if (fMungeAllowed)
  508. {
  509. fInsert = InsertMenu(hmenu, iPosition + j, dwFlags, idCmdFirst + j, pszMenuText);
  510. }
  511. else
  512. {
  513. fInsert = InsertMenu_PrivateNoMungeW(hmenu, iPosition + j, dwFlags, idCmdFirst + j, pszMenuText);
  514. }
  515. if (fInsert)
  516. {
  517. // update menuitem cmd ID:
  518. pbci->idCmd = idCmdFirst + j;
  519. j++;
  520. }
  521. }
  522. }
  523. return j + idCmdFirst;
  524. }
  525. BANDCLASSINFO * CBandSiteMenu::GetBandClassDataStruct(UINT uBand)
  526. {
  527. BANDCLASSINFO * pbci = (BANDCLASSINFO *)DPA_GetPtr(_hdpaBandClasses, uBand);
  528. return pbci;
  529. }
  530. BOOL CBandSiteMenu::DeleteBandClass( REFCLSID rclsid )
  531. {
  532. if( _hdpaBandClasses )
  533. {
  534. for( int i = 0, cnt = GetBandClassCount( NULL, FALSE ); i< cnt; i++ )
  535. {
  536. BANDCLASSINFO * pbci = (BANDCLASSINFO *)DPA_GetPtr( _hdpaBandClasses, i );
  537. ASSERT( pbci );
  538. if( IsEqualCLSID( rclsid, pbci->clsid ) )
  539. {
  540. EVAL( DPA_DeletePtr( _hdpaBandClasses, i ) == (LPVOID)pbci );
  541. if( pbci->pszName )
  542. LocalFree(pbci->pszName);
  543. LocalFree( pbci );
  544. return TRUE;
  545. }
  546. }
  547. }
  548. return FALSE;
  549. }
  550. int CBandSiteMenu::GetBandClassCount(const CATID* pcatid /*NULL*/, BOOL bMergedOnly /*FALSE*/)
  551. {
  552. int cRet = 0;
  553. if( _hdpaBandClasses != NULL )
  554. {
  555. int cBands = DPA_GetPtrCount(_hdpaBandClasses);
  556. if( pcatid || bMergedOnly ) // filter request
  557. {
  558. for( int i = 0; i < cBands; i++ )
  559. {
  560. BANDCLASSINFO * pbci = (BANDCLASSINFO *)DPA_FastGetPtr( _hdpaBandClasses, i );
  561. if( pbci->idCmd || !bMergedOnly )
  562. {
  563. if( pcatid )
  564. {
  565. if( IsEqualGUID( pbci->catid, *pcatid ) )
  566. cRet++;
  567. }
  568. else
  569. cRet++;
  570. }
  571. }
  572. }
  573. else
  574. cRet = cBands;
  575. }
  576. return cRet;
  577. }
  578. void CBandSiteMenu::_AddNewFSBand(LPCITEMIDLIST pidl, BOOL fNoTitleText, DWORD dwPrivID)
  579. {
  580. IDeskBand *ptb = NULL;
  581. BOOL fISF = FALSE;
  582. // this was a drag of a link or folder
  583. // FEATURE: We should use a different test:
  584. // DWORD dwAttrib = (SFGAO_FOLDER | SFGAO_BROWSABLE);
  585. // IEGetAttributesOf(pidl, &dwAttrib);
  586. // if (SFGAO_BROWSABLE != dwAttrib)
  587. // or we could reuse SHCreateBandForPidl().
  588. if (IsURLChild(pidl, TRUE))
  589. {
  590. // create browser to show web sites
  591. ptb = CBrowserBand_Create(pidl);
  592. }
  593. else
  594. {
  595. IFolderBandPriv *pfbp;
  596. // create an ISF band to show folders as hotlinks
  597. fISF = TRUE;
  598. ASSERT(pidl); // o.w. CISFBand_CreateEx will fail
  599. if (FAILED(CISFBand_CreateEx(NULL, pidl, IID_PPV_ARG(IFolderBandPriv, &pfbp))))
  600. {
  601. // we need to give a pretty
  602. // generic message: "can't create toolbar for %1".
  603. TCHAR szName[MAX_URL_STRING];
  604. szName[0] = 0;
  605. SHGetNameAndFlags(pidl, SHGDN_NORMAL, szName, SIZECHARS(szName), NULL);
  606. MLShellMessageBox(NULL,
  607. MAKEINTRESOURCE(IDS_CANTISFBAND),
  608. MAKEINTRESOURCE(IDS_WEBBARTITLE),
  609. MB_OK|MB_ICONERROR, szName);
  610. }
  611. else
  612. {
  613. pfbp->SetNoText(fNoTitleText);
  614. if (SUCCEEDED(pfbp->QueryInterface(IID_PPV_ARG(IDeskBand, &ptb))))
  615. {
  616. if (dwPrivID != -1)
  617. {
  618. VARIANTARG v;
  619. v.vt = VT_I4;
  620. v.lVal = dwPrivID;
  621. // find out if the private id this holds is the same as what we're asking for
  622. IUnknown_Exec(ptb, &CGID_ISFBand, ISFBID_PRIVATEID, 0, &v, NULL);
  623. // qlaunch and qlinks get logged
  624. // (should we key off of host or CSIDL or both?)
  625. // FEATURE: UASSIST todo: qlinks NYI
  626. if (dwPrivID == CSIDL_APPDATA)
  627. {
  628. ASSERT(v.vt == VT_I4);
  629. v.lVal = UEMIND_SHELL; // UEMIND_SHELL/BROWSER
  630. IUnknown_Exec(ptb, &CGID_ShellDocView, SHDVID_UEMLOG, 0, &v, NULL);
  631. }
  632. }
  633. }
  634. pfbp->Release();
  635. }
  636. }
  637. if (ptb)
  638. {
  639. HRESULT hr = _pbs->AddBand(ptb);
  640. if (SUCCEEDED(hr) && fISF)
  641. _pbs->SetBandState(ShortFromResult(hr), BSSF_NOTITLE, fNoTitleText ? BSSF_NOTITLE : 0);
  642. ptb->Release();
  643. }
  644. }
  645. void CBandSiteMenu::_ToggleSpecialFolderBand(int iFolder, LPTSTR pszSubPath, BOOL fNoTitleText)
  646. {
  647. DWORD dwBandID;
  648. if (SUCCEEDED(_FindBand(&CLSID_ISFBand, iFolder, &dwBandID)))
  649. {
  650. _pbs->RemoveBand(dwBandID);
  651. }
  652. else
  653. {
  654. LPITEMIDLIST pidl;
  655. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, iFolder, &pidl)))
  656. {
  657. if (pszSubPath)
  658. {
  659. TCHAR szPath[MAX_PATH];
  660. SHGetPathFromIDList(pidl, szPath);
  661. PathCombine(szPath, szPath, pszSubPath);
  662. ILFree(pidl);
  663. pidl = ILCreateFromPath(szPath);
  664. ASSERT(pidl); // o.w. AddNewFSBand will fail
  665. }
  666. _AddNewFSBand(pidl, fNoTitleText, iFolder);
  667. ILFree(pidl);
  668. }
  669. }
  670. }
  671. int CALLBACK SetCaptionCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  672. {
  673. switch (uMsg)
  674. {
  675. case BFFM_INITIALIZED:
  676. TCHAR szTitle[80];
  677. MLLoadShellLangString(IDS_NEWFSBANDCAPTION, szTitle, ARRAYSIZE(szTitle));
  678. SetWindowText(hwnd, szTitle);
  679. break;
  680. case BFFM_VALIDATEFAILEDA:
  681. case BFFM_VALIDATEFAILEDW:
  682. MLShellMessageBox(hwnd,
  683. uMsg == BFFM_VALIDATEFAILEDA ? MAKEINTRESOURCE(IDS_ERROR_GOTOA)
  684. : MAKEINTRESOURCE(IDS_ERROR_GOTOW),
  685. MAKEINTRESOURCE(IDS_WEBBARTITLE),
  686. MB_OK|MB_ICONERROR, (LPVOID)lParam);
  687. return 1; // 1:leave dialog up for another try...
  688. /*NOTREACHED*/
  689. }
  690. return 0;
  691. }
  692. void CBandSiteMenu::_BrowseForNewFolderBand()
  693. {
  694. BROWSEINFO bi = {0};
  695. LPITEMIDLIST pidl;
  696. TCHAR szTitle[256];
  697. TCHAR szPath[MAX_URL_STRING];
  698. if (_pbs)
  699. IUnknown_GetWindow(_pbs, &bi.hwndOwner);
  700. ASSERT(bi.pidlRoot == NULL);
  701. MLLoadShellLangString(IDS_NEWFSBANDTITLE, szTitle, ARRAYSIZE(szTitle));
  702. bi.lpszTitle = szTitle;
  703. bi.pszDisplayName = szPath;
  704. bi.ulFlags = (BIF_EDITBOX | BIF_VALIDATE | BIF_USENEWUI | BIF_BROWSEINCLUDEURLS);
  705. bi.lpfn = SetCaptionCallback;
  706. pidl = SHBrowseForFolder(&bi);
  707. if (pidl)
  708. {
  709. _AddNewFSBand(pidl, FALSE, -1);
  710. ILFree(pidl);
  711. }
  712. }
  713. void CBandSiteMenu::_ToggleComcatBand(UINT idCmd)
  714. {
  715. BANDCLASSINFO* pbci = (BANDCLASSINFO*)DPA_GetPtr(_hdpaBandClasses, idCmd);
  716. IUnknown* punk;
  717. DWORD dwBandID;
  718. if (SUCCEEDED(_FindBand(&pbci->clsid, -1, &dwBandID)))
  719. {
  720. _pbs->RemoveBand(dwBandID);
  721. }
  722. else if (S_OK == CoCreateInstance(pbci->clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (LPVOID*)&punk))
  723. {
  724. // Language returns S_FALSE and doesn't initialize punk leave us to fault
  725. IPersistStreamInit * ppsi;
  726. // Some Bands don't work if IPersistStreamInit::InitNew() isn't called.
  727. // This includes the QuickLinks Band.
  728. if (SUCCEEDED(punk->QueryInterface(IID_IPersistStreamInit, (LPVOID*)&ppsi)))
  729. {
  730. ppsi->InitNew();
  731. ppsi->Release();
  732. }
  733. _pbs->AddBand(punk);
  734. punk->Release();
  735. }
  736. }