* Sync up to trunk HEAD (r62285). Branch guys deserve the significant speedups too ;)
[reactos.git] / base / shell / rshell / CMenuBand.cpp
1 /*
2 * Shell Menu Band
3 *
4 * Copyright 2014 David Quintana
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20 #include "precomp.h"
21 #include <windowsx.h>
22 #include <shlwapi_undoc.h>
23
24 #define TBSTYLE_EX_VERTICAL 4
25
26 WINE_DEFAULT_DEBUG_CHANNEL(CMenuBand);
27
28 #define TIMERID_HOTTRACK 1
29 #define SUBCLASS_ID_MENUBAND 1
30
31 extern "C" BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList);
32
33 class CMenuBand;
34 class CMenuFocusManager;
35
36 class CMenuToolbarBase
37 {
38 protected:
39 CMenuBand * m_menuBand;
40 HWND m_hwnd;
41 DWORD m_dwMenuFlags;
42 INT m_hotItem;
43 WNDPROC m_SubclassOld;
44
45 private:
46 static LRESULT CALLBACK s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
47
48 public:
49 CMenuToolbarBase(CMenuBand *menuBand);
50 virtual ~CMenuToolbarBase() {}
51
52 HRESULT IsWindowOwner(HWND hwnd);
53 HRESULT CreateToolbar(HWND hwndParent, DWORD dwFlags);
54 HRESULT GetWindow(HWND *phwnd);
55 HRESULT ShowWindow(BOOL fShow);
56 HRESULT Close();
57
58 virtual HRESULT FillToolbar() = 0;
59 virtual HRESULT PopupItem(UINT uItem) = 0;
60 virtual HRESULT HasSubMenu(UINT uItem) = 0;
61 virtual HRESULT OnContextMenu(NMMOUSE * rclick) = 0;
62 virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult);
63
64 HRESULT PopupSubMenu(UINT index, IShellMenu* childShellMenu);
65 HRESULT PopupSubMenu(UINT index, HMENU menu);
66 HRESULT DoContextMenu(IContextMenu* contextMenu);
67
68 HRESULT ChangeHotItem(DWORD changeType);
69 HRESULT OnHotItemChange(const NMTBHOTITEM * hot);
70
71 protected:
72 LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
73 };
74
75 class CMenuStaticToolbar :
76 public CMenuToolbarBase
77 {
78 private:
79 HMENU m_hmenu;
80
81 public:
82 CMenuStaticToolbar(CMenuBand *menuBand);
83 virtual ~CMenuStaticToolbar() {}
84
85 HRESULT SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags);
86 HRESULT GetMenu(HMENU *phmenu, HWND *phwnd, DWORD *pdwFlags);
87
88 virtual HRESULT FillToolbar();
89 virtual HRESULT PopupItem(UINT uItem);
90 virtual HRESULT HasSubMenu(UINT uItem);
91 virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult);
92 virtual HRESULT OnContextMenu(NMMOUSE * rclick);
93
94 };
95
96 class CMenuSFToolbar :
97 public CMenuToolbarBase
98 {
99 private:
100 IShellFolder * m_shellFolder;
101 LPCITEMIDLIST m_idList;
102 HKEY m_hKey;
103
104 public:
105 CMenuSFToolbar(CMenuBand *menuBand);
106 virtual ~CMenuSFToolbar();
107
108 HRESULT SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags);
109 HRESULT GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv);
110
111 virtual HRESULT FillToolbar();
112 virtual HRESULT PopupItem(UINT uItem);
113 virtual HRESULT HasSubMenu(UINT uItem);
114 virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult);
115 virtual HRESULT OnContextMenu(NMMOUSE * rclick);
116
117 private:
118 LPITEMIDLIST GetPidlFromId(UINT uItem, INT* pIndex = NULL);
119 };
120
121 class CMenuBand :
122 public CComCoClass<CMenuBand>,
123 public CComObjectRootEx<CComMultiThreadModelNoCS>,
124 public IDeskBand,
125 public IObjectWithSite,
126 public IInputObject,
127 public IPersistStream,
128 public IOleCommandTarget,
129 public IServiceProvider,
130 public IMenuPopup,
131 public IMenuBand,
132 public IShellMenu2,
133 public IWinEventHandler,
134 public IShellMenuAcc
135 {
136 private:
137 CMenuFocusManager * m_focusManager;
138 CMenuStaticToolbar * m_staticToolbar;
139 CMenuSFToolbar * m_SFToolbar;
140
141 CComPtr<IOleWindow> m_site;
142 CComPtr<IShellMenuCallback> m_psmc;
143 CComPtr<IMenuPopup> m_subMenuChild;
144 CComPtr<IMenuPopup> m_subMenuParent;
145
146 UINT m_uId;
147 UINT m_uIdAncestor;
148 DWORD m_dwFlags;
149 PVOID m_UserData;
150 HMENU m_hmenu;
151 HWND m_menuOwner;
152
153 BOOL m_useBigIcons;
154 HWND m_topLevelWindow;
155
156 CMenuToolbarBase * m_hotBar;
157 INT m_hotItem;
158
159 public:
160 CMenuBand();
161 ~CMenuBand();
162
163 DECLARE_NOT_AGGREGATABLE(CMenuBand)
164 DECLARE_PROTECT_FINAL_CONSTRUCT()
165
166 BEGIN_COM_MAP(CMenuBand)
167 COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IMenuPopup)
168 COM_INTERFACE_ENTRY_IID(IID_IShellMenu, IShellMenu)
169 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
170 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IDeskBand)
171 COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)
172 COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
173 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
174 COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject)
175 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
176 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersistStream)
177 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
178 COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup)
179 COM_INTERFACE_ENTRY_IID(IID_IMenuBand, IMenuBand)
180 COM_INTERFACE_ENTRY_IID(IID_IShellMenu2, IShellMenu2)
181 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
182 COM_INTERFACE_ENTRY_IID(IID_IShellMenuAcc, IShellMenuAcc)
183 END_COM_MAP()
184
185 // *** IDeskBand methods ***
186 virtual HRESULT STDMETHODCALLTYPE GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi);
187
188 // *** IDockingWindow methods ***
189 virtual HRESULT STDMETHODCALLTYPE ShowDW(BOOL fShow);
190 virtual HRESULT STDMETHODCALLTYPE CloseDW(DWORD dwReserved);
191 virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved);
192
193 // *** IOleWindow methods ***
194 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
195 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
196
197 // *** IObjectWithSite methods ***
198 virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite);
199 virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, PVOID *ppvSite);
200
201 // *** IInputObject methods ***
202 virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg);
203 virtual HRESULT STDMETHODCALLTYPE HasFocusIO();
204 virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg);
205
206 // *** IPersistStream methods ***
207 virtual HRESULT STDMETHODCALLTYPE IsDirty();
208 virtual HRESULT STDMETHODCALLTYPE Load(IStream *pStm);
209 virtual HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty);
210 virtual HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize);
211
212 // *** IPersist methods ***
213 virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
214
215 // *** IOleCommandTarget methods ***
216 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText);
217 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
218
219 // *** IServiceProvider methods ***
220 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
221
222 // *** IMenuPopup methods ***
223 virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags);
224 virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType);
225 virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet);
226
227 // *** IDeskBar methods ***
228 virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient);
229 virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient);
230 virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(RECT *prc);
231
232 // *** IMenuBand methods ***
233 virtual HRESULT STDMETHODCALLTYPE IsMenuMessage(MSG *pmsg);
234 virtual HRESULT STDMETHODCALLTYPE TranslateMenuMessage(MSG *pmsg, LRESULT *plRet);
235
236 // *** IShellMenu methods ***
237 virtual HRESULT STDMETHODCALLTYPE Initialize(IShellMenuCallback *psmc, UINT uId, UINT uIdAncestor, DWORD dwFlags);
238 virtual HRESULT STDMETHODCALLTYPE GetMenuInfo(IShellMenuCallback **ppsmc, UINT *puId, UINT *puIdAncestor, DWORD *pdwFlags);
239 virtual HRESULT STDMETHODCALLTYPE SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags);
240 virtual HRESULT STDMETHODCALLTYPE GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv);
241 virtual HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags);
242 virtual HRESULT STDMETHODCALLTYPE GetMenu(HMENU *phmenu, HWND *phwnd, DWORD *pdwFlags);
243 virtual HRESULT STDMETHODCALLTYPE InvalidateItem(LPSMDATA psmd, DWORD dwFlags);
244 virtual HRESULT STDMETHODCALLTYPE GetState(LPSMDATA psmd);
245 virtual HRESULT STDMETHODCALLTYPE SetMenuToolbar(IUnknown *punk, DWORD dwFlags);
246
247 // *** IWinEventHandler methods ***
248 virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult);
249 virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd);
250
251 // *** IShellMenu2 methods ***
252 virtual HRESULT STDMETHODCALLTYPE GetSubMenu(THIS);
253 virtual HRESULT STDMETHODCALLTYPE SetToolbar(THIS);
254 virtual HRESULT STDMETHODCALLTYPE SetMinWidth(THIS);
255 virtual HRESULT STDMETHODCALLTYPE SetNoBorder(THIS);
256 virtual HRESULT STDMETHODCALLTYPE SetTheme(THIS);
257
258 // *** IShellMenuAcc methods ***
259 virtual HRESULT STDMETHODCALLTYPE GetTop(THIS);
260 virtual HRESULT STDMETHODCALLTYPE GetBottom(THIS);
261 virtual HRESULT STDMETHODCALLTYPE GetTracked(THIS);
262 virtual HRESULT STDMETHODCALLTYPE GetParentSite(THIS);
263 virtual HRESULT STDMETHODCALLTYPE GetState(THIS);
264 virtual HRESULT STDMETHODCALLTYPE DoDefaultAction(THIS);
265 virtual HRESULT STDMETHODCALLTYPE IsEmpty(THIS);
266
267 HRESULT _CallCBWithItemId(UINT Id, UINT uMsg, WPARAM wParam, LPARAM lParam);
268 HRESULT _CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam);
269 HRESULT _TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y);
270 HRESULT _GetTopLevelWindow(HWND*topLevel);
271 HRESULT _OnHotItemChanged(CMenuToolbarBase * tb, INT id);
272 HRESULT _MenuItemHotTrack(DWORD changeType);
273 HRESULT _OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude);
274
275 BOOL UseBigIcons()
276 {
277 return m_useBigIcons;
278 }
279
280 private:
281 HRESULT _CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id = 0, LPITEMIDLIST pidl = NULL);
282 };
283
284 class CMenuFocusManager :
285 public CComCoClass<CMenuFocusManager>,
286 public CComObjectRootEx<CComMultiThreadModelNoCS>
287 {
288 private:
289 static DWORD TlsIndex;
290
291 static CMenuFocusManager * GetManager()
292 {
293 return reinterpret_cast<CMenuFocusManager *>(TlsGetValue(TlsIndex));
294 }
295
296 public:
297 static CMenuFocusManager * AcquireManager()
298 {
299 CMenuFocusManager * obj = NULL;
300
301 if (!TlsIndex)
302 {
303 if ((TlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
304 return NULL;
305 }
306
307 obj = GetManager();
308
309 if (!obj)
310 {
311 obj = new CComObject<CMenuFocusManager>();
312 TlsSetValue(TlsIndex, obj);
313 }
314
315 obj->AddRef();
316
317 return obj;
318 }
319
320 static void ReleaseManager(CMenuFocusManager * obj)
321 {
322 if (!obj->Release())
323 {
324 TlsSetValue(TlsIndex, NULL);
325 }
326 }
327
328 private:
329 static LRESULT CALLBACK s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
330 {
331 return GetManager()->GetMsgHook(nCode, wParam, lParam);
332 }
333
334 private:
335 // TODO: make dynamic
336 #define MAX_RECURSE 20
337 CMenuBand* m_bandStack[MAX_RECURSE];
338 int m_bandCount;
339
340 HRESULT PushToArray(CMenuBand * item)
341 {
342 if (m_bandCount >= MAX_RECURSE)
343 return E_OUTOFMEMORY;
344
345 m_bandStack[m_bandCount++] = item;
346 return S_OK;
347 }
348
349 HRESULT PopFromArray(CMenuBand ** pItem)
350 {
351 if (pItem)
352 *pItem = NULL;
353
354 if (m_bandCount <= 0)
355 return E_FAIL;
356
357 m_bandCount--;
358
359 if (pItem)
360 *pItem = m_bandStack[m_bandCount];
361
362 m_bandStack[m_bandCount] = NULL;
363
364 return S_OK;
365 }
366
367 HRESULT PeekArray(CMenuBand ** pItem)
368 {
369 if (!pItem)
370 return E_FAIL;
371
372 *pItem = NULL;
373
374 if (m_bandCount <= 0)
375 return E_FAIL;
376
377 *pItem = m_bandStack[m_bandCount - 1];
378
379 return S_OK;
380 }
381
382 protected:
383 CMenuFocusManager() :
384 m_currentBand(NULL),
385 m_currentFocus(NULL),
386 m_bandCount(0)
387 {
388 m_threadId = GetCurrentThreadId();
389 }
390
391 ~CMenuFocusManager()
392 {
393 }
394
395 public:
396
397 DECLARE_NOT_AGGREGATABLE(CMenuFocusManager)
398 DECLARE_PROTECT_FINAL_CONSTRUCT()
399 BEGIN_COM_MAP(CMenuFocusManager)
400 END_COM_MAP()
401
402 private:
403 CMenuBand * m_currentBand;
404 HWND m_currentFocus;
405 HHOOK m_hHook;
406 DWORD m_threadId;
407
408 LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
409 {
410 if (nCode < 0)
411 return CallNextHookEx(m_hHook, nCode, wParam, lParam);
412
413 BOOL callNext = TRUE;
414 BOOL fRemoved = wParam;
415 MSG* msg = reinterpret_cast<MSG*>(lParam);
416
417 if (nCode == HC_ACTION)
418 {
419 // Do whatever is necessary here
420
421 switch (msg->message)
422 {
423 case WM_CLOSE:
424 break;
425 case WM_SYSKEYDOWN:
426 case WM_KEYDOWN:
427 switch (msg->wParam)
428 {
429 case VK_MENU:
430 case VK_LMENU:
431 case VK_RMENU:
432 m_currentBand->_MenuItemHotTrack(MPOS_FULLCANCEL);
433 break;
434 case VK_LEFT:
435 m_currentBand->_MenuItemHotTrack(MPOS_SELECTLEFT);
436 break;
437 case VK_RIGHT:
438 m_currentBand->_MenuItemHotTrack(MPOS_SELECTRIGHT);
439 break;
440 case VK_UP:
441 m_currentBand->_MenuItemHotTrack(VK_UP);
442 break;
443 case VK_DOWN:
444 m_currentBand->_MenuItemHotTrack(VK_DOWN);
445 break;
446 }
447 break;
448 case WM_CHAR:
449 //if (msg->wParam >= 'a' && msg->wParam <= 'z')
450 //{
451 // callNext = FALSE;
452 // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam);
453 //}
454 break;
455 case WM_ACTIVATE:
456 break;
457
458 }
459
460 if (!callNext)
461 return 0;
462 }
463
464 return CallNextHookEx(m_hHook, nCode, wParam, lParam);
465 }
466
467 HRESULT PlaceHooks(HWND window)
468 {
469 //SetCapture(window);
470 m_hHook = SetWindowsHookEx(WH_GETMESSAGE, s_GetMsgHook, NULL, m_threadId);
471 return S_OK;
472 }
473
474 HRESULT RemoveHooks(HWND window)
475 {
476 UnhookWindowsHookEx(m_hHook);
477 //ReleaseCapture();
478 return S_OK;
479 }
480
481 HRESULT UpdateFocus(CMenuBand * newBand)
482 {
483 HRESULT hr;
484
485 hr = RemoveHooks(m_currentFocus);
486
487 if (FAILED(hr) || !newBand)
488 {
489 m_currentFocus = NULL;
490 m_currentBand = NULL;
491 return S_OK;
492 }
493
494 HWND newFocus;
495 hr = newBand->_GetTopLevelWindow(&newFocus);
496 if (FAILED(hr))
497 return hr;
498
499 hr = PlaceHooks(m_currentFocus);
500 if (FAILED(hr))
501 return hr;
502
503 m_currentFocus = newFocus;
504 m_currentBand = newBand;
505
506 return S_OK;
507 }
508
509 public:
510 HRESULT PushMenu(CMenuBand * mb)
511 {
512 HRESULT hr;
513
514 hr = PushToArray(mb);
515 if (FAILED(hr))
516 return hr;
517
518 return UpdateFocus(mb);
519 }
520
521 HRESULT PopMenu(CMenuBand * mb)
522 {
523 CMenuBand * mbc;
524 HRESULT hr;
525
526 hr = PopFromArray(&mbc);
527 if (FAILED(hr))
528 return hr;
529
530 if (mb != mbc)
531 return E_FAIL;
532
533 hr = PeekArray(&mbc);
534
535 return UpdateFocus(mbc);
536 }
537 };
538
539 DWORD CMenuFocusManager::TlsIndex = 0;
540
541 extern "C"
542 HRESULT CMenuBand_Constructor(REFIID riid, LPVOID *ppv)
543 {
544 *ppv = NULL;
545
546 CMenuBand * site = new CComObject<CMenuBand>();
547
548 if (!site)
549 return E_OUTOFMEMORY;
550
551 HRESULT hr = site->QueryInterface(riid, ppv);
552
553 if (FAILED(hr))
554 site->Release();
555
556 return hr;
557 }
558
559 CMenuToolbarBase::CMenuToolbarBase(CMenuBand *menuBand) :
560 m_menuBand(menuBand),
561 m_hwnd(NULL),
562 m_dwMenuFlags(0)
563 {
564 }
565
566 HRESULT CMenuToolbarBase::IsWindowOwner(HWND hwnd)
567 {
568 return (m_hwnd && m_hwnd == hwnd) ? S_OK : S_FALSE;
569 }
570
571 HRESULT CMenuToolbarBase::ShowWindow(BOOL fShow)
572 {
573 ::ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE);
574
575 HIMAGELIST ilBig, ilSmall;
576 Shell_GetImageLists(&ilBig, &ilSmall);
577
578 if (m_menuBand->UseBigIcons())
579 {
580 SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(ilBig));
581 }
582 else
583 {
584 SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(ilSmall));
585 }
586
587 return S_OK;
588 }
589
590 HRESULT CMenuToolbarBase::Close()
591 {
592 DestroyWindow(m_hwnd);
593 m_hwnd = NULL;
594 return S_OK;
595 }
596
597 HRESULT CMenuToolbarBase::CreateToolbar(HWND hwndParent, DWORD dwFlags)
598 {
599 LONG tbStyles = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
600 TBSTYLE_TOOLTIPS | TBSTYLE_TRANSPARENT | TBSTYLE_REGISTERDROP | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_CUSTOMERASE |
601 CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_TOP;
602 LONG tbExStyles = TBSTYLE_EX_DOUBLEBUFFER;
603
604 if (dwFlags & SMINIT_VERTICAL)
605 {
606 tbStyles |= CCS_VERT;
607 tbExStyles |= TBSTYLE_EX_VERTICAL | WS_EX_TOOLWINDOW;
608 }
609
610 RECT rc;
611
612 if (!::GetClientRect(hwndParent, &rc) || (rc.left == rc.right) || (rc.top == rc.bottom))
613 {
614 rc.left = 0;
615 rc.top = 0;
616 rc.right = 1;
617 rc.bottom = 1;
618 }
619
620 HWND hwndToolbar = CreateWindowEx(
621 tbExStyles, TOOLBARCLASSNAMEW, NULL,
622 tbStyles, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
623 hwndParent, NULL, _AtlBaseModule.GetModuleInstance(), 0);
624
625 if (hwndToolbar == NULL)
626 return E_FAIL;
627
628 ::SetParent(hwndToolbar, hwndParent);
629
630 m_hwnd = hwndToolbar;
631
632 /* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */
633 SendMessageW(m_hwnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
634
635 HIMAGELIST ilBig, ilSmall;
636 Shell_GetImageLists(&ilBig, &ilSmall);
637
638 //if (dwFlags & SMINIT_TOPLEVEL)
639 //{
640 // /* Hide the placeholders for the button images */
641 // SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0);
642 //}
643 //else
644 if (m_menuBand->UseBigIcons())
645 {
646 SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(ilBig));
647 }
648 else
649 {
650 SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, reinterpret_cast<LPARAM>(ilSmall));
651 }
652
653 SetWindowLongPtr(m_hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
654 m_SubclassOld = (WNDPROC) SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(CMenuToolbarBase::s_SubclassProc));
655
656 return S_OK;
657 }
658
659 HRESULT CMenuToolbarBase::GetWindow(HWND *phwnd)
660 {
661 if (!phwnd)
662 return E_FAIL;
663
664 *phwnd = m_hwnd;
665
666 return S_OK;
667 }
668
669 LRESULT CALLBACK CMenuToolbarBase::s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
670 {
671 CMenuToolbarBase * pthis = reinterpret_cast<CMenuToolbarBase *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
672 return pthis->SubclassProc(hWnd, uMsg, wParam, lParam);
673 }
674
675 LRESULT CMenuToolbarBase::SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
676 {
677 switch (uMsg)
678 {
679 case WM_TIMER:
680 if (wParam == TIMERID_HOTTRACK)
681 {
682 m_menuBand->_OnPopupSubMenu(NULL, NULL, NULL);
683 PopupItem(m_hotItem);
684 KillTimer(hWnd, TIMERID_HOTTRACK);
685 }
686 }
687
688 return m_SubclassOld(hWnd, uMsg, wParam, lParam);
689 }
690
691 HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot)
692 {
693 if (hot->dwFlags & HICF_LEAVING)
694 {
695 KillTimer(m_hwnd, TIMERID_HOTTRACK);
696 m_hotItem = -1;
697 m_menuBand->_OnHotItemChanged(NULL, -1);
698 m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
699 }
700 else if (m_hotItem != hot->idNew)
701 {
702 if (HasSubMenu(hot->idNew) == S_OK)
703 {
704 DWORD elapsed = 0;
705 SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0);
706 SetTimer(m_hwnd, TIMERID_HOTTRACK, elapsed, NULL);
707 }
708
709 m_hotItem = hot->idNew;
710 m_menuBand->_OnHotItemChanged(this, m_hotItem);
711 m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
712 }
713 return S_OK;
714 }
715
716 HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, IShellMenu* childShellMenu)
717 {
718 IBandSite* pBandSite;
719 IDeskBar* pDeskBar;
720
721 HRESULT hr = 0;
722 RECT rc = { 0 };
723
724 if (!SendMessage(m_hwnd, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
725 return E_FAIL;
726
727 POINT a = { rc.left, rc.top };
728 POINT b = { rc.right, rc.bottom };
729
730 ClientToScreen(m_hwnd, &a);
731 ClientToScreen(m_hwnd, &b);
732
733 POINTL pt = { b.x, b.y };
734 RECTL rcl = { a.x, a.y, b.x, b.y }; // maybe-TODO: fetch client area of deskbar?
735
736
737 #if USE_SYSTEM_MENUSITE
738 hr = CoCreateInstance(CLSID_MenuBandSite,
739 NULL,
740 CLSCTX_INPROC_SERVER,
741 IID_PPV_ARG(IBandSite, &pBandSite));
742 #else
743 hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
744 #endif
745 if (FAILED(hr))
746 return hr;
747 #if WRAP_MENUSITE
748 hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite));
749 if (FAILED(hr))
750 return hr;
751 #endif
752
753 #if USE_SYSTEM_MENUDESKBAR
754 hr = CoCreateInstance(CLSID_MenuDeskBar,
755 NULL,
756 CLSCTX_INPROC_SERVER,
757 IID_PPV_ARG(IDeskBar, &pDeskBar));
758 #else
759 hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar));
760 #endif
761 if (FAILED(hr))
762 return hr;
763 #if WRAP_MENUDESKBAR
764 hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar));
765 if (FAILED(hr))
766 return hr;
767 #endif
768
769 hr = pDeskBar->SetClient(pBandSite);
770 if (FAILED(hr))
771 return hr;
772
773 hr = pBandSite->AddBand(childShellMenu);
774 if (FAILED(hr))
775 return hr;
776
777 CComPtr<IMenuPopup> popup;
778 hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup));
779 if (FAILED(hr))
780 return hr;
781
782 m_menuBand->_OnPopupSubMenu(popup, &pt, &rcl);
783
784 return S_OK;
785 }
786
787 HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, HMENU menu)
788 {
789 RECT rc = { 0 };
790
791 if (!SendMessage(m_hwnd, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
792 return E_FAIL;
793
794 POINT b = { rc.right, rc.bottom };
795
796 ClientToScreen(m_hwnd, &b);
797
798 HMENU popup = GetSubMenu(menu, index);
799
800 m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, b.x, b.y);
801
802 return S_OK;
803 }
804
805 HRESULT CMenuToolbarBase::DoContextMenu(IContextMenu* contextMenu)
806 {
807 HRESULT hr;
808 HMENU hPopup = CreatePopupMenu();
809
810 if (hPopup == NULL)
811 return E_FAIL;
812
813 hr = contextMenu->QueryContextMenu(hPopup, 0, 0, UINT_MAX, CMF_NORMAL);
814 if (FAILED(hr))
815 {
816 DestroyMenu(hPopup);
817 return hr;
818 }
819
820 DWORD dwPos = GetMessagePos();
821 UINT uCommand = ::TrackPopupMenu(hPopup, TPM_RETURNCMD, GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), 0, m_hwnd, NULL);
822 if (uCommand == 0)
823 return S_FALSE;
824
825 CMINVOKECOMMANDINFO cmi = { 0 };
826 cmi.cbSize = sizeof(cmi);
827 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
828 cmi.hwnd = m_hwnd;
829 hr = contextMenu->InvokeCommand(&cmi);
830
831 DestroyMenu(hPopup);
832 return hr;
833 }
834
835 HRESULT CMenuToolbarBase::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
836 {
837 theResult = 0;
838 return m_menuBand->_MenuItemHotTrack(MPOS_EXECUTE);
839 }
840
841
842 HRESULT CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType)
843 {
844 int prev = SendMessage(m_hwnd, TB_GETHOTITEM, 0, 0);
845 int index = -1;
846
847 if (dwSelectType != 0xFFFFFFFF)
848 {
849 int count = SendMessage(m_hwnd, TB_BUTTONCOUNT, 0, 0);
850
851 if (m_hotItem >= 0)
852 {
853 TBBUTTONINFO info = { 0 };
854 info.cbSize = sizeof(TBBUTTONINFO);
855 info.dwMask = 0;
856 index = SendMessage(m_hwnd, TB_GETBUTTONINFO, m_hotItem, reinterpret_cast<LPARAM>(&info));
857 }
858
859 if (dwSelectType == VK_HOME)
860 {
861 index = 0;
862 dwSelectType = VK_DOWN;
863 }
864 else if (dwSelectType == VK_END)
865 {
866 index = count - 1;
867 dwSelectType = VK_UP;
868 }
869 else if (index < 0)
870 {
871 if (dwSelectType == VK_UP)
872 {
873 index = count - 1;
874 }
875 else if (dwSelectType == VK_DOWN)
876 {
877 index = 0;
878 }
879 }
880 else
881 {
882 if (dwSelectType == VK_UP)
883 {
884 index--;
885 }
886 else if (dwSelectType == VK_DOWN)
887 {
888 index++;
889 }
890 }
891
892 TBBUTTON btn = { 0 };
893 while (index >= 0 && index < count)
894 {
895 DWORD res = SendMessage(m_hwnd, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
896 if (!res)
897 return E_FAIL;
898
899 if (btn.dwData)
900 {
901 m_hotItem = btn.idCommand;
902 if (prev != index)
903 {
904 SendMessage(m_hwnd, TB_SETHOTITEM, index, 0);
905 return m_menuBand->_OnHotItemChanged(this, m_hotItem);
906 }
907 return S_OK;
908 }
909
910 if (dwSelectType == VK_UP)
911 {
912 index--;
913 }
914 else if (dwSelectType == VK_DOWN)
915 {
916 index++;
917 }
918 }
919 }
920
921 m_hotItem = -1;
922 if (prev != index)
923 {
924 SendMessage(m_hwnd, TB_SETHOTITEM, -1, 0);
925 m_menuBand->_OnHotItemChanged(NULL, -1);
926 }
927 return S_FALSE;
928 }
929
930 BOOL
931 AllocAndGetMenuString(HMENU hMenu, UINT ItemIDByPosition, WCHAR** String)
932 {
933 int Length;
934
935 Length = GetMenuStringW(hMenu, ItemIDByPosition, NULL, 0, MF_BYPOSITION);
936
937 if (!Length)
938 return FALSE;
939
940 /* Also allocate space for the terminating NULL character */
941 ++Length;
942 *String = (PWSTR) HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR));
943
944 GetMenuStringW(hMenu, ItemIDByPosition, *String, Length, MF_BYPOSITION);
945
946 return TRUE;
947 }
948
949 CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand *menuBand) :
950 CMenuToolbarBase(menuBand),
951 m_hmenu(NULL)
952 {
953 }
954
955 HRESULT CMenuStaticToolbar::GetMenu(
956 HMENU *phmenu,
957 HWND *phwnd,
958 DWORD *pdwFlags)
959 {
960 *phmenu = m_hmenu;
961 *phwnd = NULL;
962 *pdwFlags = m_dwMenuFlags;
963
964 return S_OK;
965 }
966
967 HRESULT CMenuStaticToolbar::SetMenu(
968 HMENU hmenu,
969 HWND hwnd,
970 DWORD dwFlags)
971 {
972 m_hmenu = hmenu;
973 m_dwMenuFlags = dwFlags;
974
975 return S_OK;
976 }
977
978 HRESULT CMenuStaticToolbar::FillToolbar()
979 {
980 int i;
981 int ic = GetMenuItemCount(m_hmenu);
982
983 for (i = 0; i < ic; i++)
984 {
985 MENUITEMINFOW info;
986 TBBUTTON tbb = { 0 };
987 PWSTR MenuString = NULL;
988
989 tbb.fsState = TBSTATE_ENABLED;
990 tbb.fsStyle = 0;
991
992 info.cbSize = sizeof(info);
993 info.fMask = MIIM_FTYPE | MIIM_ID;
994
995 GetMenuItemInfoW(m_hmenu, i, TRUE, &info);
996
997 if (info.fType == MFT_STRING)
998 {
999 if (!AllocAndGetMenuString(m_hmenu, i, &MenuString))
1000 return E_OUTOFMEMORY;
1001 if (::GetSubMenu(m_hmenu, i) != NULL)
1002 tbb.fsStyle |= BTNS_DROPDOWN;
1003 tbb.iString = (INT_PTR) MenuString;
1004 tbb.idCommand = info.wID;
1005
1006 SMINFO * sminfo = new SMINFO();
1007 sminfo->dwMask = SMIM_ICON | SMIM_FLAGS;
1008 if (SUCCEEDED(m_menuBand->_CallCBWithItemId(info.wID, SMC_GETINFO, 0, reinterpret_cast<LPARAM>(sminfo))))
1009 {
1010 tbb.iBitmap = sminfo->iIcon;
1011 tbb.dwData = reinterpret_cast<DWORD_PTR>(sminfo);
1012 // FIXME: remove before deleting the toolbar or it will leak
1013 }
1014 }
1015 else
1016 {
1017 tbb.fsStyle |= BTNS_SEP;
1018 }
1019
1020 SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1021
1022 if (MenuString)
1023 HeapFree(GetProcessHeap(), 0, MenuString);
1024 }
1025
1026 return S_OK;
1027 }
1028
1029 HRESULT CMenuStaticToolbar::OnContextMenu(NMMOUSE * rclick)
1030 {
1031 CComPtr<IContextMenu> contextMenu;
1032 HRESULT hr = m_menuBand->_CallCBWithItemId(rclick->dwItemSpec, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IContextMenu), reinterpret_cast<LPARAM>(&contextMenu));
1033 if (hr != S_OK)
1034 return hr;
1035
1036 return DoContextMenu(contextMenu);
1037 }
1038
1039 HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1040 {
1041 HRESULT hr;
1042 hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1043 if (FAILED(hr))
1044 return hr;
1045
1046 return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0);
1047 }
1048
1049 HRESULT CMenuStaticToolbar::PopupItem(UINT uItem)
1050 {
1051 TBBUTTONINFO info = { 0 };
1052 info.cbSize = sizeof(TBBUTTONINFO);
1053 info.dwMask = 0;
1054 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1055 if (index < 0)
1056 return E_FAIL;
1057
1058 TBBUTTON btn = { 0 };
1059 SendMessage(m_hwnd, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
1060
1061 SMINFO * nfo = reinterpret_cast<SMINFO*>(btn.dwData);
1062 if (!nfo)
1063 return E_FAIL;
1064
1065 if (nfo->dwFlags&SMIF_TRACKPOPUP)
1066 {
1067 return PopupSubMenu(index, m_hmenu);
1068 }
1069 else
1070 {
1071 CComPtr<IShellMenu> shellMenu;
1072 HRESULT hr = m_menuBand->_CallCBWithItemId(uItem, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IShellMenu), reinterpret_cast<LPARAM>(&shellMenu));
1073 if (FAILED(hr))
1074 return hr;
1075
1076 return PopupSubMenu(index, shellMenu);
1077 }
1078 }
1079
1080 HRESULT CMenuStaticToolbar::HasSubMenu(UINT uItem)
1081 {
1082 TBBUTTONINFO info = { 0 };
1083 info.cbSize = sizeof(TBBUTTONINFO);
1084 info.dwMask = 0;
1085 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1086 if (index < 0)
1087 return E_FAIL;
1088 return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE;
1089 }
1090
1091 CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) :
1092 CMenuToolbarBase(menuBand),
1093 m_shellFolder(NULL)
1094 {
1095 }
1096
1097 CMenuSFToolbar::~CMenuSFToolbar()
1098 {
1099 }
1100
1101 HRESULT CMenuSFToolbar::FillToolbar()
1102 {
1103 HRESULT hr;
1104 int i = 0;
1105 PWSTR MenuString;
1106
1107 IEnumIDList * eidl;
1108 m_shellFolder->EnumObjects(m_hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &eidl);
1109
1110 LPITEMIDLIST item = static_cast<LPITEMIDLIST>(CoTaskMemAlloc(sizeof(ITEMIDLIST)));
1111 ULONG fetched;
1112 while ((hr = eidl->Next(1, &item, &fetched)) == S_OK)
1113 {
1114 INT index = 0;
1115 INT indexOpen = 0;
1116
1117 TBBUTTON tbb = { 0 };
1118 tbb.fsState = TBSTATE_ENABLED;
1119 tbb.fsStyle = 0;
1120
1121 CComPtr<IShellItem> psi;
1122 SHCreateShellItem(NULL, m_shellFolder, item, &psi);
1123
1124 hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &MenuString);
1125 if (FAILED(hr))
1126 return hr;
1127
1128 index = SHMapPIDLToSystemImageListIndex(m_shellFolder, item, &indexOpen);
1129
1130 SFGAOF attrs;
1131 hr = psi->GetAttributes(SFGAO_FOLDER, &attrs);
1132
1133 if (attrs != 0)
1134 {
1135 tbb.fsStyle |= BTNS_DROPDOWN;
1136 }
1137
1138 tbb.idCommand = ++i;
1139 tbb.iString = (INT_PTR) MenuString;
1140 tbb.iBitmap = index;
1141 tbb.dwData = reinterpret_cast<DWORD_PTR>(ILClone(item));
1142 // FIXME: remove before deleting the toolbar or it will leak
1143
1144 SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1145 HeapFree(GetProcessHeap(), 0, MenuString);
1146
1147 }
1148 CoTaskMemFree(item);
1149
1150 return hr;
1151 }
1152
1153 HRESULT CMenuSFToolbar::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1154 {
1155 m_shellFolder = psf;
1156 m_idList = pidlFolder;
1157 m_hKey = hKey;
1158 m_dwMenuFlags = dwFlags;
1159 return S_OK;
1160 }
1161
1162 HRESULT CMenuSFToolbar::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1163 {
1164 HRESULT hr;
1165
1166 hr = m_shellFolder->QueryInterface(riid, ppv);
1167 if (FAILED(hr))
1168 return hr;
1169
1170 if (pdwFlags)
1171 *pdwFlags = m_dwMenuFlags;
1172
1173 if (ppidl)
1174 {
1175 LPITEMIDLIST pidl = NULL;
1176
1177 if (m_idList)
1178 {
1179 pidl = ILClone(m_idList);
1180 if (!pidl)
1181 {
1182 (*(IUnknown**) ppv)->Release();
1183 return E_FAIL;
1184 }
1185 }
1186
1187 *ppidl = pidl;
1188 }
1189
1190 return hr;
1191 }
1192
1193 LPITEMIDLIST CMenuSFToolbar::GetPidlFromId(UINT uItem, INT* pIndex)
1194 {
1195 TBBUTTONINFO info = { 0 };
1196 info.cbSize = sizeof(TBBUTTONINFO);
1197 info.dwMask = 0;
1198 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1199 if (index < 0)
1200 return NULL;
1201
1202 if (pIndex)
1203 *pIndex = index;
1204
1205 TBBUTTON btn = { 0 };
1206 if (!SendMessage(m_hwnd, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn)))
1207 return NULL;
1208
1209 return reinterpret_cast<LPITEMIDLIST>(btn.dwData);
1210 }
1211
1212 HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick)
1213 {
1214 HRESULT hr;
1215 CComPtr<IContextMenu> contextMenu;
1216 LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(rclick->dwItemData);
1217
1218 hr = m_shellFolder->GetUIObjectOf(m_hwnd, 1, &pidl, IID_IContextMenu, NULL, reinterpret_cast<VOID **>(&contextMenu));
1219 if (hr != S_OK)
1220 return hr;
1221
1222 return DoContextMenu(contextMenu);
1223 }
1224
1225 HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1226 {
1227 HRESULT hr;
1228 hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1229 if (FAILED(hr))
1230 return hr;
1231
1232 return m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0);
1233 }
1234
1235 HRESULT CMenuSFToolbar::PopupItem(UINT uItem)
1236 {
1237 HRESULT hr;
1238 UINT uId;
1239 UINT uIdAncestor;
1240 DWORD flags;
1241 int index;
1242 CComPtr<IShellMenuCallback> psmc;
1243 CComPtr<IShellMenu> shellMenu;
1244
1245 LPITEMIDLIST pidl = GetPidlFromId(uItem, &index);
1246
1247 if (!pidl)
1248 return E_FAIL;
1249
1250 #if USE_SYSTEM_MENUBAND
1251 hr = CoCreateInstance(CLSID_MenuBand,
1252 NULL,
1253 CLSCTX_INPROC_SERVER,
1254 IID_PPV_ARG(IShellMenu, &shellMenu));
1255 #else
1256 hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &shellMenu));
1257 #endif
1258 if (FAILED(hr))
1259 return hr;
1260 #if WRAP_MENUBAND
1261 hr = CMenuBand_Wrapper(shellMenu, IID_PPV_ARG(IShellMenu, &shellMenu));
1262 if (FAILED(hr))
1263 return hr;
1264 #endif
1265
1266 m_menuBand->GetMenuInfo(&psmc, &uId, &uIdAncestor, &flags);
1267
1268 // FIXME: not sure waht to use as uId/uIdAncestor here
1269 hr = shellMenu->Initialize(psmc, 0, uId, SMINIT_VERTICAL);
1270 if (FAILED(hr))
1271 return hr;
1272
1273 CComPtr<IShellFolder> childFolder;
1274 hr = m_shellFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &childFolder));
1275 if (FAILED(hr))
1276 return hr;
1277
1278 hr = shellMenu->SetShellFolder(childFolder, NULL, NULL, 0);
1279 if (FAILED(hr))
1280 return hr;
1281
1282 return PopupSubMenu(index, shellMenu);
1283 }
1284
1285 HRESULT CMenuSFToolbar::HasSubMenu(UINT uItem)
1286 {
1287 HRESULT hr;
1288 CComPtr<IShellItem> psi;
1289 SHCreateShellItem(NULL, m_shellFolder, GetPidlFromId(uItem), &psi);
1290
1291 SFGAOF attrs;
1292 hr = psi->GetAttributes(SFGAO_FOLDER, &attrs);
1293 if (FAILED(hr))
1294 return hr;
1295
1296 return (attrs != 0) ? S_OK : S_FALSE;
1297 }
1298
1299 CMenuBand::CMenuBand() :
1300 m_site(NULL),
1301 m_psmc(NULL),
1302 m_staticToolbar(NULL),
1303 m_SFToolbar(NULL),
1304 m_useBigIcons(FALSE),
1305 m_hotBar(NULL),
1306 m_hotItem(-1),
1307 m_subMenuChild(NULL)
1308 {
1309 m_focusManager = CMenuFocusManager::AcquireManager();
1310 }
1311
1312 CMenuBand::~CMenuBand()
1313 {
1314 CMenuFocusManager::ReleaseManager(m_focusManager);
1315
1316 if (m_staticToolbar)
1317 delete m_staticToolbar;
1318
1319 if (m_SFToolbar)
1320 delete m_SFToolbar;
1321 }
1322
1323 HRESULT STDMETHODCALLTYPE CMenuBand::Initialize(
1324 IShellMenuCallback *psmc,
1325 UINT uId,
1326 UINT uIdAncestor,
1327 DWORD dwFlags)
1328 {
1329 if (m_psmc != psmc)
1330 m_psmc = psmc;
1331 m_uId = uId;
1332 m_uIdAncestor = uIdAncestor;
1333 m_dwFlags = dwFlags;
1334
1335 if (m_psmc)
1336 {
1337 _CallCB(SMC_CREATE, 0, reinterpret_cast<LPARAM>(&m_UserData));
1338 }
1339
1340 return S_OK;
1341 }
1342
1343 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenuInfo(
1344 IShellMenuCallback **ppsmc,
1345 UINT *puId,
1346 UINT *puIdAncestor,
1347 DWORD *pdwFlags)
1348 {
1349 if (!pdwFlags) // maybe?
1350 return E_INVALIDARG;
1351
1352 if (ppsmc)
1353 *ppsmc = m_psmc;
1354
1355 if (puId)
1356 *puId = m_uId;
1357
1358 if (puIdAncestor)
1359 *puIdAncestor = m_uIdAncestor;
1360
1361 *pdwFlags = m_dwFlags;
1362
1363 return S_OK;
1364 }
1365
1366 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenu(
1367 HMENU hmenu,
1368 HWND hwnd,
1369 DWORD dwFlags)
1370 {
1371 if (m_staticToolbar == NULL)
1372 {
1373 m_staticToolbar = new CMenuStaticToolbar(this);
1374 }
1375 m_hmenu = hmenu;
1376 m_menuOwner;
1377
1378 HRESULT hr = m_staticToolbar->SetMenu(hmenu, hwnd, dwFlags);
1379 if (FAILED(hr))
1380 return hr;
1381
1382 if (m_site)
1383 {
1384 HWND hwndParent;
1385
1386 hr = m_site->GetWindow(&hwndParent);
1387 if (FAILED(hr))
1388 return hr;
1389
1390 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
1391 if (FAILED(hr))
1392 return hr;
1393
1394 hr = m_staticToolbar->FillToolbar();
1395 }
1396
1397 return hr;
1398 }
1399
1400 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenu(
1401 HMENU *phmenu,
1402 HWND *phwnd,
1403 DWORD *pdwFlags)
1404 {
1405 if (m_staticToolbar == NULL)
1406 return E_FAIL;
1407
1408 return m_staticToolbar->GetMenu(phmenu, phwnd, pdwFlags);
1409 }
1410
1411 HRESULT STDMETHODCALLTYPE CMenuBand::SetSite(IUnknown *pUnkSite)
1412 {
1413 HWND hwndParent;
1414 HRESULT hr;
1415
1416 m_site = NULL;
1417
1418 if (pUnkSite == NULL)
1419 return S_OK;
1420
1421 hwndParent = NULL;
1422 hr = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &m_site));
1423 if (FAILED(hr))
1424 return hr;
1425
1426 hr = m_site->GetWindow(&hwndParent);
1427 if (FAILED(hr))
1428 return hr;
1429
1430 if (!::IsWindow(hwndParent))
1431 return E_FAIL;
1432
1433 if (m_staticToolbar != NULL)
1434 {
1435 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
1436 if (FAILED(hr))
1437 return hr;
1438
1439 hr = m_staticToolbar->FillToolbar();
1440 if (FAILED(hr))
1441 return hr;
1442 }
1443
1444 if (m_SFToolbar != NULL)
1445 {
1446 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1447 if (FAILED(hr))
1448 return hr;
1449
1450 hr = m_SFToolbar->FillToolbar();
1451 if (FAILED(hr))
1452 return hr;
1453 }
1454
1455 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_subMenuParent));
1456 if (FAILED(hr))
1457 return hr;
1458
1459 CComPtr<IOleWindow> pTopLevelWindow;
1460 hr = IUnknown_QueryService(m_site, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1461 if (FAILED(hr))
1462 return hr;
1463
1464 return pTopLevelWindow->GetWindow(&m_topLevelWindow);
1465 }
1466
1467 HRESULT STDMETHODCALLTYPE CMenuBand::GetSite(REFIID riid, PVOID *ppvSite)
1468 {
1469 if (m_site == NULL)
1470 return E_FAIL;
1471
1472 return m_site->QueryInterface(riid, ppvSite);
1473 }
1474
1475 HRESULT STDMETHODCALLTYPE CMenuBand::GetWindow(
1476 HWND *phwnd)
1477 {
1478 if (m_SFToolbar != NULL)
1479 return m_SFToolbar->GetWindow(phwnd);
1480
1481 if (m_staticToolbar != NULL)
1482 return m_staticToolbar->GetWindow(phwnd);
1483
1484 return E_FAIL;
1485 }
1486
1487 HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc)
1488 {
1489 SIZE sizeStaticY = { 0 };
1490 SIZE sizeShlFldY = { 0 };
1491 HWND hwndStatic = NULL;
1492 HWND hwndShlFld = NULL;
1493 HRESULT hr = S_OK;
1494
1495 if (m_staticToolbar != NULL)
1496 hr = m_staticToolbar->GetWindow(&hwndStatic);
1497 if (FAILED(hr))
1498 return hr;
1499
1500 if (m_SFToolbar != NULL)
1501 hr = m_SFToolbar->GetWindow(&hwndShlFld);
1502 if (FAILED(hr))
1503 return hr;
1504
1505 if (hwndStatic == NULL && hwndShlFld == NULL)
1506 return E_FAIL;
1507
1508 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStaticY));
1509 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFldY));
1510
1511 int sy = min(prc->bottom - prc->top, sizeStaticY.cy + sizeShlFldY.cy);
1512
1513 int syStatic = sizeStaticY.cy;
1514 int syShlFld = sy - syStatic;
1515
1516 if (hwndShlFld)
1517 {
1518 SetWindowPos(hwndShlFld, NULL,
1519 prc->left,
1520 prc->top,
1521 prc->right - prc->left,
1522 syShlFld,
1523 0);
1524 DWORD btnSize = SendMessage(hwndShlFld, TB_GETBUTTONSIZE, 0, 0);
1525 SendMessage(hwndShlFld, TB_SETBUTTONSIZE, 0, MAKELPARAM(prc->right - prc->left, HIWORD(btnSize)));
1526 }
1527 if (hwndStatic)
1528 {
1529 SetWindowPos(hwndStatic, hwndShlFld,
1530 prc->left,
1531 prc->top + syShlFld,
1532 prc->right - prc->left,
1533 syStatic,
1534 0);
1535 DWORD btnSize = SendMessage(hwndStatic, TB_GETBUTTONSIZE, 0, 0);
1536 SendMessage(hwndStatic, TB_SETBUTTONSIZE, 0, MAKELPARAM(prc->right - prc->left, HIWORD(btnSize)));
1537 }
1538
1539 return S_OK;
1540 }
1541
1542 HRESULT STDMETHODCALLTYPE CMenuBand::GetBandInfo(
1543 DWORD dwBandID,
1544 DWORD dwViewMode,
1545 DESKBANDINFO *pdbi)
1546 {
1547 HWND hwndStatic = NULL;
1548 HWND hwndShlFld = NULL;
1549 HRESULT hr = S_OK;
1550
1551 if (m_staticToolbar != NULL)
1552 hr = m_staticToolbar->GetWindow(&hwndStatic);
1553 if (FAILED(hr))
1554 return hr;
1555
1556 if (m_SFToolbar != NULL)
1557 hr = m_SFToolbar->GetWindow(&hwndShlFld);
1558 if (FAILED(hr))
1559 return hr;
1560
1561 if (hwndStatic == NULL && hwndShlFld == NULL)
1562 return E_FAIL;
1563
1564 // HACK (?)
1565 if (pdbi->dwMask == 0)
1566 {
1567 pdbi->dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
1568 }
1569
1570 if (pdbi->dwMask & DBIM_MINSIZE)
1571 {
1572 SIZE sizeStatic = { 0 };
1573 SIZE sizeShlFld = { 0 };
1574
1575 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStatic));
1576 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFld));
1577
1578 pdbi->ptMinSize.x = 0;
1579 pdbi->ptMinSize.y = sizeStatic.cy + sizeShlFld.cy;
1580 }
1581 if (pdbi->dwMask & DBIM_MAXSIZE)
1582 {
1583 SIZE sizeStatic = { 0 };
1584 SIZE sizeShlFld = { 0 };
1585
1586 if (hwndStatic) SendMessageW(hwndStatic, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeStatic));
1587 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeShlFld));
1588
1589 sizeStatic.cx += 64;
1590 sizeShlFld.cx += 64;
1591
1592 pdbi->ptMaxSize.x = max(sizeStatic.cx, sizeShlFld.cx); // ignored
1593 pdbi->ptMaxSize.y = sizeStatic.cy + sizeShlFld.cy;
1594 }
1595 if (pdbi->dwMask & DBIM_INTEGRAL)
1596 {
1597 pdbi->ptIntegral.x = 0;
1598 pdbi->ptIntegral.y = 0;
1599 }
1600 if (pdbi->dwMask & DBIM_ACTUAL)
1601 {
1602 SIZE sizeStatic = { 0 };
1603 SIZE sizeShlFld = { 0 };
1604
1605 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&sizeStatic));
1606 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&sizeShlFld));
1607 pdbi->ptActual.x = max(sizeStatic.cx, sizeShlFld.cx);
1608
1609 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStatic));
1610 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFld));
1611 pdbi->ptActual.y = sizeStatic.cy + sizeShlFld.cy;
1612 }
1613 if (pdbi->dwMask & DBIM_TITLE)
1614 wcscpy(pdbi->wszTitle, L"");
1615 if (pdbi->dwMask & DBIM_MODEFLAGS)
1616 pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
1617 if (pdbi->dwMask & DBIM_BKCOLOR)
1618 pdbi->crBkgnd = 0;
1619 return S_OK;
1620 }
1621
1622 /* IDockingWindow */
1623 HRESULT STDMETHODCALLTYPE CMenuBand::ShowDW(BOOL fShow)
1624 {
1625 HRESULT hr = S_OK;
1626
1627 if (m_staticToolbar != NULL)
1628 hr = m_staticToolbar->ShowWindow(fShow);
1629 if (FAILED(hr))
1630 return hr;
1631 if (m_SFToolbar != NULL)
1632 hr = m_SFToolbar->ShowWindow(fShow);
1633 if (FAILED(hr))
1634 return hr;
1635
1636 if (fShow)
1637 {
1638 hr = _CallCB(SMC_INITMENU, 0, 0);
1639 if (FAILED(hr))
1640 return hr;
1641 }
1642
1643 if (fShow)
1644 hr = m_focusManager->PushMenu(this);
1645 else
1646 hr = m_focusManager->PopMenu(this);
1647
1648 return S_OK;
1649 }
1650
1651 HRESULT STDMETHODCALLTYPE CMenuBand::CloseDW(DWORD dwReserved)
1652 {
1653 ShowDW(FALSE);
1654
1655 if (m_staticToolbar != NULL)
1656 return m_staticToolbar->Close();
1657
1658 if (m_SFToolbar != NULL)
1659 return m_SFToolbar->Close();
1660
1661 return S_OK;
1662 }
1663 HRESULT STDMETHODCALLTYPE CMenuBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
1664 {
1665 UNIMPLEMENTED;
1666 return S_OK;
1667 }
1668
1669 HRESULT STDMETHODCALLTYPE CMenuBand::ContextSensitiveHelp(BOOL fEnterMode)
1670 {
1671 UNIMPLEMENTED;
1672 return S_OK;
1673 }
1674
1675 HRESULT STDMETHODCALLTYPE CMenuBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
1676 {
1677 HRESULT hr;
1678
1679 hr = m_subMenuParent->SetSubMenu(this, fActivate);
1680 if (FAILED(hr))
1681 return hr;
1682
1683 if (fActivate)
1684 {
1685 CComPtr<IOleWindow> pTopLevelWindow;
1686 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1687 if (FAILED(hr))
1688 return hr;
1689
1690 hr = pTopLevelWindow->GetWindow(&m_topLevelWindow);
1691 if (FAILED(hr))
1692 return hr;
1693 }
1694 else
1695 {
1696 m_topLevelWindow = NULL;
1697 }
1698
1699 return S_FALSE;
1700 }
1701
1702 HRESULT STDMETHODCALLTYPE CMenuBand::HasFocusIO()
1703 {
1704 UNIMPLEMENTED;
1705 return S_OK;
1706 }
1707
1708 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg)
1709 {
1710 UNIMPLEMENTED;
1711 return S_OK;
1712 }
1713
1714 HRESULT STDMETHODCALLTYPE CMenuBand::IsDirty()
1715 {
1716 UNIMPLEMENTED;
1717 return S_OK;
1718 }
1719
1720 HRESULT STDMETHODCALLTYPE CMenuBand::Load(IStream *pStm)
1721 {
1722 UNIMPLEMENTED;
1723 return S_OK;
1724 }
1725
1726 HRESULT STDMETHODCALLTYPE CMenuBand::Save(IStream *pStm, BOOL fClearDirty)
1727 {
1728 UNIMPLEMENTED;
1729 return S_OK;
1730 }
1731
1732 HRESULT STDMETHODCALLTYPE CMenuBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
1733 {
1734 UNIMPLEMENTED;
1735 return S_OK;
1736 }
1737
1738 HRESULT STDMETHODCALLTYPE CMenuBand::GetClassID(CLSID *pClassID)
1739 {
1740 UNIMPLEMENTED;
1741 return S_OK;
1742 }
1743
1744 HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
1745 {
1746 UNIMPLEMENTED;
1747 return S_OK;
1748 }
1749
1750 HRESULT STDMETHODCALLTYPE CMenuBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1751 {
1752 if (!pguidCmdGroup)
1753 return E_FAIL;
1754
1755 if (IsEqualGUID(*pguidCmdGroup, CLSID_MenuBand))
1756 {
1757 if (nCmdID == 16) // set (big) icon size
1758 {
1759 this->m_useBigIcons = TRUE;
1760 return S_OK;
1761 }
1762 else if (nCmdID == 19) // popup-related
1763 {
1764 return S_FALSE;
1765 }
1766 }
1767
1768 UNIMPLEMENTED;
1769 return S_OK;
1770 }
1771
1772 HRESULT STDMETHODCALLTYPE CMenuBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
1773 {
1774 if (IsEqualIID(guidService, SID_SMenuBandChild) ||
1775 IsEqualIID(guidService, SID_SMenuBandBottom) ||
1776 IsEqualIID(guidService, SID_SMenuBandBottomSelected))
1777 return this->QueryInterface(riid, ppvObject);
1778 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService));
1779 return E_NOINTERFACE;
1780 }
1781
1782 HRESULT STDMETHODCALLTYPE CMenuBand::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
1783 {
1784 UNIMPLEMENTED;
1785 return S_OK;
1786 }
1787
1788 HRESULT STDMETHODCALLTYPE CMenuBand::OnSelect(DWORD dwSelectType)
1789 {
1790 switch (dwSelectType)
1791 {
1792 case MPOS_CHILDTRACKING:
1793 // TODO: Cancel timers?
1794 return m_subMenuParent->OnSelect(dwSelectType);
1795 case MPOS_SELECTLEFT:
1796 if (m_subMenuChild)
1797 m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
1798 return m_subMenuParent->OnSelect(dwSelectType);
1799 case MPOS_SELECTRIGHT:
1800 if (m_hotBar && m_hotItem >= 0)
1801 {
1802 // TODO: popup the current child if it has subitems, otherwise spread up.
1803 }
1804 return m_subMenuParent->OnSelect(dwSelectType);
1805 case MPOS_EXECUTE:
1806 case MPOS_FULLCANCEL:
1807 if (m_subMenuChild)
1808 m_subMenuChild->OnSelect(dwSelectType);
1809 return m_subMenuParent->OnSelect(dwSelectType);
1810 case MPOS_CANCELLEVEL:
1811 if (m_subMenuChild)
1812 m_subMenuChild->OnSelect(dwSelectType);
1813 break;
1814 }
1815 return S_FALSE;
1816 }
1817
1818 HRESULT STDMETHODCALLTYPE CMenuBand::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
1819 {
1820 UNIMPLEMENTED;
1821 return S_OK;
1822 }
1823
1824 HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
1825 {
1826 UNIMPLEMENTED;
1827 return S_OK;
1828 }
1829
1830 HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
1831 {
1832 UNIMPLEMENTED;
1833 return S_OK;
1834 }
1835
1836 HRESULT STDMETHODCALLTYPE CMenuBand::IsMenuMessage(MSG *pmsg)
1837 {
1838 //UNIMPLEMENTED;
1839 //return S_OK;
1840 return S_FALSE;
1841 //return E_NOTIMPL;
1842 }
1843
1844 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet)
1845 {
1846 //UNIMPLEMENTED;
1847 return S_FALSE;
1848 }
1849
1850 HRESULT STDMETHODCALLTYPE CMenuBand::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1851 {
1852 if (m_SFToolbar == NULL)
1853 {
1854 m_SFToolbar = new CMenuSFToolbar(this);
1855 }
1856
1857 HRESULT hr = m_SFToolbar->SetShellFolder(psf, pidlFolder, hKey, dwFlags);
1858 if (FAILED(hr))
1859 return hr;
1860
1861 if (m_site)
1862 {
1863 HWND hwndParent;
1864
1865 hr = m_site->GetWindow(&hwndParent);
1866 if (FAILED(hr))
1867 return hr;
1868
1869 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1870 if (FAILED(hr))
1871 return hr;
1872
1873 hr = m_SFToolbar->FillToolbar();
1874 }
1875
1876 return hr;
1877 }
1878
1879 HRESULT STDMETHODCALLTYPE CMenuBand::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1880 {
1881 if (m_SFToolbar)
1882 return m_SFToolbar->GetShellFolder(pdwFlags, ppidl, riid, ppv);
1883 return E_FAIL;
1884 }
1885
1886 HRESULT STDMETHODCALLTYPE CMenuBand::InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
1887 {
1888 UNIMPLEMENTED;
1889 return S_OK;
1890 }
1891
1892 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(LPSMDATA psmd)
1893 {
1894 UNIMPLEMENTED;
1895 return S_OK;
1896 }
1897
1898 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenuToolbar(IUnknown *punk, DWORD dwFlags)
1899 {
1900 UNIMPLEMENTED;
1901 return S_OK;
1902 }
1903
1904 HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1905 {
1906 *theResult = 0;
1907 switch (uMsg)
1908 {
1909 case WM_COMMAND:
1910
1911 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1912 {
1913 return m_staticToolbar->OnCommand(wParam, lParam, theResult);
1914 }
1915
1916 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1917 {
1918 return m_SFToolbar->OnCommand(wParam, lParam, theResult);
1919 }
1920
1921 return S_OK;
1922
1923 case WM_NOTIFY:
1924 NMHDR * hdr = reinterpret_cast<LPNMHDR>(lParam);
1925 NMTBCUSTOMDRAW * cdraw;
1926 NMTBHOTITEM * hot;
1927 NMMOUSE * rclick;
1928 switch (hdr->code)
1929 {
1930 case TBN_HOTITEMCHANGE:
1931 hot = reinterpret_cast<LPNMTBHOTITEM>(hdr);
1932
1933 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1934 {
1935 return m_staticToolbar->OnHotItemChange(hot);
1936 }
1937
1938 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1939 {
1940 return m_SFToolbar->OnHotItemChange(hot);
1941 }
1942
1943 return S_OK;
1944
1945 case NM_RCLICK:
1946 rclick = reinterpret_cast<LPNMMOUSE>(hdr);
1947
1948 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1949 {
1950 return m_staticToolbar->OnContextMenu(rclick);
1951 }
1952
1953 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1954 {
1955 return m_SFToolbar->OnContextMenu(rclick);
1956 }
1957
1958 return S_OK;
1959 case NM_CUSTOMDRAW:
1960 cdraw = reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr);
1961 switch (cdraw->nmcd.dwDrawStage)
1962 {
1963 case CDDS_PREPAINT:
1964 *theResult = CDRF_NOTIFYITEMDRAW;
1965 return S_OK;
1966
1967 case CDDS_ITEMPREPAINT:
1968
1969 cdraw->clrBtnFace = GetSysColor(COLOR_MENU);
1970 cdraw->clrBtnHighlight = GetSysColor(COLOR_MENUHILIGHT);
1971
1972 cdraw->clrText = GetSysColor(COLOR_MENUTEXT);
1973 cdraw->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
1974 cdraw->clrHighlightHotTrack = GetSysColor(COLOR_HIGHLIGHTTEXT);
1975
1976 RECT rc = cdraw->nmcd.rc;
1977 HDC hdc = cdraw->nmcd.hdc;
1978
1979 HBRUSH bgBrush = GetSysColorBrush(COLOR_MENU);
1980 HBRUSH hotBrush = GetSysColorBrush(COLOR_MENUHILIGHT);
1981
1982 switch (cdraw->nmcd.uItemState)
1983 {
1984 case CDIS_HOT:
1985 case CDIS_FOCUS:
1986 FillRect(hdc, &rc, hotBrush);
1987 break;
1988 default:
1989 FillRect(hdc, &rc, bgBrush);
1990 break;
1991 }
1992
1993 *theResult = TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOETCHEDEFFECT | TBCDRF_HILITEHOTTRACK | TBCDRF_NOOFFSET;
1994 return S_OK;
1995 }
1996 return S_OK;
1997 }
1998 return S_OK;
1999 }
2000
2001 return S_FALSE;
2002 }
2003
2004 HRESULT STDMETHODCALLTYPE CMenuBand::IsWindowOwner(HWND hWnd)
2005 {
2006 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
2007 return S_OK;
2008
2009 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
2010 return S_OK;
2011
2012 return S_FALSE;
2013 }
2014
2015 HRESULT STDMETHODCALLTYPE CMenuBand::GetSubMenu(THIS)
2016 {
2017 UNIMPLEMENTED;
2018 return S_OK;
2019 }
2020
2021 HRESULT STDMETHODCALLTYPE CMenuBand::SetToolbar(THIS)
2022 {
2023 UNIMPLEMENTED;
2024 return S_OK;
2025 }
2026
2027 HRESULT STDMETHODCALLTYPE CMenuBand::SetMinWidth(THIS)
2028 {
2029 UNIMPLEMENTED;
2030 return S_OK;
2031 }
2032
2033 HRESULT STDMETHODCALLTYPE CMenuBand::SetNoBorder(THIS)
2034 {
2035 UNIMPLEMENTED;
2036 return S_OK;
2037 }
2038
2039 HRESULT STDMETHODCALLTYPE CMenuBand::SetTheme(THIS)
2040 {
2041 UNIMPLEMENTED;
2042 return S_OK;
2043 }
2044
2045 HRESULT STDMETHODCALLTYPE CMenuBand::GetTop(THIS)
2046 {
2047 UNIMPLEMENTED;
2048 return S_OK;
2049 }
2050
2051 HRESULT STDMETHODCALLTYPE CMenuBand::GetBottom(THIS)
2052 {
2053 UNIMPLEMENTED;
2054 return S_OK;
2055 }
2056
2057 HRESULT STDMETHODCALLTYPE CMenuBand::GetTracked(THIS)
2058 {
2059 UNIMPLEMENTED;
2060 return S_OK;
2061 }
2062
2063 HRESULT STDMETHODCALLTYPE CMenuBand::GetParentSite(THIS)
2064 {
2065 UNIMPLEMENTED;
2066 return S_OK;
2067 }
2068
2069 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(THIS)
2070 {
2071 UNIMPLEMENTED;
2072 return S_OK;
2073 }
2074
2075 HRESULT STDMETHODCALLTYPE CMenuBand::DoDefaultAction(THIS)
2076 {
2077 UNIMPLEMENTED;
2078 return S_OK;
2079 }
2080
2081 HRESULT STDMETHODCALLTYPE CMenuBand::IsEmpty(THIS)
2082 {
2083 UNIMPLEMENTED;
2084 return S_OK;
2085 }
2086
2087 HRESULT CMenuBand::_CallCBWithItemId(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam)
2088 {
2089 return _CallCB(uMsg, wParam, lParam, id);
2090 }
2091
2092 HRESULT CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam)
2093 {
2094 return _CallCB(uMsg, wParam, lParam, 0, pidl);
2095 }
2096
2097 HRESULT CMenuBand::_CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id, LPITEMIDLIST pidl)
2098 {
2099 if (!m_psmc)
2100 return S_FALSE;
2101
2102 HWND hwnd;
2103 GetWindow(&hwnd);
2104
2105 SMDATA smData = { 0 };
2106 smData.punk = static_cast<IShellMenu2*>(this);
2107 smData.uId = id;
2108 smData.uIdParent = m_uId;
2109 smData.uIdAncestor = m_uIdAncestor;
2110 smData.hwnd = hwnd;
2111 smData.pidlItem = pidl;
2112 if (m_staticToolbar)
2113 {
2114 smData.hmenu = m_hmenu;
2115 }
2116 smData.pvUserData = NULL;
2117 if (m_SFToolbar)
2118 m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf));
2119 HRESULT hr = m_psmc->CallbackSM(&smData, uMsg, wParam, lParam);
2120 ILFree(smData.pidlFolder);
2121 if (smData.psf)
2122 smData.psf->Release();
2123 return hr;
2124 }
2125
2126 HRESULT CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y)
2127 {
2128 ::TrackPopupMenu(popup, 0, x, y, 0, m_menuOwner, NULL);
2129 return S_OK;
2130 }
2131
2132 HRESULT CMenuBand::_GetTopLevelWindow(HWND*topLevel)
2133 {
2134 *topLevel = m_topLevelWindow;
2135 return S_OK;
2136 }
2137
2138 HRESULT CMenuBand::_OnHotItemChanged(CMenuToolbarBase * tb, INT id)
2139 {
2140 if (m_hotBar && m_hotBar != tb)
2141 m_hotBar->ChangeHotItem(-1);
2142 m_hotBar = tb;
2143 m_hotItem = id;
2144 return S_OK;
2145 }
2146
2147 HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
2148 {
2149 HRESULT hr;
2150
2151 if (changeType == VK_DOWN)
2152 {
2153 if (m_SFToolbar && (m_hotBar == m_SFToolbar || m_hotBar == NULL))
2154 {
2155 hr = m_SFToolbar->ChangeHotItem(VK_DOWN);
2156 if (hr == S_FALSE)
2157 {
2158 if (m_staticToolbar)
2159 return m_staticToolbar->ChangeHotItem(VK_HOME);
2160 else
2161 return m_SFToolbar->ChangeHotItem(VK_HOME);
2162 }
2163 return hr;
2164 }
2165 else if (m_staticToolbar && m_hotBar == m_staticToolbar)
2166 {
2167 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2168 if (hr == S_FALSE)
2169 {
2170 if (m_SFToolbar)
2171 return m_SFToolbar->ChangeHotItem(VK_HOME);
2172 else
2173 return m_staticToolbar->ChangeHotItem(VK_HOME);
2174 }
2175 return hr;
2176 }
2177 }
2178 else if (changeType == VK_UP)
2179 {
2180 if (m_staticToolbar && (m_hotBar == m_staticToolbar || m_hotBar == NULL))
2181 {
2182 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2183 if (hr == S_FALSE)
2184 {
2185 if (m_SFToolbar)
2186 return m_SFToolbar->ChangeHotItem(VK_END);
2187 else
2188 return m_staticToolbar->ChangeHotItem(VK_END);
2189 }
2190 return hr;
2191 }
2192 else if (m_SFToolbar && m_hotBar == m_SFToolbar)
2193 {
2194 hr = m_SFToolbar->ChangeHotItem(VK_UP);
2195 if (hr == S_FALSE)
2196 {
2197 if (m_staticToolbar)
2198 return m_staticToolbar->ChangeHotItem(VK_END);
2199 else
2200 return m_SFToolbar->ChangeHotItem(VK_END);
2201 }
2202 return hr;
2203 }
2204 }
2205 else
2206 {
2207 m_subMenuParent->OnSelect(changeType);
2208 }
2209 return S_OK;
2210 }
2211
2212
2213 HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude)
2214 {
2215 if (m_subMenuChild)
2216 {
2217 HRESULT hr = m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
2218 if (FAILED(hr))
2219 return hr;
2220 }
2221 m_subMenuChild = popup;
2222 if (popup)
2223 {
2224 IUnknown_SetSite(popup, m_subMenuParent);
2225 popup->Popup(pAt, pExclude, MPPF_TOP | MPPF_RIGHT);
2226 }
2227 return S_OK;
2228 }