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.

3218 lines
88 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include <uxtheme.h>
  4. #define WANT_CBANDSITE_CLASS
  5. #include "bandsite.h"
  6. #include "bandobj.h"
  7. #include "caggunk.h"
  8. #include "droptgt.h"
  9. #include "resource.h"
  10. #include "bands.h"
  11. #include "legacy.h"
  12. #include "apithk.h"
  13. #include "mluisupp.h"
  14. #define TF_BANDDD 0x00400000
  15. #define DM_INIT 0 //
  16. #define DM_PERSIST 0 // trace IPS::Load, ::Save, etc.
  17. #define DM_MENU 0 // menu code
  18. #define DM_DRAG 0 // drag&drop
  19. #define DM_FOCUS 0 // focus
  20. #define DM_PERF 0 // perf tune
  21. #define DM_PERF2 0 // perf tune (verbose)
  22. #define IDM_DRAGDROP 1
  23. #define ISMOVEDDISABLED(dwBandID) ((S_OK == _IsRestricted(dwBandID, RA_MOVE, BAND_ADMIN_NOMOVE)) ? TRUE : FALSE)
  24. #define ISDDCLOSEDISABLED(dwBandID) ((S_OK == _IsRestricted(dwBandID, RA_DRAG, BAND_ADMIN_NODDCLOSE)) ? TRUE : FALSE)
  25. // drag state (NOTE from dockbar.h)
  26. #define DRAG_NIL 0 // nil
  27. #define DRAG_MOVE 1 // moving
  28. #define DRAG_SIZE 2 // sizing
  29. typedef struct {
  30. UINT cx;
  31. UINT fStyle;
  32. UINT cxMinChild;
  33. UINT cyMinChild;
  34. UINT cyIntegral;
  35. UINT cyMaxChild;
  36. UINT cyChild;
  37. } PERSISTBANDINFO_V3;
  38. typedef struct {
  39. UINT cx;
  40. UINT fStyle;
  41. UINT cxMinChild; // UNUSED. reclaim!
  42. UINT cyMinChild;
  43. UINT cyIntegral; // UNUSED
  44. UINT cyMaxChild; // UNUSED.
  45. UINT cyChild;
  46. DWORD dwAdminSettings;
  47. BITBOOL fNoTitle:1;
  48. } PERSISTBANDINFO;
  49. #define RBBIM_XPERSIST (RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE)
  50. #ifdef DEBUG
  51. extern unsigned long DbStreamTell(IStream *pstm);
  52. #else
  53. #define DbStreamTell(pstm) ((ULONG) 0)
  54. #endif
  55. UINT _FixMenuIndex(HMENU hmenu, UINT indexMenu)
  56. {
  57. UINT i;
  58. i = GetMenuItemCount(hmenu);
  59. if (indexMenu > i)
  60. indexMenu = i;
  61. return indexMenu;
  62. }
  63. #define SUPERCLASS CAggregatedUnknown
  64. HRESULT CBandSite::v_InternalQueryInterface(REFIID riid, void **ppvObj)
  65. {
  66. static const QITAB qit[] = {
  67. // perf: last tuned 980728
  68. QITABENT(CBandSite, IBandSite), // IID_IBandSite
  69. QITABENT(CBandSite, IInputObject), // IID_IInputObject
  70. QITABENT(CBandSite, IServiceProvider), // IID_IServiceProvider
  71. QITABENT(CBandSite, IOleCommandTarget), // IID_IOleCommandTarget
  72. QITABENTMULTI(CBandSite, IOleWindow, IDeskBarClient), // IID_IOleWindow
  73. QITABENT(CBandSite, IWinEventHandler), // IID_IWinEventHandler
  74. QITABENT(CBandSite, IInputObjectSite), // IID_IInputObjectSite
  75. QITABENT(CBandSite, IDeskBarClient), // IID_IDeskBarClient
  76. QITABENTMULTI(CBandSite, IPersist, IPersistStream), // rare IID_IPersist
  77. QITABENT(CBandSite, IPersistStream), // rare IID_IPersistStream
  78. QITABENT(CBandSite, IBandSiteHelper), // rare IBandSiteHelper
  79. QITABENT(CBandSite, IDropTarget), // rare IID_IDropTarget
  80. { 0 },
  81. };
  82. return QISearch(this, qit, riid, ppvObj);
  83. }
  84. DWORD _SetDataListFlags(IUnknown *punk, DWORD dwMaskBits, DWORD dwValue)
  85. {
  86. DWORD dw = 0;
  87. IShellLinkDataList *pdl;
  88. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IShellLinkDataList, &pdl))))
  89. {
  90. pdl->GetFlags(&dw);
  91. dw = (dw & ~dwMaskBits) | (dwValue & dwMaskBits);
  92. pdl->SetFlags(dw);
  93. pdl->Release();
  94. }
  95. return dw;
  96. }
  97. ///// impl of IServiceProvider
  98. HRESULT CBandSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
  99. {
  100. HRESULT hres = E_FAIL;
  101. *ppvObj = NULL; // assume error
  102. if (IsEqualIID(guidService, SID_IBandProxy))
  103. {
  104. hres = QueryService_SID_IBandProxy(_punkSite, riid, &_pbp, ppvObj);
  105. if(!_pbp)
  106. {
  107. // We need to create it ourselves since our parent couldn't help
  108. ASSERT(FALSE == _fCreatedBandProxy);
  109. hres = CreateIBandProxyAndSetSite(_punkSite, riid, &_pbp, ppvObj);
  110. if(_pbp)
  111. {
  112. ASSERT(S_OK == hres);
  113. _fCreatedBandProxy = TRUE;
  114. }
  115. }
  116. }
  117. else if (IsEqualIID(guidService, SID_ITopViewHost))
  118. {
  119. return QueryInterface(riid, ppvObj);
  120. }
  121. else if (IsEqualIID(guidService, IID_IBandSite))
  122. {
  123. // It is common for bands to save/load pidls for persistence.
  124. // CShellLink is a robust way to do this, so let's share one
  125. // among all the bands.
  126. //
  127. // NOTE: This is shared between bands, so if you request it
  128. // you must complete your use of it within the scope of your
  129. // function call!
  130. //
  131. if (IsEqualIID(riid, IID_IShellLinkA) ||
  132. IsEqualIID(riid, IID_IShellLinkW))
  133. {
  134. if (NULL == _plink)
  135. CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &_plink));
  136. if (_plink)
  137. {
  138. // we know that the bandsite is going to be pointing to local folders
  139. // to avoid a perf hit we get in loading the LINKINFO.DLL we explictly
  140. // disable that functionality here.
  141. _SetDataListFlags(_plink, SLDF_FORCE_NO_LINKINFO, SLDF_FORCE_NO_LINKINFO);
  142. hres = _plink->QueryInterface(riid, ppvObj);
  143. }
  144. }
  145. }
  146. else
  147. {
  148. hres = IUnknown_QueryService(_punkSite, guidService, riid, ppvObj);
  149. }
  150. return hres;
  151. }
  152. HRESULT CBandSite::GetWindow(HWND * lphwnd)
  153. {
  154. *lphwnd = _hwnd;
  155. return *lphwnd ? S_OK : E_FAIL;
  156. }
  157. CBandSite::CBandSite(IUnknown* punkAgg) : SUPERCLASS(punkAgg)
  158. {
  159. DWORD dwData = 0;
  160. DWORD dwSize = SIZEOF(dwData);
  161. // We assume this object was zero inited.
  162. ASSERT(!_pbp);
  163. ASSERT(FALSE == _fCreatedBandProxy);
  164. SHRegGetUSValue(SZ_REGKEY_GLOBALADMINSETTINGS, SZ_REGVALUE_GLOBALADMINSETTINGS,
  165. NULL, (LPVOID) &dwData, &dwSize, FALSE, NULL, 0);
  166. if (IsFlagSet(dwData, BAND_ADMIN_ADMINMACHINE))
  167. _fIEAKInstalled = TRUE;
  168. else
  169. _fIEAKInstalled = FALSE;
  170. _dwStyle = BSIS_AUTOGRIPPER;
  171. //
  172. // We check whether or not this succeeded in CBandSite::_Initialize
  173. //
  174. _QueryOuterInterface(IID_PPV_ARG(IBandSite, &_pbsOuter));
  175. DllAddRef();
  176. }
  177. void CBandSite::_ReleaseBandItemData(LPBANDITEMDATA pbid, int iIndex)
  178. {
  179. if (pbid->pdb)
  180. {
  181. REBARBANDINFO rbbi;
  182. pbid->pdb->CloseDW(0);
  183. if (-1 != iIndex)
  184. {
  185. // The band's hwnd is typically destroyed in CloseDW
  186. rbbi.cbSize = sizeof(rbbi);
  187. rbbi.fMask = RBBIM_CHILD | RBBIM_LPARAM;
  188. rbbi.hwndChild = NULL;
  189. rbbi.lParam = NULL;
  190. EVAL( SendMessage(_hwnd, RB_SETBANDINFO, iIndex, (LPARAM) &rbbi) );
  191. }
  192. // this is called from remove and the destroy.
  193. IUnknown_SetSite(pbid->pdb, NULL);
  194. ATOMICRELEASE(pbid->pdb);
  195. }
  196. if (pbid->pweh == _pwehCache)
  197. ATOMICRELEASE(_pwehCache);
  198. ATOMICRELEASE(pbid->pweh);
  199. LocalFree(pbid);
  200. }
  201. CBandSite::~CBandSite()
  202. {
  203. ATOMICRELEASE(_pdtobj);
  204. if(_pbp && _fCreatedBandProxy)
  205. _pbp->SetSite(NULL);
  206. ATOMICRELEASE(_pbp);
  207. ATOMICRELEASE(_pwehCache);
  208. _CacheActiveBand(NULL);
  209. _Close();
  210. SetDeskBarSite(NULL);
  211. if (_plink)
  212. _plink->Release();
  213. RELEASEOUTERINTERFACE(_pbsOuter);
  214. DllRelease();
  215. }
  216. //*** _IsBandDeleteable --
  217. // ENTRY/EXIT
  218. // idBand band ID
  219. // ret TRUE if deletable, o.w. FALSE (also FALSE on bogus band)
  220. BOOL CBandSite::_IsBandDeleteable(DWORD dwBandID)
  221. {
  222. DWORD dwState;
  223. if (FAILED(_pbsOuter->QueryBand(dwBandID, NULL, &dwState, NULL, 0))
  224. || (dwState & BSSF_UNDELETEABLE))
  225. {
  226. return FALSE;
  227. }
  228. ASSERT(dwBandID != (DWORD)-1); // make sure QueryBand catches this
  229. return TRUE;
  230. }
  231. DWORD CBandSite::_GetAdminSettings(DWORD dwBandID)
  232. {
  233. LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID));
  234. if (EVAL(pbid))
  235. return pbid->dwAdminSettings;
  236. return BAND_ADMIN_NORMAL;
  237. }
  238. void CBandSite::_SetAdminSettings(DWORD dwBandID, DWORD dwNewAdminSettings)
  239. {
  240. LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID));
  241. if (EVAL(pbid))
  242. pbid->dwAdminSettings = dwNewAdminSettings;
  243. }
  244. //*** CBandSite::IBandSite::* {
  245. /*----------------------------------------------------------
  246. Purpose: IBandSite::EnumBands method
  247. */
  248. HRESULT CBandSite::EnumBands(UINT uBand, DWORD* pdwBandID)
  249. {
  250. ASSERT((NULL == pdwBandID && (UINT)-1 == uBand) ||
  251. IS_VALID_WRITE_PTR(pdwBandID, DWORD));
  252. if (uBand == (UINT)-1)
  253. return _GetBandItemCount(); // query count
  254. LPBANDITEMDATA pbid = _GetBandItem(uBand);
  255. if (pbid)
  256. {
  257. *pdwBandID = pbid->dwBandID;
  258. return S_OK;
  259. }
  260. return E_FAIL;
  261. }
  262. /*----------------------------------------------------------
  263. Purpose: IBandSite::QueryBand method
  264. */
  265. HRESULT CBandSite::QueryBand(DWORD dwBandID, IDeskBand** ppstb, DWORD* pdwState, LPWSTR pszName, int cchName)
  266. {
  267. ASSERT(NULL == ppstb || IS_VALID_WRITE_PTR(ppstb, IDeskBand));
  268. ASSERT(NULL == pdwState || IS_VALID_WRITE_PTR(pdwState, DWORD));
  269. ASSERT(NULL == pszName || IS_VALID_WRITE_BUFFER(pszName, WCHAR, cchName));
  270. if (ppstb)
  271. *ppstb = NULL;
  272. LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
  273. if (!pbid)
  274. return E_FAIL;
  275. if (pszName)
  276. {
  277. StrCpyNW(pszName, pbid->szTitle, cchName);
  278. }
  279. if (ppstb)
  280. {
  281. *ppstb = pbid->pdb;
  282. if (pbid->pdb)
  283. {
  284. pbid->pdb->AddRef();
  285. }
  286. }
  287. if (pdwState)
  288. {
  289. *pdwState = 0;
  290. if (pbid->fShow)
  291. *pdwState = BSSF_VISIBLE;
  292. if (pbid->fNoTitle)
  293. *pdwState |= BSSF_NOTITLE;
  294. if (pbid->dwModeFlags & DBIMF_UNDELETEABLE)
  295. *pdwState |= BSSF_UNDELETEABLE;
  296. }
  297. return S_OK;
  298. }
  299. /*----------------------------------------------------------
  300. Purpose: IBandSite::SetBandState
  301. * NOTES
  302. * failure handling is inconsistent (1 band vs. all bands case)
  303. */
  304. HRESULT CBandSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
  305. {
  306. LPBANDITEMDATA pbid;
  307. HRESULT hr;
  308. if (dwBandID == (DWORD) -1)
  309. {
  310. BOOL fChange = FALSE;
  311. for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  312. {
  313. pbid = _GetBandItem(i);
  314. if (pbid)
  315. {
  316. hr = _SetBandStateHelper(pbid->dwBandID, dwMask, dwState);
  317. ASSERT(SUCCEEDED(hr));
  318. fChange |= (hr != S_OK);
  319. }
  320. else
  321. {
  322. return E_FAIL;
  323. }
  324. }
  325. if (fChange)
  326. _UpdateAllBands(FALSE, FALSE);
  327. return S_OK;
  328. }
  329. else
  330. {
  331. hr = _SetBandStateHelper(dwBandID, dwMask, dwState);
  332. if (SUCCEEDED(hr) && hr != S_OK)
  333. {
  334. _UpdateBand(dwBandID);
  335. return S_OK;
  336. }
  337. }
  338. return E_FAIL;
  339. }
  340. //***
  341. // ENTRY/EXIT
  342. // ret S_OK|changed on success, o.w. E_*.
  343. // NOTES
  344. // only a helper for SetBandState, don't call directly
  345. HRESULT CBandSite::_SetBandStateHelper(DWORD dwBandID, DWORD dwMask, DWORD dwState)
  346. {
  347. LPBANDITEMDATA pbid;
  348. pbid = _GetBandItem(_BandIDToIndex(dwBandID));
  349. if (pbid)
  350. {
  351. DWORD dwOldState;
  352. if (FAILED(QueryBand(dwBandID, NULL, &dwOldState, NULL, 0)))
  353. {
  354. ASSERT(0); // 'impossible'
  355. dwOldState = (DWORD)-1;
  356. }
  357. if (dwMask & BSSF_VISIBLE)
  358. _ShowBand(pbid, dwState & BSSF_VISIBLE);
  359. if (dwMask & BSSF_NOTITLE)
  360. pbid->fNoTitle = BOOLIFY(dwState & BSSF_NOTITLE);
  361. // FEATURE: (kkahl): BSSF_UNDELETABLE cannot currently be modified with
  362. // this interface.
  363. return ResultFromShort((dwOldState ^ dwState) & dwMask);
  364. }
  365. return E_FAIL;
  366. }
  367. //*** _CheckNotifyOnAddRemove -- handle notifies for add/remove/empty
  368. // DESCRIPTION
  369. // add/remove always sends a BSID_BANDADDED/BSID_BANDREMOVED.
  370. // remove of last always sends a DBCID_EMPTY.
  371. // in floating mode, a transition to/from 1 band does a refresh.
  372. //
  373. void CBandSite::_CheckNotifyOnAddRemove(DWORD dwBandID, int iCode)
  374. {
  375. int cBands;
  376. if (!_pct)
  377. return;
  378. if (iCode == CNOAR_CLOSEBAR)
  379. {
  380. // Shut down the whole thing
  381. cBands = 0;
  382. }
  383. else
  384. {
  385. VARIANTARG var;
  386. int nCmdID;
  387. cBands = _GetBandItemCount(); // post-op # (since op happened in caller)
  388. VariantInit(&var);
  389. var.vt = VT_UI4;
  390. var.ulVal = dwBandID;
  391. BOOL fOne = FALSE;
  392. switch (iCode)
  393. {
  394. case CNOAR_ADDBAND:
  395. fOne = (cBands == 2); // 1->2
  396. nCmdID = BSID_BANDADDED;
  397. break;
  398. case CNOAR_REMOVEBAND:
  399. fOne = (cBands == 1); // 2->1
  400. nCmdID = BSID_BANDREMOVED;
  401. break;
  402. default:
  403. ASSERT(0);
  404. return;
  405. }
  406. if ((fOne && (_dwMode & DBIF_VIEWMODE_FLOATING)))
  407. {
  408. // n.b. fBSOnly *must* be TRUE for perf
  409. _UpdateAllBands(TRUE, TRUE); // force refresh of optional gripper/title
  410. }
  411. _pct->Exec(&CGID_BandSite, nCmdID, 0, &var, NULL);
  412. }
  413. if (cBands == 0)
  414. {
  415. ASSERT(iCode != CNOAR_ADDBAND); // sanity check
  416. _pct->Exec(&CGID_DeskBarClient, DBCID_EMPTY, 0, NULL, NULL);
  417. }
  418. return;
  419. }
  420. /*----------------------------------------------------------
  421. Purpose: IBandSite::RemoveBand method
  422. */
  423. HRESULT CBandSite::RemoveBand(DWORD dwBandID)
  424. {
  425. int iIndex = _BandIDToIndex(dwBandID);
  426. LPBANDITEMDATA pbid = _GetBandItem(iIndex);
  427. if (pbid)
  428. {
  429. // Release the banditem data first, while it can still
  430. // receive cleanup notifications from its control. *Then*
  431. // delete the band item.
  432. _ReleaseBandItemData(pbid, iIndex);
  433. _DeleteBandItem(iIndex); // unhook from host (rebar)
  434. _CheckNotifyOnAddRemove(dwBandID, CNOAR_REMOVEBAND);
  435. return S_OK;
  436. }
  437. return E_FAIL;
  438. }
  439. void CBandSite::_OnCloseBand(DWORD dwBandID)
  440. {
  441. if (dwBandID == -1)
  442. {
  443. // Close everything
  444. _CheckNotifyOnAddRemove(dwBandID, CNOAR_CLOSEBAR);
  445. }
  446. else
  447. {
  448. // Close just this band
  449. LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
  450. USES_CONVERSION;
  451. if (EVAL(pbid) && ConfirmRemoveBand(_hwnd, IDS_CONFIRMCLOSEBAND,W2T(pbid->szTitle)))
  452. RemoveBand(dwBandID);
  453. }
  454. }
  455. void CBandSite::_MinimizeBand(DWORD dwBandID)
  456. {
  457. SendMessage(_hwnd, RB_MINIMIZEBAND, _BandIDToIndex(dwBandID), TRUE);
  458. }
  459. void CBandSite::_MaximizeBand(DWORD dwBandID)
  460. {
  461. SendMessage(_hwnd, RB_MAXIMIZEBAND, _BandIDToIndex(dwBandID), TRUE);
  462. }
  463. //
  464. // private insert a band into the container control by ID
  465. // returns the band ID in ShortFromResult(hres)
  466. //
  467. HRESULT CBandSite::_AddBandByID(IUnknown *punk, DWORD dwID)
  468. {
  469. IDeskBand *pdb;
  470. HRESULT hr = punk->QueryInterface(IID_PPV_ARG(IDeskBand, &pdb));
  471. if (SUCCEEDED(hr))
  472. {
  473. ASSERT(pdb);
  474. BANDITEMDATA *pbid = (BANDITEMDATA *)LocalAlloc(LPTR, sizeof(BANDITEMDATA));
  475. if (pbid)
  476. {
  477. pbid->dwBandID = dwID;
  478. pbid->pdb = pdb; // ref held by QI above
  479. pbid->fShow = TRUE; // initially visible
  480. pbid->pdb->QueryInterface(IID_PPV_ARG(IWinEventHandler, &pbid->pweh));
  481. hr = IUnknown_SetSite(pbid->pdb, SAFECAST(this, IBandSite*));
  482. if (SUCCEEDED(hr))
  483. {
  484. hr = pbid->pdb->GetWindow(&pbid->hwnd);
  485. if (SUCCEEDED(hr))
  486. {
  487. if (_AddBandItem(pbid))
  488. {
  489. if (_dwShowState == DBC_SHOW)
  490. {
  491. ASSERT(pbid->fShow);
  492. pbid->pdb->ShowDW(TRUE);
  493. _MinimizeBand(pbid->dwBandID);
  494. }
  495. _CheckNotifyOnAddRemove(pbid->dwBandID, CNOAR_ADDBAND);
  496. hr = ResultFromShort(pbid->dwBandID); // success
  497. }
  498. else
  499. {
  500. hr = E_FAIL;
  501. }
  502. }
  503. }
  504. if (FAILED(hr))
  505. {
  506. // clean up
  507. _ReleaseBandItemData(pbid, -1);
  508. }
  509. //
  510. // Now that we've added the band, clear the _SendToToolband cache.
  511. //
  512. // We need to do this because we might have gotten a message for
  513. // the band before it was inserted, in which case we'll have cached
  514. // a NULL handler for the band's hwnd (preventing the band from
  515. // getting any messages thereafter).
  516. //
  517. ATOMICRELEASE(_pwehCache);
  518. _hwndCache = NULL;
  519. }
  520. else
  521. {
  522. hr = E_OUTOFMEMORY;
  523. pdb->Release(); // don't hold on to this
  524. }
  525. }
  526. return hr;
  527. }
  528. /*----------------------------------------------------------
  529. Purpose: IBandSite::AddBand method.
  530. Insert a band into the container control.
  531. Returns: the band ID in ShortFromResult(hres)
  532. */
  533. HRESULT CBandSite::AddBand(IUnknown *punk)
  534. {
  535. HRESULT hres = _AddBandByID(punk, _dwBandIDNext);
  536. if (SUCCEEDED(hres))
  537. {
  538. _dwBandIDNext++;
  539. }
  540. return hres;
  541. }
  542. void CBandSite::_UpdateBand(DWORD dwBandID)
  543. {
  544. LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID));
  545. if (pbid)
  546. {
  547. _UpdateBandInfo(pbid, FALSE);
  548. _OnRBAutoSize(NULL);
  549. }
  550. }
  551. void CBandSite::_UpdateAllBands(BOOL fBSOnly, BOOL fNoAutoSize)
  552. {
  553. BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  554. for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  555. {
  556. LPBANDITEMDATA pbid = _GetBandItem(i);
  557. if (pbid)
  558. _UpdateBandInfo(pbid, fBSOnly);
  559. }
  560. SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
  561. if (!fNoAutoSize)
  562. {
  563. SendMessage(_hwnd, RB_SIZETORECT, 0, 0);
  564. _OnRBAutoSize(NULL);
  565. }
  566. }
  567. // *** IOleCommandTarget ***
  568. HRESULT CBandSite::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  569. {
  570. HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
  571. if (pguidCmdGroup)
  572. {
  573. if (IsEqualIID(*pguidCmdGroup, IID_IDockingWindow))
  574. {
  575. for (ULONG i=0 ; i<cCmds ; i++)
  576. {
  577. switch (rgCmds[i].cmdID)
  578. {
  579. case DBID_BANDINFOCHANGED:
  580. case DBID_PUSHCHEVRON:
  581. rgCmds[i].cmdf = OLECMDF_ENABLED;
  582. break;
  583. case DBID_PERMITAUTOHIDE:
  584. // defer decision to the bands
  585. for (int iBand = _GetBandItemCount() - 1; iBand >= 0; iBand--)
  586. {
  587. LPBANDITEMDATA pbid = _GetBandItem(iBand);
  588. if (pbid)
  589. {
  590. if (SUCCEEDED(IUnknown_QueryStatus(pbid->pdb, pguidCmdGroup, 1, &rgCmds[i], pcmdtext)) &&
  591. ((rgCmds[i].cmdf & OLECMDF_SUPPORTED) && !(rgCmds[i].cmdf & OLECMDF_ENABLED)))
  592. {
  593. break;
  594. }
  595. }
  596. }
  597. break;
  598. default:
  599. rgCmds[i].cmdf = 0;
  600. break;
  601. }
  602. }
  603. return S_OK;
  604. }
  605. else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
  606. {
  607. return IUnknown_QueryStatus(_ptbActive, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  608. }
  609. }
  610. // if we got here, we didn't handle it
  611. // forward it down
  612. return MayQSForward(_ptbActive, OCTD_DOWN, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  613. }
  614. int _QueryServiceCallback(LPBANDITEMDATA pbid, void *pv)
  615. {
  616. QSDATA* pqsd = (QSDATA*)pv;
  617. if (pbid->fShow)
  618. pqsd->hres = IUnknown_QueryService(pbid->pdb, *(pqsd->pguidService), *(pqsd->piid), pqsd->ppvObj);
  619. // stop if we found the service
  620. return SUCCEEDED(pqsd->hres) ? FALSE : TRUE;
  621. }
  622. typedef struct {
  623. HRESULT hres;
  624. const GUID *pguidCmdGroup;
  625. DWORD nCmdID;
  626. DWORD nCmdexecopt;
  627. VARIANTARG *pvarargIn;
  628. VARIANTARG *pvarargOut;
  629. } EXECDATA;
  630. int _ExecCallback(LPBANDITEMDATA pbid, void *pv)
  631. {
  632. EXECDATA* ped = (EXECDATA*)pv;
  633. ped->hres = IUnknown_Exec(pbid->pdb, ped->pguidCmdGroup, ped->nCmdID, ped->nCmdexecopt,
  634. ped->pvarargIn, ped->pvarargOut);
  635. return 1;
  636. }
  637. HRESULT CBandSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  638. {
  639. HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
  640. HRESULT hresTmp;
  641. if (pguidCmdGroup == NULL)
  642. {
  643. /*NOTHING*/
  644. ;
  645. }
  646. else if (IsEqualIID(*pguidCmdGroup, CGID_DeskBand))
  647. {
  648. switch (nCmdID)
  649. {
  650. case DBID_BANDINFOCHANGED:
  651. if (!pvarargIn)
  652. _UpdateAllBands(FALSE, FALSE);
  653. else if (pvarargIn->vt == VT_I4)
  654. _UpdateBand(pvarargIn->lVal);
  655. hres = S_OK;
  656. // forward this up.
  657. if (_pct)
  658. {
  659. _pct->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  660. }
  661. goto Lret;
  662. case DBID_PUSHCHEVRON:
  663. if (pvarargIn && pvarargIn->vt == VT_I4)
  664. {
  665. int iIndex = _BandIDToIndex(nCmdexecopt);
  666. SendMessage(_hwnd, RB_PUSHCHEVRON, iIndex, pvarargIn->lVal);
  667. hres = S_OK;
  668. }
  669. goto Lret;
  670. case DBID_MAXIMIZEBAND:
  671. if (pvarargIn && pvarargIn->vt == VT_UI4)
  672. _MaximizeBand(pvarargIn->ulVal);
  673. hres = S_OK;
  674. goto Lret;
  675. #if 1 // { FEATURE: temporary until add cbs::Select() mfunc
  676. case DBID_SHOWONLY:
  677. {
  678. int iCount = _GetBandItemCount();
  679. // pvaIn->punkVal:
  680. // punk hide everyone except me
  681. // 0 hide everyone
  682. // 1 show everyone
  683. // FEATURE: we should use pvaIn->lVal not punkVal since we're
  684. // allowing 0 & 1 !!! (and not doing addref/release)
  685. ASSERT(pvarargIn && pvarargIn->vt == VT_UNKNOWN);
  686. if (pvarargIn->punkVal == NULL || pvarargIn->punkVal == (IUnknown*)1)
  687. TraceMsg(TF_BANDDD, "cbs.e: (id=DBID_SHOWONLY, punk=%x)", pvarargIn->punkVal);
  688. // show myself, hide everyone else
  689. TraceMsg(TF_BANDDD, "cbs.Exec(DBID_SHOWONLY): n=%d", _GetBandItemCount());
  690. // wait to show this band until we've hidden the others
  691. LPBANDITEMDATA pbidShow = NULL;
  692. // FEATURE: this (IUnknown*)1 is bogus! Also mentioned above.
  693. BOOL bShowAll = (pvarargIn->punkVal == (IUnknown*)1);
  694. for (int i = iCount - 1; i >= 0; i--)
  695. {
  696. LPBANDITEMDATA pbid = _GetBandItem(i);
  697. if (pbid)
  698. {
  699. BOOL fShow;
  700. fShow = bShowAll || SHIsSameObject(pbid->pdb, pvarargIn->punkVal);
  701. if (!fShow || bShowAll)
  702. _ShowBand(pbid, fShow);
  703. else
  704. pbidShow = pbid;
  705. }
  706. }
  707. if (pbidShow)
  708. {
  709. _ShowBand(pbidShow, TRUE);
  710. // nash:37290 set focus to band on open
  711. if (_dwShowState == DBC_SHOW)
  712. IUnknown_UIActivateIO(pbidShow->pdb, TRUE, NULL);
  713. else
  714. ASSERT(0);
  715. }
  716. }
  717. break;
  718. #endif // }
  719. }
  720. }
  721. else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
  722. {
  723. return IUnknown_Exec(_ptbActive, pguidCmdGroup, nCmdID, nCmdexecopt,
  724. pvarargIn, pvarargOut);
  725. }
  726. else if (IsEqualIID(*pguidCmdGroup, CGID_DeskBarClient))
  727. {
  728. switch (nCmdID)
  729. {
  730. case DBCID_ONDRAG:
  731. if (EVAL(pvarargIn->vt == VT_I4))
  732. {
  733. ASSERT(pvarargIn->lVal == 0 || pvarargIn->lVal == DRAG_MOVE);
  734. TraceMsg(DM_TRACE, "cbs.e: DBCID_ONDRAG i=%d", pvarargIn->lVal);
  735. _fDragging = pvarargIn->lVal;
  736. }
  737. break;
  738. case DBCID_GETBAR:
  739. // return IUnkown of my IDeskBar host
  740. if ((pvarargOut != NULL) && _pdb)
  741. {
  742. ::VariantInit(pvarargOut);
  743. V_VT(pvarargOut) = VT_UNKNOWN;
  744. V_UNKNOWN(pvarargOut) = _pdb;
  745. _pdb->AddRef();
  746. hres = S_OK;
  747. goto Lret;
  748. }
  749. break;
  750. }
  751. }
  752. // if we got here, we didn't handle it
  753. // see if we should forward it down
  754. hresTmp = IsExecForward(pguidCmdGroup, nCmdID);
  755. if (SUCCEEDED(hresTmp) && HRESULT_CODE(hresTmp) > 0)
  756. {
  757. // down (singleton or broadcast)
  758. if (HRESULT_CODE(hresTmp) == OCTD_DOWN)
  759. {
  760. // down (singleton)
  761. hres = IUnknown_Exec(_ptbActive, pguidCmdGroup, nCmdID, nCmdexecopt,
  762. pvarargIn, pvarargOut);
  763. }
  764. else
  765. {
  766. // down (broadcast)
  767. // n.b. hres is a bit weird: 'last one wins'
  768. // FEATURE: should we just return S_OK?
  769. ASSERT(HRESULT_CODE(hresTmp) == OCTD_DOWNBROADCAST);
  770. EXECDATA ctd = { hres, pguidCmdGroup, nCmdID, nCmdexecopt,
  771. pvarargIn, pvarargOut };
  772. _BandItemEnumCallback(1, _ExecCallback, &ctd);
  773. hres = ctd.hres;
  774. }
  775. }
  776. Lret:
  777. return hres;
  778. }
  779. /*** _ShowBand -- show/hide band (cached state, band, and rebar band)
  780. */
  781. void CBandSite::_ShowBand(LPBANDITEMDATA pbid, BOOL fShow)
  782. {
  783. int i;
  784. pbid->fShow = BOOLIFY(fShow);
  785. if (pbid->pdb)
  786. {
  787. pbid->pdb->ShowDW(fShow && (_dwShowState == DBC_SHOW));
  788. }
  789. i = _BandIDToIndex(pbid->dwBandID);
  790. SendMessage(_hwnd, RB_SHOWBAND, i, fShow);
  791. // get me a window to draw D&D curosors on. . .
  792. SHGetTopBrowserWindow(SAFECAST(this, IBandSite*), &_hwndDD);
  793. }
  794. /*----------------------------------------------------------
  795. Purpose: IBandSite::GetBandSiteInfo
  796. */
  797. HRESULT CBandSite::GetBandSiteInfo(BANDSITEINFO * pbsinfo)
  798. {
  799. ASSERT(IS_VALID_WRITE_PTR(pbsinfo, BANDSITEINFO));
  800. if (pbsinfo->dwMask & BSIM_STATE)
  801. pbsinfo->dwState = _dwMode;
  802. if (pbsinfo->dwMask & BSIM_STYLE)
  803. pbsinfo->dwStyle = _dwStyle;
  804. return S_OK;
  805. }
  806. /*----------------------------------------------------------
  807. Purpose: IBandSite::SetBandSiteInfo
  808. */
  809. HRESULT CBandSite::SetBandSiteInfo(const BANDSITEINFO * pbsinfo)
  810. {
  811. ASSERT(IS_VALID_READ_PTR(pbsinfo, BANDSITEINFO));
  812. if (pbsinfo->dwMask & BSIM_STATE)
  813. _dwMode = pbsinfo->dwState;
  814. if (pbsinfo->dwMask & BSIM_STYLE)
  815. {
  816. // If the BSIS_SINGLECLICK style changed, change the rebar style
  817. if ( _hwnd && ((_dwStyle ^ pbsinfo->dwStyle) & BSIS_SINGLECLICK) )
  818. SHSetWindowBits(_hwnd, GWL_STYLE, RBS_DBLCLKTOGGLE, (pbsinfo->dwStyle & BSIS_SINGLECLICK)?0:RBS_DBLCLKTOGGLE);
  819. _dwStyle = pbsinfo->dwStyle;
  820. }
  821. return S_OK;
  822. }
  823. /*----------------------------------------------------------
  824. Purpose: IBandSite::GetBandObject
  825. */
  826. HRESULT CBandSite::GetBandObject(DWORD dwBandID, REFIID riid, void **ppvObj)
  827. {
  828. HRESULT hres = E_FAIL;
  829. *ppvObj = NULL;
  830. if (IsEqualIID(riid, IID_IDataObject))
  831. {
  832. *ppvObj = _DataObjForBand(dwBandID);
  833. if (*ppvObj)
  834. hres = S_OK;
  835. }
  836. else
  837. {
  838. LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
  839. if (pbid && pbid->pdb)
  840. {
  841. hres = pbid->pdb->QueryInterface(riid, ppvObj);
  842. }
  843. }
  844. return hres;
  845. }
  846. /*----------------------------------------------------------
  847. Purpose: Returns a pointer to the band item data given an
  848. externally known band ID.
  849. Returns: NULL if band ID is illegal
  850. */
  851. LPBANDITEMDATA CBandSite::_GetBandItemDataStructByID(DWORD uID)
  852. {
  853. int iBand = _BandIDToIndex(uID);
  854. if (iBand == -1)
  855. return NULL;
  856. return _GetBandItem(iBand);
  857. }
  858. __inline HRESULT _FwdWinEvent(IWinEventHandler* pweh, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  859. {
  860. ASSERT(pweh);
  861. ASSERT(hwnd == HWND_BROADCAST || pweh->IsWindowOwner(hwnd) == S_OK);
  862. return pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
  863. }
  864. /*----------------------------------------------------------
  865. Purpose: Forwards messages to the band that owns the window.
  866. Returns: TRUE if the message was forwarded
  867. */
  868. BOOL CBandSite::_SendToToolband(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  869. {
  870. BOOL fSent = FALSE;
  871. LRESULT lres = 0;
  872. if (hwnd)
  873. {
  874. if (hwnd == _hwndCache)
  875. {
  876. ASSERT(hwnd != HWND_BROADCAST);
  877. if (_pwehCache)
  878. {
  879. _FwdWinEvent(_pwehCache, hwnd, uMsg, wParam, lParam, &lres);
  880. fSent = TRUE;
  881. }
  882. }
  883. else
  884. {
  885. LPBANDITEMDATA pbid = NULL;
  886. int i;
  887. for (i = _GetBandItemCount() - 1; i >= 0; i--)
  888. {
  889. pbid = _GetBandItem(i);
  890. if (pbid)
  891. {
  892. if (pbid->pweh)
  893. {
  894. if (hwnd == HWND_BROADCAST ||
  895. (pbid->pweh->IsWindowOwner(hwnd) == S_OK))
  896. {
  897. _FwdWinEvent(pbid->pweh, hwnd, uMsg, wParam, lParam, &lres);
  898. fSent = TRUE;
  899. if (hwnd != HWND_BROADCAST)
  900. {
  901. break;
  902. }
  903. }
  904. }
  905. else
  906. {
  907. if (hwnd == HWND_BROADCAST && pbid->hwnd)
  908. {
  909. lres = SendMessage(pbid->hwnd, uMsg, wParam, lParam);
  910. fSent = TRUE;
  911. }
  912. }
  913. }
  914. }
  915. if (hwnd != HWND_BROADCAST)
  916. {
  917. ATOMICRELEASE(_pwehCache);
  918. _hwndCache = hwnd;
  919. if (fSent && pbid)
  920. {
  921. _pwehCache = pbid->pweh;
  922. _pwehCache->AddRef();
  923. }
  924. }
  925. }
  926. }
  927. if (plres)
  928. *plres = lres;
  929. return fSent;
  930. }
  931. typedef struct {
  932. HWND hwnd;
  933. HRESULT hres;
  934. } WINDOWOWNERDATA;
  935. int _IsWindowOwnerCallback(LPBANDITEMDATA pbid, void *pv)
  936. {
  937. WINDOWOWNERDATA* pwod = (WINDOWOWNERDATA*)pv;
  938. if (pbid->pweh && (pbid->pweh->IsWindowOwner(pwod->hwnd) == S_OK))
  939. {
  940. pwod->hres = S_OK;
  941. return 0;
  942. }
  943. return 1;
  944. }
  945. HRESULT CBandSite::IsWindowOwner(HWND hwnd)
  946. {
  947. if (hwnd == _hwnd)
  948. return S_OK;
  949. WINDOWOWNERDATA wod = { hwnd, S_FALSE };
  950. _BandItemEnumCallback(1, _IsWindowOwnerCallback, &wod);
  951. return wod.hres;
  952. }
  953. //*** CBandSite::IDeskBarClient::* {
  954. HRESULT CBandSite::GetSize(DWORD dwWhich, LPRECT prc)
  955. {
  956. HRESULT hres = E_FAIL;
  957. switch (dwWhich)
  958. {
  959. case DBC_GS_IDEAL:
  960. {
  961. prc->right = 0;
  962. prc->bottom = 0;
  963. BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  964. for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  965. {
  966. LPBANDITEMDATA pbid = _GetBandItem(i);
  967. if (pbid)
  968. {
  969. RECT rc;
  970. SendMessage(_hwnd, RB_GETBANDBORDERS, _BandIDToIndex(pbid->dwBandID), (LPARAM) &rc);
  971. _UpdateBandInfo(pbid, FALSE);
  972. if (pbid->fShow)
  973. {
  974. if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
  975. {
  976. prc->right = max(prc->right, pbid->ptActual.x + (rc.left + rc.right));
  977. prc->bottom += pbid->ptActual.y + rc.top + rc.bottom;
  978. }
  979. else
  980. {
  981. prc->bottom = max(prc->right, pbid->ptActual.x + (rc.left + rc.right));
  982. prc->right += pbid->ptActual.y + rc.top + rc.bottom;
  983. }
  984. }
  985. hres = S_OK;
  986. }
  987. }
  988. SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
  989. }
  990. break;
  991. case DBC_GS_SIZEDOWN:
  992. {
  993. // Used to make a band change size in chuncks
  994. SendMessage(_hwnd, RB_SIZETORECT, RBSTR_CHANGERECT, (LPARAM)prc);
  995. hres = S_OK;
  996. }
  997. break;
  998. }
  999. return hres;
  1000. }
  1001. void CBandSite::_Close()
  1002. {
  1003. if (_hwnd)
  1004. {
  1005. // (scotth): This method is getting called by the destructor,
  1006. // and calls _DeleteAllBandItems, which sends messages to _hwnd.
  1007. // _hwnd is already destroyed by this time. If you hit this assert
  1008. // it is because in debug windows it RIPs like crazy.
  1009. // 970508 (adp): pblm was that we weren't doing DestroyWnd etc.
  1010. //
  1011. // Do no remove this assert....please fix the root problem.
  1012. ASSERT(IS_VALID_HANDLE(_hwnd, WND));
  1013. SendMessage(_hwnd, WM_SETREDRAW, 0, 0);
  1014. _DeleteAllBandItems();
  1015. DestroyWindow(_hwnd);
  1016. _hwnd = 0;
  1017. }
  1018. }
  1019. HRESULT CBandSite::UIActivateDBC(DWORD dwState)
  1020. {
  1021. if (dwState != _dwShowState)
  1022. {
  1023. BOOL fShow = dwState;
  1024. _dwShowState = dwState;
  1025. // map UIActivateDBC to ShowDW
  1026. if (DBC_SHOWOBSCURE == dwState)
  1027. fShow = FALSE;
  1028. BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  1029. for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  1030. {
  1031. LPBANDITEMDATA pbid = _GetBandItem(i);
  1032. if (pbid && pbid->pdb)
  1033. pbid->pdb->ShowDW(fShow && pbid->fShow);
  1034. }
  1035. // do this now intead of at creation so that
  1036. // rebar doesn't keep trying to autosize us while
  1037. // we're not even visible
  1038. SHSetWindowBits(_hwnd, GWL_STYLE, RBS_AUTOSIZE, RBS_AUTOSIZE);
  1039. SendMessage(_hwnd, WM_SIZE, 0, 0);
  1040. SendMessage(_hwnd, WM_SETREDRAW, (DBC_SHOW == dwState) ? TRUE : fRedraw, 0);
  1041. }
  1042. return S_OK;
  1043. }
  1044. DWORD CBandSite::_GetWindowStyle(DWORD* pdwExStyle)
  1045. {
  1046. *pdwExStyle = WS_EX_TOOLWINDOW;
  1047. DWORD dwStyle = RBS_REGISTERDROP | RBS_VARHEIGHT | RBS_BANDBORDERS |
  1048. WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN |
  1049. WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN;
  1050. if (_dwStyle & BSIS_LEFTALIGN)
  1051. {
  1052. dwStyle |= RBS_VERTICALGRIPPER;
  1053. }
  1054. if (!(_dwStyle & BSIS_SINGLECLICK))
  1055. {
  1056. dwStyle |= RBS_DBLCLKTOGGLE;
  1057. }
  1058. return dwStyle;
  1059. }
  1060. HRESULT CBandSite::_Initialize(HWND hwndParent)
  1061. {
  1062. //
  1063. // I hope we have an IBandSite to talk to.
  1064. //
  1065. if (!_pbsOuter)
  1066. return E_FAIL;
  1067. if (!_hwnd)
  1068. {
  1069. DWORD dwExStyle;
  1070. DWORD dwStyle = _GetWindowStyle(&dwExStyle);
  1071. _hwnd = CreateWindowEx(dwExStyle, REBARCLASSNAME, NULL, dwStyle,
  1072. 0, 0, 0, 0, hwndParent, (HMENU) FCIDM_REBAR, HINST_THISDLL, NULL);
  1073. if (_hwnd)
  1074. {
  1075. SendMessage(_hwnd, RB_SETTEXTCOLOR, 0, CLR_DEFAULT);
  1076. SendMessage(_hwnd, RB_SETBKCOLOR, 0, CLR_DEFAULT);
  1077. SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  1078. }
  1079. }
  1080. return _hwnd ? S_OK : E_OUTOFMEMORY;
  1081. }
  1082. HRESULT CBandSite::SetDeskBarSite(IUnknown* punkSite)
  1083. {
  1084. HRESULT hr = S_OK;
  1085. if (!punkSite)
  1086. {
  1087. // Time to tell the bands to free their
  1088. // back pointers on us or we never get freed...
  1089. // 970325 for now bs::SetDeskBarSite(NULL) is 'overloaded'
  1090. // to mean do both a CloseDW and a SetSite.
  1091. // when we clean up our act and have a bs::Close iface
  1092. // we'll go back to the '#else' code below.
  1093. if (_hwnd)
  1094. _Close();
  1095. }
  1096. ATOMICRELEASE(_pct);
  1097. ATOMICRELEASE(_pdb);
  1098. ATOMICRELEASE(_punkSite);
  1099. if (_pbp && _fCreatedBandProxy)
  1100. _pbp->SetSite(punkSite);
  1101. if (punkSite)
  1102. {
  1103. _punkSite = punkSite;
  1104. _punkSite->AddRef();
  1105. if (!_hwnd)
  1106. {
  1107. HWND hwndParent;
  1108. IUnknown_GetWindow(punkSite, &hwndParent);
  1109. hr = _Initialize(hwndParent);
  1110. }
  1111. punkSite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &_pct));
  1112. punkSite->QueryInterface(IID_PPV_ARG(IDeskBar, &_pdb));
  1113. }
  1114. return hr;
  1115. }
  1116. HRESULT CBandSite::SetModeDBC(DWORD dwMode)
  1117. {
  1118. if (dwMode != _dwMode)
  1119. {
  1120. _dwMode = dwMode;
  1121. if (_hwnd)
  1122. {
  1123. DWORD dwStyle = 0;
  1124. if (dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
  1125. {
  1126. dwStyle |= CCS_VERT;
  1127. }
  1128. SHSetWindowBits(_hwnd, GWL_STYLE, CCS_VERT, dwStyle);
  1129. }
  1130. _UpdateAllBands(FALSE, FALSE);
  1131. }
  1132. return S_OK;
  1133. }
  1134. // }
  1135. IDropTarget* CBandSite::_WrapDropTargetForBand(IDropTarget* pdtBand)
  1136. {
  1137. if (!pdtBand || (_dwStyle & BSIS_NODROPTARGET))
  1138. {
  1139. // addref it for the new pointer
  1140. if (pdtBand)
  1141. pdtBand->AddRef();
  1142. return pdtBand;
  1143. }
  1144. else
  1145. {
  1146. return DropTargetWrap_CreateInstance(pdtBand, SAFECAST(this, IDropTarget*), _hwndDD);
  1147. }
  1148. }
  1149. LRESULT CBandSite::_OnNotify(LPNMHDR pnm)
  1150. {
  1151. NMOBJECTNOTIFY *pnmon = (NMOBJECTNOTIFY *)pnm;
  1152. switch (pnm->code)
  1153. {
  1154. case RBN_GETOBJECT:
  1155. {
  1156. pnmon->hResult = E_FAIL;
  1157. // if we're the drag source, then a band is dragging... we want to only
  1158. // give out the bandsite's drop target
  1159. if (pnmon->iItem != -1 && !_fDragSource)
  1160. {
  1161. LPBANDITEMDATA pbid = _GetBandItemDataStructByID(pnmon->iItem);
  1162. if (EVAL(pbid) && pbid->pdb)
  1163. {
  1164. pnmon->hResult = pbid->pdb->QueryInterface(*pnmon->piid, &pnmon->pObject);
  1165. // give a wrapped droptarget instead of the band's droptarget
  1166. if (IsEqualIID(*pnmon->piid, IID_IDropTarget))
  1167. {
  1168. IDropTarget* pdtBand;
  1169. BOOL fNeedReleasePdtBand = FALSE;
  1170. if (SUCCEEDED(pnmon->hResult))
  1171. {
  1172. pdtBand = (IDropTarget*)(pnmon->pObject);
  1173. }
  1174. else
  1175. {
  1176. CDropDummy *pdtgt = new CDropDummy(_hwndDD);
  1177. pdtBand = SAFECAST(pdtgt, IDropTarget*);
  1178. fNeedReleasePdtBand = TRUE;
  1179. }
  1180. IDropTarget* pdt = _WrapDropTargetForBand(pdtBand);
  1181. if (pdt)
  1182. {
  1183. pnmon->pObject = pdt;
  1184. pnmon->hResult = S_OK;
  1185. // we've handed off pdtBand to pdt
  1186. fNeedReleasePdtBand = TRUE;
  1187. }
  1188. if (fNeedReleasePdtBand && pdtBand)
  1189. pdtBand->Release();
  1190. }
  1191. if (FAILED(pnmon->hResult) && !(_dwStyle & BSIS_NODROPTARGET))
  1192. pnmon->hResult = QueryInterface(*pnmon->piid, &pnmon->pObject);
  1193. }
  1194. }
  1195. break;
  1196. }
  1197. case RBN_BEGINDRAG:
  1198. return _OnBeginDrag((NMREBAR*)pnm);
  1199. case RBN_AUTOSIZE:
  1200. _OnRBAutoSize((NMRBAUTOSIZE*)pnm);
  1201. break;
  1202. case RBN_CHEVRONPUSHED:
  1203. {
  1204. LPNMREBARCHEVRON pnmch = (LPNMREBARCHEVRON) pnm;
  1205. LPBANDITEMDATA pbid = _GetBandItem(pnmch->uBand);
  1206. if (EVAL(pbid))
  1207. {
  1208. MapWindowPoints(_hwnd, HWND_DESKTOP, (LPPOINT)&pnmch->rc, 2);
  1209. ToolbarMenu_Popup(_hwnd, &pnmch->rc, pbid->pdb, pbid->hwnd, 0, (DWORD)pnmch->lParamNM);
  1210. }
  1211. break;
  1212. }
  1213. case RBN_AUTOBREAK:
  1214. {
  1215. if (_dwStyle & BSIS_PREFERNOLINEBREAK)
  1216. {
  1217. Comctl32_FixAutoBreak(pnm);
  1218. }
  1219. break;
  1220. }
  1221. }
  1222. return 0;
  1223. }
  1224. void CBandSite::_OnRBAutoSize(NMRBAUTOSIZE* pnm)
  1225. {
  1226. // DRAG_MOVE: we turn off autosize during (most of) a move because
  1227. // fVertical is out of sync until the very end
  1228. if (_pdb && _GetBandItemCount() && _fDragging != DRAG_MOVE)
  1229. {
  1230. RECT rc;
  1231. int iHeightCur;
  1232. int iHeight = (int)SendMessage(_hwnd, RB_GETBARHEIGHT, 0, 0);
  1233. #ifdef DEBUG
  1234. DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  1235. #endif
  1236. GetWindowRect(_hwnd, &rc);
  1237. MapWindowRect(HWND_DESKTOP, GetParent(_hwnd), &rc);
  1238. if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
  1239. {
  1240. ASSERT((dwStyle & CCS_VERT));
  1241. iHeightCur = RECTWIDTH(rc);
  1242. rc.right = rc.left + iHeight;
  1243. }
  1244. else
  1245. {
  1246. ASSERT(!(dwStyle & CCS_VERT));
  1247. iHeightCur = RECTHEIGHT(rc);
  1248. rc.bottom = rc.top + iHeight;
  1249. }
  1250. if ((iHeightCur != iHeight) || (IsOS(OS_WHISTLERORGREATER)))
  1251. {
  1252. _pdb->OnPosRectChangeDB(&rc);
  1253. }
  1254. }
  1255. }
  1256. IDataObject* CBandSite::_DataObjForBand(DWORD dwBandID)
  1257. {
  1258. IDataObject* pdtobjReturn = NULL;
  1259. LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
  1260. if (EVAL(pbid) && pbid->pdb)
  1261. {
  1262. HRESULT hres;
  1263. CBandDataObject* pdtobj = new CBandDataObject();
  1264. if (pdtobj)
  1265. {
  1266. hres = pdtobj->Init(pbid->pdb, this, dwBandID);
  1267. if (SUCCEEDED(hres))
  1268. {
  1269. pdtobjReturn = pdtobj;
  1270. pdtobjReturn->AddRef();
  1271. }
  1272. pdtobj->Release();
  1273. }
  1274. }
  1275. return pdtobjReturn;
  1276. }
  1277. LRESULT CBandSite::_OnBeginDrag(NMREBAR* pnm)
  1278. {
  1279. LRESULT lres = 0;
  1280. DWORD dwBandID = _IndexToBandID(pnm->uBand);
  1281. IDataObject* pdtobj = _DataObjForBand(dwBandID);
  1282. ATOMICRELEASE(_pdtobj);
  1283. _uDragBand = pnm->uBand;
  1284. _pdtobj = pdtobj;
  1285. // because the RBN_BEGINDRAG is synchronous and so is SHDoDragDrop
  1286. // post this message to ourselves instead of calling dragdrop directly.
  1287. // note that we don't have a window of our own, so we post to our parent
  1288. // and let the message reflector send it back to us
  1289. PostMessage(GetParent(_hwnd), WM_COMMAND, MAKELONG(0, IDM_DRAGDROP), (LPARAM)_hwnd);
  1290. return 1;
  1291. }
  1292. // return TRUE if the user drags out of the rect of the rebar meaning that we should
  1293. // go into ole drag drop.
  1294. BOOL CBandSite::_PreDragDrop()
  1295. {
  1296. BOOL f = FALSE;
  1297. RECT rc;
  1298. POINT pt;
  1299. DWORD dwBandID = _IndexToBandID(_uDragBand); // Find the BandID before an reordering that may happen.
  1300. GetWindowRect(_hwnd, &rc);
  1301. SetCapture(_hwnd);
  1302. InflateRect(&rc, GetSystemMetrics(SM_CXEDGE) * 3, GetSystemMetrics(SM_CYEDGE) * 3);
  1303. while (GetCapture() == _hwnd)
  1304. {
  1305. MSG msg;
  1306. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1307. {
  1308. switch (msg.message)
  1309. {
  1310. case WM_MOUSEMOVE:
  1311. GetCursorPos(&pt);
  1312. if (!ISMOVEDDISABLED(dwBandID))
  1313. {
  1314. if (PtInRect(&rc, pt))
  1315. {
  1316. SendMessage(_hwnd, RB_DRAGMOVE, 0, (LPARAM)-1);
  1317. } else if (!ISDDCLOSEDISABLED(dwBandID) && _pdtobj)
  1318. {
  1319. // we've moved out of the bounds of the rebar.. switch to ole drag
  1320. f = TRUE;
  1321. SetCapture(NULL);
  1322. }
  1323. }
  1324. break;
  1325. case WM_LBUTTONUP:
  1326. case WM_LBUTTONDOWN:
  1327. case WM_MBUTTONUP:
  1328. case WM_MBUTTONDOWN:
  1329. case WM_RBUTTONUP:
  1330. case WM_RBUTTONDOWN:
  1331. // bail on any mouse button action
  1332. SetCapture(NULL);
  1333. break;
  1334. case WM_KEYDOWN:
  1335. switch (msg.wParam)
  1336. {
  1337. case VK_ESCAPE:
  1338. SetCapture(NULL);
  1339. break;
  1340. }
  1341. // fall through
  1342. default:
  1343. TranslateMessage(&msg);
  1344. DispatchMessage(&msg);
  1345. }
  1346. }
  1347. }
  1348. if (ISDDCLOSEDISABLED(dwBandID) || !_IsBandDeleteable(dwBandID))
  1349. {
  1350. /// if don't allow close, never return true for ole drag.
  1351. f = FALSE;
  1352. }
  1353. return f;
  1354. }
  1355. void CBandSite::_DoDragDrop()
  1356. {
  1357. DWORD dwBandID = _IndexToBandID(_uDragBand);
  1358. DWORD dwEffect = DROPEFFECT_MOVE;
  1359. _fDragSource = TRUE;
  1360. SendMessage(_hwnd, RB_BEGINDRAG, _uDragBand, (LPARAM)-2);
  1361. HRESULT hres = S_OK;
  1362. // first check to see if we even need to go into Ole drag, or if
  1363. // it can all be contained within the rebar
  1364. if (_PreDragDrop())
  1365. {
  1366. SHLoadOLE(SHELLNOTIFY_OLELOADED); // Browser Only - our shell32 doesn't know ole has been loaded
  1367. hres = SHDoDragDrop(_hwnd, _pdtobj, NULL, dwEffect, &dwEffect);
  1368. }
  1369. else
  1370. {
  1371. // if we kept it all within win32 dragging, then set no drop effect
  1372. dwEffect = DROPEFFECT_NONE;
  1373. }
  1374. SendMessage(_hwnd, RB_ENDDRAG, 0, 0);
  1375. _fDragSource = FALSE;
  1376. if (dwEffect & DROPEFFECT_MOVE)
  1377. {
  1378. RemoveBand(dwBandID);
  1379. }
  1380. else if (!dwEffect && hres == DRAGDROP_S_DROP)
  1381. {
  1382. // if the drop was done, but the target didn't allow
  1383. // then we float the band.
  1384. }
  1385. ATOMICRELEASE(_pdtobj);
  1386. }
  1387. HMENU CBandSite::_LoadContextMenu()
  1388. {
  1389. return LoadMenuPopup_PrivateNoMungeW(MENU_BANDSITE1);
  1390. }
  1391. HRESULT CBandSite::_OnBSCommand(int idCmd, DWORD idBandActive, LPBANDITEMDATA pbid)
  1392. {
  1393. HRESULT hr = S_OK;
  1394. switch (idCmd)
  1395. {
  1396. case BSIDM_CLOSEBAND:
  1397. _OnCloseBand(idBandActive);
  1398. break;
  1399. case BSIDM_SHOWTITLEBAND:
  1400. ASSERT(idBandActive != (DWORD)-1 && pbid);
  1401. if (pbid)
  1402. {
  1403. pbid->fNoTitle = !pbid->fNoTitle;
  1404. _UpdateBandInfo(pbid, FALSE);
  1405. }
  1406. break;
  1407. case BSIDM_IEAK_DISABLE_MOVE:
  1408. case BSIDM_IEAK_DISABLE_DDCLOSE:
  1409. ASSERT(idBandActive != (DWORD)-1);
  1410. if (idBandActive != (DWORD)-1)
  1411. {
  1412. static const int idCmds[] = { BSIDM_IEAK_DISABLE_MOVE, BSIDM_IEAK_DISABLE_DDCLOSE };
  1413. static const int idFlags[] = { BAND_ADMIN_NOMOVE, BAND_ADMIN_NODDCLOSE };
  1414. DWORD dwFlag = SHSearchMapInt(idCmds, idFlags, ARRAYSIZE(idCmds), idCmd);
  1415. DWORD dwAdminSettings = _GetAdminSettings(idBandActive);
  1416. // Toggle Setting.
  1417. ToggleFlag(dwAdminSettings, dwFlag);
  1418. // Set Menu Item Check Mark appropriately.
  1419. _SetAdminSettings(idBandActive, dwAdminSettings);
  1420. }
  1421. break;
  1422. default:
  1423. ASSERT(0);
  1424. hr = E_FAIL;
  1425. break;
  1426. }
  1427. return hr;
  1428. }
  1429. // returns the index of the band hit by lParam using context menu semantics (lParam == -1 for keyboard)
  1430. int CBandSite::_ContextMenuHittest(LPARAM lParam, POINT* ppt)
  1431. {
  1432. int iBandIndex;
  1433. if (lParam == (LPARAM) -1)
  1434. {
  1435. // Keyboard activation. Use active band.
  1436. DWORD dwBandID = _BandIDFromPunk(_ptbActive);
  1437. iBandIndex = _BandIDToIndex(dwBandID);
  1438. LPBANDITEMDATA pbid = _GetBandItem(iBandIndex);
  1439. if (pbid)
  1440. {
  1441. RECT rc;
  1442. GetWindowRect(pbid->hwnd, &rc);
  1443. ppt->x = rc.left;
  1444. ppt->y = rc.top;
  1445. }
  1446. }
  1447. else
  1448. {
  1449. // Mouse activation. Figure out which band got clicked.
  1450. RBHITTESTINFO rbht;
  1451. ppt->x = GET_X_LPARAM(lParam);
  1452. ppt->y = GET_Y_LPARAM(lParam);
  1453. rbht.pt = *ppt;
  1454. ScreenToClient(_hwnd, &rbht.pt);
  1455. SendMessage(_hwnd, RB_HITTEST, 0, (LPARAM)&rbht);
  1456. iBandIndex = rbht.iBand;
  1457. }
  1458. return iBandIndex;
  1459. }
  1460. HRESULT CBandSite::_OnContextMenu(WPARAM wParam, LPARAM lParam)
  1461. {
  1462. HRESULT hres = S_OK;
  1463. HMENU hmenu = CreatePopupMenu();
  1464. if (hmenu)
  1465. {
  1466. HRESULT hresT;
  1467. int idCmd = 1;
  1468. IContextMenu *pcm, *pcmParent = NULL, *pcmChild = NULL;
  1469. POINT pt;
  1470. int iBandIndex = _ContextMenuHittest(lParam, &pt);
  1471. // map rebar index to band id
  1472. // get band info for that band id
  1473. DWORD idBandActive = _IndexToBandID(iBandIndex);
  1474. LPBANDITEMDATA pbid = _GetBandItemDataStructByID(idBandActive);
  1475. //
  1476. // self (top)
  1477. //
  1478. int idCmdBS1 = idCmd;
  1479. HMENU hmenuMe = _LoadContextMenu();
  1480. if (hmenuMe)
  1481. {
  1482. BOOL fDeleteShowTitle = TRUE;
  1483. if (pbid && !(_dwStyle & BSIS_LOCKED))
  1484. {
  1485. DESKBANDINFO dbi;
  1486. CheckMenuItem(hmenuMe, BSIDM_SHOWTITLEBAND,
  1487. pbid->fNoTitle ? MF_BYCOMMAND|MF_UNCHECKED : MF_BYCOMMAND|MF_CHECKED);
  1488. dbi.dwMask = 0; // paranoia (and needed for taskband!)
  1489. _GetBandInfo(pbid, &dbi);
  1490. // make sure pbid in sync
  1491. ASSERT((dbi.dwMask & DBIM_TITLE) || pbid->fNoTitle);
  1492. if ((dbi.dwMask & DBIM_TITLE) && _IsEnableTitle(pbid))
  1493. {
  1494. fDeleteShowTitle = FALSE;
  1495. }
  1496. }
  1497. if (fDeleteShowTitle)
  1498. {
  1499. DeleteMenu(hmenuMe, BSIDM_SHOWTITLEBAND, MF_BYCOMMAND);
  1500. }
  1501. idCmd += Shell_MergeMenus(hmenu, hmenuMe, 0, idCmd, 0x7fff, 0) - (idCmd);
  1502. DestroyMenu(hmenuMe);
  1503. }
  1504. //
  1505. // child
  1506. //
  1507. int idCmdChild = idCmd;
  1508. if (pbid && pbid->pdb)
  1509. {
  1510. // merge in band's menu (at front)
  1511. hresT = pbid->pdb->QueryInterface(IID_PPV_ARG(IContextMenu, &pcmChild));
  1512. if (SUCCEEDED(hresT))
  1513. {
  1514. // 0=at front
  1515. hresT = pcmChild->QueryContextMenu(hmenu, 0, idCmd, 0x7fff, 0);
  1516. if (SUCCEEDED(hresT))
  1517. idCmd += HRESULT_CODE(hresT);
  1518. }
  1519. }
  1520. //
  1521. // self (bottom)
  1522. //
  1523. int idCmdBS2 = idCmd;
  1524. if (!(_dwStyle & BSIS_NOCONTEXTMENU))
  1525. {
  1526. hmenuMe = LoadMenuPopup_PrivateNoMungeW(MENU_BANDSITE2);
  1527. if (hmenuMe)
  1528. {
  1529. // disable 'Close Band' if it's marked undeleteable
  1530. // nash:17821: don't disable when 0 bands (so user can easily
  1531. // get out of toasted mode)
  1532. if ((idBandActive == (DWORD)-1) || // if mouse not over a band, delete close menu item
  1533. (!_IsBandDeleteable(idBandActive) ||
  1534. ISDDCLOSEDISABLED(idBandActive)) ||
  1535. (_dwStyle & BSIS_LOCKED))
  1536. {
  1537. DeleteMenu(hmenuMe, BSIDM_CLOSEBAND, MF_BYCOMMAND);
  1538. }
  1539. if (!_fIEAKInstalled)
  1540. {
  1541. DeleteMenu(hmenuMe, BSIDM_IEAK_DISABLE_DDCLOSE, MF_BYCOMMAND);
  1542. DeleteMenu(hmenuMe, BSIDM_IEAK_DISABLE_MOVE, MF_BYCOMMAND);
  1543. }
  1544. else
  1545. {
  1546. DWORD dwAdminSettings = _GetAdminSettings(idBandActive);
  1547. if (IsFlagSet(dwAdminSettings, BAND_ADMIN_NODDCLOSE))
  1548. _CheckMenuItem(hmenuMe, BSIDM_IEAK_DISABLE_DDCLOSE, TRUE);
  1549. if (IsFlagSet(dwAdminSettings, BAND_ADMIN_NOMOVE))
  1550. _CheckMenuItem(hmenuMe, BSIDM_IEAK_DISABLE_MOVE, TRUE);
  1551. }
  1552. idCmd += Shell_MergeMenus(hmenu, hmenuMe, (UINT) -1, idCmd, 0x7fff, 0) - (idCmd);
  1553. DestroyMenu(hmenuMe);
  1554. }
  1555. }
  1556. //
  1557. // parent
  1558. //
  1559. int idCmdParent = idCmd;
  1560. if (_punkSite)
  1561. {
  1562. UINT uFlags = 0;
  1563. ASSERT(_pcm3Parent == NULL);
  1564. if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcm3Parent))))
  1565. {
  1566. uFlags |= CMF_ICM3;
  1567. }
  1568. hresT = _punkSite->QueryInterface(IID_PPV_ARG(IContextMenu, &pcmParent));
  1569. if (SUCCEEDED(hresT))
  1570. {
  1571. // APPCOMPAT: fix parents and kids to handle...
  1572. // we'd like to pass in -1 but not everyone handles that.
  1573. // workaround: use _FixMenuIndex...
  1574. hresT = pcmParent->QueryContextMenu(hmenu, _FixMenuIndex(hmenu, -1), idCmd, 0x7fff, uFlags);
  1575. ASSERT(SUCCEEDED(hresT));
  1576. idCmd += HRESULT_CODE(hresT);
  1577. }
  1578. }
  1579. //
  1580. // do it
  1581. //
  1582. {
  1583. HWND hwndParent = GetParent(_hwnd);
  1584. if (!hwndParent)
  1585. hwndParent = _hwnd;
  1586. idCmd = TrackPopupMenu(hmenu,
  1587. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  1588. pt.x, pt.y, 0, hwndParent, NULL);
  1589. }
  1590. if (idCmd)
  1591. {
  1592. // must test from smallest to largest
  1593. ASSERT(idCmdBS1 <= idCmdChild);
  1594. ASSERT(idCmdChild <= idCmdBS2); // o.w. test in wrong order
  1595. ASSERT(idCmdBS2 <= idCmdParent);
  1596. if ((idCmd>= idCmdBS1) && (idCmd < idCmdChild))
  1597. {
  1598. idCmd -= idCmdBS1;
  1599. hres = _OnBSCommand(idCmd, idBandActive, pbid);
  1600. }
  1601. else if ((idCmd>= idCmdBS2) && (idCmd < idCmdParent))
  1602. {
  1603. idCmd -= idCmdBS2;
  1604. hres = _OnBSCommand(idCmd, idBandActive, pbid);
  1605. }
  1606. else
  1607. {
  1608. // A parent or child command
  1609. if (idCmd < idCmdParent)
  1610. {
  1611. pcm = pcmChild;
  1612. idCmd -= idCmdChild;
  1613. }
  1614. else
  1615. {
  1616. pcm = pcmParent;
  1617. idCmd -= idCmdParent;
  1618. }
  1619. ASSERT(pcm);
  1620. //
  1621. // Call InvokeCommand
  1622. //
  1623. CMINVOKECOMMANDINFOEX ici =
  1624. {
  1625. SIZEOF(CMINVOKECOMMANDINFOEX),
  1626. 0L,
  1627. _hwnd,
  1628. (LPSTR)MAKEINTRESOURCE(idCmd),
  1629. NULL, NULL,
  1630. SW_NORMAL,
  1631. };
  1632. hres = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
  1633. }
  1634. }
  1635. ATOMICRELEASE(_pcm3Parent);
  1636. if (pcmParent)
  1637. pcmParent->Release();
  1638. if (pcmChild)
  1639. pcmChild->Release();
  1640. DestroyMenu(hmenu);
  1641. }
  1642. return hres;
  1643. }
  1644. /*----------------------------------------------------------
  1645. Purpose: IWinEventHandler::OnWinEvent
  1646. Processes messages passed on from the bar. Forward
  1647. messages to the bands as appropriate.
  1648. */
  1649. HRESULT CBandSite::OnWinEvent(HWND h, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  1650. {
  1651. HRESULT hres = E_FAIL;
  1652. HWND hwnd = HWND_BROADCAST;
  1653. switch (uMsg)
  1654. {
  1655. case WM_WININICHANGE:
  1656. _UpdateAllBands(FALSE, FALSE);
  1657. goto L_WM_SYSCOLORCHANGE;
  1658. case WM_SYSCOLORCHANGE:
  1659. case WM_PALETTECHANGED:
  1660. L_WM_SYSCOLORCHANGE:
  1661. // propagate to rebar
  1662. if (_hwnd)
  1663. SendMessage(_hwnd, uMsg, wParam, lParam);
  1664. // by not returning here, it will get forwarded to the bands also...
  1665. break;
  1666. case WM_CONTEXTMENU:
  1667. // if it came from the keyboard, wParam is somewhat useless. it's always out hwnd
  1668. if (IS_WM_CONTEXTMENU_KEYBOARD(lParam))
  1669. hwnd = GetFocus();
  1670. else
  1671. hwnd = (HWND)wParam;
  1672. break;
  1673. case WM_COMMAND:
  1674. hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
  1675. break;
  1676. case WM_NOTIFY:
  1677. if (lParam)
  1678. hwnd = ((LPNMHDR)lParam)->hwndFrom;
  1679. break;
  1680. case WM_INITMENUPOPUP:
  1681. case WM_MEASUREITEM:
  1682. case WM_DRAWITEM:
  1683. case WM_MENUCHAR:
  1684. if (_pcm3Parent)
  1685. {
  1686. //
  1687. // If _pcm3Parent, then we've got a context menu up and
  1688. // an ICM3 client who might care about this message.
  1689. //
  1690. hwnd = _hwnd;
  1691. }
  1692. break;
  1693. default:
  1694. return E_FAIL;
  1695. }
  1696. LRESULT lres = 0;
  1697. if (hwnd)
  1698. {
  1699. if (_hwnd == hwnd)
  1700. {
  1701. // a message for us
  1702. switch (uMsg)
  1703. {
  1704. case WM_NOTIFY:
  1705. lres = _OnNotify((LPNMHDR)lParam);
  1706. hres = S_OK;
  1707. break;
  1708. case WM_COMMAND:
  1709. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1710. {
  1711. case IDM_DRAGDROP:
  1712. _DoDragDrop();
  1713. break;
  1714. }
  1715. break;
  1716. case WM_INITMENUPOPUP:
  1717. case WM_MEASUREITEM:
  1718. case WM_DRAWITEM:
  1719. case WM_MENUCHAR:
  1720. ASSERT(_pcm3Parent);
  1721. hres = _pcm3Parent->HandleMenuMsg2(uMsg, wParam, lParam, &lres);
  1722. break;
  1723. }
  1724. }
  1725. else
  1726. {
  1727. if (_SendToToolband(hwnd, uMsg, wParam, lParam, &lres))
  1728. hres = S_OK;
  1729. }
  1730. }
  1731. switch (uMsg)
  1732. {
  1733. case WM_WININICHANGE:
  1734. SendMessage(_hwnd, WM_SIZE, 0, 0);
  1735. break;
  1736. case WM_CONTEXTMENU:
  1737. if (!lres)
  1738. return _OnContextMenu(wParam, lParam);
  1739. break;
  1740. }
  1741. if (plres)
  1742. *plres = lres;
  1743. return hres;
  1744. }
  1745. HRESULT CBandSite_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  1746. {
  1747. CBandSite *pbs = new CBandSite(pUnkOuter);
  1748. if (pbs)
  1749. {
  1750. *ppunk = pbs->_GetInner();
  1751. return S_OK;
  1752. }
  1753. *ppunk = NULL;
  1754. return E_OUTOFMEMORY;
  1755. }
  1756. //*** CBandSite::IPersistStream*::* {
  1757. //
  1758. HRESULT CBandSite::GetClassID(CLSID *pClassID)
  1759. {
  1760. *pClassID = CLSID_RebarBandSite;
  1761. return S_OK;
  1762. }
  1763. HRESULT CBandSite::IsDirty(void)
  1764. {
  1765. ASSERT(0);
  1766. return S_FALSE; // FEATURE: never be dirty?
  1767. }
  1768. HRESULT CBandSite::_AddBand(IUnknown* punk)
  1769. {
  1770. if (_pbsOuter)
  1771. {
  1772. // Give the outer guy first crack
  1773. return _pbsOuter->AddBand(punk);
  1774. }
  1775. else
  1776. {
  1777. return AddBand(punk);
  1778. }
  1779. }
  1780. //
  1781. // Persisted CBandSite, use types that have fixes sizes
  1782. //
  1783. struct SBandSite
  1784. {
  1785. DWORD cbSize;
  1786. DWORD cbVersion;
  1787. DWORD cBands;
  1788. // ...followed by length-preceded bands
  1789. };
  1790. #define SBS_WOADMIN_VERSION 3 // Before we added admin settings.
  1791. #define SBS_VERSION 8
  1792. //*** CBandSite::Load, Save --
  1793. // DESCRIPTION
  1794. // for each band...
  1795. // Load Read (i); OLFS(obj)+AddBand; Read (rbbi); RB_SBI
  1796. // Save RB_GBI; Write(i); OSTS(obj)+nil ; Write(rbbi)
  1797. // NOTES
  1798. // FEATURE: needs error recovery
  1799. // WARNING: we might have done a CreateBand w/o an AddBand; if so our
  1800. // assumption about the rebar bands and the iunknowns being 'parallel'
  1801. // is bogus.
  1802. HRESULT CBandSite::Load(IStream *pstm)
  1803. {
  1804. HRESULT hres;
  1805. SBandSite sfoo;
  1806. hres = IStream_Read(pstm, &sfoo, SIZEOF(sfoo)); // pstm->Read
  1807. if (hres == S_OK)
  1808. {
  1809. if (!(sfoo.cbSize == SIZEOF(SBandSite) &&
  1810. (sfoo.cbVersion == SBS_VERSION || sfoo.cbVersion == SBS_WOADMIN_VERSION)))
  1811. {
  1812. hres = E_FAIL;
  1813. }
  1814. IBandSiteHelper *pbsh;
  1815. hres = QueryInterface(IID_PPV_ARG(IBandSiteHelper, &pbsh));
  1816. if (EVAL(SUCCEEDED(hres)))
  1817. {
  1818. BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  1819. for (DWORD i = 0; i < sfoo.cBands && SUCCEEDED(hres); ++i)
  1820. {
  1821. DWORD j;
  1822. hres = IStream_Read(pstm, &j, SIZEOF(j)); // pstm->Read
  1823. if (hres == S_OK)
  1824. {
  1825. if (j == i) // for sanity check
  1826. {
  1827. IUnknown* punk;
  1828. hres = pbsh->LoadFromStreamBS(pstm, IID_PPV_ARG(IUnknown, &punk));
  1829. if (SUCCEEDED(hres))
  1830. {
  1831. hres = _AddBand(punk);
  1832. if (SUCCEEDED(hres))
  1833. {
  1834. hres = _LoadBandInfo(pstm, i, sfoo.cbVersion);
  1835. }
  1836. punk->Release();
  1837. }
  1838. }
  1839. else
  1840. {
  1841. hres = E_FAIL;
  1842. }
  1843. }
  1844. }
  1845. SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
  1846. pbsh->Release();
  1847. }
  1848. _UpdateAllBands(FALSE, TRUE); // force refresh
  1849. }
  1850. return hres;
  1851. }
  1852. HRESULT CBandSite::Save(IStream *pstm, BOOL fClearDirty)
  1853. {
  1854. HRESULT hres;
  1855. SBandSite sfoo;
  1856. TraceMsg(DM_PERSIST, "cbs.s enter(this=%x pstm=%x) tell()=%x", this, pstm, DbStreamTell(pstm));
  1857. sfoo.cbSize = SIZEOF(SBandSite);
  1858. sfoo.cbVersion = SBS_VERSION;
  1859. sfoo.cBands = _GetBandItemCount();
  1860. TraceMsg(DM_PERSIST, "cdb.s: cbands=%d", sfoo.cBands);
  1861. hres = pstm->Write(&sfoo, SIZEOF(sfoo), NULL);
  1862. if (SUCCEEDED(hres))
  1863. {
  1864. for (DWORD i = 0; i < sfoo.cBands; i++)
  1865. {
  1866. // FEATURE: put seek ptr so can resync after bogus streams
  1867. hres = pstm->Write(&i, SIZEOF(i), NULL); // for sanity check
  1868. if (SUCCEEDED(hres))
  1869. {
  1870. LPBANDITEMDATA pbid = _GetBandItem(i);
  1871. if (EVAL(pbid) && pbid->pdb)
  1872. {
  1873. IBandSiteHelper *pbsh;
  1874. hres = QueryInterface(IID_PPV_ARG(IBandSiteHelper, &pbsh));
  1875. if (SUCCEEDED(hres))
  1876. {
  1877. hres = pbsh->SaveToStreamBS(SAFECAST(pbid->pdb, IUnknown*), pstm);
  1878. pbsh->Release();
  1879. }
  1880. }
  1881. hres = _SaveBandInfo(pstm, i);
  1882. ASSERT(SUCCEEDED(hres));
  1883. }
  1884. }
  1885. }
  1886. TraceMsg(DM_PERSIST, "cbs.s leave tell()=%x", DbStreamTell(pstm));
  1887. return hres;
  1888. }
  1889. HRESULT CBandSite::GetSizeMax(ULARGE_INTEGER *pcbSize)
  1890. {
  1891. static const ULARGE_INTEGER cbMax = { SIZEOF(SBandSite), 0 };
  1892. *pcbSize = cbMax;
  1893. return S_OK;
  1894. }
  1895. BOOL CBandSite::_IsHeightReasonable(UINT cy)
  1896. {
  1897. static UINT s_cyMon = 0;
  1898. if (s_cyMon == 0)
  1899. {
  1900. HMONITOR hmon = MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST);
  1901. if (hmon)
  1902. {
  1903. RECT rc;
  1904. if (GetMonitorRect(hmon, &rc))
  1905. {
  1906. s_cyMon = RECTHEIGHT(rc);
  1907. }
  1908. }
  1909. }
  1910. return (s_cyMon != 0) ? (cy < 4 * s_cyMon) : TRUE;
  1911. }
  1912. // returns: IStream::Read() semantics, S_OK means complete read
  1913. HRESULT CBandSite::_LoadBandInfo(IStream *pstm, int i, DWORD dwVersion)
  1914. {
  1915. PERSISTBANDINFO bi;
  1916. HRESULT hres;
  1917. DWORD dwSize = SIZEOF(bi);
  1918. bi.dwAdminSettings = BAND_ADMIN_NORMAL; // Assume Normal since it's not specified
  1919. if (SBS_WOADMIN_VERSION == dwVersion)
  1920. dwSize = SIZEOF(PERSISTBANDINFO_V3);
  1921. hres = IStream_Read(pstm, &bi, dwSize); // pstm->Read
  1922. if (hres == S_OK)
  1923. {
  1924. //
  1925. // Sanity-check the height specified by PERSISTBANDINFO before proceeding.
  1926. // Some people are hitting a stress scenario where a bad height gets
  1927. // persisted out. If the height is not reasonable, then just discard
  1928. // the sizing values (leaving the defaults in place).
  1929. //
  1930. if (_IsHeightReasonable(bi.cyChild))
  1931. {
  1932. REBARBANDINFO rbbi;
  1933. rbbi.cbSize = SIZEOF(rbbi);
  1934. rbbi.fMask = RBBIM_XPERSIST;
  1935. rbbi.cx = bi.cx;
  1936. rbbi.fStyle = bi.fStyle;
  1937. // these things can change from instantiation to instantiation.
  1938. // we want to restore the visual state, not the sizing rules.
  1939. // the sizing rules re retreived each time in getbandinfo
  1940. rbbi.cyMinChild = -1;
  1941. rbbi.cyMaxChild = -1;
  1942. rbbi.cyIntegral = -1;
  1943. rbbi.cxMinChild = -1;
  1944. if (rbbi.fStyle & RBBS_VARIABLEHEIGHT)
  1945. {
  1946. rbbi.cyChild = bi.cyChild;
  1947. }
  1948. else
  1949. {
  1950. rbbi.cyMinChild = bi.cyMinChild;
  1951. }
  1952. SendMessage(_hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi);
  1953. }
  1954. LPBANDITEMDATA pbid = _GetBandItem(i);
  1955. if (pbid)
  1956. {
  1957. pbid->dwAdminSettings = bi.dwAdminSettings;
  1958. pbid->fNoTitle = bi.fNoTitle;
  1959. }
  1960. }
  1961. return hres;
  1962. }
  1963. HRESULT CBandSite::_SaveBandInfo(IStream *pstm, int i)
  1964. {
  1965. REBARBANDINFO rbbi = {0};
  1966. PERSISTBANDINFO bi = {0};
  1967. LPBANDITEMDATA pbid;
  1968. rbbi.cbSize = SIZEOF(rbbi);
  1969. rbbi.fMask = RBBIM_XPERSIST;
  1970. SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi);
  1971. ASSERT((rbbi.fMask & RBBIM_XPERSIST) == RBBIM_XPERSIST);
  1972. bi.cx = rbbi.cx;
  1973. bi.fStyle = rbbi.fStyle;
  1974. bi.cyMinChild = rbbi.cyMinChild;
  1975. bi.cyChild = rbbi.cyChild;
  1976. pbid = _GetBandItem(i);
  1977. if (pbid)
  1978. {
  1979. bi.dwAdminSettings = pbid->dwAdminSettings;
  1980. bi.fNoTitle = pbid->fNoTitle;
  1981. }
  1982. return pstm->Write(&bi, SIZEOF(bi), NULL);
  1983. }
  1984. void CBandSite::_CacheActiveBand(IUnknown *ptb)
  1985. {
  1986. if (ptb == _ptbActive)
  1987. return;
  1988. if (SHIsSameObject(ptb, _ptbActive))
  1989. return;
  1990. ATOMICRELEASE(_ptbActive);
  1991. if (ptb != NULL)
  1992. {
  1993. #ifdef DEBUG
  1994. // better be an IInputObject or else why did you call us?
  1995. IInputObject *pio;
  1996. if (EVAL(SUCCEEDED(ptb->QueryInterface(IID_PPV_ARG(IInputObject, &pio)))))
  1997. pio->Release();
  1998. // overly strict, but in our case it's true...
  1999. IDeskBand *pdb;
  2000. if (EVAL(SUCCEEDED(ptb->QueryInterface(IID_PPV_ARG(IDeskBand, &pdb)))))
  2001. pdb->Release();
  2002. #endif
  2003. _ptbActive = ptb;
  2004. _ptbActive->AddRef();
  2005. }
  2006. return;
  2007. }
  2008. DWORD CBandSite::_BandIDFromPunk(IUnknown* punk)
  2009. {
  2010. DWORD dwBandID = -1;
  2011. DWORD dwBandIDTest;
  2012. int cBands = EnumBands(-1, NULL);
  2013. IUnknown* punkTest;
  2014. if (punk)
  2015. {
  2016. for (int i = 0; i < cBands; i++)
  2017. {
  2018. if (SUCCEEDED(EnumBands(i, &dwBandIDTest)))
  2019. {
  2020. if (SUCCEEDED(GetBandObject(dwBandIDTest, IID_PPV_ARG(IUnknown, &punkTest))))
  2021. {
  2022. BOOL fEq = SHIsSameObject(punk, punkTest);
  2023. punkTest->Release();
  2024. if (fEq)
  2025. {
  2026. dwBandID = dwBandIDTest;
  2027. break;
  2028. }
  2029. }
  2030. }
  2031. }
  2032. }
  2033. return dwBandID;
  2034. }
  2035. //*** IInputObjectSite methods ***
  2036. HRESULT CBandSite::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
  2037. {
  2038. if (_ptbActive)
  2039. {
  2040. if (!SHIsSameObject(_ptbActive, punk))
  2041. {
  2042. // Deactivate current band since the current band is
  2043. // not the caller
  2044. TraceMsg(TF_ACCESSIBILITY, "CBandSite::OnFocusChangeIS (hwnd=0x%08X) deactivate band", _hwnd);
  2045. UIActivateIO(FALSE, NULL);
  2046. }
  2047. }
  2048. if (fSetFocus)
  2049. _CacheActiveBand(punk);
  2050. return IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), fSetFocus);
  2051. }
  2052. //*** IInputObject methods ***
  2053. HRESULT CBandSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
  2054. {
  2055. HRESULT hres = E_FAIL;
  2056. TraceMsg(TF_ACCESSIBILITY, "CBandSite::UIActivateIO (hwnd=0x%08X) fActivate=%d", _hwnd, fActivate);
  2057. ASSERT(NULL == lpMsg || IS_VALID_WRITE_PTR(lpMsg, MSG));
  2058. if (_ptbActive)
  2059. {
  2060. hres = IUnknown_UIActivateIO(_ptbActive, fActivate, lpMsg);
  2061. }
  2062. else
  2063. {
  2064. hres = OnFocusChangeIS(NULL, fActivate);
  2065. }
  2066. if (fActivate)
  2067. {
  2068. if (!_ptbActive)
  2069. {
  2070. if (IsVK_TABCycler(lpMsg))
  2071. hres = _CycleFocusBS(lpMsg);
  2072. else
  2073. hres = S_OK;
  2074. }
  2075. }
  2076. else
  2077. {
  2078. _CacheActiveBand(NULL);
  2079. }
  2080. return hres;
  2081. }
  2082. HRESULT CBandSite::HasFocusIO()
  2083. {
  2084. // Rebar should never get focus
  2085. // NT #288832 Is one case where (GetFocus() == _hwnd)
  2086. // which is caused when the "Folder Bar" disappears.
  2087. // CExplorerBand::ShowDW() calls ShowWindow(hwndTreeView, SW_HIDE)
  2088. // which by default sets focus to the parent (us).
  2089. // This is ok because when this function is called,
  2090. // it will return E_FAIL which the caller will treat
  2091. // as S_FALSE and give the focus to the next deserving
  2092. // dude in line.
  2093. return IUnknown_HasFocusIO(_ptbActive);
  2094. }
  2095. HRESULT CBandSite::TranslateAcceleratorIO(LPMSG lpMsg)
  2096. {
  2097. TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) key=%d", _hwnd, lpMsg->wParam);
  2098. if (IUnknown_TranslateAcceleratorIO(_ptbActive, lpMsg) == S_OK)
  2099. {
  2100. TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) key=%d; handled by active band", _hwnd, lpMsg->wParam);
  2101. // active band handled it
  2102. return S_OK;
  2103. }
  2104. else if (IsVK_TABCycler(lpMsg))
  2105. {
  2106. TraceMsg(TF_ACCESSIBILITY, "CBandSite::TranslateAcceleratorIO (hwnd=0x%08X) cycle focus", _hwnd);
  2107. // it's a tab; cycle focus
  2108. return _CycleFocusBS(lpMsg);
  2109. }
  2110. return S_FALSE;
  2111. }
  2112. int CBandSite::_BandIndexFromPunk(IUnknown *punk)
  2113. {
  2114. for (int i = 0; i < _GetBandItemCount(); i++)
  2115. {
  2116. LPBANDITEMDATA pbid = _GetBandItem(i);
  2117. if (EVAL(pbid) && SHIsSameObject(pbid->pdb, punk))
  2118. return i;
  2119. }
  2120. return -1;
  2121. }
  2122. BOOL CBandSite::_IsBandTabstop(LPBANDITEMDATA pbid)
  2123. {
  2124. // A band is a tabstop if it is visible and has WS_TABSTOP
  2125. if (pbid->fShow && pbid->hwnd && IsWindowVisible(pbid->hwnd))
  2126. {
  2127. if (WS_TABSTOP & GetWindowStyle(pbid->hwnd))
  2128. return TRUE;
  2129. }
  2130. return FALSE;
  2131. }
  2132. #define INCDEC(i, fDec) (fDec ? i - 1 : i + 1)
  2133. IUnknown* CBandSite::_GetNextTabstopBand(IUnknown* ptb, BOOL fBackwards)
  2134. {
  2135. // Find the first tabstop candidate
  2136. int iBandCount = _GetBandItemCount();
  2137. int iBand = _BandIndexFromPunk(ptb);
  2138. if (iBand == -1)
  2139. {
  2140. // Start at the end/beginning
  2141. if (fBackwards)
  2142. iBand = iBandCount - 1;
  2143. else
  2144. iBand = 0;
  2145. }
  2146. else
  2147. {
  2148. // Start one off the current band
  2149. iBand = INCDEC(iBand, fBackwards);
  2150. }
  2151. // Loop til we find a tabstop band or we run off the end
  2152. while (0 <= iBand && iBand < iBandCount)
  2153. {
  2154. LPBANDITEMDATA pbid = _GetBandItem(iBand);
  2155. if (EVAL(pbid))
  2156. {
  2157. if (_IsBandTabstop(pbid))
  2158. return pbid->pdb;
  2159. }
  2160. // Try the next band
  2161. iBand = INCDEC(iBand, fBackwards);
  2162. }
  2163. return NULL;
  2164. }
  2165. HRESULT CBandSite::_CycleFocusBS(LPMSG lpMsg)
  2166. {
  2167. HRESULT hr = S_FALSE;
  2168. IUnknown* ptbSave = NULL;
  2169. if (_ptbActive)
  2170. {
  2171. // Save off the active band in ptbSave
  2172. ptbSave = _ptbActive;
  2173. ptbSave->AddRef();
  2174. // Deactivate active band and clear cache
  2175. IUnknown_UIActivateIO(_ptbActive, FALSE, NULL);
  2176. _CacheActiveBand(NULL);
  2177. }
  2178. if (ptbSave && IsVK_CtlTABCycler(lpMsg))
  2179. {
  2180. // If ctl-tab and a band was active, then reject focus
  2181. ASSERT(hr == S_FALSE);
  2182. }
  2183. else
  2184. {
  2185. BOOL fShift = (GetKeyState(VK_SHIFT) < 0);
  2186. // Loop til we find a tabstop and successfully activate it
  2187. // or til we run out of bands.
  2188. // FEATURE: todo -- call SetFocus if UIActivateIO fails?
  2189. IUnknown* ptbNext = ptbSave;
  2190. while (ptbNext = _GetNextTabstopBand(ptbNext, fShift))
  2191. {
  2192. if (IUnknown_UIActivateIO(ptbNext, TRUE, lpMsg) == S_OK)
  2193. {
  2194. hr = S_OK;
  2195. break;
  2196. }
  2197. }
  2198. }
  2199. ATOMICRELEASE(ptbSave);
  2200. return hr;
  2201. }
  2202. //*** CBandSite::IBandSiteHelper::* {
  2203. // stuff to make it possible to overload the OleLoad/Save stuff so the
  2204. // taskbar band does not have to be CoCreat able. kinda a hack...
  2205. HRESULT CBandSite::LoadFromStreamBS(IStream *pstm, REFIID riid, void **ppv)
  2206. {
  2207. return OleLoadFromStream(pstm, riid, ppv);
  2208. }
  2209. HRESULT CBandSite::SaveToStreamBS(IUnknown *punk, IStream *pstm)
  2210. {
  2211. IPersistStream *ppstm;
  2212. HRESULT hres = punk->QueryInterface(IID_PPV_ARG(IPersistStream, &ppstm));
  2213. if (SUCCEEDED(hres))
  2214. {
  2215. hres = OleSaveToStream(ppstm, pstm);
  2216. ppstm->Release();
  2217. }
  2218. return hres;
  2219. }
  2220. // }
  2221. // *** IDropTarget *** {
  2222. HRESULT CBandSite::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  2223. {
  2224. TraceMsg(TF_BANDDD, "CBandSite::DragEnter %d %d", pt.x, pt.y);
  2225. if (!_fDragSource)
  2226. {
  2227. FORMATETC fmte = {g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
  2228. _dwDropEffect = DROPEFFECT_NONE;
  2229. if (pdtobj->QueryGetData(&fmte) == S_OK)
  2230. {
  2231. _dwDropEffect = DROPEFFECT_MOVE;
  2232. }
  2233. else
  2234. {
  2235. LPITEMIDLIST pidl;
  2236. if (SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
  2237. {
  2238. ASSERT(pidl && IS_VALID_PIDL(pidl));
  2239. DWORD dwAttrib = SFGAO_FOLDER | SFGAO_BROWSABLE;
  2240. IEGetAttributesOf(pidl, &dwAttrib);
  2241. ILFree(pidl);
  2242. DWORD dwRAction;
  2243. if (FAILED(IUnknown_HandleIRestrict(_punkSite, &RID_RDeskBars, RA_DROP, NULL, &dwRAction)))
  2244. dwRAction = RR_ALLOW;
  2245. if (dwRAction == RR_DISALLOW)
  2246. _dwDropEffect = DROPEFFECT_NONE;
  2247. else
  2248. {
  2249. // if it's not a folder nor a browseable object, we can't host it.
  2250. if ((dwAttrib & SFGAO_FOLDER) ||
  2251. (dwAttrib & SFGAO_BROWSABLE) && (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT))
  2252. _dwDropEffect = DROPEFFECT_LINK | DROPEFFECT_COPY;
  2253. _dwDropEffect |= GetPreferedDropEffect(pdtobj);
  2254. }
  2255. }
  2256. }
  2257. *pdwEffect &= _dwDropEffect;
  2258. }
  2259. return S_OK;
  2260. }
  2261. HRESULT CBandSite::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  2262. {
  2263. TraceMsg(TF_BANDDD, "CBandSite::DragOver %d %d", ptl.x, ptl.y);
  2264. if (_fDragSource)
  2265. {
  2266. RECT rc;
  2267. POINT pt;
  2268. pt.x = ptl.x;
  2269. pt.y = ptl.y;
  2270. GetWindowRect(_hwnd, &rc);
  2271. if (PtInRect(&rc, pt))
  2272. SendMessage(_hwnd, RB_DRAGMOVE, 0, (LPARAM)-1);
  2273. }
  2274. else
  2275. {
  2276. *pdwEffect &= _dwDropEffect;
  2277. }
  2278. return S_OK;
  2279. }
  2280. HRESULT CBandSite::DragLeave(void)
  2281. {
  2282. return S_OK;
  2283. }
  2284. HRESULT CBandSite::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  2285. {
  2286. HRESULT hres = E_FAIL;
  2287. TraceMsg(TF_BANDDD, "CBandSite::Drop");
  2288. if (_fDragSource)
  2289. {
  2290. SendMessage(_hwnd, RB_ENDDRAG, 0, 0);
  2291. *pdwEffect = DROPEFFECT_NONE;
  2292. hres = S_OK;
  2293. }
  2294. else
  2295. {
  2296. FORMATETC fmte = {g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
  2297. STGMEDIUM stg;
  2298. IUnknown *punk = NULL;
  2299. LPITEMIDLIST pidl;
  2300. // if it was an object of our type, create it!
  2301. if ((*pdwEffect & DROPEFFECT_MOVE) &&
  2302. SUCCEEDED(pdtobj->GetData(&fmte, &stg)))
  2303. {
  2304. hres = OleLoadFromStream(stg.pstm, IID_PPV_ARG(IUnknown, &punk));
  2305. if (SUCCEEDED(hres))
  2306. {
  2307. *pdwEffect = DROPEFFECT_MOVE;
  2308. }
  2309. ReleaseStgMedium(&stg);
  2310. }
  2311. else if ((*pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_LINK)) &&
  2312. SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
  2313. {
  2314. hres = SHCreateBandForPidl(pidl, &punk, (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT));
  2315. ILFree(pidl);
  2316. if (SUCCEEDED(hres))
  2317. {
  2318. if (*pdwEffect & DROPEFFECT_LINK)
  2319. *pdwEffect = DROPEFFECT_LINK;
  2320. else
  2321. *pdwEffect = DROPEFFECT_COPY;
  2322. }
  2323. }
  2324. if (punk)
  2325. {
  2326. hres = _AddBand(punk);
  2327. if (SUCCEEDED(hres))
  2328. {
  2329. DWORD dwState;
  2330. dwState = IDataObject_GetDeskBandState(pdtobj);
  2331. SetBandState(ShortFromResult(hres), BSSF_NOTITLE, dwState & BSSF_NOTITLE);
  2332. }
  2333. punk->Release();
  2334. }
  2335. }
  2336. if (FAILED(hres))
  2337. *pdwEffect = DROPEFFECT_NONE;
  2338. return hres;
  2339. }
  2340. // }
  2341. //*** ::_MergeBS -- merge two bandsites into one
  2342. // ENTRY/EXIT
  2343. // pdtDst [INOUT] destination DropTarget (always from bandsite)
  2344. // pbsSrc [INOUT] source bandsite; deleted if all bands moved successfully
  2345. // ret S_OK if all bands moved; S_FALSE if some moved; E_* o.w.
  2346. // NOTES
  2347. // note that if all the bands are moved successfully, pbsSrc will be deleted
  2348. // as a side-effect.
  2349. // pdtDst is assumed to accept multiple drops (bandsite does).
  2350. // pdtDst may be from marshal/unmarshal (tray bandsite).
  2351. HRESULT _MergeBS(IDropTarget *pdtDst, IBandSite *pbsSrc)
  2352. {
  2353. HRESULT hres = E_FAIL;
  2354. DWORD idBand;
  2355. pbsSrc->AddRef(); // don't go away until we're all done!
  2356. // drag each band in turn
  2357. while (SUCCEEDED(pbsSrc->EnumBands(0, &idBand)))
  2358. {
  2359. // note our (bogus?) assumption that bands which can't be
  2360. // dragged will percolate down to a contiguous range of
  2361. // iBands 0..n. if that's bogus i'm not sure how we can
  2362. // keep track of where we are.
  2363. IDataObject *pdoSrc;
  2364. hres = pbsSrc->GetBandObject(idBand, IID_PPV_ARG(IDataObject, &pdoSrc));
  2365. if (SUCCEEDED(hres))
  2366. {
  2367. DWORD dwEffect = DROPEFFECT_MOVE | DROPEFFECT_COPY;
  2368. hres = SHSimulateDrop(pdtDst, pdoSrc, 0, NULL, &dwEffect);
  2369. pdoSrc->Release();
  2370. if (SUCCEEDED(hres) && (dwEffect & DROPEFFECT_MOVE))
  2371. {
  2372. hres = pbsSrc->RemoveBand(idBand);
  2373. ASSERT(SUCCEEDED(hres));
  2374. }
  2375. }
  2376. // we failed to move the band, bail
  2377. if (FAILED(hres))
  2378. {
  2379. ASSERT(0);
  2380. break;
  2381. }
  2382. }
  2383. pbsSrc->Release();
  2384. TraceMsg(DM_DRAG, "dba.ms: ret hres=%x", hres);
  2385. return hres;
  2386. }
  2387. void CBandSite::_BandItemEnumCallback(int dincr, PFNBANDITEMENUMCALLBACK pfnCB, void *pv)
  2388. {
  2389. UINT iFirst = 0;
  2390. ASSERT(dincr == 1 || dincr == -1);
  2391. if (dincr < 0)
  2392. {
  2393. iFirst = _GetBandItemCount() - 1; // start from last
  2394. }
  2395. for (UINT i = iFirst; i < (UINT) _GetBandItemCount(); i += dincr)
  2396. {
  2397. LPBANDITEMDATA pbid = _GetBandItem(i);
  2398. if (pbid && !pfnCB(pbid, pv))
  2399. break;
  2400. }
  2401. }
  2402. void CBandSite::_DeleteAllBandItems()
  2403. {
  2404. for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  2405. {
  2406. LPBANDITEMDATA pbid = _GetBandItem(i);
  2407. // Release the banditem data first, while it can still
  2408. // receive cleanup notifications from its control. *Then*
  2409. // delete the band item.
  2410. if (pbid)
  2411. _ReleaseBandItemData(pbid, i);
  2412. // REARCHITECT: chrisfra 5/13/97 if you skip deleting, rebar can
  2413. // rearrange on delete, moving a band so that it is never seen
  2414. // and consequently we leak BrandBand and much else
  2415. _DeleteBandItem(i); // unhook from host (rebar)
  2416. }
  2417. }
  2418. LPBANDITEMDATA CBandSite::_GetBandItem(int i)
  2419. {
  2420. REBARBANDINFO rbbi;
  2421. rbbi.cbSize = SIZEOF(rbbi);
  2422. rbbi.fMask = RBBIM_LPARAM;
  2423. rbbi.lParam = NULL; // in case of failure below
  2424. if (_hwnd)
  2425. SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi);
  2426. return (LPBANDITEMDATA)rbbi.lParam;
  2427. }
  2428. int CBandSite::_GetBandItemCount()
  2429. {
  2430. int cel = 0;
  2431. if (_hwnd)
  2432. {
  2433. ASSERT(IS_VALID_HANDLE(_hwnd, WND));
  2434. cel = (int)SendMessage(_hwnd, RB_GETBANDCOUNT, 0, 0);
  2435. }
  2436. return cel;
  2437. }
  2438. void CBandSite::_GetBandInfo(LPBANDITEMDATA pbid, DESKBANDINFO *pdbi)
  2439. {
  2440. pdbi->dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
  2441. pdbi->ptMinSize = pbid->ptMinSize;
  2442. pdbi->ptMaxSize = pbid->ptMaxSize;
  2443. pdbi->ptIntegral = pbid->ptIntegral;
  2444. pdbi->ptActual = pbid->ptActual;
  2445. StrCpyW(pdbi->wszTitle, pbid->szTitle);
  2446. pdbi->dwModeFlags = pbid->dwModeFlags;
  2447. pdbi->crBkgnd = pbid->crBkgnd;
  2448. if (pbid->pdb)
  2449. {
  2450. pbid->pdb->GetBandInfo(pbid->dwBandID, _dwMode, pdbi);
  2451. }
  2452. if (pdbi->wszTitle[0] == 0)
  2453. {
  2454. pdbi->dwMask &= ~DBIM_TITLE;
  2455. }
  2456. pbid->ptMinSize = pdbi->ptMinSize;
  2457. pbid->ptMaxSize = pdbi->ptMaxSize;
  2458. pbid->ptIntegral = pdbi->ptIntegral;
  2459. pbid->ptActual = pdbi->ptActual;
  2460. StrCpyW(pbid->szTitle, pdbi->wszTitle);
  2461. pbid->dwModeFlags = pdbi->dwModeFlags;
  2462. pbid->crBkgnd = pdbi->crBkgnd;
  2463. if (!(pdbi->dwMask & DBIM_TITLE)) // title not supported
  2464. pbid->fNoTitle = TRUE;
  2465. ASSERT(pdbi->dwModeFlags & DBIMF_VARIABLEHEIGHT ? pbid->ptIntegral.y : TRUE);
  2466. }
  2467. void CBandSite::_BandInfoFromBandItem(REBARBANDINFO *prbbi, LPBANDITEMDATA pbid, BOOL fBSOnly)
  2468. {
  2469. // REVIEW: could be optimized more
  2470. DESKBANDINFO dbi;
  2471. if (!fBSOnly)
  2472. _GetBandInfo(/*INOUT*/ pbid, &dbi);
  2473. // now add the view as a band in the rebar
  2474. // add links band
  2475. prbbi->fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_IDEALSIZE | RBBIM_TEXT;
  2476. if (fBSOnly)
  2477. prbbi->fMask = RBBIM_STYLE|RBBIM_TEXT;
  2478. // clear the bits the are band settable
  2479. prbbi->fStyle |= RBBS_FIXEDBMP;
  2480. prbbi->fStyle &= ~(RBBS_NOGRIPPER | RBBS_GRIPPERALWAYS | RBBS_VARIABLEHEIGHT | RBBS_USECHEVRON);
  2481. if (_dwStyle & BSIS_NOGRIPPER)
  2482. prbbi->fStyle |= RBBS_NOGRIPPER;
  2483. else if (_dwStyle & BSIS_ALWAYSGRIPPER)
  2484. prbbi->fStyle |= RBBS_GRIPPERALWAYS;
  2485. else
  2486. {
  2487. // BSIS_AUTOGRIPPER...
  2488. if (!(prbbi->fStyle & RBBS_FIXEDSIZE) &&
  2489. !(_dwMode & DBIF_VIEWMODE_FLOATING))
  2490. prbbi->fStyle |= RBBS_GRIPPERALWAYS;
  2491. }
  2492. if (pbid->dwModeFlags & DBIMF_VARIABLEHEIGHT)
  2493. prbbi->fStyle |= RBBS_VARIABLEHEIGHT;
  2494. if (pbid->dwModeFlags & DBIMF_USECHEVRON)
  2495. prbbi->fStyle |= RBBS_USECHEVRON;
  2496. if (pbid->dwModeFlags & DBIMF_BREAK)
  2497. prbbi->fStyle |= RBBS_BREAK;
  2498. if (pbid->dwModeFlags & DBIMF_TOPALIGN)
  2499. prbbi->fStyle |= RBBS_TOPALIGN;
  2500. if (!fBSOnly)
  2501. {
  2502. prbbi->hwndChild = pbid->hwnd;
  2503. prbbi->wID = pbid->dwBandID;
  2504. // set up the geometries
  2505. prbbi->cxMinChild = pbid->ptMinSize.x;
  2506. prbbi->cyMinChild = pbid->ptMinSize.y;
  2507. prbbi->cyMaxChild = pbid->ptMaxSize.y;
  2508. prbbi->cyIntegral = pbid->ptIntegral.y;
  2509. if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
  2510. {
  2511. // after we're up, it's the "ideal" point
  2512. prbbi->cxIdeal = pbid->ptActual.y;
  2513. }
  2514. else
  2515. {
  2516. // after we're up, it's the "ideal" point
  2517. prbbi->cxIdeal = pbid->ptActual.x;
  2518. }
  2519. if (prbbi->cxIdeal == (UINT)-1)
  2520. prbbi->cxIdeal = 0;
  2521. if (pbid->dwModeFlags & DBIMF_BKCOLOR)
  2522. {
  2523. if (dbi.dwMask & DBIM_BKCOLOR)
  2524. {
  2525. prbbi->fMask |= RBBIM_COLORS;
  2526. prbbi->clrFore = CLR_DEFAULT;
  2527. prbbi->clrBack = dbi.crBkgnd;
  2528. }
  2529. }
  2530. ASSERT(pbid->fNoTitle || (dbi.dwMask & DBIM_TITLE)); // pbid in sync?
  2531. }
  2532. SHUnicodeToTChar(pbid->szTitle, prbbi->lpText, prbbi->cch);
  2533. if (!pbid->fNoTitle && _IsEnableTitle(pbid) && !(_dwStyle & BSIS_NOCAPTION))
  2534. {
  2535. prbbi->fStyle &= ~RBBS_HIDETITLE;
  2536. }
  2537. else
  2538. {
  2539. // No text please
  2540. prbbi->fStyle |= RBBS_HIDETITLE;
  2541. }
  2542. // Make this band a tabstop. Itbar will override v_SetTabstop
  2543. // since for the browser we don't want every band to be a tabstop.
  2544. v_SetTabstop(prbbi);
  2545. }
  2546. void CBandSite::v_SetTabstop(LPREBARBANDINFO prbbi)
  2547. {
  2548. // We specify that a band should be a tabstop by setting the WS_TABSTOP
  2549. // bit. Never make RBBS_FIXEDSIZE bands (i.e., the brand) tabstops.
  2550. if (prbbi && prbbi->hwndChild && !(prbbi->fStyle & RBBS_FIXEDSIZE))
  2551. SHSetWindowBits(prbbi->hwndChild, GWL_STYLE, WS_TABSTOP, WS_TABSTOP);
  2552. }
  2553. //*** cbs::_IsEnableTitle -- should we enable (ungray) title
  2554. // DESCRIPTION
  2555. // used for handing back title and for enabling menu
  2556. // NOTES
  2557. // pbid unused...
  2558. //
  2559. #ifndef UNIX
  2560. _inline
  2561. #endif
  2562. BOOL CBandSite::_IsEnableTitle(LPBANDITEMDATA pbid)
  2563. {
  2564. ASSERT(pbid);
  2565. return (/*pbid && !pbid->fNoTitle &&*/
  2566. !((_dwMode & DBIF_VIEWMODE_FLOATING) && _GetBandItemCount() <= 1));
  2567. }
  2568. BOOL CBandSite::_UpdateBandInfo(LPBANDITEMDATA pbid, BOOL fBSOnly)
  2569. {
  2570. REBARBANDINFO rbbi = {SIZEOF(rbbi)};
  2571. int iRB = _BandIDToIndex(pbid->dwBandID);
  2572. // now update the info
  2573. rbbi.fMask = RBBIM_ID | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
  2574. if (fBSOnly)
  2575. rbbi.fMask = RBBIM_STYLE;
  2576. SendMessage(_hwnd, RB_GETBANDINFO, iRB, (LPARAM)&rbbi);
  2577. if (!fBSOnly)
  2578. {
  2579. if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
  2580. {
  2581. pbid->ptActual.x = rbbi.cyChild;
  2582. pbid->ptActual.y = rbbi.cxIdeal;
  2583. }
  2584. else
  2585. {
  2586. pbid->ptActual.x = rbbi.cxIdeal;
  2587. pbid->ptActual.y = rbbi.cyChild;
  2588. }
  2589. pbid->ptMinSize.x = rbbi.cxMinChild;
  2590. pbid->ptMinSize.y = rbbi.cyMinChild;
  2591. pbid->ptMaxSize.y = rbbi.cyMaxChild;
  2592. }
  2593. TCHAR szBand[40];
  2594. rbbi.lpText = szBand;
  2595. rbbi.cch = ARRAYSIZE(szBand);
  2596. _BandInfoFromBandItem(&rbbi, pbid, fBSOnly);
  2597. return BOOLFROMPTR(SendMessage(_hwnd, RB_SETBANDINFO, (UINT)iRB, (LPARAM)&rbbi));
  2598. }
  2599. BOOL CBandSite::_AddBandItem(LPBANDITEMDATA pbid)
  2600. {
  2601. REBARBANDINFO rbbi = {SIZEOF(rbbi)};
  2602. pbid->ptActual.x = -1;
  2603. pbid->ptActual.y = -1;
  2604. TCHAR szBand[40];
  2605. rbbi.lpText = szBand;
  2606. rbbi.cch = ARRAYSIZE(szBand);
  2607. _BandInfoFromBandItem(&rbbi, pbid, FALSE);
  2608. rbbi.cyChild = pbid->ptActual.y;
  2609. rbbi.fMask |= RBBIM_LPARAM;
  2610. rbbi.lParam = (LPARAM)pbid;
  2611. ASSERT(rbbi.fMask & RBBIM_ID);
  2612. return BOOLFROMPTR(SendMessage(_hwnd, RB_INSERTBAND, (UINT) (pbid->dwModeFlags & DBIMF_ADDTOFRONT) ? 0 : -1, (LPARAM)&rbbi));
  2613. }
  2614. void CBandSite::_DeleteBandItem(int i)
  2615. {
  2616. SendMessage(_hwnd, RB_DELETEBAND, i, 0);
  2617. }
  2618. DWORD CBandSite::_IndexToBandID(int i)
  2619. {
  2620. REBARBANDINFO rbbi = {SIZEOF(rbbi)};
  2621. rbbi.fMask = RBBIM_ID;
  2622. if (SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi))
  2623. return rbbi.wID;
  2624. else
  2625. return -1;
  2626. }
  2627. /*----------------------------------------------------------
  2628. Purpose: Given the band ID, returns the internal band index.
  2629. */
  2630. int CBandSite::_BandIDToIndex(DWORD dwBandID)
  2631. {
  2632. int nRet = -1;
  2633. if (_hwnd)
  2634. nRet = (int)SendMessage(_hwnd, RB_IDTOINDEX, (WPARAM) dwBandID, (LPARAM) 0);
  2635. return nRet;
  2636. }
  2637. /*----------------------------------------------------------
  2638. Purpose: The Parent Site may want to override what the admin
  2639. specified.
  2640. Return Values:
  2641. S_OK: Do lock band.
  2642. S_FALSE: Do NOT Lock band.
  2643. */
  2644. HRESULT CBandSite::_IsRestricted(DWORD dwBandID, DWORD dwRestrictAction, DWORD dwBandFlags)
  2645. {
  2646. HRESULT hr;
  2647. DWORD dwRestrictionAction;
  2648. hr = IUnknown_HandleIRestrict(_punkSite, &RID_RDeskBars, dwRestrictAction, NULL, &dwRestrictionAction);
  2649. if (RR_NOCHANGE == dwRestrictionAction) // If our parent didn't handle it, we will.
  2650. dwRestrictionAction = IsFlagSet(_GetAdminSettings(dwBandID), dwBandFlags) ? RR_DISALLOW : RR_ALLOW;
  2651. if (RR_DISALLOW == dwRestrictionAction)
  2652. hr = S_OK;
  2653. else
  2654. hr = S_FALSE;
  2655. ASSERT(SUCCEEDED(hr)); // FAIL(hr) other than hr == E_NOTIMPLE; is not good.
  2656. return hr;
  2657. }
  2658. BOOL ConfirmRemoveBand(HWND hwnd, UINT uID, LPCTSTR pszName)
  2659. {
  2660. TCHAR szTemp[1024], *pszTemp2, *pszStr, szTitle[80];
  2661. BOOL bRet = TRUE;
  2662. DWORD dwLen;
  2663. MLLoadString(IDS_CONFIRMCLOSETITLE, szTitle, ARRAYSIZE(szTitle));
  2664. // Calling FormatMessage with FORMAT_MESSAGE_FROM_HMODULE fails
  2665. MLLoadString(uID, szTemp, ARRAYSIZE(szTemp));
  2666. dwLen = (lstrlen(szTemp) + lstrlen(pszName) + 1) * sizeof(TCHAR);
  2667. if((pszTemp2 = (TCHAR *)LocalAlloc(LPTR, dwLen)) != NULL)
  2668. {
  2669. _FormatMessage(szTemp, pszTemp2, dwLen, pszName);
  2670. MLLoadString(IDS_CONFIRMCLOSETEXT, szTemp, ARRAYSIZE(szTemp));
  2671. dwLen = (lstrlen(szTemp) + lstrlen(pszTemp2) + 1) * sizeof(TCHAR);
  2672. if((pszStr = (TCHAR *)LocalAlloc(LPTR, dwLen)) != NULL)
  2673. {
  2674. _FormatMessage(szTemp, pszStr, dwLen, pszTemp2);
  2675. bRet = (IDOK == SHMessageBoxCheck(hwnd, pszStr, szTitle, MB_OKCANCEL, IDOK, TEXT("WarnBeforeCloseBand")));
  2676. LocalFree(pszStr);
  2677. }
  2678. LocalFree(pszTemp2);
  2679. }
  2680. return bRet;
  2681. }