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