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.

1209 lines
33 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "mnstatic.h"
  4. #include "menuband.h"
  5. #include "itbar.h"
  6. #include "dpastuff.h" // COrderList_*
  7. #include "resource.h"
  8. #include "mnbase.h"
  9. #include "oleacc.h"
  10. #include "apithk.h"
  11. #include "menuisf.h"
  12. HMENU g_hmenuStopWatch = NULL;
  13. UINT g_idCmdStopWatch = 0;
  14. //*** IDTTOIDM -- convert idtCmd to idmMenu
  15. // NOTES
  16. // as an optimization, we make the toolbar idtCmd the same as the menu idm.
  17. // this macro (hopefully) makes things a bit clearer in the code by making
  18. // the type conversion explicit.
  19. #define IDTTOIDM(idtBtn) (idtBtn)
  20. BOOL TBHasImage(HWND hwnd, int iImageIndex);
  21. //------------------------------------------------------------------------
  22. //
  23. // CMenuStaticToolbar::CMenuStaticData class
  24. //
  25. //------------------------------------------------------------------------
  26. CMenuStaticToolbar::CMenuStaticData::~CMenuStaticData()
  27. {
  28. ATOMICRELEASE(_punkSubMenu);
  29. }
  30. void CMenuStaticToolbar::CMenuStaticData::SetSubMenu(IUnknown* punk)
  31. {
  32. ATOMICRELEASE(_punkSubMenu);
  33. _punkSubMenu = punk;
  34. if (_punkSubMenu)
  35. _punkSubMenu->AddRef();
  36. }
  37. HRESULT CMenuStaticToolbar::CMenuStaticData::GetSubMenu(const GUID* pguidService, REFIID riid, void** ppvObj)
  38. {
  39. if (_punkSubMenu)
  40. {
  41. if (pguidService)
  42. {
  43. return IUnknown_QueryService(_punkSubMenu, *pguidService, riid, ppvObj);
  44. }
  45. else
  46. return _punkSubMenu->QueryInterface(riid, ppvObj);
  47. }
  48. else
  49. return E_NOINTERFACE;
  50. }
  51. //------------------------------------------------------------------------
  52. //
  53. // CMenuStaticToolbar
  54. //
  55. //------------------------------------------------------------------------
  56. CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand* pmb, HMENU hmenu, HWND hwnd, UINT idCmd, DWORD dwFlags)
  57. : CMenuToolbarBase(pmb, dwFlags)
  58. {
  59. _hmenu = hmenu;
  60. _hwndMenuOwner = hwnd;
  61. _idCmd = idCmd;
  62. _iDragOverButton = -1;
  63. _fDirty = TRUE;
  64. }
  65. CMenuStaticToolbar::~CMenuStaticToolbar()
  66. {
  67. if (!(_dwFlags & SMSET_DONTOWN))
  68. {
  69. DestroyMenu(_hmenu);
  70. }
  71. }
  72. STDMETHODIMP CMenuStaticToolbar::QueryInterface(REFIID riid, void** ppvObj)
  73. {
  74. static const QITAB qit[] =
  75. {
  76. QITABENT(CMenuStaticToolbar, IDropTarget),
  77. { 0 },
  78. };
  79. // BUGBUG: If you QI MenuStatic for a drop target, you get a different
  80. // one than if you QI MenuShellFolder. This breaks COM identity rules.
  81. // Proper fix would be to implement a drop target that encapsulates both.
  82. HRESULT hres = QISearch(this, qit, riid, ppvObj);
  83. if (FAILED(hres))
  84. hres = CMenuToolbarBase::QueryInterface(riid, ppvObj);
  85. return hres;
  86. }
  87. void CMenuStaticToolbar::_CheckSeparators()
  88. {
  89. if (_fHasTopSep)
  90. {
  91. if (_pcmb->_pmtbTop->DontShowEmpty() )
  92. {
  93. if (!_fTopSepRemoved)
  94. {
  95. SendMessage(_hwndMB, TB_DELETEBUTTON, 0, 0);
  96. _fTopSepRemoved = TRUE;
  97. }
  98. }
  99. else
  100. {
  101. if (_fTopSepRemoved)
  102. {
  103. MENUITEMINFO mii = {0};
  104. mii.cbSize = sizeof(mii);
  105. mii.fType = MFT_SEPARATOR;
  106. _Insert(0, &mii);
  107. _fTopSepRemoved = FALSE;
  108. }
  109. }
  110. }
  111. if (_fHasBottomSep)
  112. {
  113. if (_pcmb->_pmtbBottom->DontShowEmpty() )
  114. {
  115. if (!_fBottomSepRemoved)
  116. {
  117. SendMessage(_hwndMB, TB_DELETEBUTTON, ToolBar_ButtonCount(_hwndMB) - 1, 0);
  118. _fBottomSepRemoved = TRUE;
  119. }
  120. }
  121. else
  122. {
  123. if (_fBottomSepRemoved)
  124. {
  125. MENUITEMINFO mii = {0};
  126. mii.cbSize = sizeof(mii);
  127. mii.fType = SMIT_SEPARATOR;
  128. _Insert(-1, &mii);
  129. _fBottomSepRemoved = FALSE;
  130. }
  131. }
  132. }
  133. }
  134. void CMenuStaticToolbar::v_Show(BOOL fShow, BOOL fForceUpdate)
  135. {
  136. CMenuToolbarBase::v_Show(fShow, fForceUpdate);
  137. _fShowMB = fShow;
  138. if (fShow)
  139. {
  140. _fFirstTime = FALSE;
  141. _fClickHandled = FALSE;
  142. _FillToolbar();
  143. _pcmb->SetTracked(NULL);
  144. ToolBar_SetHotItem(_hwndMB, -1);
  145. // Have the menubar think about changing its height
  146. IUnknown_QueryServiceExec(_pcmb->_punkSite, SID_SMenuPopup, &CGID_MENUDESKBAR,
  147. MBCID_SETEXPAND, (int)_pcmb->_fExpanded, NULL, NULL);
  148. if (fForceUpdate)
  149. v_UpdateButtons(FALSE);
  150. #if 0
  151. // need top level frame available for D&D if possible.
  152. _hwndDD = GetParent(_hwndMB);
  153. IOleWindow *pOleWindow;
  154. HRESULT hr = IUnknown_QueryService(_pcmb->_punkSite, SID_STopLevelBrowser
  155. , IID_IOleWindow, (void **)&pOleWindow);
  156. if(SUCCEEDED(hr))
  157. {
  158. ASSERT(pOleWindow);
  159. pOleWindow->GetWindow(&_hwndDD);
  160. pOleWindow->Release();
  161. }
  162. #endif
  163. CDelegateDropTarget::Init();
  164. }
  165. else
  166. KillTimer(_hwndMB, MBTIMER_UEMTIMEOUT);
  167. // n.b. for !fShow, we don't kill the tracked site chain. we
  168. // count on this in startmnu.cpp!CStartMenuCallback::_OnExecItem,
  169. // where we walk up the chain to find all hit 'nodes'. if we need
  170. // to change this we could fire a 'pre-exec' event.
  171. }
  172. void CMenuStaticToolbar::_Insert(int iIndex, MENUITEMINFO* pmii)
  173. {
  174. CMenuStaticData* pmsd = new CMenuStaticData();
  175. if (pmsd)
  176. {
  177. BYTE bTBStyle = TBSTYLE_BUTTON | TBSTYLE_DROPDOWN;
  178. SMINFO sminfo = {0};
  179. sminfo.dwMask = SMIM_TYPE | SMIM_FLAGS | SMIM_ICON;
  180. // These are somethings that the callback does not fill in:
  181. if ( pmii->hSubMenu )
  182. sminfo.dwFlags |= SMIF_SUBMENU;
  183. if ( pmii->fState & MFS_CHECKED)
  184. sminfo.dwFlags |= SMIF_CHECKED;
  185. if (pmii->fState & MFS_DISABLED || pmii->fState & MFS_GRAYED)
  186. sminfo.dwFlags |= SMIF_DISABLED;
  187. if ( pmii->fType & MFT_SEPARATOR)
  188. {
  189. sminfo.dwType = SMIT_SEPARATOR;
  190. bTBStyle &= ~TBSTYLE_BUTTON;
  191. bTBStyle |= TBSTYLE_SEP;
  192. }
  193. else
  194. sminfo.dwType = SMIT_STRING;
  195. if (!_fVerticalMB)
  196. bTBStyle |= TBSTYLE_AUTOSIZE;
  197. if (S_OK != CallCB(pmii->wID, SMC_GETINFO, 0, (LPARAM)&sminfo))
  198. {
  199. sminfo.iIcon = -1;
  200. }
  201. pmsd->_dwFlags = sminfo.dwFlags;
  202. // Now add it to the toolbar
  203. TBBUTTON tbb = {0};
  204. tbb.iBitmap = sminfo.iIcon;
  205. tbb.idCommand = pmii->wID;
  206. tbb.dwData = (DWORD_PTR)pmsd;
  207. tbb.fsState = (sminfo.dwFlags & SMIF_HIDDEN)?TBSTATE_HIDDEN : TBSTATE_ENABLED;
  208. tbb.fsStyle = bTBStyle;
  209. TCHAR szMenuString[MAX_PATH];
  210. if (pmii->fType & MFT_OWNERDRAW)
  211. {
  212. // dwTypeData is user defined 32 bit value, not a string if MFT_OWNERDRAW is set
  213. // then the (unicode) string is the very first element in a structure dwItemData
  214. // points to
  215. LPWSTR pwsz = (LPWSTR)pmii->dwItemData;
  216. SHUnicodeToTChar(pwsz, szMenuString, ARRAYSIZE(szMenuString));
  217. tbb.iString = (INT_PTR)(szMenuString);
  218. }
  219. else
  220. tbb.iString = (INT_PTR)(LPTSTR)pmii->dwTypeData;
  221. SendMessage(_hwndMB, TB_INSERTBUTTON, iIndex, (LPARAM)&tbb);
  222. }
  223. }
  224. /*----------------------------------------------------------
  225. Purpose: GetMenu method
  226. */
  227. HRESULT CMenuStaticToolbar::GetMenu(HMENU* phmenu, HWND* phwnd, DWORD* pdwFlags)
  228. {
  229. if (phmenu)
  230. *phmenu = _hmenu;
  231. if (phwnd)
  232. *phwnd = _hwndMenuOwner;
  233. if (pdwFlags)
  234. *pdwFlags = _dwFlags;
  235. return NOERROR;
  236. }
  237. HRESULT CMenuStaticToolbar::SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags)
  238. {
  239. // When we are merging in a new menu, we need to destroy the old one if we own it.
  240. if (_hmenu && !(_dwFlags & SMSET_DONTOWN))
  241. {
  242. DestroyMenu(_hmenu);
  243. }
  244. _hmenu = hmenu;
  245. // If we're processing a change notify, we cannot do anything that will modify state.
  246. if (_pcmb->_pmbState &&
  247. _pcmb->_pmbState->IsProcessingChangeNotify())
  248. {
  249. _fDirty = TRUE;
  250. }
  251. else
  252. {
  253. EmptyToolbar();
  254. _pcmb->_fInSubMenu = FALSE;
  255. IUnknown_SetSite(_pcmb->_pmpSubMenu, NULL);
  256. ATOMICRELEASE(_pcmb->_pmpSubMenu);
  257. if (_fShowMB)
  258. _FillToolbar();
  259. BOOL fSmooth = FALSE;
  260. #ifdef CLEARTYPE // Don't use SPI_CLEARTYPE because it's defined because of APIThk, but not in NT.
  261. SystemParametersInfo(SPI_GETCLEARTYPE, 0, &fSmooth, 0);
  262. #endif
  263. // This causes a paint to occur right away instead of waiting until the
  264. // next message dispatch which could take a noticably long time.
  265. RedrawWindow(_hwndMB, NULL, NULL, (fSmooth? RDW_ERASE: 0) | RDW_INVALIDATE | RDW_UPDATENOW);
  266. }
  267. return NOERROR;
  268. }
  269. CMenuStaticToolbar::CMenuStaticData* CMenuStaticToolbar::_IDToData(int idCmd)
  270. {
  271. CMenuStaticData* pmsd= NULL;
  272. // Initialize to NULL in case the GetButtonInfo Fails. We won't fault because
  273. // the lParam is just stack garbage.
  274. TBBUTTONINFO tbbi = {0};
  275. int iPos;
  276. tbbi.cbSize = SIZEOF(tbbi);
  277. tbbi.dwMask = TBIF_LPARAM;
  278. iPos = ToolBar_GetButtonInfo(_hwndMB, idCmd, &tbbi);
  279. if (iPos >= 0)
  280. pmsd = (CMenuStaticData*)tbbi.lParam;
  281. return pmsd;
  282. }
  283. HRESULT CMenuStaticToolbar::v_CreateTrackPopup(int idCmd, REFIID riid, void** ppvObj)
  284. {
  285. HRESULT hres = E_OUTOFMEMORY;
  286. int iPos = (int)SendMessage(_hwndMB, TB_COMMANDTOINDEX, idCmd, 0);
  287. if (iPos >= 0)
  288. {
  289. CTrackPopupBar* ptpb = new CTrackPopupBar(_pcmb->_pmbState->GetContext(), iPos, _hmenu, _hwndMenuOwner);
  290. if (ptpb)
  291. {
  292. hres = ptpb->QueryInterface(riid, ppvObj);
  293. if (SUCCEEDED(hres))
  294. IUnknown_SetSite(SAFECAST(ptpb, IMenuPopup*), SAFECAST(_pcmb, IMenuPopup*));
  295. PostMessage(_pcmb->_pmbState->GetSubclassedHWND(), g_nMBAutomation, (WPARAM)_hmenu, (LPARAM)iPos);
  296. ptpb->Release();
  297. }
  298. }
  299. return hres;
  300. }
  301. HRESULT CMenuStaticToolbar::v_GetSubMenu(int idCmd, const GUID* pguidService, REFIID riid, void** ppvObj)
  302. {
  303. HRESULT hres = E_FAIL;
  304. CMenuStaticData* pmsd = _IDToData(idCmd);
  305. ASSERT(IS_VALID_WRITE_PTR(ppvObj, void*));
  306. *ppvObj = NULL;
  307. if (pmsd)
  308. {
  309. // Get the cached submenu
  310. hres = pmsd->GetSubMenu(pguidService, riid, ppvObj);
  311. // Did that fail?
  312. if (FAILED(hres) && (pmsd->_dwFlags & SMIF_SUBMENU) &&
  313. IsEqualGUID(riid, IID_IShellMenu))
  314. {
  315. // Yes; ask the callback for it
  316. hres = CallCB(idCmd, SMC_GETOBJECT, (WPARAM)&riid, (LPARAM)ppvObj);
  317. if (S_OK != hres)
  318. {
  319. hres = E_OUTOFMEMORY; // Set to error case incase something happens
  320. // Callback didn't handle it, try and see if we can get it
  321. MENUITEMINFO mii;
  322. mii.cbSize = sizeof(MENUITEMINFO);
  323. mii.fMask = MIIM_SUBMENU | MIIM_ID;
  324. if (GetMenuItemInfoWrap(_hmenu, idCmd, MF_BYCOMMAND, &mii) && mii.hSubMenu)
  325. {
  326. IShellMenu* psm = (IShellMenu*)new CMenuBand();
  327. if (psm)
  328. {
  329. UINT uIdAncestor = _pcmb->_uIdAncestor;
  330. if (uIdAncestor == ANCESTORDEFAULT)
  331. uIdAncestor = idCmd;
  332. psm->Initialize(_pcmb->_psmcb, idCmd, uIdAncestor, SMINIT_VERTICAL);
  333. psm->SetMenu(mii.hSubMenu, _hwndMenuOwner, SMSET_TOP | SMSET_DONTOWN);
  334. hres = psm->QueryInterface(riid, ppvObj);
  335. psm->Release();
  336. }
  337. }
  338. }
  339. if (*ppvObj)
  340. {
  341. // Cache it now
  342. pmsd->SetSubMenu((IUnknown*)*ppvObj);
  343. // Initialize the fonts
  344. VARIANT Var;
  345. Var.vt = VT_UNKNOWN;
  346. Var.byref = SAFECAST(_pcmb->_pmbm, IUnknown*);
  347. IUnknown_Exec((IUnknown*)*ppvObj, &CGID_MenuBand, MBANDCID_SETFONTS, 0, &Var, NULL);
  348. // Set the CMenuBandState into the new menuband
  349. Var.vt = VT_INT_PTR;
  350. Var.byref = _pcmb->_pmbState;
  351. IUnknown_Exec((IUnknown*)*ppvObj, &CGID_MenuBand, MBANDCID_SETSTATEOBJECT, 0, &Var, NULL);
  352. }
  353. }
  354. }
  355. return hres;
  356. }
  357. HRESULT CMenuStaticToolbar::v_GetInfoTip(int idCmd, LPTSTR psz, UINT cch)
  358. {
  359. return CallCB(idCmd, SMC_GETINFOTIP, (WPARAM)psz, (LPARAM)cch);
  360. }
  361. HRESULT CMenuStaticToolbar::v_ExecItem(int idCmd)
  362. {
  363. HRESULT hres = CallCB(idCmd, SMC_EXEC, 0, 0);
  364. if (S_OK != hres && _hwndMenuOwner)
  365. {
  366. PostMessage(_hwndMenuOwner, WM_COMMAND, idCmd, 0);
  367. hres = NOERROR;
  368. }
  369. return hres;
  370. }
  371. DWORD CMenuStaticToolbar::v_GetFlags(int idCmd)
  372. {
  373. CMenuStaticData* pmsd = _IDToData(idCmd);
  374. // Toolbar is allowed to pass a bad command in the case of erasing the background
  375. if (pmsd)
  376. {
  377. return pmsd->_dwFlags;
  378. }
  379. else
  380. return 0;
  381. }
  382. void CMenuStaticToolbar::v_SendMenuNotification(UINT idCmd, BOOL fClear)
  383. {
  384. if (S_FALSE == CallCB(idCmd, SMC_SELECTITEM, (WPARAM)fClear, 0))
  385. {
  386. UINT uFlags = (UINT)-1;
  387. if (v_GetFlags(idCmd) & SMIF_SUBMENU)
  388. uFlags = MF_POPUP;
  389. if (!fClear)
  390. uFlags = MF_HILITE;
  391. PostMessage(_pcmb->_pmbState->GetSubclassedHWND(), WM_MENUSELECT,
  392. MAKEWPARAM(idCmd, uFlags), fClear? NULL : (LPARAM)_hmenu);
  393. }
  394. }
  395. BOOL CMenuStaticToolbar::v_TrackingSubContextMenu()
  396. {
  397. return (_pcm != NULL);
  398. }
  399. void CMenuStaticToolbar::CreateToolbar(HWND hwndParent)
  400. {
  401. if (!_hwndMB)
  402. {
  403. _hwndMB = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, TEXT("Menu"),
  404. WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
  405. WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  406. CCS_NODIVIDER | CCS_NOPARENTALIGN |
  407. CCS_NORESIZE | TBSTYLE_REGISTERDROP,
  408. 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
  409. if (!_hwndMB)
  410. {
  411. TraceMsg(TF_MENUBAND, "CMenuStaticToolbar::CreateToolbar: Failed to Create Toolbar");
  412. return;
  413. }
  414. SendMessage(_hwndMB, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
  415. SendMessage(_hwndMB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  416. // Set the format to ANSI or UNICODE as appropriate.
  417. ToolBar_SetUnicodeFormat(_hwndMB, DLL_IS_UNICODE);
  418. _SubclassWindow(_hwndMB);
  419. _RegisterWindow(_hwndMB, NULL, SHCNE_UPDATEIMAGE);
  420. SIZE size;
  421. RECT rc;
  422. SystemParametersInfoA(SPI_GETWORKAREA, SIZEOF(RECT), &rc, FALSE);
  423. //HACKHACK: THIS WILL FORCE NO WRAP TO HAPPEN FOR PROPER WIDTH CALC WHEN PAGER IS PRESENT.
  424. size.cx = RECTWIDTH(rc);
  425. size.cy = 32000;
  426. ToolBar_SetBoundingSize(_hwndMB, &size);
  427. CMenuToolbarBase::CreateToolbar(hwndParent);
  428. }
  429. else if (GetParent(_hwndMB) != hwndParent)
  430. {
  431. ::SetParent(_hwndMB, hwndParent);
  432. }
  433. }
  434. STDMETHODIMP CMenuStaticToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  435. {
  436. if (SHCNE_UPDATEIMAGE == lEvent) // global
  437. {
  438. if (pidl1)
  439. {
  440. int iImage = *(int UNALIGNED *)((BYTE *)pidl1 + 2);
  441. IEInvalidateImageList(); // We may need to use different icons.
  442. if ( pidl2 )
  443. {
  444. iImage = SHHandleUpdateImage( pidl2 );
  445. if ( iImage == -1 )
  446. {
  447. return E_FAIL;
  448. }
  449. }
  450. if (iImage == -1 || TBHasImage(_hwndMB, iImage))
  451. {
  452. v_Refresh();
  453. }
  454. }
  455. else
  456. {
  457. v_Refresh();
  458. }
  459. return S_OK;
  460. }
  461. return E_FAIL;
  462. }
  463. LRESULT CMenuStaticToolbar::_DefWindowProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  464. {
  465. LRESULT lres = 0;
  466. switch(uMessage)
  467. {
  468. case WM_TIMER:
  469. if (_OnTimer(wParam))
  470. return 1;
  471. break;
  472. case WM_GETOBJECT:
  473. // Yet another poor design choice on the part of the accessibility team.
  474. // Typically, if you do not answer a WM_* you return 0. They choose 0 as their success
  475. // code.
  476. return _DefWindowProcMB(hwnd, uMessage, wParam, lParam);
  477. break;
  478. }
  479. return CNotifySubclassWndProc::_DefWindowProc(hwnd, uMessage, wParam, lParam);
  480. }
  481. //***
  482. // NOTES
  483. // idtCmd is currently always -1. we'll need other values when we're
  484. // called from CallCB. however we can't do that until we fix mnfolder.cpp.
  485. HRESULT CMenuStaticToolbar::v_GetState(int idtCmd, LPSMDATA psmd)
  486. {
  487. psmd->dwMask = SMDM_HMENU;
  488. psmd->hmenu = _hmenu;
  489. psmd->hwnd = _hwndMenuOwner;
  490. psmd->uIdParent = _idCmd;
  491. if (idtCmd == -1)
  492. idtCmd = GetButtonCmd(_hwndMB, ToolBar_GetHotItem(_hwndMB));
  493. psmd->uId = IDTTOIDM(idtCmd);
  494. psmd->punk = SAFECAST(_pcmb, IShellMenu*);
  495. psmd->punk->AddRef();
  496. return S_OK;
  497. }
  498. HRESULT CMenuStaticToolbar::CallCB(UINT idCmd, DWORD dwMsg, WPARAM wParam, LPARAM lParam)
  499. {
  500. if (!_pcmb->_psmcb)
  501. return S_FALSE;
  502. SMDATA smd;
  503. HRESULT hres = S_FALSE;
  504. // todo: call v_GetState (but see comment in mnfolder.cpp)
  505. smd.dwMask = SMDM_HMENU;
  506. smd.hmenu = _hmenu;
  507. smd.hwnd = _hwndMenuOwner;
  508. smd.uIdParent = _idCmd;
  509. smd.uIdAncestor = _pcmb->_uIdAncestor;
  510. smd.uId = idCmd;
  511. smd.punk = SAFECAST(_pcmb, IShellMenu*);
  512. smd.pvUserData = _pcmb->_pvUserData;
  513. hres = _pcmb->_psmcb->CallbackSM(&smd, dwMsg, wParam, lParam);
  514. return hres;
  515. }
  516. HRESULT CMenuStaticToolbar::v_CallCBItem(int idtCmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  517. {
  518. int idm;
  519. idm = IDTTOIDM(idtCmd);
  520. return CallCB(idm, uMsg, wParam, lParam);
  521. }
  522. void CMenuStaticToolbar::v_UpdateButtons(BOOL fNegotiateSize)
  523. {
  524. if (_hwndMB)
  525. {
  526. _SetToolbarState();
  527. int cxMin, cxMax;
  528. v_CalcWidth(&cxMin, &cxMax);
  529. SendMessage(_hwndMB, TB_SETBUTTONWIDTH, 0, MAKELONG(cxMin, cxMax));
  530. SendMessage(_hwndMB, TB_AUTOSIZE, 0, 0);
  531. // Should we renegotiate size? AND are we vertical,
  532. // because we cannot renegoitate when horizontal.
  533. if (fNegotiateSize && _fVerticalMB)
  534. NegotiateSize();
  535. }
  536. }
  537. BOOL CMenuStaticToolbar::v_UpdateIconSize(UINT uIconSize, BOOL fUpdateButtons)
  538. {
  539. if (-1 == uIconSize)
  540. uIconSize = _uIconSizeMB;
  541. BOOL fChanged = (_uIconSizeMB != uIconSize);
  542. _uIconSizeMB = uIconSize;
  543. if (_hwndMB)
  544. {
  545. HIMAGELIST himl = NULL;
  546. if (_fVerticalMB)
  547. {
  548. HIMAGELIST himlLarge, himlSmall;
  549. // set the imagelist size
  550. Shell_GetImageLists(&himlLarge, &himlSmall);
  551. himl = (_uIconSizeMB == ISFBVIEWMODE_LARGEICONS ) ? himlLarge : himlSmall;
  552. }
  553. // sending a null himl is significant.. it means no image list
  554. SendMessage(_hwndMB, TB_SETIMAGELIST, 0, (LPARAM)himl);
  555. if (fUpdateButtons)
  556. v_UpdateButtons(TRUE);
  557. }
  558. return fChanged;
  559. }
  560. void CMenuStaticToolbar::_OnGetDispInfo(LPNMHDR pnm, BOOL fUnicode)
  561. {
  562. LPNMTBDISPINFO pdi = (LPNMTBDISPINFO)pnm;
  563. CMenuStaticData* pdata = (CMenuStaticData*)pdi->lParam;
  564. if(pdi->dwMask & TBNF_IMAGE)
  565. {
  566. if (_fVerticalMB)
  567. {
  568. SMINFO smi;
  569. smi.dwMask = SMIM_ICON;
  570. if (CallCB(pdi->idCommand, SMC_GETINFO, 0, (LPARAM)&smi) == S_OK)
  571. pdi->iImage = smi.iIcon;
  572. else
  573. pdi->iImage = -1;
  574. }
  575. else
  576. pdi->iImage = -1;
  577. }
  578. if(pdi->dwMask & TBNF_TEXT)
  579. {
  580. if(pdi->pszText)
  581. {
  582. if(fUnicode)
  583. {
  584. pdi->pszText[0] = TEXT('\0');
  585. }
  586. else
  587. {
  588. pdi->pszText[0] = 0;
  589. }
  590. }
  591. }
  592. pdi->dwMask |= TBNF_DI_SETITEM;
  593. return;
  594. }
  595. LRESULT CMenuStaticToolbar::_OnGetObject(NMOBJECTNOTIFY* pon)
  596. {
  597. pon->hResult = QueryInterface(*pon->piid, &pon->pObject);
  598. return 1;
  599. }
  600. LRESULT CMenuStaticToolbar::_OnNotify(LPNMHDR pnm)
  601. {
  602. LRESULT lres = 0;
  603. switch (pnm->code)
  604. {
  605. case TBN_DRAGOUT:
  606. lres = 0;
  607. break;
  608. case TBN_DELETINGBUTTON:
  609. {
  610. if (!_fEmptyingToolbar)
  611. {
  612. TBNOTIFY *ptbn = (TBNOTIFY*)pnm;
  613. CMenuStaticData* pmsd = (CMenuStaticData*)ptbn->tbButton.dwData;
  614. if (pmsd)
  615. delete pmsd;
  616. }
  617. break;
  618. }
  619. case NM_TOOLTIPSCREATED:
  620. SHSetWindowBits(((NMTOOLTIPSCREATED*)pnm)->hwndToolTips, GWL_STYLE, TTS_ALWAYSTIP | TTS_TOPMOST, TTS_ALWAYSTIP | TTS_TOPMOST);
  621. SendMessage(((NMTOOLTIPSCREATED*)pnm)->hwndToolTips, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)MAXSHORT);
  622. break;
  623. case NM_RCLICK:
  624. lres = _OnContextMenu(NULL, GetMessagePos());
  625. break;
  626. case NM_CUSTOMDRAW:
  627. lres = _OnCustomDraw((NMCUSTOMDRAW*)pnm);
  628. g_hmenuStopWatch = _hmenu;
  629. g_idCmdStopWatch = _idCmd;
  630. break;
  631. case TBN_GETDISPINFOA:
  632. _OnGetDispInfo(pnm, FALSE);
  633. break;
  634. case TBN_GETDISPINFOW:
  635. _OnGetDispInfo(pnm, TRUE);
  636. break;
  637. case TBN_GETOBJECT:
  638. lres = _OnGetObject((NMOBJECTNOTIFY*)pnm);
  639. break;
  640. case TBN_MAPACCELERATOR:
  641. lres = _OnAccelerator((NMCHAR*)pnm);
  642. break;
  643. default:
  644. lres = CMenuToolbarBase::_OnNotify(pnm);
  645. }
  646. return(lres);
  647. }
  648. void CMenuStaticToolbar::_FillToolbar()
  649. {
  650. if (_fDirty && _hmenu && _hwndMB && !_pcmb->_fClosing)
  651. {
  652. EmptyToolbar();
  653. BOOL_PTR fRedraw = SendMessage(_hwndMB, WM_SETREDRAW, FALSE, 0);
  654. TCHAR szName[MAX_PATH];
  655. MENUITEMINFO mii;
  656. mii.cbSize = sizeof(mii);
  657. mii.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
  658. int iCount = GetMenuItemCount(_hmenu);
  659. for (int i = 0; i < iCount; i++)
  660. {
  661. mii.dwTypeData = szName;
  662. mii.cch = ARRAYSIZE(szName);
  663. if (GetMenuItemInfoWrap(_hmenu, i, MF_BYPOSITION, &mii))
  664. {
  665. if (mii.fType & MFT_SEPARATOR)
  666. {
  667. if (i == 0)
  668. _fHasTopSep = TRUE;
  669. else if (i == iCount - 1)
  670. _fHasBottomSep = TRUE;
  671. }
  672. _Insert(i, &mii);
  673. }
  674. }
  675. if (iCount == 0)
  676. _fEmpty = TRUE;
  677. SendMessage(_hwndMB, WM_SETREDRAW, fRedraw, 0);
  678. _fDirty = FALSE;
  679. v_UpdateButtons(FALSE);
  680. _pcmb->ResizeMenuBar();
  681. }
  682. }
  683. void CMenuStaticToolbar::v_OnDeleteButton(LPVOID pData)
  684. {
  685. CMenuStaticData* pmsd = (CMenuStaticData*)pData;
  686. if (pmsd)
  687. delete pmsd;
  688. }
  689. void CMenuStaticToolbar::v_OnEmptyToolbar()
  690. {
  691. CMenuToolbarBase::v_OnEmptyToolbar();
  692. _fDirty = TRUE;
  693. _fHasTopSep = FALSE;
  694. _fHasBottomSep = FALSE;
  695. _fTopSepRemoved = FALSE;
  696. _fBottomSepRemoved = FALSE;
  697. }
  698. void CMenuStaticToolbar::v_Close()
  699. {
  700. if (_hwndMB)
  701. {
  702. _UnregisterWindow(_hwndMB);
  703. _UnsubclassWindow(_hwndMB);
  704. }
  705. CMenuToolbarBase::v_Close();
  706. }
  707. void CMenuStaticToolbar::v_Refresh()
  708. {
  709. EmptyToolbar();
  710. _FillToolbar();
  711. }
  712. /*----------------------------------------------------------
  713. Purpose: IWinEventHandler::IsWindowOwner method
  714. Processes messages passed on from the menuband.
  715. */
  716. STDMETHODIMP CMenuStaticToolbar::IsWindowOwner(HWND hwnd)
  717. {
  718. if ( hwnd == _hwndMB || hwnd == HWND_BROADCAST)
  719. {
  720. return S_OK;
  721. }
  722. else
  723. {
  724. return S_FALSE;
  725. }
  726. }
  727. /*----------------------------------------------------------
  728. Purpose: CDelegateDropTarget::GetWindowsDDT
  729. */
  730. HRESULT CMenuStaticToolbar::GetWindowsDDT (HWND * phwndLock, HWND * phwndScroll)
  731. {
  732. *phwndLock = _hwndMB;
  733. *phwndScroll = _hwndMB;
  734. return S_OK;
  735. }
  736. /*----------------------------------------------------------
  737. Purpose: CDelegateDropTarget::HitTestDDT
  738. */
  739. HRESULT CMenuStaticToolbar::HitTestDDT (UINT nEvent, LPPOINT ppt, DWORD_PTR * pdwId, DWORD *pdwEffect)
  740. {
  741. switch (nEvent)
  742. {
  743. case HTDDT_ENTER:
  744. // OLE is in its modal drag/drop loop, and it has the capture.
  745. // We shouldn't take the capture back during this time.
  746. if (!(_pcmb->_dwFlags & SMINIT_RESTRICT_DRAGDROP))
  747. {
  748. _pcmb->_pmbState->HasDrag(TRUE);
  749. GetMessageFilter()->PreventCapture(TRUE);
  750. if (_pcmb->_pmtbShellFolder &&
  751. _pcmb->_pmtbShellFolder->DontShowEmpty())
  752. {
  753. DAD_ShowDragImage(FALSE);
  754. _pcmb->_pmtbShellFolder->DontShowEmpty(FALSE);
  755. _pcmb->ResizeMenuBar();
  756. UpdateWindow(_hwndMB);
  757. DAD_ShowDragImage(TRUE);
  758. }
  759. return S_OK;
  760. }
  761. else
  762. return S_FALSE;
  763. case HTDDT_OVER:
  764. {
  765. TBINSERTMARK tbim;
  766. *pdwEffect = DROPEFFECT_NONE;
  767. POINT pt = *ppt;
  768. if (!ToolBar_InsertMarkHitTest(_hwndMB, &pt, &tbim))
  769. {
  770. int idCmd = GetButtonCmd(_hwndMB, tbim.iButton);
  771. if (v_GetFlags(idCmd) & SMIF_DROPCASCADE &&
  772. tbim.iButton != _iDragOverButton)
  773. {
  774. DAD_ShowDragImage(FALSE);
  775. _pcmb->SetTracked(this);
  776. _iDragOverButton = tbim.iButton;
  777. SetTimer(_hwndMB, MBTIMER_DRAGOVER, MBTIMER_TIMEOUT, NULL);
  778. _pcmb->_SiteOnSelect(MPOS_CHILDTRACKING);
  779. BOOL_PTR fOldAnchor = ToolBar_SetAnchorHighlight(_hwndMB, FALSE);
  780. ToolBar_SetHotItem(_hwndMB, _iDragOverButton);
  781. ToolBar_SetAnchorHighlight(_hwndMB, fOldAnchor);
  782. UpdateWindow(_hwndMB);
  783. DAD_ShowDragImage(TRUE);
  784. }
  785. }
  786. }
  787. break;
  788. case HTDDT_LEAVE:
  789. // We can take the capture back anytime now
  790. _pcmb->_pmbState->HasDrag(FALSE);
  791. _SetTimer(MBTIMER_DRAGPOPDOWN);
  792. GetMessageFilter()->PreventCapture(FALSE);
  793. _iDragOverButton = -1;
  794. #if 0
  795. DAD_ShowDragImage(FALSE);
  796. ToolBar_SetHotItem(_hwndMB, -1);
  797. DAD_ShowDragImage(TRUE);
  798. #endif
  799. break;
  800. }
  801. return S_OK;
  802. }
  803. /*----------------------------------------------------------
  804. Purpose: CDelegateDropTarget::GetObjectDDT
  805. */
  806. HRESULT CMenuStaticToolbar::GetObjectDDT (DWORD_PTR dwId, REFIID riid, LPVOID * ppvObj)
  807. {
  808. return E_NOTIMPL;
  809. }
  810. /*----------------------------------------------------------
  811. Purpose: CDelegateDropTarget::OnDropDDT
  812. */
  813. HRESULT CMenuStaticToolbar::OnDropDDT (IDropTarget *pdt, IDataObject *pdtobj,
  814. DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect)
  815. {
  816. return E_NOTIMPL;
  817. }
  818. HRESULT CMenuStaticToolbar::v_InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
  819. {
  820. HRESULT hres = S_FALSE;
  821. if (NULL == psmd)
  822. {
  823. if (dwFlags & SMINV_REFRESH)
  824. {
  825. // Refresh the whole thing
  826. v_Refresh();
  827. hres = TRUE;
  828. }
  829. }
  830. // Are we dealing with an Hmenu?
  831. // Have we filled it yet? (If not, then we can skip the invalidate
  832. // here, because we'll catch it when we fill it.)
  833. else if ((psmd->dwMask & SMDM_HMENU) && !_fDirty)
  834. {
  835. // Yes; What are they asking for?
  836. int iPos = -1; // Assume this is a position
  837. int idCmd = -1;
  838. // Did they pass an ID instead of a position?
  839. if (dwFlags & SMINV_ID)
  840. {
  841. // Yes; Crack out the position.
  842. iPos = GetMenuPosFromID(_hmenu, psmd->uId);
  843. idCmd = psmd->uId;
  844. }
  845. if (dwFlags & SMINV_POSITION)
  846. {
  847. iPos = psmd->uId;
  848. idCmd = GetMenuItemID(_hmenu, iPos);
  849. }
  850. if (dwFlags & SMINV_REFRESH)
  851. {
  852. // Do they want to refresh a sepcific button?
  853. if (idCmd >= 0)
  854. {
  855. // Yes;
  856. // First delete the old one if it exists.
  857. int iTBPos = ToolBar_CommandToIndex(_hwndMB, idCmd);
  858. if (iTBPos >= 0)
  859. SendMessage(_hwndMB, TB_DELETEBUTTON, iTBPos, 0);
  860. // Now Insert a new one
  861. MENUITEMINFO mii;
  862. TCHAR szName[MAX_PATH];
  863. mii.cbSize = sizeof(mii);
  864. mii.cch = ARRAYSIZE(szName);
  865. mii.dwTypeData = szName;
  866. mii.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
  867. // This can fail...
  868. if (GetMenuItemInfoWrap(_hmenu, iPos, MF_BYPOSITION, &mii))
  869. {
  870. _Insert(iPos, &mii);
  871. hres = S_OK;
  872. }
  873. }
  874. else
  875. {
  876. // No; Refresh the whole thing
  877. v_Refresh();
  878. }
  879. if (!_fShowMB)
  880. _pcmb->_fForceButtonUpdate = TRUE;
  881. _pcmb->ResizeMenuBar();
  882. }
  883. }
  884. return hres;
  885. }
  886. void CMenuStaticToolbar::GetSize(SIZE* psize)
  887. {
  888. _CheckSeparators();
  889. CMenuToolbarBase::GetSize(psize);
  890. }
  891. LRESULT CMenuStaticToolbar::_OnAccelerator(NMCHAR* pnmChar)
  892. {
  893. SMDATA smdOut = {0};
  894. SMDATA smd = {0};
  895. smd.punk = SAFECAST(_pcmb, IShellMenu*);
  896. smd.uIdParent = _pcmb->_uId;
  897. if (_pcmb->_psmcb &&
  898. S_FALSE != _pcmb->_psmcb->CallbackSM(&smd, SMC_MAPACCELERATOR, (WPARAM)pnmChar->ch, (LPARAM)&smdOut))
  899. {
  900. pnmChar->dwItemNext = ToolBar_CommandToIndex(_hwndMB, smdOut.uId);;
  901. return TRUE;
  902. }
  903. return FALSE;
  904. }
  905. LRESULT CMenuStaticToolbar::_OnContextMenu(WPARAM wParam, LPARAM lParam)
  906. {
  907. LRESULT lres = 0;
  908. MyLockSetForegroundWindow(FALSE);
  909. if (!(_pcmb->_dwFlags & SMINIT_RESTRICT_CONTEXTMENU))
  910. {
  911. RECT rc;
  912. LPRECT prcExclude = NULL;
  913. POINT pt;
  914. int i;
  915. if (lParam != (LPARAM)-1)
  916. {
  917. pt.x = GET_X_LPARAM(lParam);
  918. pt.y = GET_Y_LPARAM(lParam);
  919. POINT pt2 = pt;
  920. MapWindowPoints(HWND_DESKTOP, _hwndMB, &pt2, 1);
  921. i = ToolBar_HitTest(_hwndMB, &pt2);
  922. }
  923. else
  924. {
  925. // keyboard context menu.
  926. i = (int)SendMessage(_hwndMB, TB_GETHOTITEM, 0, 0);
  927. if (i >= 0)
  928. {
  929. SendMessage(_hwndMB, TB_GETITEMRECT, i, (LPARAM)&rc);
  930. MapWindowPoints(_hwndMB, HWND_DESKTOP, (LPPOINT)&rc, 2);
  931. pt.x = rc.left;
  932. pt.y = rc.bottom;
  933. prcExclude = &rc;
  934. }
  935. }
  936. if (i >= 0)
  937. {
  938. UINT idCmd = GetButtonCmd(_hwndMB, i);
  939. if (S_OK == CallCB(idCmd, SMC_GETOBJECT, (WPARAM)(GUID*)&IID_IContextMenu, (LPARAM)(VOID**)(&_pcm)))
  940. {
  941. TPMPARAMS tpm;
  942. TPMPARAMS * ptpm = NULL;
  943. if (prcExclude)
  944. {
  945. tpm.cbSize = SIZEOF(tpm);
  946. tpm.rcExclude = *((LPRECT)prcExclude);
  947. ptpm = &tpm;
  948. }
  949. HMENU hmenu = CreatePopupMenu();
  950. if (hmenu)
  951. {
  952. KillTimer(_hwndMB, MBTIMER_INFOTIP);
  953. _pcmb->_pmbState->HideTooltip(FALSE);
  954. _pcm->QueryContextMenu(hmenu, 0, 0, -1, 0);
  955. idCmd = TrackPopupMenuEx(hmenu,
  956. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  957. pt.x, pt.y, _hwndMB, ptpm);
  958. CMINVOKECOMMANDINFO ici = {
  959. SIZEOF(CMINVOKECOMMANDINFO),
  960. 0,
  961. _hwndMB,
  962. MAKEINTRESOURCEA(idCmd),
  963. NULL, NULL,
  964. SW_NORMAL,
  965. };
  966. _pcm->InvokeCommand(&ici);
  967. DestroyMenu(hmenu);
  968. }
  969. ATOMICRELEASE(_pcm);
  970. }
  971. }
  972. GetMessageFilter()->RetakeCapture();
  973. }
  974. return lres;
  975. }
  976. STDMETHODIMP CMenuStaticToolbar::OnWinEvent(HWND hwnd, UINT dwMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  977. {
  978. if (WM_CONTEXTMENU == dwMsg)
  979. {
  980. *plres = _OnContextMenu(wParam, lParam);
  981. }
  982. else
  983. return CMenuToolbarBase::OnWinEvent(hwnd, dwMsg, wParam, lParam, plres);
  984. return S_OK;
  985. }