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.

2621 lines
74 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "iface.h"
  4. #include "itbdrop.h"
  5. #include "sftbar.h"
  6. #include "resource.h"
  7. #include "dpastuff.h"
  8. #include "shlwapi.h"
  9. #include "cobjsafe.h"
  10. #include <iimgctx.h>
  11. #include "uemapp.h"
  12. #include "mluisupp.h"
  13. extern UINT g_idFSNotify;
  14. #define TF_SFTBAR 0x10000000 // Same ID as the AugMISF stuff
  15. #define PGMP_RECALCSIZE 200
  16. // do not set CMD_ID_FIRST to 0. we use this to see if anything is selected
  17. #define CMD_ID_FIRST 1
  18. #define CMD_ID_LAST 0x7fff
  19. CSFToolbar::CSFToolbar()
  20. {
  21. #ifdef CASCADE_DEBUG
  22. _fCascadeFolder = TRUE;
  23. #endif
  24. _dwStyle = TBSTYLE_TOOLTIPS;
  25. _fDirty = TRUE; // we havn't enumerated, so our state is dirty
  26. _fRegisterChangeNotify = TRUE;
  27. _fAllowReorder = TRUE;
  28. _tbim.iButton = -1;
  29. _iDragSource = -1;
  30. _lEvents = SHCNE_DRIVEADD|SHCNE_CREATE|SHCNE_MKDIR|SHCNE_DRIVEREMOVED|
  31. SHCNE_DELETE|SHCNE_RMDIR|SHCNE_RENAMEITEM|SHCNE_RENAMEFOLDER|
  32. SHCNE_MEDIAINSERTED|SHCNE_MEDIAREMOVED|SHCNE_NETUNSHARE|SHCNE_NETSHARE|
  33. SHCNE_UPDATEITEM|SHCNE_UPDATEIMAGE|SHCNE_ASSOCCHANGED|
  34. SHCNE_UPDATEDIR|SHCNE_EXTENDED_EVENT;
  35. }
  36. CSFToolbar::~CSFToolbar()
  37. {
  38. ATOMICRELEASE(_pcmSF);
  39. _ReleaseShellFolder();
  40. ILFree(_pidl);
  41. ASSERT(NULL == _hdpa);
  42. if (_hwndWorkerWindow)
  43. DestroyWindow(_hwndWorkerWindow);
  44. OrderList_Destroy(&_hdpaOrder);
  45. }
  46. HRESULT CSFToolbar::QueryInterface(REFIID riid, void **ppvObj)
  47. {
  48. static const QITAB qit[] = {
  49. QITABENT(CSFToolbar, IWinEventHandler),
  50. QITABENT(CSFToolbar, IShellChangeNotify),
  51. QITABENT(CSFToolbar, IDropTarget),
  52. QITABENT(CSFToolbar, IContextMenu),
  53. QITABENT(CSFToolbar, IShellFolderBand),
  54. { 0 },
  55. };
  56. return QISearch(this, qit, riid, ppvObj);
  57. }
  58. HRESULT CSFToolbar::SetShellFolder(IShellFolder* psf, LPCITEMIDLIST pidl)
  59. {
  60. HRESULT hres = E_INVALIDARG;
  61. // Save the old values
  62. LPITEMIDLIST pidlSave = _pidl;
  63. IShellFolder *psfSave = _psf;
  64. ITranslateShellChangeNotify *ptscnSave = _ptscn;
  65. _psf = NULL;
  66. _pidl = NULL;
  67. _ptscn = NULL;
  68. ASSERT(NULL == psf || IS_VALID_CODE_PTR(psf, IShellFolder));
  69. ASSERT(NULL == pidl || IS_VALID_PIDL(pidl));
  70. if (psf || pidl)
  71. {
  72. if (psf)
  73. {
  74. _psf = psf;
  75. _psf->AddRef();
  76. _psf->QueryInterface(IID_ITranslateShellChangeNotify, (LPVOID *)&_ptscn);
  77. }
  78. if (pidl)
  79. _pidl = ILClone(pidl);
  80. hres = S_OK;
  81. }
  82. if (SUCCEEDED(hres))
  83. {
  84. ILFree(pidlSave);
  85. if (psfSave)
  86. psfSave->Release();
  87. if (ptscnSave)
  88. ptscnSave->Release();
  89. }
  90. else
  91. {
  92. ASSERT(_psf == NULL);
  93. ASSERT(_pidl == NULL);
  94. ASSERT(_ptscn == NULL);
  95. // we failed -- restore the old values
  96. _psf = psfSave;
  97. _pidl = pidlSave;
  98. _ptscn = ptscnSave;
  99. }
  100. // This code is here for ShellFolderToolbar reuse. When setting a new shell folder
  101. // into an existing band, we will refresh. Note that this is a noop on a new band.
  102. _RememberOrder();
  103. _SetDirty(TRUE);
  104. if (_fShow)
  105. _FillToolbar();
  106. return hres;
  107. }
  108. HWND CSFToolbar::_CreatePager(HWND hwndParent)
  109. {
  110. if (!_fMulticolumn)
  111. {
  112. _hwndPager = CreateWindowEx(0, WC_PAGESCROLLER, NULL,
  113. WS_CHILD | WS_TABSTOP |
  114. WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  115. 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
  116. if (_hwndPager)
  117. {
  118. hwndParent = _hwndPager;
  119. }
  120. }
  121. return hwndParent;
  122. }
  123. void CSFToolbar::_CreateToolbar(HWND hwndParent)
  124. {
  125. if (!_hwndTB)
  126. {
  127. hwndParent = _CreatePager(hwndParent);
  128. _hwndTB = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL,
  129. WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
  130. WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  131. CCS_NODIVIDER | CCS_NOPARENTALIGN |
  132. CCS_NORESIZE | _dwStyle,
  133. 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
  134. if (_hwndPager)
  135. SendMessage(_hwndPager, PGM_SETCHILD, 0, (LPARAM)_hwndTB);
  136. if (!_hwndTB)
  137. {
  138. TraceMsg(TF_ERROR, "_hwndTB failed");
  139. return;
  140. }
  141. SendMessage(_hwndTB, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
  142. // Set the format to ANSI or UNICODE as appropriate.
  143. ToolBar_SetUnicodeFormat(_hwndTB, DLL_IS_UNICODE);
  144. if (_hwndPager)
  145. {
  146. // Set the format to ANSI or UNICODE as appropriate.
  147. ToolBar_SetUnicodeFormat(_hwndPager, DLL_IS_UNICODE);
  148. }
  149. #if 0 // Not going to do this for IE5.
  150. ToolBar_SetExtendedStyle(_hwndTB,
  151. TBSTYLE_EX_HIDECLIPPEDBUTTONS,
  152. TBSTYLE_EX_HIDECLIPPEDBUTTONS);
  153. #endif
  154. // Make sure we're on the same wavelength.
  155. SendMessage(_hwndTB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  156. RECT rc;
  157. SIZE size;
  158. SystemParametersInfoA(SPI_GETWORKAREA, SIZEOF(RECT), &rc, FALSE);
  159. if (!_hwndPager)
  160. {
  161. size.cx = RECTWIDTH(rc);
  162. size.cy = GetSystemMetrics(SM_CYSCREEN) - (2 * GetSystemMetrics(SM_CYEDGE)); // Need to subrtact off the borders
  163. }
  164. else
  165. {
  166. //HACKHACK: THIS WILL FORCE NO WRAP TO HAPPEN FOR PROPER WIDTH CALC WHEN PAGER IS PRESENT.
  167. size.cx = RECTWIDTH(rc);
  168. size.cy = 32000;
  169. }
  170. ToolBar_SetBoundingSize(_hwndTB, &size);
  171. }
  172. else
  173. {
  174. if (_hwndPager && GetParent(_hwndPager) != hwndParent)
  175. SetParent(_hwndPager, hwndParent);
  176. }
  177. if (FAILED(_GetTopBrowserWindow(&_hwndDD)))
  178. _hwndDD = GetParent(_hwndTB);
  179. }
  180. #define MAX_COMMANDID 0xFFFF // We're allowed one word of command ids (tested at 5)
  181. int CSFToolbar::_GetCommandID()
  182. {
  183. int id = -1;
  184. if (!_fCheckIds)
  185. {
  186. id = _nNextCommandID++;
  187. }
  188. else
  189. {
  190. // We are reusing command ids and must verify that
  191. // the current one is not in use. This is slow, but
  192. // I assume the number of buttons on one of these
  193. // bands is relatively few.
  194. //
  195. for (int i = 0 ; i <= MAX_COMMANDID ; i++)
  196. {
  197. TBBUTTONINFO tbbiDummy = {0};
  198. tbbiDummy.cbSize = SIZEOF(tbbiDummy);
  199. tbbiDummy.dwMask = 0; // we don't care about data, just existence
  200. if (-1 != ToolBar_GetButtonInfo(_hwndTB, _nNextCommandID, &tbbiDummy))
  201. {
  202. // A button by this id wasn't found, so the id must be free
  203. //
  204. id = _nNextCommandID++;
  205. break;
  206. }
  207. _nNextCommandID++;
  208. _nNextCommandID %= MAX_COMMANDID;
  209. }
  210. }
  211. if (_nNextCommandID > MAX_COMMANDID)
  212. {
  213. _nNextCommandID = 0;
  214. _fCheckIds = TRUE;
  215. }
  216. return(id);
  217. }
  218. /*----------------------------------------------------------
  219. Purpose: This function determines the toolbar button style for the
  220. given pidl.
  221. Returns S_OK if pdwMIFFlags is also set (i.e., the object
  222. supported IMenuBandItem to provide more info). S_FALSE if only
  223. *pdwTBStyle is set.
  224. */
  225. HRESULT CSFToolbar::_TBStyleForPidl(LPCITEMIDLIST pidl,
  226. DWORD * pdwTBStyle, DWORD* pdwTBState, DWORD * pdwMIFFlags,int* piIcon)
  227. {
  228. HRESULT hres = S_FALSE;
  229. DWORD dwStyle = TBSTYLE_BUTTON;
  230. if (!_fAccelerators)
  231. dwStyle |= TBSTYLE_NOPREFIX;
  232. *pdwMIFFlags = 0;
  233. *pdwTBStyle = dwStyle;
  234. *piIcon = -1;
  235. *pdwTBState = TBSTATE_ENABLED;
  236. return hres;
  237. }
  238. PIBDATA CSFToolbar::_CreateItemData(PORDERITEM poi)
  239. {
  240. return new IBDATA(poi);
  241. }
  242. PIBDATA CSFToolbar::_AddOrderItemTB(PORDERITEM poi, int index, TBBUTTON* ptbb)
  243. {
  244. TCHAR szName[MAX_PATH];
  245. // We need to do this even for NULL because _ObtainPIDLName cooks
  246. // up the word "(Empty)" as necessary.
  247. _ObtainPIDLName(poi ? poi->pidl : NULL, szName, SIZECHARS(szName));
  248. TBBUTTON tbb = {0};
  249. DWORD dwMIFFlags;
  250. DWORD dwStyle;
  251. DWORD dwState;
  252. int iIcon;
  253. int iCommandID = _GetCommandID();
  254. BOOL bNoIcon = FALSE;
  255. if (!ptbb)
  256. ptbb = &tbb;
  257. if (S_OK == _TBStyleForPidl(poi ? poi->pidl : NULL, &dwStyle, &dwState, &dwMIFFlags,&iIcon) &&
  258. !(dwMIFFlags & SMIF_ICON))
  259. {
  260. bNoIcon = TRUE;
  261. }
  262. PIBDATA pibdata = _CreateItemData(poi);
  263. if (pibdata)
  264. {
  265. pibdata->SetFlags(dwMIFFlags);
  266. pibdata->SetNoIcon(bNoIcon);
  267. if(!bNoIcon && iIcon != -1)
  268. ptbb->iBitmap = iIcon;
  269. else
  270. ptbb->iBitmap = I_IMAGECALLBACK;
  271. ptbb->idCommand = iCommandID;
  272. ptbb->fsState = (BYTE)dwState;
  273. ptbb->fsStyle = (BYTE)dwStyle;
  274. ptbb->dwData = (DWORD_PTR)pibdata;
  275. ptbb->iString = (INT_PTR)szName;
  276. // Disregard variablewidth if we are vertical
  277. if (_fVariableWidth && !_fVertical)
  278. ptbb->fsStyle |= TBSTYLE_AUTOSIZE;
  279. if (ptbb->idCommand != -1)
  280. {
  281. if (SendMessage(_hwndTB, TB_INSERTBUTTON, index, (LPARAM)ptbb))
  282. {
  283. TraceMsg(TF_BAND, "SFToolbar::_AddPidl %d 0x%x [%s]", ptbb->idCommand, ptbb->dwData, ptbb->iString);
  284. }
  285. else
  286. {
  287. delete pibdata;
  288. pibdata = NULL;
  289. }
  290. }
  291. }
  292. return pibdata;
  293. }
  294. void CSFToolbar::_ObtainPIDLName(LPCITEMIDLIST pidl, LPTSTR psz, int cchMax)
  295. {
  296. STRRET strret;
  297. if SUCCEEDED(_psf->GetDisplayNameOf(pidl, SHGDN_NORMAL, &strret))
  298. {
  299. StrRetToBuf(&strret, pidl, psz, cchMax);
  300. }
  301. }
  302. int CSFToolbar::_GetBitmap(int iCommandID, PIBDATA pibdata, BOOL fUseCache)
  303. {
  304. int iBitmap;
  305. if(_fNoIcons || pibdata->GetNoIcon())
  306. iBitmap = -1;
  307. else
  308. {
  309. iBitmap = OrderItem_GetSystemImageListIndex(pibdata->GetOrderItem(), _psf, fUseCache);
  310. }
  311. return iBitmap;
  312. }
  313. void CSFToolbar::_OnGetDispInfo(LPNMHDR pnm, BOOL fUnicode)
  314. {
  315. LPNMTBDISPINFO pdi = (LPNMTBDISPINFO)pnm;
  316. PIBDATA pibdata = (PIBDATA)pdi->lParam;
  317. LPITEMIDLIST pidl = pibdata->GetPidl();
  318. if(pdi->dwMask & TBNF_IMAGE)
  319. {
  320. pdi->iImage = _GetBitmap(pdi->idCommand, pibdata, TRUE);
  321. }
  322. if(pdi->dwMask & TBNF_TEXT) {
  323. if(pdi->pszText) {
  324. if(fUnicode) {
  325. pdi->pszText[0] = TEXT('\0');
  326. }else {
  327. pdi->pszText[0] = 0;
  328. }
  329. }
  330. }
  331. pdi->dwMask |= TBNF_DI_SETITEM;
  332. return;
  333. }
  334. // Adds pidl as a new button, handles ILFree(pidl) for the caller
  335. //
  336. BOOL CSFToolbar::_AddPidl(LPITEMIDLIST pidl, int index)
  337. {
  338. if (_hdpa)
  339. {
  340. PORDERITEM poi = OrderItem_Create(pidl, index);
  341. if (poi)
  342. {
  343. int iPos = DPA_InsertPtr(_hdpa, index, poi);
  344. if (-1 != iPos)
  345. {
  346. // If we did not load an order, then new items should
  347. // show up alphabetically in the list, not at the bottom.
  348. if (!_fHasOrder)
  349. {
  350. // Sort by name
  351. _SortDPA(_hdpa);
  352. // Find the index of the order item. We use this index as
  353. // the toolbar insert index.
  354. index = DPA_GetPtrIndex(_hdpa, poi);
  355. }
  356. if (_AddOrderItemTB(poi, index, NULL))
  357. {
  358. return TRUE;
  359. }
  360. DPA_DeletePtr(_hdpa, iPos);
  361. }
  362. OrderItem_Free(poi);
  363. return FALSE;
  364. }
  365. }
  366. ILFree(pidl);
  367. return FALSE;
  368. }
  369. BOOL CSFToolbar::_FilterPidl(LPCITEMIDLIST pidl)
  370. {
  371. return FALSE;
  372. }
  373. void CSFToolbar::s_NewItem(LPVOID pvParam, LPCITEMIDLIST pidl)
  374. {
  375. CSFToolbar* psft = (CSFToolbar*)pvParam;
  376. psft->v_NewItem(pidl);
  377. }
  378. HRESULT CSFToolbar::_GetIEnumIDList(DWORD dwEnumFlags, IEnumIDList **ppenum)
  379. {
  380. ASSERT(_psf);
  381. // Pass in a NULL hwnd so the enumerator does not show any UI while
  382. // we're filling a band.
  383. return IShellFolder_EnumObjects(_psf, NULL, dwEnumFlags, ppenum);
  384. }
  385. void CSFToolbar::_FillDPA(HDPA hdpa, HDPA hdpaSort, DWORD dwEnumFlags)
  386. {
  387. IEnumIDList* penum;
  388. int cItems = 0;
  389. BOOL f9x = IsOS(OS_WINDOWS);
  390. if (!_psf)
  391. return;
  392. if (SUCCEEDED(_GetIEnumIDList(dwEnumFlags, &penum)))
  393. {
  394. LPITEMIDLIST pidl;
  395. ULONG ul;
  396. while (S_OK == penum->Next(1, &pidl, &ul))
  397. {
  398. cItems++;
  399. if (_FilterPidl(pidl) || !OrderList_Append(hdpa, pidl, -1))
  400. {
  401. TraceMsg(TF_MENUBAND, "SFToolbar (0x%x)::_FillDPA : Did not Add Pidl (0x%x).", this, pidl);
  402. ILFree(pidl);
  403. }
  404. // Windows 9x issue
  405. if (cItems > 1000 && f9x)
  406. {
  407. // Here's the deal:
  408. // When enumerating NTdev, we have 10,000 items. If each item is 20 pixels
  409. // long, we end up with 200,000 pixels. Windows can only display 32,000 pixels,
  410. // or 1,600 items in the default case. I'm limiting to 1,000 items = 20,000 so that
  411. // we have some room for reasonable font sizes.
  412. break;
  413. }
  414. }
  415. penum->Release();
  416. }
  417. ORDERINFO oinfo;
  418. int iInsertIndex = _tbim.iButton + 1; // This is the button where the cursor sat.
  419. // So, We want to insert after that
  420. if (iInsertIndex >= ToolBar_ButtonCount(_hwndTB)) // But, if it's at the end,
  421. iInsertIndex = -1; // Convert the insert to an append.
  422. // - Comments in rhyme by lamadio
  423. oinfo.psf = _psf;
  424. (oinfo.psf)->AddRef();
  425. oinfo.dwSortBy = (_fHasOrder || _fDropping)? ((_fNoNameSort ? OI_SORTBYORDINAL : OI_SORTBYNAME)): OI_MERGEBYNAME;
  426. OrderList_Merge(hdpa, hdpaSort, _fDropping ? iInsertIndex : _DefaultInsertIndex(), (LPARAM) &oinfo,
  427. s_NewItem, (LPVOID)this);
  428. ATOMICRELEASE(oinfo.psf);
  429. }
  430. // This function re-enumerates the IShellFolder, keeping things ordered correctly.
  431. // At some point it may reduce flicker by not removing buttons that don't change.
  432. //
  433. void CSFToolbar::_FillToolbar()
  434. {
  435. HDPA hdpaSort;
  436. HDPA hdpa;
  437. if (!_fDirty || !_psf)
  438. return;
  439. // If we have an order array, use that, otherwise
  440. // use the currently viewed items
  441. if (_hdpaOrder)
  442. hdpaSort = _hdpaOrder; // already sorted by name
  443. else
  444. {
  445. hdpaSort = _hdpa;
  446. _SortDPA(hdpaSort);
  447. }
  448. hdpa = DPA_Create(hdpaSort ? DPA_GetPtrCount(hdpaSort) : 12);
  449. if (hdpa)
  450. {
  451. _FillDPA(hdpa, hdpaSort, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS);
  452. // NOTE: if many buttons were moved at the same time
  453. // the notifications may be spread out as the files
  454. // are copied and we'd only insert the first time.
  455. // This is probably okay.
  456. //
  457. _fDropping = FALSE;
  458. // For the case of dragging a new item into the band (or one
  459. // just showing up) we could re-sort _hdpa by ordinal (which
  460. // would match the current button order), and iterate through hdpa
  461. // to see where a button needs to be inserted or removed.
  462. // This would be way less flicker and toolbar painting
  463. // than always blowing away the current buttons and reinserting them...
  464. //
  465. // For now be lazy and do extra work.
  466. //
  467. // remove buttons and replace _hdpa with hdpa
  468. if (_hdpa)
  469. {
  470. EmptyToolbar();
  471. ASSERT(!_hdpa);
  472. }
  473. _hdpa = hdpa;
  474. SendMessage(_hwndTB, WM_SETREDRAW, FALSE, 0);
  475. // add buttons back in
  476. DEBUG_CODE( BOOL bFailed = FALSE; )
  477. int i = 0;
  478. while (i < DPA_GetPtrCount(_hdpa))
  479. {
  480. PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i);
  481. // ASSERT(bFailed || poi->nOrder == i);
  482. if (_AddOrderItemTB(poi, -1, NULL))
  483. {
  484. i++;
  485. }
  486. else
  487. {
  488. DPA_DeletePtr(_hdpa, i);
  489. DEBUG_CODE( bFailed = TRUE; )
  490. }
  491. }
  492. }
  493. SendMessage(_hwndTB, WM_SETREDRAW, TRUE, 0);
  494. // if we used an _hdpaOrder then we don't need it any more
  495. OrderList_Destroy(&_hdpaOrder);
  496. _UpdateButtons();
  497. _SetDirty(FALSE);
  498. _ToolbarChanged();
  499. TraceMsg(TF_BAND, "SFToolbar::_FillToolbar found %d items", DPA_GetPtrCount(_hdpa));
  500. }
  501. void CSFToolbar::EmptyToolbar()
  502. {
  503. if (_hwndTB)
  504. {
  505. TraceMsg(TF_BAND, "SFToolbar::EmptyToolbar %d items", _hdpa ? DPA_GetPtrCount(_hdpa) : 0);
  506. while (InlineDeleteButton(0))
  507. {
  508. // delete the buttons
  509. }
  510. }
  511. OrderList_Destroy(&_hdpa);
  512. _fDirty = TRUE;
  513. _nNextCommandID = 0;
  514. }
  515. void CSFToolbar::_SetDirty(BOOL fDirty)
  516. {
  517. _fDirty = fDirty;
  518. }
  519. UINT CSFToolbar::_IndexToID(int iIndex)
  520. {
  521. TBBUTTON tbb;
  522. if (SendMessage(_hwndTB, TB_GETBUTTON, iIndex, (LPARAM)&tbb))
  523. {
  524. return tbb.idCommand;
  525. }
  526. return (UINT)-1;
  527. }
  528. // if ptbbi is specified, dwMask must be filled in
  529. //
  530. LPITEMIDLIST CSFToolbar::_GetButtonFromPidl(LPCITEMIDLIST pidl, TBBUTTONINFO * ptbbi, int * pIndex)
  531. {
  532. int i;
  533. if (!_hdpa)
  534. return NULL;
  535. for (i = DPA_GetPtrCount(_hdpa)-1 ; i >= 0 ; i--)
  536. {
  537. HRESULT hres;
  538. PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i);
  539. ASSERT(poi);
  540. if (poi->pidl) {
  541. hres = _psf->CompareIDs(0, pidl, poi->pidl);
  542. if (ResultFromShort(0) == hres)
  543. {
  544. if (pIndex)
  545. *pIndex = i;
  546. if (ptbbi)
  547. {
  548. int id = _IndexToID(i);
  549. if (id != -1) {
  550. ptbbi->cbSize = SIZEOF(*ptbbi);
  551. if (-1 == ToolBar_GetButtonInfo(_hwndTB, id, ptbbi))
  552. {
  553. ZeroMemory(ptbbi, SIZEOF(*ptbbi));
  554. }
  555. }
  556. else
  557. {
  558. ZeroMemory(ptbbi, SIZEOF(*ptbbi));
  559. }
  560. }
  561. return poi->pidl;
  562. }
  563. }
  564. }
  565. return NULL;
  566. }
  567. // On an add, tack the new button on the end
  568. void CSFToolbar::_OnFSNotifyAdd(LPCITEMIDLIST pidl)
  569. {
  570. // be paranoid and make sure we don't duplicate an item
  571. //
  572. if (!_GetButtonFromPidl(pidl, NULL, NULL))
  573. {
  574. LPITEMIDLIST pidlNew;
  575. if (_fFSNotify && !_ptscn)
  576. {
  577. if (FAILED(SHGetRealIDL(_psf, pidl, &pidlNew)))
  578. pidlNew = NULL;
  579. }
  580. else
  581. {
  582. pidlNew = ILClone(pidl);
  583. }
  584. if (pidlNew)
  585. {
  586. if (!_FilterPidl(pidlNew))
  587. {
  588. int index = _DefaultInsertIndex();
  589. if (_fDropping)
  590. {
  591. if (-1 == _tbim.iButton)
  592. index = 0; // if qlinks has no items, _tbim.iButton is -1, but you can't insert there...
  593. else if (_tbim.dwFlags & TBIMHT_AFTER)
  594. index = _tbim.iButton + 1;
  595. else
  596. index = _tbim.iButton;
  597. }
  598. // We need to store this as the new order because a drag and drop has occured.
  599. // We will store this order and use it until the end of time.
  600. if (_fDropping)
  601. {
  602. _fHasOrder = TRUE;
  603. _fChangedOrder = TRUE;
  604. }
  605. _AddPidl(pidlNew, index);
  606. OrderList_Reorder(_hdpa);
  607. if (_fDropping)
  608. {
  609. _Dropped(index, FALSE);
  610. _fDropping = FALSE;
  611. }
  612. }
  613. else
  614. {
  615. ILFree(pidlNew);
  616. }
  617. }
  618. }
  619. }
  620. // This function syncronously removes the button, and deletes it's contents.
  621. // This avoids Reentrancy problems, as well as Leaks caused by unhooked toolbars
  622. BOOL_PTR CSFToolbar::InlineDeleteButton(int iIndex)
  623. {
  624. BOOL_PTR fRet = FALSE;
  625. TBBUTTONINFO tbbi = {0};
  626. tbbi.cbSize = SIZEOF(tbbi);
  627. tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX;
  628. if (ToolBar_GetButtonInfo(_hwndTB, iIndex, &tbbi) >= 0)
  629. {
  630. PIBDATA pibdata = (PIBDATA)tbbi.lParam;
  631. tbbi.lParam = NULL;
  632. ToolBar_SetButtonInfo(_hwndTB, iIndex, &tbbi);
  633. fRet = SendMessage(_hwndTB, TB_DELETEBUTTON, iIndex, 0);
  634. if (pibdata)
  635. delete pibdata;
  636. }
  637. return fRet;
  638. }
  639. // On a remove, rip out the old button and adjust existing ones
  640. void CSFToolbar::_OnFSNotifyRemove(LPCITEMIDLIST pidl)
  641. {
  642. int i;
  643. LPITEMIDLIST pidlButton = _GetButtonFromPidl(pidl, NULL, &i);
  644. if (pidlButton)
  645. {
  646. // remove it from the DPA before nuking the button. There is a rentrancy issue here.
  647. DPA_DeletePtr(_hdpa, i);
  648. InlineDeleteButton(i);
  649. ILFree(pidlButton);
  650. _fChangedOrder = TRUE;
  651. }
  652. }
  653. // On a rename, just change the text of the old button
  654. //
  655. void CSFToolbar::_OnFSNotifyRename(LPCITEMIDLIST pidlFrom, LPCITEMIDLIST pidlTo)
  656. {
  657. TBBUTTONINFO tbbi = {0};
  658. LPITEMIDLIST pidlButton;
  659. int i;
  660. tbbi.cbSize = SIZEOF(tbbi);
  661. tbbi.dwMask = TBIF_COMMAND | TBIF_LPARAM;
  662. pidlButton = _GetButtonFromPidl(pidlFrom, &tbbi, &i);
  663. if (pidlButton)
  664. {
  665. LPITEMIDLIST pidlNew;
  666. if (_fFSNotify && !_ptscn)
  667. {
  668. if (FAILED(SHGetRealIDL(_psf, pidlTo, &pidlNew)))
  669. pidlNew = NULL;
  670. }
  671. else
  672. {
  673. pidlNew = ILClone(pidlTo);
  674. }
  675. if (pidlNew)
  676. {
  677. LPITEMIDLIST pidlFree = pidlNew;
  678. PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i);
  679. if (EVAL(poi))
  680. {
  681. pidlFree = poi->pidl;
  682. poi->pidl = pidlNew;
  683. STRRET strret;
  684. TCHAR szName[MAX_PATH];
  685. if (SUCCEEDED(_psf->GetDisplayNameOf(pidlNew, SHGDN_NORMAL, &strret)) &&
  686. SUCCEEDED(StrRetToBuf(&strret, pidlNew, szName, ARRAYSIZE(szName))))
  687. {
  688. // _GetButtonFromPidl filled in tbbi.cbSize and tbbi.idCommand
  689. //
  690. PIBDATA pibdata = (PIBDATA)tbbi.lParam;
  691. if (pibdata)
  692. pibdata->SetOrderItem(poi);
  693. tbbi.dwMask = TBIF_TEXT;
  694. tbbi.pszText = szName;
  695. EVAL(ToolBar_SetButtonInfo(_hwndTB, tbbi.idCommand, &tbbi));
  696. // Just so that it's new location gets persisted
  697. _fChangedOrder = TRUE;
  698. }
  699. }
  700. ILFree(pidlFree);
  701. }
  702. }
  703. }
  704. // On a complete update remove the old button and add it again
  705. //
  706. void CSFToolbar::_OnFSNotifyUpdate(LPCITEMIDLIST pidl)
  707. {
  708. TBBUTTONINFO tbbi = {0};
  709. tbbi.cbSize = SIZEOF(tbbi);
  710. tbbi.dwMask = TBIF_COMMAND;
  711. LPITEMIDLIST pidlButton = _GetButtonFromPidl(pidl, &tbbi, NULL);
  712. if (pidlButton)
  713. {
  714. STRRET strret;
  715. TCHAR szName[MAX_PATH];
  716. if (SUCCEEDED(_psf->GetDisplayNameOf(pidlButton, SHGDN_NORMAL, &strret)) &&
  717. SUCCEEDED(StrRetToBuf(&strret, pidlButton, szName, ARRAYSIZE(szName))))
  718. {
  719. int iBitmap = _GetBitmap(tbbi.idCommand, _IDToPibData(tbbi.idCommand, NULL), FALSE);
  720. if (iBitmap >= 0)
  721. {
  722. tbbi.dwMask = TBIF_IMAGE | TBIF_TEXT;
  723. tbbi.iImage = iBitmap;
  724. tbbi.pszText = szName;
  725. ToolBar_SetButtonInfo(_hwndTB, tbbi.idCommand, &tbbi);
  726. }
  727. }
  728. }
  729. }
  730. void CSFToolbar::_Refresh()
  731. {
  732. if (!_hdpa)
  733. return;
  734. _RememberOrder();
  735. _SetDirty(TRUE);
  736. if (_fShow)
  737. _FillToolbar();
  738. }
  739. LRESULT CSFToolbar::_OnTimer(WPARAM wParam)
  740. {
  741. return 0;
  742. }
  743. LRESULT CSFToolbar::_DefWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  744. {
  745. switch (uMsg)
  746. {
  747. case WM_DRAWITEM:
  748. case WM_MEASUREITEM:
  749. case WM_INITMENUPOPUP:
  750. case WM_MENUSELECT:
  751. if (_pcm2)
  752. _pcm2->HandleMenuMsg(uMsg, wParam, lParam);
  753. break;
  754. case WM_MENUCHAR:
  755. {
  756. LRESULT lres = 0;
  757. IContextMenu3* pcm3;
  758. if (_pcm2 && SUCCEEDED(_pcm2->QueryInterface(IID_IContextMenu3, (void**)&pcm3)))
  759. {
  760. pcm3->HandleMenuMsg2(uMsg, wParam, lParam, &lres);
  761. pcm3->Release();
  762. }
  763. return lres;
  764. }
  765. break;
  766. case WM_TIMER:
  767. if (_OnTimer(wParam))
  768. {
  769. return 1;
  770. }
  771. break;
  772. }
  773. return CNotifySubclassWndProc::_DefWindowProc(hwnd, uMsg, wParam, lParam);
  774. }
  775. /*----------------------------------------------------------
  776. Purpose:
  777. For future use. when renaming a parent of this shell folder
  778. we should rebind to it and refill us.
  779. S_OK Indicates successful handling of this notification
  780. S_FALSE Indicates the notification is not a handled situation.
  781. The caller should handle the notification in this case.
  782. Other Failure code indicates a problem. Caller should abort
  783. operation or handle the notification itself.
  784. */
  785. HRESULT CSFToolbar::_OnRenameFolder(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  786. {
  787. return S_FALSE;
  788. }
  789. HRESULT CSFToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidlOrg1, LPCITEMIDLIST pidlOrg2)
  790. {
  791. HRESULT hres;
  792. LPITEMIDLIST pidl1 = (LPITEMIDLIST)pidlOrg1;
  793. LPITEMIDLIST pidl2 = (LPITEMIDLIST)pidlOrg2;
  794. LPITEMIDLIST pidl1ToFree = NULL; // Used if we allocate a pidl that needs to be freed. (::TranslateIDs())
  795. LPITEMIDLIST pidl2ToFree = NULL;
  796. LPITEMIDLIST pidlOut1Event2 = NULL; // Used if we allocate a pidl that needs to be freed. (::TranslateIDs())
  797. LPITEMIDLIST pidlOut2Event2 = NULL;
  798. LONG lEvent2 = (LONG)-1;
  799. if (_ptscn)
  800. {
  801. hres = _ptscn->TranslateIDs(&lEvent, pidlOrg1, pidlOrg2, &pidl1, &pidl2,
  802. &lEvent2, &pidlOut1Event2, &pidlOut2Event2);
  803. if (FAILED(hres))
  804. return hres;
  805. else
  806. {
  807. // if pidl1 doesn't equal pidlOrg1, then pidl1 was allocated and needs to be freed.
  808. pidl1ToFree = ((pidlOrg1 == pidl1) ? NULL : pidl1);
  809. pidl2ToFree = ((pidlOrg2 == pidl2) ? NULL : pidl2);
  810. }
  811. ASSERT(NULL == pidl1 || IS_VALID_PIDL(pidl1));
  812. ASSERT(NULL == pidl2 || IS_VALID_PIDL(pidl2));
  813. }
  814. hres = OnTranslatedChange(lEvent, pidl1, pidl2);
  815. // Do we have a second event to process?
  816. if (SUCCEEDED(hres) && lEvent2 != (LONG)-1)
  817. {
  818. // Yes, then go do it.
  819. hres = OnTranslatedChange(lEvent2, pidlOut1Event2, pidlOut2Event2);
  820. }
  821. ILFree(pidlOut1Event2);
  822. ILFree(pidlOut2Event2);
  823. ILFree(pidl1ToFree);
  824. ILFree(pidl2ToFree);
  825. return hres;
  826. }
  827. #ifdef DEBUG
  828. void DBPrPidl(LPCSTR szPre, LPCITEMIDLIST pidl)
  829. {
  830. TCHAR szName[MAX_PATH];
  831. szName[0] = '\0';
  832. if (pidl)
  833. SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szName, SIZECHARS(szName), NULL);
  834. TraceMsg(TF_WARNING, "%hs%s", szPre, szName);
  835. return;
  836. }
  837. #endif
  838. HRESULT CSFToolbar::OnTranslatedChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  839. {
  840. HRESULT hres = S_OK;
  841. BOOL fSizeChanged = FALSE;
  842. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: lEvent=%x", lEvent);
  843. // If we weren't given a pidl we won't register for
  844. // SHChangeNotify calls, but our IShellChange interface
  845. // can still be QI()d so someone could errantly call us.
  846. //
  847. // If we change to using QS() for IShellChange interface
  848. // then we can put this check there...
  849. //
  850. if (NULL == _pidl)
  851. {
  852. // HACKHACK (scotth): resource-based menus (CMenuISF) don't set _pidl.
  853. // Right now allow SHCNE_UPDATEDIR thru...
  854. if (SHCNE_UPDATEDIR == lEvent)
  855. goto HandleUpdateDir;
  856. TraceMsg(TF_WARNING, "CSFToolbar::OnChange - _pidl is NULL");
  857. hres = E_FAIL;
  858. goto CleanUp;
  859. }
  860. if ( lEvent != SHCNE_UPDATEIMAGE && lEvent != SHCNE_RENAMEITEM && lEvent != SHCNE_RENAMEFOLDER &&
  861. lEvent != SHCNE_UPDATEDIR && lEvent != SHCNE_MEDIAREMOVED && lEvent != SHCNE_MEDIAINSERTED &&
  862. lEvent != SHCNE_EXTENDED_EVENT)
  863. {
  864. // We only handle notifications for immediate kids. (except SHCNE_RENAMEFOLDER)
  865. //
  866. if (!_IsChildID(pidl1, TRUE))
  867. {
  868. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Not a child. Bailing");
  869. hres = E_FAIL;
  870. goto CleanUp;
  871. }
  872. }
  873. // Have we been shown yet?
  874. if (_hdpa == NULL)
  875. {
  876. // No. Well, then punt this. We'll catch it on the first enum.
  877. hres = E_FAIL;
  878. goto CleanUp;
  879. }
  880. switch (lEvent)
  881. {
  882. case SHCNE_EXTENDED_EVENT:
  883. {
  884. SHChangeDWORDAsIDList UNALIGNED * pdwidl = (SHChangeDWORDAsIDList UNALIGNED *)pidl1;
  885. if (pdwidl->dwItem1 == SHCNEE_ORDERCHANGED)
  886. {
  887. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Reorder event");
  888. // Do this first so that we can say "We can handle it". This prevents the
  889. // mnfolder code that works around a bug in some installers where they don't
  890. // send a Create Folder before the create item in that folder. It causes an
  891. // update dir...
  892. if (!pidl2 || ILIsEqual(_pidl, pidl2))
  893. {
  894. // if this reorder came from us, blow it off
  895. if (!SHChangeMenuWasSentByMe(this, pidl1))
  896. {
  897. // load new order stream
  898. _LoadOrderStream();
  899. // rebuild toolbar
  900. _SetDirty(TRUE);
  901. if (_fShow)
  902. _FillToolbar();
  903. }
  904. hres = S_OK;
  905. }
  906. }
  907. }
  908. break;
  909. case SHCNE_DRIVEADD:
  910. case SHCNE_CREATE:
  911. case SHCNE_MKDIR:
  912. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Adding item");
  913. pidl1 = ILFindLastID(pidl1);
  914. _OnFSNotifyAdd(pidl1);
  915. fSizeChanged = TRUE;
  916. break;
  917. case SHCNE_DRIVEREMOVED:
  918. case SHCNE_DELETE:
  919. case SHCNE_RMDIR:
  920. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Removing item");
  921. pidl1 = ILFindLastID(pidl1);
  922. _OnFSNotifyRemove(pidl1);
  923. fSizeChanged = TRUE;
  924. break;
  925. case SHCNE_RENAMEFOLDER:
  926. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameFolder");
  927. // Break if notif is handled or if this is not for our kid.
  928. //
  929. hres = _OnRenameFolder(pidl1, pidl2);
  930. if (S_OK == hres)
  931. {
  932. fSizeChanged = TRUE;
  933. break;
  934. }
  935. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameFolder Falling through to RenameItem");
  936. // fall through
  937. case SHCNE_RENAMEITEM:
  938. {
  939. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameItem");
  940. BOOL fOurKid1, fOurKid2;
  941. LPCITEMIDLIST p1 = pidl1;
  942. LPCITEMIDLIST p2 = pidl2;
  943. pidl1 = ILFindLastID(pidl1);
  944. pidl2 = ILFindLastID(pidl2);
  945. // An item can be renamed out of this folder.
  946. // Convert that into a remove.
  947. //
  948. fOurKid1 = _IsChildID(p1, TRUE);
  949. fOurKid2 = _IsChildID(p2, TRUE);
  950. if (fOurKid1 && fOurKid2)
  951. {
  952. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Both are children");
  953. _OnFSNotifyRename(pidl1, pidl2);
  954. fSizeChanged = TRUE;
  955. hres = S_OK;
  956. break;
  957. }
  958. else if (fOurKid1)
  959. {
  960. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Only one is a child. Removing pidl 1");
  961. _OnFSNotifyRemove(pidl1);
  962. fSizeChanged = TRUE;
  963. break;
  964. }
  965. else if (fOurKid2)
  966. {
  967. // An item can be renamed into this folder.
  968. // Convert that into an add.
  969. //
  970. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Only one is a child. Adding pidl2");
  971. _OnFSNotifyAdd(pidl2);
  972. fSizeChanged = TRUE;
  973. break;
  974. }
  975. else
  976. {
  977. // (we get here for guys below us who we don't care about,
  978. // and also for the fallthru from SHCNE_RENAMEFOLDER)
  979. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Not our children");
  980. /*NOTHING*/
  981. hres = E_FAIL;
  982. }
  983. break;
  984. }
  985. case SHCNE_MEDIAINSERTED:
  986. case SHCNE_MEDIAREMOVED:
  987. case SHCNE_NETUNSHARE:
  988. if (_IsEqualID(pidl1))
  989. goto HandleUpdateDir;
  990. case SHCNE_NETSHARE:
  991. case SHCNE_UPDATEITEM:
  992. if (_IsChildID(pidl1, TRUE))
  993. {
  994. pidl1 = ILFindLastID(pidl1);
  995. _OnFSNotifyUpdate(pidl1);
  996. fSizeChanged = TRUE;
  997. }
  998. break;
  999. case SHCNE_UPDATEDIR:
  1000. // in OnChange we picked off update dir notify and we didn't translate ids
  1001. // now we can use ILIsEqual -- translate ids won't translate pidls in case
  1002. // of update dir because it looks for immediate child of its, and fails when
  1003. // it receives its own pidl
  1004. // NOTE: When sftbar is registered recursivly, we only get the pidl of the
  1005. // top pane. It is forwarded down to the children. Since this is now a "Child"
  1006. // of the top pane, we check to see if this pidl is a child of that pidl, hence the
  1007. // ILIsParent(pidl1, _pidl)
  1008. // HACKHACK, HUGE HACK: normaly w/ update dir pidl2 is NULL but in start menu
  1009. // augmergeisf can change some other notify (e.g. rename folder) to update dir
  1010. // in which case pidl2 is not null and we have to see if it is our child to do the
  1011. // update (11/18/98) reljai
  1012. if (_IsEqualID(pidl1) || // Calling UpdateDir on _THIS_ folder
  1013. _IsChildID(pidl1, FALSE) || // BUGBUG (lamadio) Is this needed?
  1014. (pidl2 && _IsChildID(pidl2, FALSE)) || // A changed to update (see comment)
  1015. _IsParentID(pidl1)) // Some parent in the chain (because it's recursive)
  1016. {
  1017. HandleUpdateDir:
  1018. // NOTE: if a series of UPDATEIMAGE notifies gets
  1019. // translated to UPDATEDIR and we flicker-perf
  1020. // _FillToolbar, we may lose image updates
  1021. // (in which case, _Refresh would fix it)
  1022. //
  1023. TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: ******* Evil Update Dir *******");
  1024. _Refresh();
  1025. // don't set this here because filltoolbar will update
  1026. //fSizeChanged = TRUE;
  1027. }
  1028. break;
  1029. case SHCNE_ASSOCCHANGED:
  1030. IEInvalidateImageList(); // We may need to use different icons.
  1031. _Refresh(); // full refresh for now.
  1032. break;
  1033. case SHCNE_UPDATEIMAGE: // global
  1034. if (pidl1)
  1035. {
  1036. int iImage = *(int UNALIGNED *)((BYTE *)pidl1 + 2);
  1037. IEInvalidateImageList(); // We may need to use different icons.
  1038. if ( pidl2 )
  1039. {
  1040. iImage = SHHandleUpdateImage( pidl2 );
  1041. if ( iImage == -1 )
  1042. {
  1043. break;
  1044. }
  1045. }
  1046. if (iImage == -1 || TBHasImage(_hwndTB, iImage))
  1047. _Refresh();
  1048. } else
  1049. _Refresh();
  1050. // BUGBUG do we need an _UpdateButtons and fSizeChanged?
  1051. break;
  1052. default:
  1053. hres = E_FAIL;
  1054. break;
  1055. }
  1056. if (fSizeChanged)
  1057. {
  1058. if (_hwndPager)
  1059. SendMessage(_hwndPager, PGMP_RECALCSIZE, (WPARAM) 0, (LPARAM) 0);
  1060. _ToolbarChanged();
  1061. }
  1062. CleanUp:
  1063. return hres;
  1064. }
  1065. BOOL TBHasImage(HWND hwnd, int iImageIndex)
  1066. {
  1067. BOOL fRefresh = FALSE;
  1068. for (int i = ToolBar_ButtonCount(hwnd) - 1 ; i >= 0 ; i--)
  1069. {
  1070. TBBUTTON tbb;
  1071. if (SendMessage(hwnd, TB_GETBUTTON, i, (LPARAM)&tbb))
  1072. {
  1073. if (tbb.iBitmap == iImageIndex)
  1074. {
  1075. fRefresh = TRUE;
  1076. break;
  1077. }
  1078. }
  1079. }
  1080. return fRefresh;
  1081. }
  1082. void CSFToolbar::_SetToolbarState()
  1083. {
  1084. SHSetWindowBits(_hwndTB, GWL_STYLE, TBSTYLE_LIST,
  1085. (_uIconSize != ISFBVIEWMODE_SMALLICONS || _fNoShowText) ? 0 : TBSTYLE_LIST);
  1086. }
  1087. int CSFToolbar::_DefaultInsertIndex()
  1088. {
  1089. return DA_LAST;
  1090. }
  1091. BOOL CSFToolbar::_IsParentID(LPCITEMIDLIST pidl)
  1092. {
  1093. // Is the pidl passed in a parent of one of the IDs in the namespace
  1094. // or the only one i've got?
  1095. if (_ptscn)
  1096. return S_OK == _ptscn->IsEqualID(NULL, pidl);
  1097. else
  1098. return ILIsParent(pidl, _pidl, FALSE);
  1099. }
  1100. BOOL CSFToolbar::_IsEqualID(LPCITEMIDLIST pidl)
  1101. {
  1102. if (_ptscn)
  1103. return S_OK == _ptscn->IsEqualID(pidl, NULL);
  1104. else
  1105. return ILIsEqual(_pidl, pidl);
  1106. }
  1107. BOOL CSFToolbar::_IsChildID(LPCITEMIDLIST pidlChild, BOOL fImmediate)
  1108. {
  1109. if (_ptscn)
  1110. return S_OK == _ptscn->IsChildID(pidlChild, fImmediate);
  1111. else
  1112. return ILIsParent(_pidl, pidlChild, fImmediate);
  1113. }
  1114. void CSFToolbar::v_CalcWidth(int* pcxMin, int* pcxMax)
  1115. {
  1116. ASSERT(IS_VALID_WRITE_PTR(pcxMin, int));
  1117. ASSERT(IS_VALID_WRITE_PTR(pcxMax, int));
  1118. // Calculate a decent button width given current state
  1119. HIMAGELIST himl;
  1120. int cxMax = 0;
  1121. int cxMin = 0;
  1122. himl = (HIMAGELIST)SendMessage(_hwndTB, TB_GETIMAGELIST, 0, 0);
  1123. if (himl)
  1124. {
  1125. int cy;
  1126. // Start with the width of the button
  1127. ImageList_GetIconSize(himl, &cxMax, &cy);
  1128. // We want at least a bit of space around the icon
  1129. if (_uIconSize != ISFBVIEWMODE_SMALLICONS)
  1130. cxMax += 20;
  1131. else
  1132. cxMax += 4 * GetSystemMetrics(SM_CXEDGE);
  1133. }
  1134. // Add in any additional space needed
  1135. // Text takes up a bit more space
  1136. if (!_fNoShowText)
  1137. {
  1138. cxMax += 20;
  1139. // Horizontal text takes up a lot
  1140. // if we're smallicon with text (horizontal button)
  1141. // mode, use the minimized metric to mimic the taskbar
  1142. if (_uIconSize == ISFBVIEWMODE_SMALLICONS)
  1143. cxMax = GetSystemMetrics(SM_CXMINIMIZED);
  1144. }
  1145. *pcxMin = cxMin;
  1146. *pcxMax = cxMax;
  1147. }
  1148. // Adjust buttons based on current state.
  1149. //
  1150. void CSFToolbar::_UpdateButtons()
  1151. {
  1152. if (_hwndTB)
  1153. {
  1154. // set "list" (text on right) or not (text underneath)
  1155. // NOTE: list mode always displays some text, don't do it if no text
  1156. _SetToolbarState();
  1157. v_CalcWidth(&_cxMin, &_cxMax);
  1158. SendMessage(_hwndTB, TB_SETBUTTONWIDTH, 0, MAKELONG(_cxMin, _cxMax));
  1159. // We just changed the layout
  1160. //
  1161. SendMessage(_hwndTB, TB_AUTOSIZE, 0, 0);
  1162. if (_hwndPager)
  1163. {
  1164. LRESULT lButtonSize = SendMessage(_hwndTB, TB_GETBUTTONSIZE, 0, 0);
  1165. Pager_SetScrollInfo(_hwndPager, 50, 1, HIWORD(lButtonSize));
  1166. SendMessage(_hwndPager, PGMP_RECALCSIZE, (WPARAM) 0, (LPARAM) 0);
  1167. }
  1168. }
  1169. }
  1170. /*----------------------------------------------------------
  1171. Purpose: Helper function that calls IShellFolder::GetUIObjectOf().
  1172. Returns: pointer to the requested interface
  1173. NULL if failed
  1174. */
  1175. LPVOID CSFToolbar::_GetUIObjectOfPidl(LPCITEMIDLIST pidl, REFIID riid)
  1176. {
  1177. LPCITEMIDLIST * apidl = &pidl;
  1178. LPVOID pv;
  1179. if (FAILED(_psf->GetUIObjectOf(GetHWNDForUIObject(), 1, apidl, riid, 0, &pv)))
  1180. {
  1181. pv = NULL;
  1182. }
  1183. return(pv);
  1184. }
  1185. INT_PTR CALLBACK CSFToolbar::_RenameDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1186. {
  1187. switch (uMsg)
  1188. {
  1189. case WM_INITDIALOG:
  1190. {
  1191. ASSERT(lParam);
  1192. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1193. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  1194. // cross-lang platform support
  1195. SHSetDefaultDialogFont(hDlg, IDD_NAME);
  1196. HWND hwndEdit = GetDlgItem(hDlg, IDD_NAME);
  1197. SendMessage(hwndEdit, EM_LIMITTEXT, MAX_PATH - 1, 0);
  1198. TCHAR szText[MAX_PATH + 80];
  1199. TCHAR szTemplate[80];
  1200. HWND hwndLabel = GetDlgItem(hDlg, IDD_PROMPT);
  1201. GetWindowText(hwndLabel, szTemplate, ARRAYSIZE(szTemplate));
  1202. StringCchPrintf(szText, ARRAYSIZE(szText), szTemplate, lParam); // truncation ok, it's just display text
  1203. SetWindowText(hwndLabel, szText);
  1204. SetWindowText(hwndEdit, (LPTSTR)lParam);
  1205. break;
  1206. }
  1207. case WM_DESTROY:
  1208. SHRemoveDefaultDialogFont(hDlg);
  1209. return FALSE;
  1210. case WM_COMMAND:
  1211. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1212. {
  1213. case IDD_NAME:
  1214. {
  1215. if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_UPDATE)
  1216. {
  1217. LPTSTR lpstrName = (LPTSTR) GetWindowLongPtr(hDlg, DWLP_USER);
  1218. EnableOKButtonFromID(hDlg, IDD_NAME);
  1219. GetDlgItemText(hDlg, IDD_NAME, lpstrName, MAX_PATH);
  1220. }
  1221. break;
  1222. }
  1223. case IDOK:
  1224. {
  1225. TCHAR szTmp[MAX_PATH];
  1226. StringCchCopy(szTmp, ARRAYSIZE(szTmp), (LPTSTR) GetWindowLongPtr(hDlg, DWLP_USER)); // truncation is ok, this is just a renaming something
  1227. if (PathCleanupSpec(NULL,szTmp))
  1228. {
  1229. HWND hwnd;
  1230. MLShellMessageBox(hDlg,
  1231. MAKEINTRESOURCE(IDS_FAVS_INVALIDFN),
  1232. MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES), MB_OK | MB_ICONHAND);
  1233. hwnd = GetDlgItem(hDlg, IDD_NAME);
  1234. SetWindowText(hwnd, TEXT('\0'));
  1235. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  1236. SetFocus(hwnd);
  1237. break;
  1238. }
  1239. }
  1240. // fall through
  1241. case IDCANCEL:
  1242. EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
  1243. break;
  1244. default:
  1245. return FALSE;
  1246. }
  1247. break;
  1248. default:
  1249. return FALSE;
  1250. }
  1251. return TRUE;
  1252. }
  1253. // This window proc is used for a temporary worker window that is used to position dialogs
  1254. // as well as maintain the correct Z-Order
  1255. // NOTE: This is used in mnfolder as well.
  1256. LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1257. {
  1258. switch(uMsg)
  1259. {
  1260. // Make sure activation tracks back to the parent.
  1261. case WM_ACTIVATE:
  1262. {
  1263. if (WA_ACTIVE != LOWORD(wParam))
  1264. goto DefWnd;
  1265. SetActiveWindow(GetParent(hwnd));
  1266. return FALSE;
  1267. }
  1268. case WM_WINDOWPOSCHANGING:
  1269. {
  1270. WINDOWPOS* pwp = (WINDOWPOS*)lParam;
  1271. pwp->flags |= SWP_NOOWNERZORDER;
  1272. }
  1273. break;
  1274. }
  1275. DefWnd:
  1276. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1277. }
  1278. HWND CSFToolbar::CreateWorkerWindow()
  1279. {
  1280. if (!_hwndWorkerWindow)
  1281. {
  1282. _hwndWorkerWindow = SHCreateWorkerWindow(HiddenWndProc, GetHWNDForUIObject(), WS_EX_TOOLWINDOW /*| WS_EX_TOPMOST */, WS_POPUP, 0, _hwndTB);
  1283. }
  1284. return _hwndWorkerWindow;
  1285. }
  1286. HRESULT CSFToolbar::_OnRename(POINT *ppt, int id)
  1287. {
  1288. ASSERT(_psf);
  1289. TCHAR szName[MAX_PATH];
  1290. LPCITEMIDLIST pidl = _IDToPidl(id);
  1291. _ObtainPIDLName(pidl, szName, ARRAYSIZE(szName));
  1292. // create a temp window so that placement of the dialog will be close to the point.
  1293. // do this so that we'll use USER's code to get placement correctly w/ respect to multimon and work area
  1294. _hwndWorkerWindow = CreateWorkerWindow();
  1295. SetWindowPos(_hwndWorkerWindow, NULL, ppt->x, ppt->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  1296. // Now the horrible work of disabling our UI parent window so we can go modal.
  1297. // In an ideal world, we would pass our true parent window and USER will do
  1298. // all the work of modality, but we have to use our worker window thingie
  1299. // to get the dialog positioned correctly with respect to multimon,
  1300. // so we have to find the modal parent and disable him the hard way.
  1301. //
  1302. IUnknown *punkSite;
  1303. IUnknown *punkTLB;
  1304. // Doesn't matter what we SAFECAST "this" to; just pick something to keep the compiler happy
  1305. IUnknown_GetSite(SAFECAST(this, IWinEventHandler*), IID_PPV_ARG(IUnknown, &punkSite));
  1306. IUnknown_QueryService(punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IUnknown, &punkTLB));
  1307. // Tell OLE to go modal
  1308. HRESULT hrModeless = IUnknown_EnableModless(punkTLB, FALSE);
  1309. // Tell USER to go modal
  1310. HWND hwndDisable;
  1311. IUnknown_GetWindow(punkTLB, &hwndDisable);
  1312. BOOL bPrevEnabled = FALSE;
  1313. while (hwndDisable && (GetWindowLong(hwndDisable, GWL_STYLE) & WS_CHILD))
  1314. hwndDisable = GetParent(hwndDisable);
  1315. if (hwndDisable)
  1316. bPrevEnabled = !EnableWindow(hwndDisable, FALSE);
  1317. while (1)
  1318. {
  1319. if (DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_ISFBANDRENAME), _hwndWorkerWindow, _RenameDlgProc, (LPARAM)szName) != IDOK)
  1320. break;
  1321. WCHAR wsz[MAX_PATH];
  1322. SHTCharToUnicode(szName, wsz, ARRAYSIZE(wsz));
  1323. if (SUCCEEDED(_psf->SetNameOf(_hwndWorkerWindow, pidl, wsz, 0, NULL)))
  1324. {
  1325. SHChangeNotifyHandleEvents();
  1326. _SaveOrderStream();
  1327. break;
  1328. }
  1329. }
  1330. // (must undo modality in reverse order)
  1331. // Tell USER to return to modeless (as appropriate)
  1332. if (hwndDisable)
  1333. EnableWindow(hwndDisable, bPrevEnabled);
  1334. // Tell OLE to return to modeless (as appropriate)
  1335. if (SUCCEEDED(hrModeless))
  1336. IUnknown_EnableModless(punkTLB, TRUE);
  1337. ATOMICRELEASE(punkTLB);
  1338. ATOMICRELEASE(punkSite);
  1339. return S_OK;
  1340. }
  1341. BOOL CSFToolbar::_UpdateIconSize(UINT uIconSize, BOOL fUpdateButtons)
  1342. {
  1343. BOOL fChanged = (_uIconSize != uIconSize);
  1344. _uIconSize = uIconSize;
  1345. TraceMsg(TF_BAND, "ISFBand::_UpdateIconSize going %hs", (_uIconSize == ISFBVIEWMODE_LARGEICONS ? "LARGE" : (_uIconSize == ISFBVIEWMODE_SMALLICONS ? "SMALL" : "LOGOS")));
  1346. if (_hwndTB)
  1347. {
  1348. HIMAGELIST himl = NULL;
  1349. if (!_fNoIcons)
  1350. {
  1351. HIMAGELIST himlLarge, himlSmall;
  1352. // set the imagelist size
  1353. Shell_GetImageLists(&himlLarge, &himlSmall);
  1354. himl = (_uIconSize == ISFBVIEWMODE_LARGEICONS ) ? himlLarge : himlSmall;
  1355. }
  1356. // sending a null himl is significant.. it means no image list
  1357. SendMessage(_hwndTB, TB_SETIMAGELIST, 0, (LPARAM)himl);
  1358. if (fUpdateButtons)
  1359. _UpdateButtons();
  1360. }
  1361. return fChanged;
  1362. }
  1363. HMENU CSFToolbar::_GetContextMenu(IContextMenu* pcm, int* pid)
  1364. {
  1365. HMENU hmenu = CreatePopupMenu();
  1366. if (hmenu) {
  1367. UINT fFlags = CMF_CANRENAME;
  1368. if (0 > GetKeyState(VK_SHIFT))
  1369. fFlags |= CMF_EXTENDEDVERBS;
  1370. pcm->QueryContextMenu(hmenu, 0, *pid, CMD_ID_LAST, fFlags);
  1371. }
  1372. return hmenu;
  1373. }
  1374. void CSFToolbar::_OnDefaultContextCommand(int idCmd)
  1375. {
  1376. }
  1377. HRESULT CSFToolbar::_GetTopBrowserWindow(HWND* phwnd)
  1378. {
  1379. IUnknown * punkSite;
  1380. HRESULT hr = IUnknown_GetSite(SAFECAST(this, IWinEventHandler*), IID_IUnknown, (void**)&punkSite);
  1381. if (SUCCEEDED(hr))
  1382. {
  1383. hr = SHGetTopBrowserWindow(punkSite, phwnd);
  1384. punkSite->Release();
  1385. }
  1386. return hr;
  1387. }
  1388. HRESULT CSFToolbar::_OnOpen(int id, BOOL fExplore)
  1389. {
  1390. HRESULT hr = E_FAIL;
  1391. LPCITEMIDLIST pidl = _IDToPidl(id);
  1392. if (pidl)
  1393. {
  1394. IUnknown* punkSite;
  1395. hr = IUnknown_GetSite(SAFECAST(this, IWinEventHandler*), IID_IUnknown, (void**)&punkSite);
  1396. if (SUCCEEDED(hr))
  1397. {
  1398. DWORD dwFlags = SBSP_DEFBROWSER | SBSP_DEFMODE;
  1399. if (fExplore)
  1400. dwFlags |= SBSP_EXPLOREMODE;
  1401. hr = SHNavigateToFavorite(_psf, pidl, punkSite, dwFlags);
  1402. punkSite->Release();
  1403. }
  1404. }
  1405. return hr;
  1406. }
  1407. HRESULT CSFToolbar::_HandleSpecialCommand(IContextMenu* pcm, PPOINT ppt, int id, int idCmd)
  1408. {
  1409. TCHAR szCommandString[40];
  1410. HRESULT hres = ContextMenu_GetCommandStringVerb(pcm,
  1411. idCmd,
  1412. szCommandString,
  1413. ARRAYSIZE(szCommandString));
  1414. if (SUCCEEDED(hres))
  1415. {
  1416. if (lstrcmpi(szCommandString, TEXT("rename")) == 0)
  1417. return _OnRename(ppt, id);
  1418. else if (lstrcmpi(szCommandString, TEXT("open")) == 0)
  1419. return _OnOpen(id, FALSE);
  1420. else if (lstrcmpi(szCommandString, TEXT("explore")) == 0)
  1421. return _OnOpen(id, TRUE);
  1422. }
  1423. return S_FALSE;
  1424. }
  1425. LRESULT CSFToolbar::_DoContextMenu(IContextMenu* pcm, LPPOINT ppt, int id, LPRECT prcExclude)
  1426. {
  1427. LRESULT lres = 0;
  1428. int idCmdFirst = CMD_ID_FIRST;
  1429. HMENU hmContext = _GetContextMenu(pcm, &idCmdFirst);
  1430. if (hmContext)
  1431. {
  1432. int idCmd;
  1433. if (_hwndToolTips)
  1434. SendMessage(_hwndToolTips, TTM_ACTIVATE, FALSE, 0L);
  1435. TPMPARAMS tpm;
  1436. TPMPARAMS * ptpm = NULL;
  1437. if (prcExclude)
  1438. {
  1439. tpm.cbSize = SIZEOF(tpm);
  1440. tpm.rcExclude = *((LPRECT)prcExclude);
  1441. ptpm = &tpm;
  1442. }
  1443. idCmd = TrackPopupMenuEx(hmContext,
  1444. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  1445. ppt->x, ppt->y, _hwndTB, ptpm);
  1446. if (_hwndToolTips)
  1447. SendMessage(_hwndToolTips, TTM_ACTIVATE, TRUE, 0L);
  1448. if (idCmd)
  1449. {
  1450. if (idCmd < idCmdFirst)
  1451. {
  1452. _OnDefaultContextCommand(idCmd);
  1453. }
  1454. else
  1455. {
  1456. idCmd -= idCmdFirst;
  1457. if (_HandleSpecialCommand(pcm, ppt, id, idCmd) != S_OK)
  1458. {
  1459. _hwndWorkerWindow = CreateWorkerWindow();
  1460. SetWindowPos(_hwndWorkerWindow, NULL, ppt->x, ppt->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  1461. CMINVOKECOMMANDINFO ici = {
  1462. SIZEOF(CMINVOKECOMMANDINFO),
  1463. 0,
  1464. _hwndWorkerWindow,
  1465. MAKEINTRESOURCEA(idCmd),
  1466. NULL, NULL,
  1467. SW_NORMAL,
  1468. };
  1469. pcm->InvokeCommand(&ici);
  1470. }
  1471. }
  1472. }
  1473. // if we get this far
  1474. // we need to return handled so that WM_CONTEXTMENU doesn't come through
  1475. lres = 1;
  1476. DestroyMenu(hmContext);
  1477. }
  1478. return lres;
  1479. }
  1480. LRESULT CSFToolbar::_OnContextMenu(WPARAM wParam, LPARAM lParam)
  1481. {
  1482. LRESULT lres = 0;
  1483. RECT rc;
  1484. LPRECT prcExclude = NULL;
  1485. POINT pt;
  1486. int i;
  1487. if (lParam != (LPARAM)-1) {
  1488. pt.x = GET_X_LPARAM(lParam);
  1489. pt.y = GET_Y_LPARAM(lParam);
  1490. POINT pt2 = pt;
  1491. MapWindowPoints(HWND_DESKTOP, _hwndTB, &pt2, 1);
  1492. i = ToolBar_HitTest(_hwndTB, &pt2);
  1493. } else {
  1494. // keyboard context menu.
  1495. i = (int)SendMessage(_hwndTB, TB_GETHOTITEM, 0, 0);
  1496. if (i >= 0) {
  1497. SendMessage(_hwndTB, TB_GETITEMRECT, i, (LPARAM)&rc);
  1498. MapWindowPoints(_hwndTB, HWND_DESKTOP, (LPPOINT)&rc, 2);
  1499. pt.x = rc.left;
  1500. pt.y = rc.bottom;
  1501. prcExclude = &rc;
  1502. }
  1503. }
  1504. TraceMsg(TF_BAND, "NM_RCLICK %d,%d = %d", pt.x, pt.y, i);
  1505. if (i >= 0)
  1506. {
  1507. UINT id = _IndexToID(i);
  1508. LPCITEMIDLIST pidl = _IDToPidl(id, NULL);
  1509. if (pidl)
  1510. {
  1511. LPCONTEXTMENU pcm = (LPCONTEXTMENU)_GetUIObjectOfPidl(pidl, IID_IContextMenu);
  1512. if (pcm)
  1513. {
  1514. // grab pcm2 for owner draw support
  1515. pcm->QueryInterface(IID_IContextMenu2, (LPVOID *)&_pcm2);
  1516. ToolBar_MarkButton(_hwndTB, id, TRUE);
  1517. lres = _DoContextMenu(pcm, &pt, id, prcExclude);
  1518. ToolBar_MarkButton(_hwndTB, id, FALSE);
  1519. if (lres)
  1520. _FlushNotifyMessages(_hwndTB);
  1521. ATOMICRELEASE(_pcm2);
  1522. pcm->Release();
  1523. }
  1524. }
  1525. }
  1526. return lres;
  1527. }
  1528. LRESULT CSFToolbar::_OnCustomDraw(NMCUSTOMDRAW* pnmcd)
  1529. {
  1530. return CDRF_DODEFAULT;
  1531. }
  1532. void CSFToolbar::_OnDragBegin(int iItem, DWORD dwPreferedEffect)
  1533. {
  1534. LPCITEMIDLIST pidl = _IDToPidl(iItem, &_iDragSource);
  1535. ToolBar_SetHotItem(_hwndTB, _iDragSource);
  1536. if (_hwndTB)
  1537. DragDrop(_hwndTB, _psf, pidl, dwPreferedEffect, NULL);
  1538. _iDragSource = -1;
  1539. }
  1540. LRESULT CSFToolbar::_OnHotItemChange(NMTBHOTITEM * pnm)
  1541. {
  1542. LPNMTBHOTITEM lpnmhi = (LPNMTBHOTITEM)pnm;
  1543. if (_hwndPager && (lpnmhi->dwFlags & (HICF_ARROWKEYS | HICF_ACCELERATOR)) )
  1544. {
  1545. int iOldPos, iNewPos;
  1546. RECT rc, rcPager;
  1547. int heightPager;
  1548. int iSelected = lpnmhi->idNew;
  1549. iOldPos = (int)SendMessage(_hwndPager, PGM_GETPOS, (WPARAM)0, (LPARAM)0);
  1550. iNewPos = iOldPos;
  1551. SendMessage(_hwndTB, TB_GETITEMRECT, (WPARAM)iSelected, (LPARAM)&rc);
  1552. if (rc.top < iOldPos)
  1553. {
  1554. iNewPos =rc.top;
  1555. }
  1556. GetClientRect(_hwndPager, &rcPager);
  1557. heightPager = RECTHEIGHT(rcPager);
  1558. if (rc.top >= iOldPos + heightPager)
  1559. {
  1560. iNewPos += (rc.bottom - (iOldPos + heightPager)) ;
  1561. }
  1562. if (iNewPos != iOldPos)
  1563. SendMessage(_hwndPager, PGM_SETPOS, (WPARAM)0, (LPARAM)iNewPos);
  1564. }
  1565. return 0;
  1566. }
  1567. void CSFToolbar::_OnToolTipsCreated(NMTOOLTIPSCREATED* pnm)
  1568. {
  1569. _hwndToolTips = pnm->hwndToolTips;
  1570. SHSetWindowBits(_hwndToolTips, GWL_STYLE, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX);
  1571. // set the AutoPopTime (the duration of showing the tooltip) to a large value
  1572. SendMessage(_hwndToolTips, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)MAXSHORT);
  1573. }
  1574. LRESULT CSFToolbar::_OnNotify(LPNMHDR pnm)
  1575. {
  1576. LRESULT lres = 0;
  1577. //The following statement traps all pager control notification messages.
  1578. if((pnm->code <= PGN_FIRST) && (pnm->code >= PGN_LAST))
  1579. {
  1580. return SendMessage(_hwndTB, WM_NOTIFY, (WPARAM)0, (LPARAM)pnm);
  1581. }
  1582. switch (pnm->code)
  1583. {
  1584. case TBN_DRAGOUT:
  1585. {
  1586. TBNOTIFY *ptbn = (TBNOTIFY*)pnm;
  1587. _OnDragBegin(ptbn->iItem, 0);
  1588. lres = 1;
  1589. break;
  1590. }
  1591. case TBN_HOTITEMCHANGE:
  1592. _OnHotItemChange((LPNMTBHOTITEM)pnm);
  1593. break;
  1594. case TBN_GETINFOTIP:
  1595. {
  1596. LPNMTBGETINFOTIP pnmTT = (LPNMTBGETINFOTIP)pnm;
  1597. UINT uiCmd = pnmTT->iItem;
  1598. DWORD dwFlags = _fNoShowText ? QITIPF_USENAME | QITIPF_LINKNOTARGET : QITIPF_LINKNOTARGET;
  1599. if (!GetInfoTipEx(_psf, dwFlags, _IDToPidl(uiCmd), pnmTT->pszText, pnmTT->cchTextMax))
  1600. {
  1601. TBBUTTONINFO tbbi = { 0};
  1602. tbbi.cbSize = SIZEOF(tbbi);
  1603. tbbi.dwMask = TBIF_TEXT;
  1604. tbbi.pszText = pnmTT->pszText;
  1605. tbbi.cchText = pnmTT->cchTextMax;
  1606. lres = (-1 != ToolBar_GetButtonInfo(_hwndTB, uiCmd, &tbbi));
  1607. }
  1608. break;
  1609. }
  1610. //BUGBUG: Right now I am calling the same function for both A and W version if this notification supports
  1611. // Strings then it needs to thunk. Right now its only used for image
  1612. case TBN_GETDISPINFOA:
  1613. _OnGetDispInfo(pnm, FALSE);
  1614. break;
  1615. case TBN_GETDISPINFOW:
  1616. _OnGetDispInfo(pnm, TRUE);
  1617. break;
  1618. case NM_TOOLTIPSCREATED:
  1619. _OnToolTipsCreated((NMTOOLTIPSCREATED*)pnm);
  1620. break;
  1621. case NM_RCLICK:
  1622. lres = _OnContextMenu(NULL, GetMessagePos());
  1623. break;
  1624. case NM_CUSTOMDRAW:
  1625. return _OnCustomDraw((NMCUSTOMDRAW*)pnm);
  1626. }
  1627. return(lres);
  1628. }
  1629. DWORD CSFToolbar::_GetAttributesOfPidl(LPCITEMIDLIST pidl, DWORD dwAttribs)
  1630. {
  1631. if (FAILED(_psf->GetAttributesOf(1, &pidl, &dwAttribs)))
  1632. dwAttribs = 0;
  1633. return dwAttribs;
  1634. }
  1635. PIBDATA CSFToolbar::_PosToPibData(UINT iPos)
  1636. {
  1637. ASSERT(IsWindow(_hwndTB));
  1638. // Initialize to NULL in case the GetButton Fails.
  1639. TBBUTTON tbb = {0};
  1640. PIBDATA pibData = NULL;
  1641. if (ToolBar_GetButton(_hwndTB, iPos, &tbb))
  1642. {
  1643. pibData = (PIBDATA)tbb.dwData;
  1644. }
  1645. return pibData;
  1646. }
  1647. PIBDATA CSFToolbar::_IDToPibData(UINT uiCmd, int * piPos)
  1648. {
  1649. PIBDATA pibdata = NULL;
  1650. // Initialize to NULL in case the GetButtonInfo Fails.
  1651. TBBUTTONINFO tbbi = {0};
  1652. int iPos;
  1653. tbbi.cbSize = SIZEOF(tbbi);
  1654. tbbi.dwMask = TBIF_LPARAM;
  1655. iPos = ToolBar_GetButtonInfo(_hwndTB, uiCmd, &tbbi);
  1656. if (iPos >= 0)
  1657. pibdata = (PIBDATA)tbbi.lParam;
  1658. if (piPos)
  1659. *piPos = iPos;
  1660. return pibdata;
  1661. }
  1662. LPCITEMIDLIST CSFToolbar::_IDToPidl(UINT uiCmd, int *piPos)
  1663. {
  1664. LPCITEMIDLIST pidl;
  1665. PIBDATA pibdata = _IDToPibData(uiCmd, piPos);
  1666. if (pibdata)
  1667. pidl = pibdata->GetPidl();
  1668. else
  1669. pidl = NULL;
  1670. return pidl;
  1671. }
  1672. /*----------------------------------------------------------
  1673. Purpose: IWinEventHandler::OnWinEvent method
  1674. Processes messages passed on from the bandsite.
  1675. */
  1676. HRESULT CSFToolbar::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  1677. {
  1678. *plres = 0;
  1679. // We are addref'n here because during the course of the
  1680. // Context menu, the view could be changed which free's the menu.
  1681. // We will release after we're sure the this pointer is no longer needed.
  1682. AddRef();
  1683. switch (uMsg) {
  1684. case WM_WININICHANGE:
  1685. if ((SHIsExplorerIniChange(wParam, lParam) == EICH_UNKNOWN) ||
  1686. (wParam == SPI_SETNONCLIENTMETRICS))
  1687. {
  1688. _UpdateIconSize(_uIconSize, TRUE);
  1689. _Refresh();
  1690. goto L_WM_SYSCOLORCHANGE;
  1691. }
  1692. break;
  1693. case WM_SYSCOLORCHANGE:
  1694. L_WM_SYSCOLORCHANGE:
  1695. SendMessage(_hwndTB, uMsg, wParam, lParam);
  1696. InvalidateRect(_hwndTB, NULL, TRUE);
  1697. break;
  1698. case WM_PALETTECHANGED:
  1699. InvalidateRect( _hwndTB, NULL, FALSE );
  1700. SendMessage( _hwndTB, uMsg, wParam, lParam );
  1701. break;
  1702. case WM_COMMAND:
  1703. *plres = _OnCommand(wParam, lParam);
  1704. break;
  1705. case WM_NOTIFY:
  1706. *plres = _OnNotify((LPNMHDR)lParam);
  1707. break;
  1708. case WM_CONTEXTMENU:
  1709. *plres = _OnContextMenu(wParam, lParam);
  1710. break;
  1711. }
  1712. Release();
  1713. return S_OK;
  1714. }
  1715. // Map the information loaded (or ctor) into _psf, [_pidl]
  1716. //
  1717. HRESULT CSFToolbar::_AfterLoad()
  1718. {
  1719. HRESULT hres = S_OK;
  1720. // if we have a pidl then we need to get ready
  1721. // for notifications...
  1722. //
  1723. if (_pidl)
  1724. {
  1725. // pidls must be rooted off the desktop
  1726. //
  1727. _fFSNotify = TRUE;
  1728. // shortcut -- just specifying a pidl is good enough
  1729. //
  1730. if (!_psf)
  1731. {
  1732. _fPSFBandDesktop = TRUE;
  1733. hres = IEBindToObject(_pidl, &_psf);
  1734. }
  1735. }
  1736. return(hres);
  1737. }
  1738. // IDropTarget implementation
  1739. //
  1740. /*----------------------------------------------------------
  1741. Purpose: CDelegateDropTarget::GetWindowsDDT
  1742. */
  1743. HRESULT CSFToolbar::GetWindowsDDT(HWND * phwndLock, HWND * phwndScroll)
  1744. {
  1745. *phwndLock = _hwndTB;
  1746. *phwndScroll = _hwndTB;
  1747. return S_OK;
  1748. }
  1749. /*----------------------------------------------------------
  1750. Purpose: CDelegateDropTarget::HitTestDDT
  1751. */
  1752. HRESULT CSFToolbar::HitTestDDT(UINT nEvent, LPPOINT ppt, DWORD_PTR * pdwId, DWORD *pdwEffect)
  1753. {
  1754. TBINSERTMARK tbim;
  1755. switch (nEvent)
  1756. {
  1757. case HTDDT_ENTER:
  1758. return S_OK;
  1759. case HTDDT_OVER:
  1760. {
  1761. int iButton = IBHT_BACKGROUND; // assume we hit the background
  1762. // if we're the source, this may be a move operation
  1763. //
  1764. *pdwEffect = (_iDragSource >= 0) ? DROPEFFECT_MOVE : DROPEFFECT_NONE;
  1765. if (!ToolBar_InsertMarkHitTest(_hwndTB, ppt, &tbim))
  1766. {
  1767. if (tbim.dwFlags & TBIMHT_BACKGROUND)
  1768. {
  1769. RECT rc;
  1770. GetClientRect(_hwndTB, &rc);
  1771. // are we outside the toolbar window entirely?
  1772. if (!PtInRect(&rc, *ppt))
  1773. {
  1774. // rebar already did the hittesting so we are on the rebar
  1775. // but not the toolbar => we are in the title part
  1776. if (!_AllowDropOnTitle())
  1777. {
  1778. // yes; don't allow drop here
  1779. iButton = IBHT_OUTSIDEWINDOW;
  1780. *pdwEffect = DROPEFFECT_NONE;
  1781. }
  1782. // set tbim.iButton to invalid value so we don't draw insert mark
  1783. tbim.iButton = -1;
  1784. }
  1785. }
  1786. else
  1787. {
  1788. // nope, we hit a real button
  1789. //
  1790. if (tbim.iButton == _iDragSource)
  1791. {
  1792. iButton = IBHT_SOURCE; // don't drop on the source button
  1793. }
  1794. else
  1795. {
  1796. iButton = tbim.iButton;
  1797. }
  1798. tbim.iButton = IBHT_BACKGROUND;
  1799. // we never force a move operation if we're on a real button
  1800. *pdwEffect = DROPEFFECT_NONE;
  1801. }
  1802. }
  1803. *pdwId = iButton;
  1804. }
  1805. break;
  1806. case HTDDT_LEAVE:
  1807. // Reset
  1808. tbim.iButton = IBHT_BACKGROUND;
  1809. tbim.dwFlags = 0;
  1810. break;
  1811. default:
  1812. return E_INVALIDARG;
  1813. }
  1814. // update ui
  1815. if (tbim.iButton != _tbim.iButton || tbim.dwFlags != _tbim.dwFlags)
  1816. {
  1817. if (ppt)
  1818. _tbim = tbim;
  1819. // for now I don't want to rely on non-filesystem IShellFolder
  1820. // implementations to call our OnChange method when a drop occurs,
  1821. // so don't even show the insert mark.
  1822. //
  1823. if (_fFSNotify || _iDragSource >= 0)
  1824. {
  1825. DAD_ShowDragImage(FALSE);
  1826. ToolBar_SetInsertMark(_hwndTB, &tbim);
  1827. DAD_ShowDragImage(TRUE);
  1828. }
  1829. }
  1830. return S_OK;
  1831. }
  1832. /*----------------------------------------------------------
  1833. Purpose: CDelegateDropTarget::GetObjectDDT
  1834. */
  1835. HRESULT CSFToolbar::GetObjectDDT(DWORD_PTR dwId, REFIID riid, LPVOID * ppvObj)
  1836. {
  1837. HRESULT hres = E_NOINTERFACE;
  1838. *ppvObj = NULL;
  1839. if ((IBHT_SOURCE == dwId) || (IBHT_OUTSIDEWINDOW == dwId))
  1840. {
  1841. // do nothing
  1842. }
  1843. else if (IBHT_BACKGROUND == dwId)
  1844. {
  1845. // nash:41937: not sure how, but _psf can be NULL...
  1846. if (EVAL(_psf))
  1847. hres = _psf->CreateViewObject(_hwndTB, riid, ppvObj);
  1848. }
  1849. else
  1850. {
  1851. LPCITEMIDLIST pidl = _IDToPidl((UINT)dwId, NULL);
  1852. if (pidl)
  1853. {
  1854. *ppvObj = _GetUIObjectOfPidl(pidl, riid);
  1855. if (*ppvObj)
  1856. hres = S_OK;
  1857. }
  1858. }
  1859. //TraceMsg(TF_BAND, "SFToolbar::GetObject(%d) returns %x", dwId, hres);
  1860. return hres;
  1861. }
  1862. HRESULT CSFToolbar::_SaveOrderStream()
  1863. {
  1864. if (_fChangedOrder)
  1865. {
  1866. // Notify everyone that the order changed
  1867. SHSendChangeMenuNotify(this, SHCNEE_ORDERCHANGED, 0, _pidl);
  1868. _fChangedOrder = FALSE;
  1869. return S_OK;
  1870. }
  1871. else
  1872. return S_FALSE;
  1873. }
  1874. void CSFToolbar::_Dropped(int nIndex, BOOL fDroppedOnSource)
  1875. {
  1876. _fDropped = TRUE;
  1877. _fChangedOrder = TRUE;
  1878. // Save new order stream
  1879. _SaveOrderStream();
  1880. if (fDroppedOnSource)
  1881. _FlushNotifyMessages(_hwndTB);
  1882. }
  1883. /*----------------------------------------------------------
  1884. Purpose: CDelegateDropTarget::OnDropDDT
  1885. */
  1886. HRESULT CSFToolbar::OnDropDDT(IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect)
  1887. {
  1888. // Are we NOT the drag source?
  1889. if (_iDragSource == -1)
  1890. {
  1891. // No, we're not. Well, then the source may be the chevron menu
  1892. // representing the hidden items in this menu. Let's check
  1893. LPITEMIDLIST pidl;
  1894. if (SUCCEEDED(SHPidlFromDataObject2(pdtobj, &pidl)))
  1895. {
  1896. // We've got a pidl, Are we the parent? Do we have a button?
  1897. int iIndex;
  1898. if (ILIsParent(_pidl, pidl, TRUE) &&
  1899. _GetButtonFromPidl(ILFindLastID(pidl), NULL, &iIndex))
  1900. {
  1901. // We are the parent! Then let's copy that down and set it
  1902. // as the drag source so that down below we reorder.
  1903. _iDragSource = iIndex;
  1904. }
  1905. ILFree(pidl);
  1906. }
  1907. }
  1908. if (_iDragSource >= 0)
  1909. {
  1910. if (_fAllowReorder)
  1911. {
  1912. TraceMsg(TF_BAND, "SFToolbar::OnDrop reorder %d to %d %s", _iDragSource, _tbim.iButton, _tbim.dwFlags & TBIMHT_AFTER ? "A" : "B");
  1913. int iNewLocation = _tbim.iButton;
  1914. if (_tbim.dwFlags & TBIMHT_AFTER)
  1915. iNewLocation++;
  1916. if (iNewLocation > _iDragSource)
  1917. iNewLocation--;
  1918. if (ToolBar_MoveButton(_hwndTB, _iDragSource, iNewLocation))
  1919. {
  1920. PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, _iDragSource);
  1921. DPA_DeletePtr(_hdpa, _iDragSource);
  1922. DPA_InsertPtr(_hdpa, iNewLocation, poi);
  1923. OrderList_Reorder(_hdpa);
  1924. // If we're dropping again, then we don't need the _hdpaOrder...
  1925. OrderList_Destroy(&_hdpaOrder);
  1926. // A reorder has occurred. We need to use the order stream as the order...
  1927. _fHasOrder = TRUE;
  1928. _fDropping = TRUE;
  1929. _Dropped(iNewLocation, TRUE);
  1930. _fDropping = FALSE;
  1931. _RememberOrder();
  1932. _SetDirty(TRUE);
  1933. }
  1934. }
  1935. // Don't forget to reset this!
  1936. _iDragSource = -1;
  1937. DragLeave();
  1938. }
  1939. else
  1940. {
  1941. // We want to override the default to be LINK (SHIFT+CONTROL)
  1942. if ((GetPreferedDropEffect(pdtobj) == 0) &&
  1943. !(*pgrfKeyState & (MK_CONTROL | MK_SHIFT | MK_ALT)))
  1944. {
  1945. // NOTE: not all data objects will allow us to call SetData()
  1946. _SetPreferedDropEffect(pdtobj, DROPEFFECT_LINK);
  1947. }
  1948. _fDropping = TRUE;
  1949. return S_OK;
  1950. }
  1951. return S_FALSE;
  1952. }
  1953. void CSFToolbar::_SortDPA(HDPA hdpa)
  1954. {
  1955. // If we don't have a _psf, then we certainly can't sort it
  1956. // If we don't have a hdpa, then we certainly can't sort it
  1957. // If the hdpa is empty, then there's no point in sorting it
  1958. if (_psf && hdpa && DPA_GetPtrCount(hdpa))
  1959. {
  1960. ORDERINFO oinfo;
  1961. oinfo.psf = _psf;
  1962. (oinfo.psf)->AddRef();
  1963. oinfo.dwSortBy = (_fNoNameSort ? OI_SORTBYORDINAL : OI_SORTBYNAME);
  1964. DPA_Sort(hdpa, OrderItem_Compare, (LPARAM)&oinfo);
  1965. ATOMICRELEASE(oinfo.psf);
  1966. }
  1967. }
  1968. void CSFToolbar::_RememberOrder()
  1969. {
  1970. OrderList_Destroy(&_hdpaOrder);
  1971. if (_hdpa)
  1972. {
  1973. _hdpaOrder = OrderList_Clone(_hdpa);
  1974. _SortDPA(_hdpaOrder);
  1975. }
  1976. }
  1977. HMENU CSFToolbar::_GetBaseContextMenu()
  1978. {
  1979. HMENU hmenu = LoadMenuPopup_PrivateNoMungeW(MENU_ISFBAND);
  1980. // no logo view, remove the menu item...
  1981. HMENU hView = GetSubMenu( hmenu, 0 );
  1982. DeleteMenu( hView, ISFBIDM_LOGOS, MF_BYCOMMAND );
  1983. return hmenu;
  1984. }
  1985. HMENU CSFToolbar::_GetContextMenu()
  1986. {
  1987. HMENU hmenuSrc = _GetBaseContextMenu();
  1988. if (hmenuSrc)
  1989. {
  1990. MENUITEMINFO mii;
  1991. mii.cbSize = SIZEOF(mii);
  1992. mii.fMask = MIIM_STATE;
  1993. mii.fState = MF_CHECKED;
  1994. UINT uCmdId = ISFBIDM_LOGOS;
  1995. if ( _uIconSize != ISFBVIEWMODE_LOGOS )
  1996. uCmdId = (_uIconSize == ISFBVIEWMODE_LARGEICONS ? ISFBIDM_LARGE : ISFBIDM_SMALL);
  1997. SetMenuItemInfo(hmenuSrc, uCmdId, MF_BYCOMMAND, &mii);
  1998. if (!_fNoShowText)
  1999. SetMenuItemInfo(hmenuSrc, ISFBIDM_SHOWTEXT, MF_BYCOMMAND, &mii);
  2000. if (!_fFSNotify || !_pidl || ILIsEmpty(_pidl))
  2001. DeleteMenu(hmenuSrc, ISFBIDM_OPEN, MF_BYCOMMAND);
  2002. HMENU hView = GetSubMenu( hmenuSrc, 0 );
  2003. DeleteMenu( hView, ISFBIDM_LOGOS, MF_BYCOMMAND );
  2004. }
  2005. return hmenuSrc;
  2006. }
  2007. // IContextMenu implementation
  2008. //
  2009. HRESULT CSFToolbar::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  2010. {
  2011. HMENU hmenuSrc = _GetContextMenu();
  2012. int i = 0;
  2013. if ( hmenuSrc )
  2014. {
  2015. i += Shell_MergeMenus(hmenu, hmenuSrc, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
  2016. DestroyMenu(hmenuSrc);
  2017. }
  2018. if (!_pcmSF && _fAllowRename && _psf)
  2019. {
  2020. _psf->CreateViewObject(_hwndTB, IID_IContextMenu, (LPVOID*)&_pcmSF);
  2021. }
  2022. if (_pcmSF)
  2023. {
  2024. HRESULT hresT;
  2025. _idCmdSF = i - idCmdFirst;
  2026. hresT = _pcmSF->QueryContextMenu(hmenu, indexMenu + i, i, 0x7fff, CMF_BANDCMD);
  2027. if (SUCCEEDED(hresT))
  2028. i += HRESULT_CODE(hresT);
  2029. }
  2030. return i;
  2031. }
  2032. BOOL CSFToolbar::_UpdateShowText(BOOL fNoShowText)
  2033. {
  2034. BOOL fChanged = (!_fNoShowText != !fNoShowText);
  2035. _fNoShowText = (fNoShowText != 0);
  2036. TraceMsg(TF_BAND, "ISFBand::_UpdateShowText turning text %hs", _fNoShowText ? "OFF" : "ON");
  2037. if (_hwndTB)
  2038. {
  2039. SendMessage(_hwndTB, TB_SETMAXTEXTROWS, _fNoShowText ? 0 : 1, 0L);
  2040. _UpdateButtons();
  2041. }
  2042. return fChanged;
  2043. }
  2044. HRESULT CSFToolbar::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
  2045. {
  2046. BOOL fChanged = FALSE;
  2047. int idCmd = -1;
  2048. if (!HIWORD(lpici->lpVerb))
  2049. idCmd = LOWORD(lpici->lpVerb);
  2050. switch (idCmd)
  2051. {
  2052. case ISFBIDM_REFRESH:
  2053. _Refresh();
  2054. break;
  2055. case ISFBIDM_OPEN:
  2056. OpenFolderPidl(_pidl);
  2057. break;
  2058. case ISFBIDM_LARGE:
  2059. fChanged = _UpdateIconSize(ISFBVIEWMODE_LARGEICONS, TRUE);
  2060. break;
  2061. case ISFBIDM_SMALL:
  2062. fChanged = _UpdateIconSize(ISFBVIEWMODE_SMALLICONS, TRUE);
  2063. break;
  2064. case ISFBIDM_SHOWTEXT:
  2065. fChanged = _UpdateShowText(!_fNoShowText);
  2066. break;
  2067. default:
  2068. if (_pcmSF && idCmd >= _idCmdSF)
  2069. {
  2070. LPCSTR lpOldVerb = lpici->lpVerb;
  2071. lpici->lpVerb = MAKEINTRESOURCEA(idCmd -= _idCmdSF);
  2072. _pcmSF->InvokeCommand(lpici);
  2073. _FlushNotifyMessages(_hwndTB);
  2074. lpici->lpVerb = lpOldVerb;
  2075. }
  2076. else
  2077. TraceMsg(TF_BAND, "SFToolbar::InvokeCommand %d not handled", idCmd);
  2078. break;
  2079. }
  2080. // Our minimum sizes have changed, notify the bandsite
  2081. //
  2082. if (fChanged)
  2083. _ToolbarChanged();
  2084. return(S_OK);
  2085. }
  2086. HRESULT CSFToolbar::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax)
  2087. {
  2088. return(E_NOTIMPL);
  2089. }
  2090. void CSFToolbar::_RegisterToolbar()
  2091. {
  2092. // Since _SubclassWindow protects against multiply subclassing,
  2093. // This call is safe, and ensures that the toolbar is subclassed before
  2094. // even trying to register it for change notify.
  2095. if (_hwndTB && _SubclassWindow(_hwndTB) && _fRegisterChangeNotify)
  2096. _RegisterChangeNotify();
  2097. CDelegateDropTarget::Init();
  2098. }
  2099. void CSFToolbar::_UnregisterToolbar()
  2100. {
  2101. if (_hwndTB)
  2102. {
  2103. if (_fRegisterChangeNotify)
  2104. _UnregisterChangeNotify();
  2105. _UnsubclassWindow(_hwndTB);
  2106. }
  2107. }
  2108. void CSFToolbar::_RegisterChangeNotify()
  2109. {
  2110. // Since we want to register for change notify ONLY once,
  2111. // and only if this is a file system toolbar.
  2112. if (!_fFSNRegistered && _fFSNotify)
  2113. {
  2114. if (_ptscn)
  2115. _ptscn->Register(_hwndTB, g_idFSNotify, _lEvents);
  2116. else
  2117. _RegisterWindow(_hwndTB, _pidl, _lEvents);
  2118. _fFSNRegistered = TRUE;
  2119. }
  2120. }
  2121. void CSFToolbar::_UnregisterChangeNotify()
  2122. {
  2123. // Only unregister if we have been registered.
  2124. if (_hwndTB && _fFSNRegistered && _fFSNotify)
  2125. {
  2126. _fFSNRegistered = FALSE;
  2127. if (_ptscn)
  2128. _ptscn->Unregister();
  2129. else
  2130. _UnregisterWindow(_hwndTB);
  2131. }
  2132. }
  2133. void CSFToolbar::_ReleaseShellFolder()
  2134. {
  2135. if (_psf)
  2136. {
  2137. IUnknown_SetOwner(_psf, NULL);
  2138. ATOMICRELEASE(_psf);
  2139. }
  2140. ATOMICRELEASE(_ptscn);
  2141. }
  2142. /*----------------------------------------------------------
  2143. Purpose: IWinEventHandler::IsWindowOwner method.
  2144. */
  2145. HRESULT CSFToolbar::IsWindowOwner(HWND hwnd)
  2146. {
  2147. if (hwnd == _hwndTB ||
  2148. hwnd == _hwndToolTips ||
  2149. hwnd == _hwndPager)
  2150. return S_OK;
  2151. return S_FALSE;
  2152. }