Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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