[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 = MAKEINTRESOURCEA(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 HRESULT CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType)
939 {
940 int prev = m_hotItem;
941 int index = -1;
942
943 if (dwSelectType != 0xFFFFFFFF)
944 {
945 int count = SendMessage(m_hwndToolbar, TB_BUTTONCOUNT, 0, 0);
946
947 if (m_hotItem >= 0)
948 {
949 TBBUTTONINFO info = { 0 };
950 info.cbSize = sizeof(TBBUTTONINFO);
951 info.dwMask = 0;
952 index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, m_hotItem, reinterpret_cast<LPARAM>(&info));
953 }
954
955 if (dwSelectType == VK_HOME)
956 {
957 index = 0;
958 dwSelectType = VK_DOWN;
959 }
960 else if (dwSelectType == VK_END)
961 {
962 index = count - 1;
963 dwSelectType = VK_UP;
964 }
965 else if (index < 0)
966 {
967 if (dwSelectType == VK_UP)
968 {
969 index = count - 1;
970 }
971 else if (dwSelectType == VK_DOWN)
972 {
973 index = 0;
974 }
975 }
976 else
977 {
978 if (dwSelectType == VK_UP)
979 {
980 index--;
981 }
982 else if (dwSelectType == VK_DOWN)
983 {
984 index++;
985 }
986 }
987
988 TBBUTTON btn = { 0 };
989 while (index >= 0 && index < count)
990 {
991 DWORD res = SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
992 if (!res)
993 return E_FAIL;
994
995 if (btn.dwData)
996 {
997 m_hotItem = btn.idCommand;
998 if (prev != m_hotItem)
999 {
1000 SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0);
1001 return m_menuBand->_OnHotItemChanged(this, m_hotItem);
1002 }
1003 return S_OK;
1004 }
1005
1006 if (dwSelectType == VK_UP)
1007 {
1008 index--;
1009 }
1010 else if (dwSelectType == VK_DOWN)
1011 {
1012 index++;
1013 }
1014 }
1015 }
1016
1017 m_hotItem = -1;
1018 if (prev != m_hotItem)
1019 {
1020 SendMessage(m_hwndToolbar, TB_SETHOTITEM, -1, 0);
1021 m_menuBand->_OnHotItemChanged(NULL, -1);
1022 }
1023 return S_FALSE;
1024 }
1025
1026 BOOL
1027 AllocAndGetMenuString(HMENU hMenu, UINT ItemIDByPosition, WCHAR** String)
1028 {
1029 int Length;
1030
1031 Length = GetMenuStringW(hMenu, ItemIDByPosition, NULL, 0, MF_BYPOSITION);
1032
1033 if (!Length)
1034 return FALSE;
1035
1036 /* Also allocate space for the terminating NULL character */
1037 ++Length;
1038 *String = (PWSTR) HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR));
1039
1040 GetMenuStringW(hMenu, ItemIDByPosition, *String, Length, MF_BYPOSITION);
1041
1042 return TRUE;
1043 }
1044
1045 CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand *menuBand) :
1046 CMenuToolbarBase(menuBand, FALSE),
1047 m_hmenu(NULL)
1048 {
1049 }
1050
1051 HRESULT CMenuStaticToolbar::GetMenu(
1052 HMENU *phmenu,
1053 HWND *phwnd,
1054 DWORD *pdwFlags)
1055 {
1056 *phmenu = m_hmenu;
1057 *phwnd = NULL;
1058 *pdwFlags = m_dwMenuFlags;
1059
1060 return S_OK;
1061 }
1062
1063 HRESULT CMenuStaticToolbar::SetMenu(
1064 HMENU hmenu,
1065 HWND hwnd,
1066 DWORD dwFlags)
1067 {
1068 m_hmenu = hmenu;
1069 m_dwMenuFlags = dwFlags;
1070
1071 return S_OK;
1072 }
1073
1074 HRESULT CMenuStaticToolbar::FillToolbar()
1075 {
1076 int i;
1077 int ic = GetMenuItemCount(m_hmenu);
1078
1079 for (i = 0; i < ic; i++)
1080 {
1081 MENUITEMINFOW info;
1082 TBBUTTON tbb = { 0 };
1083 PWSTR MenuString = NULL;
1084
1085 tbb.fsState = TBSTATE_ENABLED;
1086 tbb.fsStyle = 0;
1087
1088 info.cbSize = sizeof(info);
1089 info.fMask = MIIM_FTYPE | MIIM_ID;
1090
1091 GetMenuItemInfoW(m_hmenu, i, TRUE, &info);
1092
1093 if (info.fType == MFT_STRING)
1094 {
1095 if (!AllocAndGetMenuString(m_hmenu, i, &MenuString))
1096 return E_OUTOFMEMORY;
1097 if (::GetSubMenu(m_hmenu, i) != NULL)
1098 tbb.fsStyle |= BTNS_DROPDOWN;
1099 tbb.iString = (INT_PTR) MenuString;
1100 tbb.idCommand = info.wID;
1101
1102 SMINFO * sminfo = new SMINFO();
1103 sminfo->dwMask = SMIM_ICON | SMIM_FLAGS;
1104 if (SUCCEEDED(m_menuBand->_CallCBWithItemId(info.wID, SMC_GETINFO, 0, reinterpret_cast<LPARAM>(sminfo))))
1105 {
1106 tbb.iBitmap = sminfo->iIcon;
1107 tbb.dwData = reinterpret_cast<DWORD_PTR>(sminfo);
1108 // FIXME: remove before deleting the toolbar or it will leak
1109 }
1110 }
1111 else
1112 {
1113 tbb.fsStyle |= BTNS_SEP;
1114 }
1115
1116 SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1117
1118 if (MenuString)
1119 HeapFree(GetProcessHeap(), 0, MenuString);
1120 }
1121
1122 return S_OK;
1123 }
1124
1125 HRESULT CMenuStaticToolbar::OnContextMenu(NMMOUSE * rclick)
1126 {
1127 CComPtr<IContextMenu> contextMenu;
1128 HRESULT hr = m_menuBand->_CallCBWithItemId(rclick->dwItemSpec, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IContextMenu), reinterpret_cast<LPARAM>(&contextMenu));
1129 if (hr != S_OK)
1130 return hr;
1131
1132 return DoContextMenu(contextMenu);
1133 }
1134
1135 HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1136 {
1137 HRESULT hr;
1138 hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1139 if (FAILED(hr))
1140 return hr;
1141
1142 // in case the clicked item has a submenu, we do not need to execute the item
1143 if (hr == S_FALSE)
1144 return hr;
1145
1146 return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0);
1147 }
1148
1149 HRESULT CMenuStaticToolbar::PopupItem(UINT uItem)
1150 {
1151 TBBUTTONINFO info = { 0 };
1152 info.cbSize = sizeof(TBBUTTONINFO);
1153 info.dwMask = 0;
1154 int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1155 if (index < 0)
1156 return E_FAIL;
1157
1158 TBBUTTON btn = { 0 };
1159 SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
1160
1161 SMINFO * nfo = reinterpret_cast<SMINFO*>(btn.dwData);
1162 if (!nfo)
1163 return E_FAIL;
1164
1165 if (nfo->dwFlags&SMIF_TRACKPOPUP)
1166 {
1167 return PopupSubMenu(index, m_hmenu);
1168 }
1169 else
1170 {
1171 CComPtr<IShellMenu> shellMenu;
1172 HRESULT hr = m_menuBand->_CallCBWithItemId(uItem, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IShellMenu), reinterpret_cast<LPARAM>(&shellMenu));
1173 if (FAILED(hr))
1174 return hr;
1175
1176 return PopupSubMenu(uItem, index, shellMenu);
1177 }
1178 }
1179
1180 HRESULT CMenuStaticToolbar::HasSubMenu(UINT uItem)
1181 {
1182 TBBUTTONINFO info = { 0 };
1183 info.cbSize = sizeof(TBBUTTONINFO);
1184 info.dwMask = 0;
1185 int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1186 if (index < 0)
1187 return E_FAIL;
1188 return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE;
1189 }
1190
1191 CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) :
1192 CMenuToolbarBase(menuBand, TRUE),
1193 m_shellFolder(NULL)
1194 {
1195 }
1196
1197 CMenuSFToolbar::~CMenuSFToolbar()
1198 {
1199 }
1200
1201 HRESULT CMenuSFToolbar::FillToolbar()
1202 {
1203 HRESULT hr;
1204 int i = 0;
1205 PWSTR MenuString;
1206
1207 IEnumIDList * eidl;
1208 m_shellFolder->EnumObjects(m_hwndToolbar, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &eidl);
1209
1210 LPITEMIDLIST item = static_cast<LPITEMIDLIST>(CoTaskMemAlloc(sizeof(ITEMIDLIST)));
1211 ULONG fetched;
1212 while ((hr = eidl->Next(1, &item, &fetched)) == S_OK)
1213 {
1214 INT index = 0;
1215 INT indexOpen = 0;
1216
1217 TBBUTTON tbb = { 0 };
1218 tbb.fsState = TBSTATE_ENABLED;
1219 tbb.fsStyle = 0;
1220
1221 CComPtr<IShellItem> psi;
1222 hr = SHCreateShellItem(NULL, m_shellFolder, item, &psi);
1223 if (FAILED(hr))
1224 return hr;
1225
1226 hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &MenuString);
1227 if (FAILED(hr))
1228 return hr;
1229
1230 index = SHMapPIDLToSystemImageListIndex(m_shellFolder, item, &indexOpen);
1231
1232 SFGAOF attrs;
1233 hr = psi->GetAttributes(SFGAO_FOLDER, &attrs);
1234
1235 if (attrs != 0)
1236 {
1237 tbb.fsStyle |= BTNS_DROPDOWN;
1238 }
1239
1240 tbb.idCommand = ++i;
1241 tbb.iString = (INT_PTR) MenuString;
1242 tbb.iBitmap = index;
1243 tbb.dwData = reinterpret_cast<DWORD_PTR>(ILClone(item));
1244 // FIXME: remove before deleting the toolbar or it will leak
1245
1246 SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1247 HeapFree(GetProcessHeap(), 0, MenuString);
1248
1249 }
1250 CoTaskMemFree(item);
1251
1252 // If no items were added, show the "empty" placeholder
1253 if (i == 0)
1254 {
1255 TBBUTTON tbb = { 0 };
1256 PCWSTR MenuString = L"(Empty)";
1257
1258 tbb.fsState = 0/*TBSTATE_DISABLED*/;
1259 tbb.fsStyle = 0;
1260 tbb.iString = (INT_PTR) MenuString;
1261 tbb.iBitmap = -1;
1262
1263 SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1264
1265 return S_OK;
1266 }
1267
1268 return hr;
1269 }
1270
1271 HRESULT CMenuSFToolbar::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1272 {
1273 m_shellFolder = psf;
1274 m_idList = pidlFolder;
1275 m_hKey = hKey;
1276 m_dwMenuFlags = dwFlags;
1277 return S_OK;
1278 }
1279
1280 HRESULT CMenuSFToolbar::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1281 {
1282 HRESULT hr;
1283
1284 hr = m_shellFolder->QueryInterface(riid, ppv);
1285 if (FAILED(hr))
1286 return hr;
1287
1288 if (pdwFlags)
1289 *pdwFlags = m_dwMenuFlags;
1290
1291 if (ppidl)
1292 {
1293 LPITEMIDLIST pidl = NULL;
1294
1295 if (m_idList)
1296 {
1297 pidl = ILClone(m_idList);
1298 if (!pidl)
1299 {
1300 (*(IUnknown**) ppv)->Release();
1301 return E_FAIL;
1302 }
1303 }
1304
1305 *ppidl = pidl;
1306 }
1307
1308 return hr;
1309 }
1310
1311 LPITEMIDLIST CMenuSFToolbar::GetPidlFromId(UINT uItem, INT* pIndex)
1312 {
1313 TBBUTTONINFO info = { 0 };
1314 info.cbSize = sizeof(TBBUTTONINFO);
1315 info.dwMask = 0;
1316 int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1317 if (index < 0)
1318 return NULL;
1319
1320 if (pIndex)
1321 *pIndex = index;
1322
1323 TBBUTTON btn = { 0 };
1324 if (!SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn)))
1325 return NULL;
1326
1327 return reinterpret_cast<LPITEMIDLIST>(btn.dwData);
1328 }
1329
1330 HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick)
1331 {
1332 HRESULT hr;
1333 CComPtr<IContextMenu> contextMenu;
1334 LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(rclick->dwItemData);
1335
1336 hr = m_shellFolder->GetUIObjectOf(m_hwndToolbar, 1, &pidl, IID_IContextMenu, NULL, reinterpret_cast<VOID **>(&contextMenu));
1337 if (hr != S_OK)
1338 return hr;
1339
1340 return DoContextMenu(contextMenu);
1341 }
1342
1343 HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1344 {
1345 HRESULT hr;
1346 hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1347 if (FAILED(hr))
1348 return hr;
1349
1350 // in case the clicked item has a submenu, we do not need to execute the item
1351 if (hr == S_FALSE)
1352 return hr;
1353
1354 return m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0);
1355 }
1356
1357 HRESULT CMenuSFToolbar::PopupItem(UINT uItem)
1358 {
1359 HRESULT hr;
1360 UINT uId;
1361 UINT uIdAncestor;
1362 DWORD flags;
1363 int index;
1364 CComPtr<IShellMenuCallback> psmc;
1365 CComPtr<IShellMenu> shellMenu;
1366
1367 LPITEMIDLIST pidl = GetPidlFromId(uItem, &index);
1368
1369 if (!pidl)
1370 return E_FAIL;
1371
1372 #if USE_SYSTEM_MENUBAND
1373 hr = CoCreateInstance(CLSID_MenuBand,
1374 NULL,
1375 CLSCTX_INPROC_SERVER,
1376 IID_PPV_ARG(IShellMenu, &shellMenu));
1377 #else
1378 hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &shellMenu));
1379 #endif
1380 if (FAILED(hr))
1381 return hr;
1382 #if WRAP_MENUBAND
1383 hr = CMenuBand_Wrapper(shellMenu, IID_PPV_ARG(IShellMenu, &shellMenu));
1384 if (FAILED(hr))
1385 return hr;
1386 #endif
1387
1388 m_menuBand->GetMenuInfo(&psmc, &uId, &uIdAncestor, &flags);
1389
1390 // FIXME: not sure what to use as uId/uIdAncestor here
1391 hr = shellMenu->Initialize(psmc, 0, uId, SMINIT_VERTICAL);
1392 if (FAILED(hr))
1393 return hr;
1394
1395 CComPtr<IShellFolder> childFolder;
1396 hr = m_shellFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &childFolder));
1397 if (FAILED(hr))
1398 return hr;
1399
1400 hr = shellMenu->SetShellFolder(childFolder, NULL, NULL, 0);
1401 if (FAILED(hr))
1402 return hr;
1403
1404 return PopupSubMenu(uItem, index, shellMenu);
1405 }
1406
1407 HRESULT CMenuSFToolbar::HasSubMenu(UINT uItem)
1408 {
1409 HRESULT hr;
1410 CComPtr<IShellItem> psi;
1411 hr = SHCreateShellItem(NULL, m_shellFolder, GetPidlFromId(uItem), &psi);
1412 if (FAILED(hr))
1413 return S_FALSE;
1414
1415 SFGAOF attrs;
1416 hr = psi->GetAttributes(SFGAO_FOLDER, &attrs);
1417 if (FAILED(hr))
1418 return hr;
1419
1420 return (attrs != 0) ? S_OK : S_FALSE;
1421 }
1422
1423 CMenuBand::CMenuBand() :
1424 m_staticToolbar(NULL),
1425 m_SFToolbar(NULL),
1426 m_site(NULL),
1427 m_psmc(NULL),
1428 m_subMenuChild(NULL),
1429 m_useBigIcons(FALSE),
1430 m_hotBar(NULL),
1431 m_hotItem(-1),
1432 m_popupItem(-1)
1433 {
1434 m_focusManager = CMenuFocusManager::AcquireManager();
1435
1436 m_marlett = CreateFont(
1437 0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET,
1438 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
1439 DEFAULT_QUALITY, FF_DONTCARE, L"Marlett");
1440 }
1441
1442 CMenuBand::~CMenuBand()
1443 {
1444 CMenuFocusManager::ReleaseManager(m_focusManager);
1445
1446 if (m_staticToolbar)
1447 delete m_staticToolbar;
1448
1449 if (m_SFToolbar)
1450 delete m_SFToolbar;
1451
1452 DeleteObject(m_marlett);
1453 }
1454
1455 HRESULT STDMETHODCALLTYPE CMenuBand::Initialize(
1456 IShellMenuCallback *psmc,
1457 UINT uId,
1458 UINT uIdAncestor,
1459 DWORD dwFlags)
1460 {
1461 if (m_psmc != psmc)
1462 m_psmc = psmc;
1463 m_uId = uId;
1464 m_uIdAncestor = uIdAncestor;
1465 m_dwFlags = dwFlags;
1466
1467 if (m_psmc)
1468 {
1469 _CallCB(SMC_CREATE, 0, reinterpret_cast<LPARAM>(&m_UserData));
1470 }
1471
1472 return S_OK;
1473 }
1474
1475 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenuInfo(
1476 IShellMenuCallback **ppsmc,
1477 UINT *puId,
1478 UINT *puIdAncestor,
1479 DWORD *pdwFlags)
1480 {
1481 if (!pdwFlags) // maybe?
1482 return E_INVALIDARG;
1483
1484 if (ppsmc)
1485 *ppsmc = m_psmc;
1486
1487 if (puId)
1488 *puId = m_uId;
1489
1490 if (puIdAncestor)
1491 *puIdAncestor = m_uIdAncestor;
1492
1493 *pdwFlags = m_dwFlags;
1494
1495 return S_OK;
1496 }
1497
1498 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenu(
1499 HMENU hmenu,
1500 HWND hwnd,
1501 DWORD dwFlags)
1502 {
1503 if (m_staticToolbar == NULL)
1504 {
1505 m_staticToolbar = new CMenuStaticToolbar(this);
1506 }
1507 m_hmenu = hmenu;
1508 m_menuOwner;
1509
1510 HRESULT hr = m_staticToolbar->SetMenu(hmenu, hwnd, dwFlags);
1511 if (FAILED(hr))
1512 return hr;
1513
1514 if (m_site)
1515 {
1516 HWND hwndParent;
1517
1518 hr = m_site->GetWindow(&hwndParent);
1519 if (FAILED(hr))
1520 return hr;
1521
1522 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
1523 if (FAILED(hr))
1524 return hr;
1525
1526 hr = m_staticToolbar->FillToolbar();
1527 }
1528
1529 return hr;
1530 }
1531
1532 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenu(
1533 HMENU *phmenu,
1534 HWND *phwnd,
1535 DWORD *pdwFlags)
1536 {
1537 if (m_staticToolbar == NULL)
1538 return E_FAIL;
1539
1540 return m_staticToolbar->GetMenu(phmenu, phwnd, pdwFlags);
1541 }
1542
1543 HRESULT STDMETHODCALLTYPE CMenuBand::SetSite(IUnknown *pUnkSite)
1544 {
1545 HWND hwndParent;
1546 HRESULT hr;
1547
1548 m_site = NULL;
1549
1550 if (pUnkSite == NULL)
1551 return S_OK;
1552
1553 hwndParent = NULL;
1554 hr = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &m_site));
1555 if (FAILED(hr))
1556 return hr;
1557
1558 hr = m_site->GetWindow(&hwndParent);
1559 if (FAILED(hr))
1560 return hr;
1561
1562 if (!::IsWindow(hwndParent))
1563 return E_FAIL;
1564
1565 if (m_staticToolbar != NULL)
1566 {
1567 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
1568 if (FAILED(hr))
1569 return hr;
1570
1571 hr = m_staticToolbar->FillToolbar();
1572 if (FAILED(hr))
1573 return hr;
1574 }
1575
1576 if (m_SFToolbar != NULL)
1577 {
1578 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1579 if (FAILED(hr))
1580 return hr;
1581
1582 hr = m_SFToolbar->FillToolbar();
1583 if (FAILED(hr))
1584 return hr;
1585 }
1586
1587 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_subMenuParent));
1588 if (FAILED(hr))
1589 return hr;
1590
1591 CComPtr<IOleWindow> pTopLevelWindow;
1592 hr = IUnknown_QueryService(m_site, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1593 if (FAILED(hr))
1594 return hr;
1595
1596 return pTopLevelWindow->GetWindow(&m_topLevelWindow);
1597 }
1598
1599 HRESULT STDMETHODCALLTYPE CMenuBand::GetSite(REFIID riid, PVOID *ppvSite)
1600 {
1601 if (m_site == NULL)
1602 return E_FAIL;
1603
1604 return m_site->QueryInterface(riid, ppvSite);
1605 }
1606
1607 HRESULT STDMETHODCALLTYPE CMenuBand::GetWindow(
1608 HWND *phwnd)
1609 {
1610 if (m_SFToolbar != NULL)
1611 return m_SFToolbar->GetWindow(phwnd);
1612
1613 if (m_staticToolbar != NULL)
1614 return m_staticToolbar->GetWindow(phwnd);
1615
1616 return E_FAIL;
1617 }
1618
1619 HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc)
1620 {
1621 SIZE sizeStatic = { 0 };
1622 SIZE sizeShlFld = { 0 };
1623 HRESULT hr = S_OK;
1624
1625 if (m_staticToolbar != NULL)
1626 hr = m_staticToolbar->GetIdealSize(sizeStatic);
1627 if (FAILED(hr))
1628 return hr;
1629
1630 if (m_SFToolbar != NULL)
1631 hr = m_SFToolbar->GetIdealSize(sizeShlFld);
1632 if (FAILED(hr))
1633 return hr;
1634
1635 if (m_staticToolbar == NULL && m_SFToolbar == NULL)
1636 return E_FAIL;
1637
1638 int sy = min(prc->bottom - prc->top, sizeStatic.cy + sizeShlFld.cy);
1639
1640 int syStatic = sizeStatic.cy;
1641 int syShlFld = sy - syStatic;
1642
1643 if (m_SFToolbar)
1644 {
1645 m_SFToolbar->SetPosSize(
1646 prc->left,
1647 prc->top,
1648 prc->right - prc->left,
1649 syShlFld);
1650 }
1651 if (m_staticToolbar)
1652 {
1653 m_staticToolbar->SetPosSize(
1654 prc->left,
1655 prc->top + syShlFld,
1656 prc->right - prc->left,
1657 syStatic);
1658 }
1659
1660 return S_OK;
1661 }
1662 HRESULT STDMETHODCALLTYPE CMenuBand::GetBandInfo(
1663 DWORD dwBandID,
1664 DWORD dwViewMode,
1665 DESKBANDINFO *pdbi)
1666 {
1667 SIZE sizeStatic = { 0 };
1668 SIZE sizeShlFld = { 0 };
1669
1670 HRESULT hr = S_OK;
1671
1672 if (m_staticToolbar != NULL)
1673 hr = m_staticToolbar->GetIdealSize(sizeStatic);
1674 if (FAILED(hr))
1675 return hr;
1676
1677 if (m_SFToolbar != NULL)
1678 hr = m_SFToolbar->GetIdealSize(sizeShlFld);
1679 if (FAILED(hr))
1680 return hr;
1681
1682 if (m_staticToolbar == NULL && m_SFToolbar == NULL)
1683 return E_FAIL;
1684
1685 pdbi->ptMaxSize.x = max(sizeStatic.cx, sizeShlFld.cx) + 20;
1686 pdbi->ptMaxSize.y = sizeStatic.cy + sizeShlFld.cy;
1687
1688 return S_OK;
1689 }
1690
1691 /* IDockingWindow */
1692 HRESULT STDMETHODCALLTYPE CMenuBand::ShowDW(BOOL fShow)
1693 {
1694 HRESULT hr = S_OK;
1695
1696 if (m_staticToolbar != NULL)
1697 hr = m_staticToolbar->ShowWindow(fShow);
1698 if (FAILED(hr))
1699 return hr;
1700 if (m_SFToolbar != NULL)
1701 hr = m_SFToolbar->ShowWindow(fShow);
1702 if (FAILED(hr))
1703 return hr;
1704
1705 if (fShow)
1706 {
1707 hr = _CallCB(SMC_INITMENU, 0, 0);
1708 if (FAILED(hr))
1709 return hr;
1710 }
1711
1712 if (fShow)
1713 hr = m_focusManager->PushMenu(this);
1714 else
1715 hr = m_focusManager->PopMenu(this);
1716
1717 return S_OK;
1718 }
1719
1720 HRESULT STDMETHODCALLTYPE CMenuBand::CloseDW(DWORD dwReserved)
1721 {
1722 ShowDW(FALSE);
1723
1724 if (m_staticToolbar != NULL)
1725 return m_staticToolbar->Close();
1726
1727 if (m_SFToolbar != NULL)
1728 return m_SFToolbar->Close();
1729
1730 return S_OK;
1731 }
1732 HRESULT STDMETHODCALLTYPE CMenuBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
1733 {
1734 UNIMPLEMENTED;
1735 return S_OK;
1736 }
1737
1738 HRESULT STDMETHODCALLTYPE CMenuBand::ContextSensitiveHelp(BOOL fEnterMode)
1739 {
1740 UNIMPLEMENTED;
1741 return S_OK;
1742 }
1743
1744 HRESULT STDMETHODCALLTYPE CMenuBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
1745 {
1746 HRESULT hr;
1747
1748 hr = m_subMenuParent->SetSubMenu(this, fActivate);
1749 if (FAILED(hr))
1750 return hr;
1751
1752 if (fActivate)
1753 {
1754 CComPtr<IOleWindow> pTopLevelWindow;
1755 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1756 if (FAILED(hr))
1757 return hr;
1758
1759 hr = pTopLevelWindow->GetWindow(&m_topLevelWindow);
1760 if (FAILED(hr))
1761 return hr;
1762 }
1763 else
1764 {
1765 m_topLevelWindow = NULL;
1766 }
1767
1768 return S_FALSE;
1769 }
1770
1771 HRESULT STDMETHODCALLTYPE CMenuBand::HasFocusIO()
1772 {
1773 UNIMPLEMENTED;
1774 return S_OK;
1775 }
1776
1777 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg)
1778 {
1779 UNIMPLEMENTED;
1780 return S_OK;
1781 }
1782
1783 HRESULT STDMETHODCALLTYPE CMenuBand::IsDirty()
1784 {
1785 UNIMPLEMENTED;
1786 return S_OK;
1787 }
1788
1789 HRESULT STDMETHODCALLTYPE CMenuBand::Load(IStream *pStm)
1790 {
1791 UNIMPLEMENTED;
1792 return S_OK;
1793 }
1794
1795 HRESULT STDMETHODCALLTYPE CMenuBand::Save(IStream *pStm, BOOL fClearDirty)
1796 {
1797 UNIMPLEMENTED;
1798 return S_OK;
1799 }
1800
1801 HRESULT STDMETHODCALLTYPE CMenuBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
1802 {
1803 UNIMPLEMENTED;
1804 return S_OK;
1805 }
1806
1807 HRESULT STDMETHODCALLTYPE CMenuBand::GetClassID(CLSID *pClassID)
1808 {
1809 UNIMPLEMENTED;
1810 return S_OK;
1811 }
1812
1813 HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
1814 {
1815 UNIMPLEMENTED;
1816 return S_OK;
1817 }
1818
1819 HRESULT STDMETHODCALLTYPE CMenuBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1820 {
1821 if (!pguidCmdGroup)
1822 return E_FAIL;
1823
1824 if (IsEqualGUID(*pguidCmdGroup, CLSID_MenuBand))
1825 {
1826 if (nCmdID == 16) // set (big) icon size
1827 {
1828 this->m_useBigIcons = nCmdexecopt == 2;
1829 return S_OK;
1830 }
1831 else if (nCmdID == 19) // popup-related
1832 {
1833 return S_FALSE;
1834 }
1835 }
1836
1837 UNIMPLEMENTED;
1838 return S_OK;
1839 }
1840
1841 HRESULT STDMETHODCALLTYPE CMenuBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
1842 {
1843 if (IsEqualIID(guidService, SID_SMenuBandChild) ||
1844 IsEqualIID(guidService, SID_SMenuBandBottom) ||
1845 IsEqualIID(guidService, SID_SMenuBandBottomSelected))
1846 return this->QueryInterface(riid, ppvObject);
1847 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService));
1848 return E_NOINTERFACE;
1849 }
1850
1851 HRESULT STDMETHODCALLTYPE CMenuBand::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
1852 {
1853 UNIMPLEMENTED;
1854 return S_OK;
1855 }
1856
1857 HRESULT STDMETHODCALLTYPE CMenuBand::OnSelect(DWORD dwSelectType)
1858 {
1859 switch (dwSelectType)
1860 {
1861 case MPOS_CHILDTRACKING:
1862 // TODO: Cancel timers?
1863 return m_subMenuParent->OnSelect(dwSelectType);
1864 case MPOS_SELECTLEFT:
1865 if (m_subMenuChild)
1866 m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
1867 return m_subMenuParent->OnSelect(dwSelectType);
1868 case MPOS_SELECTRIGHT:
1869 if (m_hotBar && m_hotItem >= 0)
1870 {
1871 // TODO: popup the current child if it has subitems, otherwise spread up.
1872 }
1873 return m_subMenuParent->OnSelect(dwSelectType);
1874 case MPOS_EXECUTE:
1875 case MPOS_FULLCANCEL:
1876 if (m_subMenuChild)
1877 m_subMenuChild->OnSelect(dwSelectType);
1878 return m_subMenuParent->OnSelect(dwSelectType);
1879 case MPOS_CANCELLEVEL:
1880 if (m_subMenuChild)
1881 m_subMenuChild->OnSelect(dwSelectType);
1882 break;
1883 }
1884 return S_FALSE;
1885 }
1886
1887 HRESULT STDMETHODCALLTYPE CMenuBand::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
1888 {
1889 UNIMPLEMENTED;
1890 return S_OK;
1891 }
1892
1893 HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
1894 {
1895 UNIMPLEMENTED;
1896 return S_OK;
1897 }
1898
1899 HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
1900 {
1901 // HACK, so I can test for a submenu in the DeskBar
1902 //UNIMPLEMENTED;
1903 if (ppunkClient)
1904 {
1905 if (m_subMenuChild)
1906 *ppunkClient = m_subMenuChild;
1907 else
1908 *ppunkClient = NULL;
1909 }
1910 return S_OK;
1911 }
1912
1913 HRESULT STDMETHODCALLTYPE CMenuBand::IsMenuMessage(MSG *pmsg)
1914 {
1915 //UNIMPLEMENTED;
1916 //return S_OK;
1917 return S_FALSE;
1918 //return E_NOTIMPL;
1919 }
1920
1921 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet)
1922 {
1923 //UNIMPLEMENTED;
1924 return S_FALSE;
1925 }
1926
1927 HRESULT STDMETHODCALLTYPE CMenuBand::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1928 {
1929 if (m_SFToolbar == NULL)
1930 {
1931 m_SFToolbar = new CMenuSFToolbar(this);
1932 }
1933
1934 HRESULT hr = m_SFToolbar->SetShellFolder(psf, pidlFolder, hKey, dwFlags);
1935 if (FAILED(hr))
1936 return hr;
1937
1938 if (m_site)
1939 {
1940 HWND hwndParent;
1941
1942 hr = m_site->GetWindow(&hwndParent);
1943 if (FAILED(hr))
1944 return hr;
1945
1946 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1947 if (FAILED(hr))
1948 return hr;
1949
1950 hr = m_SFToolbar->FillToolbar();
1951 }
1952
1953 return hr;
1954 }
1955
1956 HRESULT STDMETHODCALLTYPE CMenuBand::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1957 {
1958 if (m_SFToolbar)
1959 return m_SFToolbar->GetShellFolder(pdwFlags, ppidl, riid, ppv);
1960 return E_FAIL;
1961 }
1962
1963 HRESULT STDMETHODCALLTYPE CMenuBand::InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
1964 {
1965 UNIMPLEMENTED;
1966 return S_OK;
1967 }
1968
1969 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(LPSMDATA psmd)
1970 {
1971 UNIMPLEMENTED;
1972 return S_OK;
1973 }
1974
1975 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenuToolbar(IUnknown *punk, DWORD dwFlags)
1976 {
1977 UNIMPLEMENTED;
1978 return S_OK;
1979 }
1980
1981 HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1982 {
1983 RECT rc;
1984 HDC hdc;
1985 HBRUSH bgBrush;
1986 HBRUSH hotBrush;
1987
1988 *theResult = 0;
1989 switch (uMsg)
1990 {
1991 case WM_COMMAND:
1992
1993 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1994 {
1995 return m_staticToolbar->OnCommand(wParam, lParam, theResult);
1996 }
1997
1998 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1999 {
2000 return m_SFToolbar->OnCommand(wParam, lParam, theResult);
2001 }
2002
2003 return S_OK;
2004
2005 case WM_NOTIFY:
2006 NMHDR * hdr = reinterpret_cast<LPNMHDR>(lParam);
2007 NMTBCUSTOMDRAW * cdraw;
2008 NMTBHOTITEM * hot;
2009 NMMOUSE * rclick;
2010 NMPGCALCSIZE* csize;
2011 TBBUTTONINFO btni;
2012 switch (hdr->code)
2013 {
2014 case PGN_CALCSIZE:
2015 csize = reinterpret_cast<LPNMPGCALCSIZE>(hdr);
2016
2017 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
2018 {
2019 SIZE tbs;
2020 m_staticToolbar->GetIdealSize(tbs);
2021 if (csize->dwFlag == PGF_CALCHEIGHT)
2022 {
2023 csize->iHeight = tbs.cy;
2024 }
2025 else if (csize->dwFlag == PGF_CALCWIDTH)
2026 {
2027 csize->iHeight = tbs.cx;
2028 }
2029 }
2030
2031 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
2032 {
2033 SIZE tbs;
2034 m_SFToolbar->GetIdealSize(tbs);
2035 if (csize->dwFlag == PGF_CALCHEIGHT)
2036 {
2037 csize->iHeight = tbs.cy;
2038 }
2039 else if (csize->dwFlag == PGF_CALCWIDTH)
2040 {
2041 csize->iHeight = tbs.cx;
2042 }
2043 }
2044 return S_OK;
2045
2046 case TBN_DROPDOWN:
2047
2048 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
2049 {
2050 WPARAM wp = reinterpret_cast<LPNMTOOLBAR>(hdr)->iItem;
2051 return m_staticToolbar->OnCommand(wp, 0, theResult);
2052 }
2053
2054 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
2055 {
2056 WPARAM wp = reinterpret_cast<LPNMTOOLBAR>(hdr)->iItem;
2057 return m_SFToolbar->OnCommand(wp, 0, theResult);
2058 }
2059
2060 return S_OK;
2061
2062 case TBN_HOTITEMCHANGE:
2063 hot = reinterpret_cast<LPNMTBHOTITEM>(hdr);
2064
2065 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
2066 {
2067 return m_staticToolbar->OnHotItemChange(hot);
2068 }
2069
2070 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
2071 {
2072 return m_SFToolbar->OnHotItemChange(hot);
2073 }
2074
2075 return S_OK;
2076
2077 case NM_RCLICK:
2078 rclick = reinterpret_cast<LPNMMOUSE>(hdr);
2079
2080 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
2081 {
2082 return m_staticToolbar->OnContextMenu(rclick);
2083 }
2084
2085 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
2086 {
2087 return m_SFToolbar->OnContextMenu(rclick);
2088 }
2089
2090 return S_OK;
2091
2092 case NM_CUSTOMDRAW:
2093 cdraw = reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr);
2094 switch (cdraw->nmcd.dwDrawStage)
2095 {
2096 case CDDS_PREPAINT:
2097 *theResult = CDRF_NOTIFYITEMDRAW;
2098 return S_OK;
2099
2100 case CDDS_ITEMPREPAINT:
2101
2102 cdraw->clrBtnFace = GetSysColor(COLOR_MENU);
2103 cdraw->clrBtnHighlight = GetSysColor(COLOR_MENUHILIGHT);
2104
2105 cdraw->clrText = GetSysColor(COLOR_MENUTEXT);
2106 cdraw->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
2107 cdraw->clrHighlightHotTrack = GetSysColor(COLOR_HIGHLIGHTTEXT);
2108
2109 bgBrush = GetSysColorBrush(COLOR_MENU);
2110 hotBrush = GetSysColorBrush(COLOR_MENUHILIGHT);
2111
2112 rc = cdraw->nmcd.rc;
2113 hdc = cdraw->nmcd.hdc;
2114
2115 if (cdraw->nmcd.uItemState != CDIS_DISABLED &&
2116 ((INT)cdraw->nmcd.dwItemSpec == m_hotItem ||
2117 (m_hotItem < 0 && (INT)cdraw->nmcd.dwItemSpec == m_popupItem)))
2118 {
2119 cdraw->nmcd.uItemState = CDIS_HOT;
2120 }
2121
2122 switch (cdraw->nmcd.uItemState)
2123 {
2124 case CDIS_HOT:
2125 case CDIS_FOCUS:
2126 FillRect(hdc, &rc, hotBrush);
2127 break;
2128 default:
2129 FillRect(hdc, &rc, bgBrush);
2130 break;
2131 }
2132
2133 *theResult = CDRF_NOTIFYPOSTPAINT | TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | 0x00800000; // FIXME: the last bit is Vista+, for debugging only
2134 return S_OK;
2135
2136 case CDDS_ITEMPOSTPAINT:
2137 btni.cbSize = sizeof(btni);
2138 btni.dwMask = TBIF_STYLE;
2139 SendMessage(hWnd, TB_GETBUTTONINFO, cdraw->nmcd.dwItemSpec, reinterpret_cast<LPARAM>(&btni));
2140 if (btni.fsStyle & BTNS_DROPDOWN)
2141 {
2142 SelectObject(cdraw->nmcd.hdc, m_marlett);
2143 WCHAR text [] = L"8";
2144 SetBkMode(cdraw->nmcd.hdc, TRANSPARENT);
2145 DrawTextEx(cdraw->nmcd.hdc, text, 1, &cdraw->nmcd.rc, DT_NOCLIP | DT_VCENTER | DT_RIGHT | DT_SINGLELINE, NULL);
2146 }
2147 *theResult = TRUE;
2148 return S_OK;
2149 }
2150 return S_OK;
2151 }
2152 return S_OK;
2153 }
2154
2155 return S_FALSE;
2156 }
2157
2158 HRESULT STDMETHODCALLTYPE CMenuBand::IsWindowOwner(HWND hWnd)
2159 {
2160 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
2161 return S_OK;
2162
2163 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
2164 return S_OK;
2165
2166 return S_FALSE;
2167 }
2168
2169 HRESULT STDMETHODCALLTYPE CMenuBand::GetSubMenu(THIS)
2170 {
2171 UNIMPLEMENTED;
2172 return S_OK;
2173 }
2174
2175 HRESULT STDMETHODCALLTYPE CMenuBand::SetToolbar(THIS)
2176 {
2177 UNIMPLEMENTED;
2178 return S_OK;
2179 }
2180
2181 HRESULT STDMETHODCALLTYPE CMenuBand::SetMinWidth(THIS)
2182 {
2183 UNIMPLEMENTED;
2184 return S_OK;
2185 }
2186
2187 HRESULT STDMETHODCALLTYPE CMenuBand::SetNoBorder(THIS)
2188 {
2189 UNIMPLEMENTED;
2190 return S_OK;
2191 }
2192
2193 HRESULT STDMETHODCALLTYPE CMenuBand::SetTheme(THIS)
2194 {
2195 UNIMPLEMENTED;
2196 return S_OK;
2197 }
2198
2199 HRESULT STDMETHODCALLTYPE CMenuBand::GetTop(THIS)
2200 {
2201 UNIMPLEMENTED;
2202 return S_OK;
2203 }
2204
2205 HRESULT STDMETHODCALLTYPE CMenuBand::GetBottom(THIS)
2206 {
2207 UNIMPLEMENTED;
2208 return S_OK;
2209 }
2210
2211 HRESULT STDMETHODCALLTYPE CMenuBand::GetTracked(THIS)
2212 {
2213 UNIMPLEMENTED;
2214 return S_OK;
2215 }
2216
2217 HRESULT STDMETHODCALLTYPE CMenuBand::GetParentSite(THIS)
2218 {
2219 UNIMPLEMENTED;
2220 return S_OK;
2221 }
2222
2223 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(THIS)
2224 {
2225 UNIMPLEMENTED;
2226 return S_OK;
2227 }
2228
2229 HRESULT STDMETHODCALLTYPE CMenuBand::DoDefaultAction(THIS)
2230 {
2231 UNIMPLEMENTED;
2232 return S_OK;
2233 }
2234
2235 HRESULT STDMETHODCALLTYPE CMenuBand::IsEmpty(THIS)
2236 {
2237 UNIMPLEMENTED;
2238 return S_OK;
2239 }
2240
2241 HRESULT CMenuBand::_CallCBWithItemId(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam)
2242 {
2243 return _CallCB(uMsg, wParam, lParam, id);
2244 }
2245
2246 HRESULT CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam)
2247 {
2248 return _CallCB(uMsg, wParam, lParam, 0, pidl);
2249 }
2250
2251 HRESULT CMenuBand::_CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id, LPITEMIDLIST pidl)
2252 {
2253 if (!m_psmc)
2254 return S_FALSE;
2255
2256 HWND hwnd;
2257 GetWindow(&hwnd);
2258
2259 SMDATA smData = { 0 };
2260 smData.punk = static_cast<IShellMenu2*>(this);
2261 smData.uId = id;
2262 smData.uIdParent = m_uId;
2263 smData.uIdAncestor = m_uIdAncestor;
2264 smData.hwnd = hwnd;
2265 smData.pidlItem = pidl;
2266 if (m_staticToolbar)
2267 {
2268 smData.hmenu = m_hmenu;
2269 }
2270 smData.pvUserData = NULL;
2271 if (m_SFToolbar)
2272 m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf));
2273 HRESULT hr = m_psmc->CallbackSM(&smData, uMsg, wParam, lParam);
2274 ILFree(smData.pidlFolder);
2275 if (smData.psf)
2276 smData.psf->Release();
2277 return hr;
2278 }
2279
2280 HRESULT CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y)
2281 {
2282 ::TrackPopupMenu(popup, 0, x, y, 0, m_menuOwner, NULL);
2283 return S_OK;
2284 }
2285
2286 HRESULT CMenuBand::_GetTopLevelWindow(HWND*topLevel)
2287 {
2288 *topLevel = m_topLevelWindow;
2289 return S_OK;
2290 }
2291
2292 HRESULT CMenuBand::_OnHotItemChanged(CMenuToolbarBase * tb, INT id)
2293 {
2294 if (m_hotBar && m_hotBar != tb)
2295 m_hotBar->ChangeHotItem(-1);
2296 m_hotBar = tb;
2297 m_hotItem = id;
2298 if (m_staticToolbar) m_staticToolbar->InvalidateDraw();
2299 if (m_SFToolbar) m_SFToolbar->InvalidateDraw();
2300 return S_OK;
2301 }
2302
2303 HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
2304 {
2305 HRESULT hr;
2306
2307 if (changeType == VK_DOWN)
2308 {
2309 if (m_SFToolbar && (m_hotBar == m_SFToolbar || m_hotBar == NULL))
2310 {
2311 hr = m_SFToolbar->ChangeHotItem(VK_DOWN);
2312 if (hr == S_FALSE)
2313 {
2314 if (m_staticToolbar)
2315 return m_staticToolbar->ChangeHotItem(VK_HOME);
2316 else
2317 return m_SFToolbar->ChangeHotItem(VK_HOME);
2318 }
2319 return hr;
2320 }
2321 else if (m_staticToolbar && m_hotBar == m_staticToolbar)
2322 {
2323 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2324 if (hr == S_FALSE)
2325 {
2326 if (m_SFToolbar)
2327 return m_SFToolbar->ChangeHotItem(VK_HOME);
2328 else
2329 return m_staticToolbar->ChangeHotItem(VK_HOME);
2330 }
2331 return hr;
2332 }
2333 }
2334 else if (changeType == VK_UP)
2335 {
2336 if (m_staticToolbar && (m_hotBar == m_staticToolbar || m_hotBar == NULL))
2337 {
2338 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2339 if (hr == S_FALSE)
2340 {
2341 if (m_SFToolbar)
2342 return m_SFToolbar->ChangeHotItem(VK_END);
2343 else
2344 return m_staticToolbar->ChangeHotItem(VK_END);
2345 }
2346 return hr;
2347 }
2348 else if (m_SFToolbar && m_hotBar == m_SFToolbar)
2349 {
2350 hr = m_SFToolbar->ChangeHotItem(VK_UP);
2351 if (hr == S_FALSE)
2352 {
2353 if (m_staticToolbar)
2354 return m_staticToolbar->ChangeHotItem(VK_END);
2355 else
2356 return m_SFToolbar->ChangeHotItem(VK_END);
2357 }
2358 return hr;
2359 }
2360 }
2361 else
2362 {
2363 m_subMenuParent->OnSelect(changeType);
2364 }
2365 return S_OK;
2366 }
2367
2368 HRESULT CMenuBand::_OnPopupSubMenu(INT popupItem, IMenuPopup * popup, POINTL * pAt, RECTL * pExclude)
2369 {
2370 if (m_subMenuChild)
2371 {
2372 HRESULT hr = m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
2373 if (FAILED(hr))
2374 return hr;
2375 }
2376 m_popupItem = popupItem;
2377 m_subMenuChild = popup;
2378 if (popup)
2379 {
2380 IUnknown_SetSite(popup, m_subMenuParent);
2381 popup->Popup(pAt, pExclude, MPPF_RIGHT);
2382 }
2383 if (m_staticToolbar) m_staticToolbar->InvalidateDraw();
2384 if (m_SFToolbar) m_SFToolbar->InvalidateDraw();
2385 return S_OK;
2386 }