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