[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 <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_childMenu;
144
145 UINT m_uId;
146 UINT m_uIdAncestor;
147 DWORD m_dwFlags;
148 PVOID m_UserData;
149 HMENU m_hmenu;
150 HWND m_menuOwner;
151
152 BOOL m_useBigIcons;
153 HWND m_topLevelWindow;
154
155 CMenuToolbarBase * m_hotBar;
156 INT m_hotItem;
157
158 public:
159 CMenuBand();
160 ~CMenuBand();
161
162 DECLARE_NOT_AGGREGATABLE(CMenuBand)
163 DECLARE_PROTECT_FINAL_CONSTRUCT()
164
165 BEGIN_COM_MAP(CMenuBand)
166 COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IMenuPopup)
167 COM_INTERFACE_ENTRY_IID(IID_IShellMenu, IShellMenu)
168 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
169 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IDeskBand)
170 COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)
171 COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
172 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
173 COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject)
174 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
175 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersistStream)
176 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
177 COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup)
178 COM_INTERFACE_ENTRY_IID(IID_IMenuBand, IMenuBand)
179 COM_INTERFACE_ENTRY_IID(IID_IShellMenu2, IShellMenu2)
180 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
181 COM_INTERFACE_ENTRY_IID(IID_IShellMenuAcc, IShellMenuAcc)
182 END_COM_MAP()
183
184 // *** IDeskBand methods ***
185 virtual HRESULT STDMETHODCALLTYPE GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi);
186
187 // *** IDockingWindow methods ***
188 virtual HRESULT STDMETHODCALLTYPE ShowDW(BOOL fShow);
189 virtual HRESULT STDMETHODCALLTYPE CloseDW(DWORD dwReserved);
190 virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved);
191
192 // *** IOleWindow methods ***
193 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
194 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
195
196 // *** IObjectWithSite methods ***
197 virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite);
198 virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, PVOID *ppvSite);
199
200 // *** IInputObject methods ***
201 virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg);
202 virtual HRESULT STDMETHODCALLTYPE HasFocusIO();
203 virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg);
204
205 // *** IPersistStream methods ***
206 virtual HRESULT STDMETHODCALLTYPE IsDirty();
207 virtual HRESULT STDMETHODCALLTYPE Load(IStream *pStm);
208 virtual HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty);
209 virtual HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize);
210
211 // *** IPersist methods ***
212 virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
213
214 // *** IOleCommandTarget methods ***
215 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText);
216 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
217
218 // *** IServiceProvider methods ***
219 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
220
221 // *** IMenuPopup methods ***
222 virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags);
223 virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType);
224 virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet);
225
226 // *** IDeskBar methods ***
227 virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient);
228 virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient);
229 virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(RECT *prc);
230
231 // *** IMenuBand methods ***
232 virtual HRESULT STDMETHODCALLTYPE IsMenuMessage(MSG *pmsg);
233 virtual HRESULT STDMETHODCALLTYPE TranslateMenuMessage(MSG *pmsg, LRESULT *plRet);
234
235 // *** IShellMenu methods ***
236 virtual HRESULT STDMETHODCALLTYPE Initialize(IShellMenuCallback *psmc, UINT uId, UINT uIdAncestor, DWORD dwFlags);
237 virtual HRESULT STDMETHODCALLTYPE GetMenuInfo(IShellMenuCallback **ppsmc, UINT *puId, UINT *puIdAncestor, DWORD *pdwFlags);
238 virtual HRESULT STDMETHODCALLTYPE SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags);
239 virtual HRESULT STDMETHODCALLTYPE GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv);
240 virtual HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags);
241 virtual HRESULT STDMETHODCALLTYPE GetMenu(HMENU *phmenu, HWND *phwnd, DWORD *pdwFlags);
242 virtual HRESULT STDMETHODCALLTYPE InvalidateItem(LPSMDATA psmd, DWORD dwFlags);
243 virtual HRESULT STDMETHODCALLTYPE GetState(LPSMDATA psmd);
244 virtual HRESULT STDMETHODCALLTYPE SetMenuToolbar(IUnknown *punk, DWORD dwFlags);
245
246 // *** IWinEventHandler methods ***
247 virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult);
248 virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd);
249
250 // *** IShellMenu2 methods ***
251 virtual HRESULT STDMETHODCALLTYPE GetSubMenu(THIS);
252 virtual HRESULT STDMETHODCALLTYPE SetToolbar(THIS);
253 virtual HRESULT STDMETHODCALLTYPE SetMinWidth(THIS);
254 virtual HRESULT STDMETHODCALLTYPE SetNoBorder(THIS);
255 virtual HRESULT STDMETHODCALLTYPE SetTheme(THIS);
256
257 // *** IShellMenuAcc methods ***
258 virtual HRESULT STDMETHODCALLTYPE GetTop(THIS);
259 virtual HRESULT STDMETHODCALLTYPE GetBottom(THIS);
260 virtual HRESULT STDMETHODCALLTYPE GetTracked(THIS);
261 virtual HRESULT STDMETHODCALLTYPE GetParentSite(THIS);
262 virtual HRESULT STDMETHODCALLTYPE GetState(THIS);
263 virtual HRESULT STDMETHODCALLTYPE DoDefaultAction(THIS);
264 virtual HRESULT STDMETHODCALLTYPE IsEmpty(THIS);
265
266 HRESULT _CallCBWithItemId(UINT Id, UINT uMsg, WPARAM wParam, LPARAM lParam);
267 HRESULT _CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam);
268 HRESULT _TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y);
269 HRESULT _GetTopLevelWindow(HWND*topLevel);
270 HRESULT _OnHotItemChanged(CMenuToolbarBase * tb, INT id);
271 HRESULT _MenuItemHotTrack(DWORD changeType);
272 HRESULT _OnPopupSubMenu(IMenuPopup * popup);
273
274 BOOL UseBigIcons()
275 {
276 return m_useBigIcons;
277 }
278
279 private:
280 HRESULT _CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id = 0, LPITEMIDLIST pidl = NULL);
281 };
282
283 class CMenuFocusManager :
284 public CComCoClass<CMenuFocusManager>,
285 public CComObjectRootEx<CComMultiThreadModelNoCS>
286 {
287 private:
288 static DWORD TlsIndex;
289
290 static CMenuFocusManager * GetManager()
291 {
292 return reinterpret_cast<CMenuFocusManager *>(TlsGetValue(TlsIndex));
293 }
294
295 public:
296 static CMenuFocusManager * AcquireManager()
297 {
298 CMenuFocusManager * obj = NULL;
299
300 if (!TlsIndex)
301 {
302 if ((TlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
303 return NULL;
304 }
305
306 obj = GetManager();
307
308 if (!obj)
309 {
310 obj = new CComObject<CMenuFocusManager>();
311 TlsSetValue(TlsIndex, obj);
312 }
313
314 obj->AddRef();
315
316 return obj;
317 }
318
319 static void ReleaseManager(CMenuFocusManager * obj)
320 {
321 if (!obj->Release())
322 {
323 TlsSetValue(TlsIndex, NULL);
324 }
325 }
326
327 private:
328 static LRESULT CALLBACK s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
329 {
330 return GetManager()->GetMsgHook(nCode, wParam, lParam);
331 }
332
333 private:
334 // TODO: make dynamic
335 #define MAX_RECURSE 100
336 CMenuBand* m_bandStack[MAX_RECURSE];
337 int m_bandCount;
338
339 HRESULT PushToArray(CMenuBand * item)
340 {
341 if (m_bandCount >= MAX_RECURSE)
342 return E_OUTOFMEMORY;
343
344 m_bandStack[m_bandCount++] = item;
345 return S_OK;
346 }
347
348 HRESULT PopFromArray(CMenuBand ** pItem)
349 {
350 if (pItem)
351 *pItem = NULL;
352
353 if (m_bandCount <= 0)
354 return E_FAIL;
355
356 m_bandCount--;
357
358 if (pItem)
359 *pItem = m_bandStack[m_bandCount];
360
361 return S_OK;
362 }
363
364 HRESULT PeekArray(CMenuBand ** pItem)
365 {
366 if (!pItem)
367 return E_FAIL;
368
369 *pItem = NULL;
370
371 if (m_bandCount <= 0)
372 return E_FAIL;
373
374 *pItem = m_bandStack[m_bandCount - 1];
375
376 return S_OK;
377 }
378
379 protected:
380 CMenuFocusManager() :
381 m_currentBand(NULL),
382 m_currentFocus(NULL),
383 m_bandCount(0)
384 {
385 m_threadId = GetCurrentThreadId();
386 }
387
388 ~CMenuFocusManager()
389 {
390 }
391
392 public:
393
394 DECLARE_NOT_AGGREGATABLE(CMenuFocusManager)
395 DECLARE_PROTECT_FINAL_CONSTRUCT()
396 BEGIN_COM_MAP(CMenuFocusManager)
397 END_COM_MAP()
398
399 private:
400 CMenuBand * m_currentBand;
401 HWND m_currentFocus;
402 HHOOK m_hHook;
403 DWORD m_threadId;
404
405 LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
406 {
407 if (nCode < 0)
408 return CallNextHookEx(m_hHook, nCode, wParam, lParam);
409
410 BOOL callNext = TRUE;
411 BOOL fRemoved = wParam;
412 MSG* msg = reinterpret_cast<MSG*>(lParam);
413
414 if (nCode == HC_ACTION)
415 {
416 // Do whatever is necessary here
417
418 switch (msg->message)
419 {
420 case WM_CLOSE:
421 break;
422 case WM_SYSKEYDOWN:
423 case WM_KEYDOWN:
424 switch (msg->wParam)
425 {
426 case VK_MENU:
427 case VK_LMENU:
428 case VK_RMENU:
429 m_currentBand->_MenuItemHotTrack(MPOS_FULLCANCEL);
430 break;
431 case VK_LEFT:
432 m_currentBand->_MenuItemHotTrack(MPOS_SELECTLEFT);
433 break;
434 case VK_RIGHT:
435 m_currentBand->_MenuItemHotTrack(MPOS_SELECTRIGHT);
436 break;
437 case VK_UP:
438 m_currentBand->_MenuItemHotTrack(VK_UP);
439 break;
440 case VK_DOWN:
441 m_currentBand->_MenuItemHotTrack(VK_DOWN);
442 break;
443 }
444 break;
445 case WM_CHAR:
446 //if (msg->wParam >= 'a' && msg->wParam <= 'z')
447 //{
448 // callNext = FALSE;
449 // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam);
450 //}
451 break;
452 case WM_ACTIVATE:
453 break;
454
455 }
456
457 if (!callNext)
458 return 0;
459 }
460
461 return CallNextHookEx(m_hHook, nCode, wParam, lParam);
462 }
463
464 HRESULT PlaceHooks(HWND window)
465 {
466 //SetCapture(window);
467 m_hHook = SetWindowsHookEx(WH_GETMESSAGE, s_GetMsgHook, NULL, m_threadId);
468 return S_OK;
469 }
470
471 HRESULT RemoveHooks(HWND window)
472 {
473 UnhookWindowsHookEx(m_hHook);
474 //ReleaseCapture();
475 return S_OK;
476 }
477
478 HRESULT UpdateFocus(CMenuBand * newBand)
479 {
480 HRESULT hr;
481
482 hr = RemoveHooks(m_currentFocus);
483
484 if (FAILED(hr) || !newBand)
485 {
486 m_currentFocus = NULL;
487 m_currentBand = NULL;
488 return S_OK;
489 }
490
491 HWND newFocus;
492 hr = newBand->_GetTopLevelWindow(&newFocus);
493 if (FAILED(hr))
494 return hr;
495
496 hr = PlaceHooks(m_currentFocus);
497 if (FAILED(hr))
498 return hr;
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 m_menuBand->_OnPopupSubMenu(NULL);
680 PopupItem(m_hotItem);
681 KillTimer(hWnd, TIMERID_HOTTRACK);
682 }
683 }
684
685 return m_SubclassOld(hWnd, uMsg, wParam, lParam);
686 }
687
688 HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot)
689 {
690 if (hot->dwFlags & HICF_LEAVING)
691 {
692 KillTimer(m_hwnd, TIMERID_HOTTRACK);
693 m_hotItem = -1;
694 m_menuBand->_OnHotItemChanged(NULL, -1);
695 m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
696 }
697 else if (m_hotItem != hot->idNew)
698 {
699 if (HasSubMenu(hot->idNew) == S_OK)
700 {
701 DWORD elapsed = 0;
702 SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0);
703 SetTimer(m_hwnd, TIMERID_HOTTRACK, elapsed, NULL);
704 }
705
706 m_hotItem = hot->idNew;
707 m_menuBand->_OnHotItemChanged(this, m_hotItem);
708 m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
709 }
710 return S_OK;
711 }
712
713 HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, IShellMenu* childShellMenu)
714 {
715 IBandSite* pBandSite;
716 IDeskBar* pDeskBar;
717
718 HRESULT hr = 0;
719 RECT rc = { 0 };
720
721 if (!SendMessage(m_hwnd, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
722 return E_FAIL;
723
724 POINT a = { rc.left, rc.top };
725 POINT b = { rc.right, rc.bottom };
726
727 ClientToScreen(m_hwnd, &a);
728 ClientToScreen(m_hwnd, &b);
729
730 POINTL pt = { b.x, b.y };
731 RECTL rcl = { a.x, a.y, b.x, b.y }; // maybe-TODO: fetch client area of deskbar?
732
733
734 #if USE_SYSTEM_MENUSITE
735 hr = CoCreateInstance(CLSID_MenuBandSite,
736 NULL,
737 CLSCTX_INPROC_SERVER,
738 IID_PPV_ARG(IBandSite, &pBandSite));
739 #else
740 hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
741 #endif
742 if (FAILED(hr))
743 return hr;
744 #if WRAP_MENUSITE
745 hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite));
746 if (FAILED(hr))
747 return hr;
748 #endif
749
750 #if USE_SYSTEM_MENUDESKBAR
751 hr = CoCreateInstance(CLSID_MenuDeskBar,
752 NULL,
753 CLSCTX_INPROC_SERVER,
754 IID_PPV_ARG(IDeskBar, &pDeskBar));
755 #else
756 hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar));
757 #endif
758 if (FAILED(hr))
759 return hr;
760 #if WRAP_MENUDESKBAR
761 hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar));
762 if (FAILED(hr))
763 return hr;
764 #endif
765
766 hr = pDeskBar->SetClient(pBandSite);
767 if (FAILED(hr))
768 return hr;
769
770 hr = pBandSite->AddBand(childShellMenu);
771 if (FAILED(hr))
772 return hr;
773
774 CComPtr<IMenuPopup> popup;
775 hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup));
776 if (FAILED(hr))
777 return hr;
778
779 popup->Popup(&pt, &rcl, MPPF_TOP | MPPF_RIGHT);
780
781 m_menuBand->_OnPopupSubMenu(popup);
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 = SendMessage(m_hwnd, TB_GETHOTITEM, 0, 0);
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 != index)
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 != index)
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 = m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0);
1041 if (FAILED(hr))
1042 return hr;
1043
1044 return CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1045 }
1046
1047 HRESULT CMenuStaticToolbar::PopupItem(UINT uItem)
1048 {
1049 TBBUTTONINFO info = { 0 };
1050 info.cbSize = sizeof(TBBUTTONINFO);
1051 info.dwMask = 0;
1052 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1053 if (index < 0)
1054 return E_FAIL;
1055
1056 TBBUTTON btn = { 0 };
1057 SendMessage(m_hwnd, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
1058
1059 SMINFO * nfo = reinterpret_cast<SMINFO*>(btn.dwData);
1060 if (!nfo)
1061 return E_FAIL;
1062
1063 if (nfo->dwFlags&SMIF_TRACKPOPUP)
1064 {
1065 return PopupSubMenu(index, m_hmenu);
1066 }
1067 else
1068 {
1069 CComPtr<IShellMenu> shellMenu;
1070 HRESULT hr = m_menuBand->_CallCBWithItemId(uItem, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IShellMenu), reinterpret_cast<LPARAM>(&shellMenu));
1071 if (FAILED(hr))
1072 return hr;
1073
1074 return PopupSubMenu(index, shellMenu);
1075 }
1076 }
1077
1078 HRESULT CMenuStaticToolbar::HasSubMenu(UINT uItem)
1079 {
1080 TBBUTTONINFO info = { 0 };
1081 info.cbSize = sizeof(TBBUTTONINFO);
1082 info.dwMask = 0;
1083 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1084 if (index < 0)
1085 return E_FAIL;
1086 return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE;
1087 }
1088
1089 CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) :
1090 CMenuToolbarBase(menuBand),
1091 m_shellFolder(NULL)
1092 {
1093 }
1094
1095 CMenuSFToolbar::~CMenuSFToolbar()
1096 {
1097 }
1098
1099 HRESULT CMenuSFToolbar::FillToolbar()
1100 {
1101 HRESULT hr;
1102 TBBUTTON tbb = { 0 };
1103 int i = 0;
1104 PWSTR MenuString;
1105
1106 tbb.fsState = TBSTATE_ENABLED;
1107 tbb.fsStyle = 0;
1108
1109 IEnumIDList * eidl;
1110 m_shellFolder->EnumObjects(m_hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &eidl);
1111
1112 LPITEMIDLIST item = static_cast<LPITEMIDLIST>(CoTaskMemAlloc(sizeof(ITEMIDLIST)));
1113 ULONG fetched;
1114 while ((hr = eidl->Next(1, &item, &fetched)) == S_OK)
1115 {
1116 INT index = 0;
1117 INT indexOpen = 0;
1118
1119 CComPtr<IShellItem> psi;
1120 SHCreateShellItem(NULL, m_shellFolder, item, &psi);
1121
1122 hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &MenuString);
1123 if (FAILED(hr))
1124 return hr;
1125
1126 index = SHMapPIDLToSystemImageListIndex(m_shellFolder, item, &indexOpen);
1127
1128 SFGAOF attrs;
1129 hr = psi->GetAttributes(SFGAO_FOLDER, &attrs);
1130
1131 if (attrs != 0)
1132 {
1133 tbb.fsStyle |= BTNS_DROPDOWN;
1134 }
1135
1136 tbb.idCommand = ++i;
1137 tbb.iString = (INT_PTR) MenuString;
1138 tbb.iBitmap = index;
1139 tbb.dwData = reinterpret_cast<DWORD_PTR>(ILClone(item));
1140 // FIXME: remove before deleting the toolbar or it will leak
1141
1142 SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1143 HeapFree(GetProcessHeap(), 0, MenuString);
1144
1145 }
1146 CoTaskMemFree(item);
1147
1148 return hr;
1149 }
1150
1151 HRESULT CMenuSFToolbar::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1152 {
1153 m_shellFolder = psf;
1154 m_idList = pidlFolder;
1155 m_hKey = hKey;
1156 m_dwMenuFlags = dwFlags;
1157 return S_OK;
1158 }
1159
1160 HRESULT CMenuSFToolbar::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1161 {
1162 HRESULT hr;
1163
1164 hr = m_shellFolder->QueryInterface(riid, ppv);
1165 if (FAILED(hr))
1166 return hr;
1167
1168 if (pdwFlags)
1169 *pdwFlags = m_dwMenuFlags;
1170
1171 if (ppidl)
1172 {
1173 LPITEMIDLIST pidl = NULL;
1174
1175 if (m_idList)
1176 {
1177 pidl = ILClone(m_idList);
1178 if (!pidl)
1179 {
1180 (*(IUnknown**) ppv)->Release();
1181 return E_FAIL;
1182 }
1183 }
1184
1185 *ppidl = pidl;
1186 }
1187
1188 return hr;
1189 }
1190
1191 LPITEMIDLIST CMenuSFToolbar::GetPidlFromId(UINT uItem, INT* pIndex)
1192 {
1193 TBBUTTONINFO info = { 0 };
1194 info.cbSize = sizeof(TBBUTTONINFO);
1195 info.dwMask = 0;
1196 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1197 if (index < 0)
1198 return NULL;
1199
1200 if (pIndex)
1201 *pIndex = index;
1202
1203 TBBUTTON btn = { 0 };
1204 if (!SendMessage(m_hwnd, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn)))
1205 return NULL;
1206
1207 return reinterpret_cast<LPITEMIDLIST>(btn.dwData);
1208 }
1209
1210 HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick)
1211 {
1212 HRESULT hr;
1213 CComPtr<IContextMenu> contextMenu;
1214 LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(rclick->dwItemData);
1215
1216 hr = m_shellFolder->GetUIObjectOf(m_hwnd, 1, &pidl, IID_IContextMenu, NULL, reinterpret_cast<VOID **>(&contextMenu));
1217 if (hr != S_OK)
1218 return hr;
1219
1220 return DoContextMenu(contextMenu);
1221 }
1222
1223 HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1224 {
1225 HRESULT hr = m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0);
1226
1227 return CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1228 }
1229
1230 HRESULT CMenuSFToolbar::PopupItem(UINT uItem)
1231 {
1232 HRESULT hr;
1233 UINT uId;
1234 UINT uIdAncestor;
1235 DWORD flags;
1236 int index;
1237 CComPtr<IShellMenuCallback> psmc;
1238 CComPtr<IShellMenu> shellMenu;
1239
1240 LPITEMIDLIST pidl = GetPidlFromId(uItem, &index);
1241
1242 if (!pidl)
1243 return E_FAIL;
1244
1245 #if USE_SYSTEM_MENUBAND
1246 hr = CoCreateInstance(CLSID_MenuBand,
1247 NULL,
1248 CLSCTX_INPROC_SERVER,
1249 IID_PPV_ARG(IShellMenu, &shellMenu));
1250 #else
1251 hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &shellMenu));
1252 #endif
1253 if (FAILED(hr))
1254 return hr;
1255 #if WRAP_MENUBAND
1256 hr = CMenuBand_Wrapper(shellMenu, IID_PPV_ARG(IShellMenu, &shellMenu));
1257 if (FAILED(hr))
1258 return hr;
1259 #endif
1260
1261 m_menuBand->GetMenuInfo(&psmc, &uId, &uIdAncestor, &flags);
1262
1263 // FIXME: not sure waht to use as uId/uIdAncestor here
1264 hr = shellMenu->Initialize(psmc, 0, uId, SMINIT_VERTICAL);
1265 if (FAILED(hr))
1266 return hr;
1267
1268 CComPtr<IShellFolder> childFolder;
1269 hr = m_shellFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &childFolder));
1270 if (FAILED(hr))
1271 return hr;
1272
1273 hr = shellMenu->SetShellFolder(childFolder, NULL, NULL, 0);
1274 if (FAILED(hr))
1275 return hr;
1276
1277 return PopupSubMenu(index, shellMenu);
1278 }
1279
1280 HRESULT CMenuSFToolbar::HasSubMenu(UINT uItem)
1281 {
1282 HRESULT hr;
1283 CComPtr<IShellItem> psi;
1284 SHCreateShellItem(NULL, m_shellFolder, GetPidlFromId(uItem), &psi);
1285
1286 SFGAOF attrs;
1287 hr = psi->GetAttributes(SFGAO_FOLDER, &attrs);
1288 if (FAILED(hr))
1289 return hr;
1290
1291 return (attrs != 0) ? S_OK : S_FALSE;
1292 }
1293
1294 CMenuBand::CMenuBand() :
1295 m_site(NULL),
1296 m_psmc(NULL),
1297 m_staticToolbar(NULL),
1298 m_SFToolbar(NULL),
1299 m_useBigIcons(FALSE),
1300 m_hotBar(NULL),
1301 m_hotItem(-1),
1302 m_childMenu(NULL)
1303 {
1304 m_focusManager = CMenuFocusManager::AcquireManager();
1305 }
1306
1307 CMenuBand::~CMenuBand()
1308 {
1309 CMenuFocusManager::ReleaseManager(m_focusManager);
1310
1311 if (m_staticToolbar)
1312 delete m_staticToolbar;
1313
1314 if (m_SFToolbar)
1315 delete m_SFToolbar;
1316 }
1317
1318 HRESULT STDMETHODCALLTYPE CMenuBand::Initialize(
1319 IShellMenuCallback *psmc,
1320 UINT uId,
1321 UINT uIdAncestor,
1322 DWORD dwFlags)
1323 {
1324 m_psmc = psmc;
1325 m_uId = uId;
1326 m_uIdAncestor = uIdAncestor;
1327 m_dwFlags = dwFlags;
1328
1329 if (m_psmc)
1330 {
1331 _CallCB(SMC_CREATE, 0, reinterpret_cast<LPARAM>(&m_UserData));
1332 }
1333
1334 return S_OK;
1335 }
1336
1337 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenuInfo(
1338 IShellMenuCallback **ppsmc,
1339 UINT *puId,
1340 UINT *puIdAncestor,
1341 DWORD *pdwFlags)
1342 {
1343 if (!pdwFlags) // maybe?
1344 return E_INVALIDARG;
1345
1346 if (ppsmc)
1347 *ppsmc = m_psmc;
1348
1349 if (puId)
1350 *puId = m_uId;
1351
1352 if (puIdAncestor)
1353 *puIdAncestor = m_uIdAncestor;
1354
1355 *pdwFlags = m_dwFlags;
1356
1357 return S_OK;
1358 }
1359
1360 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenu(
1361 HMENU hmenu,
1362 HWND hwnd,
1363 DWORD dwFlags)
1364 {
1365 if (m_staticToolbar == NULL)
1366 {
1367 m_staticToolbar = new CMenuStaticToolbar(this);
1368 }
1369 m_hmenu = hmenu;
1370 m_menuOwner;
1371
1372 HRESULT hr = m_staticToolbar->SetMenu(hmenu, hwnd, dwFlags);
1373 if (FAILED(hr))
1374 return hr;
1375
1376 if (m_site)
1377 {
1378 HWND hwndParent;
1379
1380 hr = m_site->GetWindow(&hwndParent);
1381 if (FAILED(hr))
1382 return hr;
1383
1384 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
1385 if (FAILED(hr))
1386 return hr;
1387
1388 hr = m_staticToolbar->FillToolbar();
1389 }
1390
1391 return hr;
1392 }
1393
1394 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenu(
1395 HMENU *phmenu,
1396 HWND *phwnd,
1397 DWORD *pdwFlags)
1398 {
1399 if (m_staticToolbar == NULL)
1400 return E_FAIL;
1401
1402 return m_staticToolbar->GetMenu(phmenu, phwnd, pdwFlags);
1403 }
1404
1405 HRESULT STDMETHODCALLTYPE CMenuBand::SetSite(IUnknown *pUnkSite)
1406 {
1407 HWND hwndParent;
1408 HRESULT hr;
1409
1410 m_site = NULL;
1411
1412 if (pUnkSite == NULL)
1413 return S_OK;
1414
1415 hwndParent = NULL;
1416 hr = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &m_site));
1417 if (FAILED(hr))
1418 return hr;
1419
1420 hr = m_site->GetWindow(&hwndParent);
1421 if (FAILED(hr))
1422 return hr;
1423
1424 if (!::IsWindow(hwndParent))
1425 return E_FAIL;
1426
1427 if (m_staticToolbar != NULL)
1428 {
1429 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
1430 if (FAILED(hr))
1431 return hr;
1432
1433 hr = m_staticToolbar->FillToolbar();
1434 if (FAILED(hr))
1435 return hr;
1436 }
1437
1438 if (m_SFToolbar != NULL)
1439 {
1440 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1441 if (FAILED(hr))
1442 return hr;
1443
1444 hr = m_SFToolbar->FillToolbar();
1445 if (FAILED(hr))
1446 return hr;
1447 }
1448
1449 CComPtr<IOleWindow> pTopLevelWindow;
1450 hr = IUnknown_QueryService(m_site, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1451 if (FAILED(hr))
1452 return hr;
1453
1454 return pTopLevelWindow->GetWindow(&m_topLevelWindow);
1455 }
1456
1457 HRESULT STDMETHODCALLTYPE CMenuBand::GetSite(REFIID riid, PVOID *ppvSite)
1458 {
1459 if (m_site == NULL)
1460 return E_FAIL;
1461
1462 return m_site->QueryInterface(riid, ppvSite);
1463 }
1464
1465 HRESULT STDMETHODCALLTYPE CMenuBand::GetWindow(
1466 HWND *phwnd)
1467 {
1468 if (m_SFToolbar != NULL)
1469 return m_SFToolbar->GetWindow(phwnd);
1470
1471 if (m_staticToolbar != NULL)
1472 return m_staticToolbar->GetWindow(phwnd);
1473
1474 return E_FAIL;
1475 }
1476
1477 HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc)
1478 {
1479 SIZE sizeStaticY = { 0 };
1480 SIZE sizeShlFldY = { 0 };
1481 HWND hwndStatic = NULL;
1482 HWND hwndShlFld = NULL;
1483 HRESULT hr = S_OK;
1484
1485 if (m_staticToolbar != NULL)
1486 hr = m_staticToolbar->GetWindow(&hwndStatic);
1487 if (FAILED(hr))
1488 return hr;
1489
1490 if (m_SFToolbar != NULL)
1491 hr = m_SFToolbar->GetWindow(&hwndShlFld);
1492 if (FAILED(hr))
1493 return hr;
1494
1495 if (hwndStatic == NULL && hwndShlFld == NULL)
1496 return E_FAIL;
1497
1498 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStaticY));
1499 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFldY));
1500
1501 int sy = max(prc->bottom - prc->top, sizeStaticY.cy + sizeShlFldY.cy);
1502
1503 if (hwndShlFld)
1504 {
1505 SetWindowPos(hwndShlFld, NULL,
1506 prc->left,
1507 prc->top,
1508 prc->right - prc->left,
1509 sizeShlFldY.cy,
1510 0);
1511 DWORD btnSize = SendMessage(hwndShlFld, TB_GETBUTTONSIZE, 0, 0);
1512 SendMessage(hwndShlFld, TB_SETBUTTONSIZE, 0, MAKELPARAM(prc->right - prc->left, HIWORD(btnSize)));
1513 }
1514 if (hwndStatic)
1515 {
1516 SetWindowPos(hwndStatic, hwndShlFld,
1517 prc->left,
1518 prc->top + sizeShlFldY.cy,
1519 prc->right - prc->left,
1520 sy - sizeShlFldY.cy,
1521 0);
1522 DWORD btnSize = SendMessage(hwndStatic, TB_GETBUTTONSIZE, 0, 0);
1523 SendMessage(hwndStatic, TB_SETBUTTONSIZE, 0, MAKELPARAM(prc->right - prc->left, HIWORD(btnSize)));
1524 }
1525
1526 return S_OK;
1527 }
1528
1529 HRESULT STDMETHODCALLTYPE CMenuBand::GetBandInfo(
1530 DWORD dwBandID,
1531 DWORD dwViewMode,
1532 DESKBANDINFO *pdbi)
1533 {
1534 HWND hwndStatic = NULL;
1535 HWND hwndShlFld = NULL;
1536 HRESULT hr = S_OK;
1537
1538 if (m_staticToolbar != NULL)
1539 hr = m_staticToolbar->GetWindow(&hwndStatic);
1540 if (FAILED(hr))
1541 return hr;
1542
1543 if (m_SFToolbar != NULL)
1544 hr = m_SFToolbar->GetWindow(&hwndShlFld);
1545 if (FAILED(hr))
1546 return hr;
1547
1548 if (hwndStatic == NULL && hwndShlFld == NULL)
1549 return E_FAIL;
1550
1551 // HACK (?)
1552 if (pdbi->dwMask == 0)
1553 {
1554 pdbi->dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
1555 }
1556
1557 if (pdbi->dwMask & DBIM_MINSIZE)
1558 {
1559 SIZE sizeStatic = { 0 };
1560 SIZE sizeShlFld = { 0 };
1561
1562 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStatic));
1563 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFld));
1564
1565 pdbi->ptMinSize.x = 0;
1566 pdbi->ptMinSize.y = sizeStatic.cy + sizeShlFld.cy;
1567 }
1568 if (pdbi->dwMask & DBIM_MAXSIZE)
1569 {
1570 SIZE sizeStatic = { 0 };
1571 SIZE sizeShlFld = { 0 };
1572
1573 if (hwndStatic) SendMessageW(hwndStatic, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeStatic));
1574 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeShlFld));
1575
1576 pdbi->ptMaxSize.x = max(sizeStatic.cx, sizeShlFld.cx); // ignored
1577 pdbi->ptMaxSize.y = sizeStatic.cy + sizeShlFld.cy;
1578 }
1579 if (pdbi->dwMask & DBIM_INTEGRAL)
1580 {
1581 pdbi->ptIntegral.x = 0;
1582 pdbi->ptIntegral.y = 0;
1583 }
1584 if (pdbi->dwMask & DBIM_ACTUAL)
1585 {
1586 SIZE sizeStatic = { 0 };
1587 SIZE sizeShlFld = { 0 };
1588
1589 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&sizeStatic));
1590 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&sizeShlFld));
1591 pdbi->ptActual.x = max(sizeStatic.cx, sizeShlFld.cx);
1592
1593 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStatic));
1594 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFld));
1595 pdbi->ptActual.y = sizeStatic.cy + sizeShlFld.cy;
1596 }
1597 if (pdbi->dwMask & DBIM_TITLE)
1598 wcscpy(pdbi->wszTitle, L"");
1599 if (pdbi->dwMask & DBIM_MODEFLAGS)
1600 pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
1601 if (pdbi->dwMask & DBIM_BKCOLOR)
1602 pdbi->crBkgnd = 0;
1603 return S_OK;
1604 }
1605
1606 /* IDockingWindow */
1607 HRESULT STDMETHODCALLTYPE CMenuBand::ShowDW(BOOL fShow)
1608 {
1609 HRESULT hr = S_OK;
1610
1611 if (m_staticToolbar != NULL)
1612 hr = m_staticToolbar->ShowWindow(fShow);
1613 if (FAILED(hr))
1614 return hr;
1615 if (m_SFToolbar != NULL)
1616 hr = m_SFToolbar->ShowWindow(fShow);
1617 if (FAILED(hr))
1618 return hr;
1619
1620 if (fShow)
1621 {
1622 hr = _CallCB(SMC_INITMENU, 0, 0);
1623 if (FAILED(hr))
1624 return hr;
1625 }
1626
1627 if (fShow)
1628 hr = m_focusManager->PushMenu(this);
1629 else
1630 hr = m_focusManager->PopMenu(this);
1631
1632 return hr;
1633 }
1634
1635 HRESULT STDMETHODCALLTYPE CMenuBand::CloseDW(DWORD dwReserved)
1636 {
1637 ShowDW(FALSE);
1638
1639 if (m_staticToolbar != NULL)
1640 return m_staticToolbar->Close();
1641
1642 if (m_SFToolbar != NULL)
1643 return m_SFToolbar->Close();
1644
1645 return S_OK;
1646 }
1647 HRESULT STDMETHODCALLTYPE CMenuBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
1648 {
1649 UNIMPLEMENTED;
1650 return S_OK;
1651 }
1652
1653 HRESULT STDMETHODCALLTYPE CMenuBand::ContextSensitiveHelp(BOOL fEnterMode)
1654 {
1655 UNIMPLEMENTED;
1656 return S_OK;
1657 }
1658
1659 HRESULT STDMETHODCALLTYPE CMenuBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
1660 {
1661 HRESULT hr;
1662 CComPtr<IMenuPopup> pmp;
1663
1664 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp));
1665 if (FAILED(hr))
1666 return hr;
1667
1668 hr = pmp->SetSubMenu(this, fActivate);
1669 if (FAILED(hr))
1670 return hr;
1671
1672 if (fActivate)
1673 {
1674 CComPtr<IOleWindow> pTopLevelWindow;
1675 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1676 if (FAILED(hr))
1677 return hr;
1678
1679 hr = pTopLevelWindow->GetWindow(&m_topLevelWindow);
1680 if (FAILED(hr))
1681 return hr;
1682 }
1683 else
1684 {
1685 m_topLevelWindow = NULL;
1686 }
1687
1688 return S_FALSE;
1689 }
1690
1691 HRESULT STDMETHODCALLTYPE CMenuBand::HasFocusIO()
1692 {
1693 UNIMPLEMENTED;
1694 return S_OK;
1695 }
1696
1697 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg)
1698 {
1699 UNIMPLEMENTED;
1700 return S_OK;
1701 }
1702
1703 HRESULT STDMETHODCALLTYPE CMenuBand::IsDirty()
1704 {
1705 UNIMPLEMENTED;
1706 return S_OK;
1707 }
1708
1709 HRESULT STDMETHODCALLTYPE CMenuBand::Load(IStream *pStm)
1710 {
1711 UNIMPLEMENTED;
1712 return S_OK;
1713 }
1714
1715 HRESULT STDMETHODCALLTYPE CMenuBand::Save(IStream *pStm, BOOL fClearDirty)
1716 {
1717 UNIMPLEMENTED;
1718 return S_OK;
1719 }
1720
1721 HRESULT STDMETHODCALLTYPE CMenuBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
1722 {
1723 UNIMPLEMENTED;
1724 return S_OK;
1725 }
1726
1727 HRESULT STDMETHODCALLTYPE CMenuBand::GetClassID(CLSID *pClassID)
1728 {
1729 UNIMPLEMENTED;
1730 return S_OK;
1731 }
1732
1733 HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
1734 {
1735 UNIMPLEMENTED;
1736 return S_OK;
1737 }
1738
1739 HRESULT STDMETHODCALLTYPE CMenuBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1740 {
1741 if (!pguidCmdGroup)
1742 return E_FAIL;
1743
1744 if (IsEqualGUID(*pguidCmdGroup, CLSID_MenuBand))
1745 {
1746 if (nCmdID == 16) // set (big) icon size
1747 {
1748 this->m_useBigIcons = TRUE;
1749 return S_OK;
1750 }
1751 else if (nCmdID == 19) // popup-related
1752 {
1753 return S_FALSE;
1754 }
1755 }
1756
1757 UNIMPLEMENTED;
1758 return S_OK;
1759 }
1760
1761 HRESULT STDMETHODCALLTYPE CMenuBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
1762 {
1763 if (IsEqualIID(guidService, SID_SMenuBandChild) ||
1764 IsEqualIID(guidService, SID_SMenuBandBottom) ||
1765 IsEqualIID(guidService, SID_SMenuBandBottomSelected))
1766 return this->QueryInterface(riid, ppvObject);
1767 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService));
1768 return E_NOINTERFACE;
1769 }
1770
1771 HRESULT STDMETHODCALLTYPE CMenuBand::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
1772 {
1773 UNIMPLEMENTED;
1774 return S_OK;
1775 }
1776
1777 HRESULT STDMETHODCALLTYPE CMenuBand::OnSelect(DWORD dwSelectType)
1778 {
1779 if (dwSelectType != MPOS_CANCELLEVEL)
1780 {
1781 if (dwSelectType == MPOS_SELECTLEFT)
1782 {
1783 dwSelectType = MPOS_CANCELLEVEL;
1784 }
1785 CComPtr<IMenuPopup> pmp;
1786 HRESULT hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp));
1787 if (FAILED(hr))
1788 return hr;
1789 return pmp->OnSelect(dwSelectType);
1790 }
1791 return S_FALSE;
1792 }
1793
1794 HRESULT STDMETHODCALLTYPE CMenuBand::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
1795 {
1796 UNIMPLEMENTED;
1797 return S_OK;
1798 }
1799
1800 HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
1801 {
1802 UNIMPLEMENTED;
1803 return S_OK;
1804 }
1805
1806 HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
1807 {
1808 UNIMPLEMENTED;
1809 return S_OK;
1810 }
1811
1812 HRESULT STDMETHODCALLTYPE CMenuBand::IsMenuMessage(MSG *pmsg)
1813 {
1814 //UNIMPLEMENTED;
1815 //return S_OK;
1816 return S_FALSE;
1817 //return E_NOTIMPL;
1818 }
1819
1820 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet)
1821 {
1822 //UNIMPLEMENTED;
1823 return S_FALSE;
1824 }
1825
1826 HRESULT STDMETHODCALLTYPE CMenuBand::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1827 {
1828 if (m_SFToolbar == NULL)
1829 {
1830 m_SFToolbar = new CMenuSFToolbar(this);
1831 }
1832
1833 HRESULT hr = m_SFToolbar->SetShellFolder(psf, pidlFolder, hKey, dwFlags);
1834 if (FAILED(hr))
1835 return hr;
1836
1837 if (m_site)
1838 {
1839 HWND hwndParent;
1840
1841 hr = m_site->GetWindow(&hwndParent);
1842 if (FAILED(hr))
1843 return hr;
1844
1845 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1846 if (FAILED(hr))
1847 return hr;
1848
1849 hr = m_SFToolbar->FillToolbar();
1850 }
1851
1852 return hr;
1853 }
1854
1855 HRESULT STDMETHODCALLTYPE CMenuBand::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1856 {
1857 if (m_SFToolbar)
1858 return m_SFToolbar->GetShellFolder(pdwFlags, ppidl, riid, ppv);
1859 return E_FAIL;
1860 }
1861
1862 HRESULT STDMETHODCALLTYPE CMenuBand::InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
1863 {
1864 UNIMPLEMENTED;
1865 return S_OK;
1866 }
1867
1868 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(LPSMDATA psmd)
1869 {
1870 UNIMPLEMENTED;
1871 return S_OK;
1872 }
1873
1874 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenuToolbar(IUnknown *punk, DWORD dwFlags)
1875 {
1876 UNIMPLEMENTED;
1877 return S_OK;
1878 }
1879
1880 HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1881 {
1882 *theResult = 0;
1883 switch (uMsg)
1884 {
1885 case WM_COMMAND:
1886
1887 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1888 {
1889 return m_staticToolbar->OnCommand(wParam, lParam, theResult);
1890 }
1891
1892 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1893 {
1894 return m_SFToolbar->OnCommand(wParam, lParam, theResult);
1895 }
1896
1897 return S_OK;
1898
1899 case WM_NOTIFY:
1900 NMHDR * hdr = reinterpret_cast<LPNMHDR>(lParam);
1901 NMTBCUSTOMDRAW * cdraw;
1902 NMTBHOTITEM * hot;
1903 NMMOUSE * rclick;
1904 switch (hdr->code)
1905 {
1906 case TBN_HOTITEMCHANGE:
1907 hot = reinterpret_cast<LPNMTBHOTITEM>(hdr);
1908
1909 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1910 {
1911 return m_staticToolbar->OnHotItemChange(hot);
1912 }
1913
1914 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1915 {
1916 return m_SFToolbar->OnHotItemChange(hot);
1917 }
1918
1919 return S_OK;
1920
1921 case NM_RCLICK:
1922 rclick = reinterpret_cast<LPNMMOUSE>(hdr);
1923
1924 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1925 {
1926 return m_staticToolbar->OnContextMenu(rclick);
1927 }
1928
1929 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1930 {
1931 return m_SFToolbar->OnContextMenu(rclick);
1932 }
1933
1934 return S_OK;
1935 case NM_CUSTOMDRAW:
1936 cdraw = reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr);
1937 switch (cdraw->nmcd.dwDrawStage)
1938 {
1939 case CDDS_PREPAINT:
1940 *theResult = CDRF_NOTIFYITEMDRAW;
1941 return S_OK;
1942
1943 case CDDS_ITEMPREPAINT:
1944
1945 cdraw->clrBtnFace = GetSysColor(COLOR_MENU);
1946 cdraw->clrBtnHighlight = GetSysColor(COLOR_MENUHILIGHT);
1947
1948 cdraw->clrText = GetSysColor(COLOR_MENUTEXT);
1949 cdraw->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
1950 cdraw->clrHighlightHotTrack = GetSysColor(COLOR_HIGHLIGHTTEXT);
1951
1952 RECT rc = cdraw->nmcd.rc;
1953 HDC hdc = cdraw->nmcd.hdc;
1954
1955 HBRUSH bgBrush = GetSysColorBrush(COLOR_MENU);
1956 HBRUSH hotBrush = GetSysColorBrush(COLOR_MENUHILIGHT);
1957
1958 switch (cdraw->nmcd.uItemState)
1959 {
1960 case CDIS_HOT:
1961 case CDIS_FOCUS:
1962 FillRect(hdc, &rc, hotBrush);
1963 break;
1964 default:
1965 FillRect(hdc, &rc, bgBrush);
1966 break;
1967 }
1968
1969 *theResult = TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOETCHEDEFFECT | TBCDRF_HILITEHOTTRACK | TBCDRF_NOOFFSET;
1970 return S_OK;
1971 }
1972 return S_OK;
1973 }
1974 return S_OK;
1975 }
1976
1977 return S_FALSE;
1978 }
1979
1980 HRESULT STDMETHODCALLTYPE CMenuBand::IsWindowOwner(HWND hWnd)
1981 {
1982 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1983 return S_OK;
1984
1985 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1986 return S_OK;
1987
1988 return S_FALSE;
1989 }
1990
1991 HRESULT STDMETHODCALLTYPE CMenuBand::GetSubMenu(THIS)
1992 {
1993 UNIMPLEMENTED;
1994 return S_OK;
1995 }
1996
1997 HRESULT STDMETHODCALLTYPE CMenuBand::SetToolbar(THIS)
1998 {
1999 UNIMPLEMENTED;
2000 return S_OK;
2001 }
2002
2003 HRESULT STDMETHODCALLTYPE CMenuBand::SetMinWidth(THIS)
2004 {
2005 UNIMPLEMENTED;
2006 return S_OK;
2007 }
2008
2009 HRESULT STDMETHODCALLTYPE CMenuBand::SetNoBorder(THIS)
2010 {
2011 UNIMPLEMENTED;
2012 return S_OK;
2013 }
2014
2015 HRESULT STDMETHODCALLTYPE CMenuBand::SetTheme(THIS)
2016 {
2017 UNIMPLEMENTED;
2018 return S_OK;
2019 }
2020
2021 HRESULT STDMETHODCALLTYPE CMenuBand::GetTop(THIS)
2022 {
2023 UNIMPLEMENTED;
2024 return S_OK;
2025 }
2026
2027 HRESULT STDMETHODCALLTYPE CMenuBand::GetBottom(THIS)
2028 {
2029 UNIMPLEMENTED;
2030 return S_OK;
2031 }
2032
2033 HRESULT STDMETHODCALLTYPE CMenuBand::GetTracked(THIS)
2034 {
2035 UNIMPLEMENTED;
2036 return S_OK;
2037 }
2038
2039 HRESULT STDMETHODCALLTYPE CMenuBand::GetParentSite(THIS)
2040 {
2041 UNIMPLEMENTED;
2042 return S_OK;
2043 }
2044
2045 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(THIS)
2046 {
2047 UNIMPLEMENTED;
2048 return S_OK;
2049 }
2050
2051 HRESULT STDMETHODCALLTYPE CMenuBand::DoDefaultAction(THIS)
2052 {
2053 UNIMPLEMENTED;
2054 return S_OK;
2055 }
2056
2057 HRESULT STDMETHODCALLTYPE CMenuBand::IsEmpty(THIS)
2058 {
2059 UNIMPLEMENTED;
2060 return S_OK;
2061 }
2062
2063 HRESULT CMenuBand::_CallCBWithItemId(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam)
2064 {
2065 return _CallCB(uMsg, wParam, lParam, id);
2066 }
2067
2068 HRESULT CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam)
2069 {
2070 return _CallCB(uMsg, wParam, lParam, 0, pidl);
2071 }
2072
2073 HRESULT CMenuBand::_CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id, LPITEMIDLIST pidl)
2074 {
2075 if (!m_psmc)
2076 return S_FALSE;
2077
2078 HWND hwnd;
2079 GetWindow(&hwnd);
2080
2081 SMDATA smData = { 0 };
2082 smData.punk = static_cast<IShellMenu2*>(this);
2083 smData.uId = id;
2084 smData.uIdParent = m_uId;
2085 smData.uIdAncestor = m_uIdAncestor;
2086 smData.hwnd = hwnd;
2087 smData.pidlItem = pidl;
2088 if (m_staticToolbar)
2089 {
2090 smData.hmenu = m_hmenu;
2091 }
2092 smData.pvUserData = NULL;
2093 if (m_SFToolbar)
2094 m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf));
2095 HRESULT hr = m_psmc->CallbackSM(&smData, uMsg, wParam, lParam);
2096 ILFree(smData.pidlFolder);
2097 if (smData.psf)
2098 smData.psf->Release();
2099 return hr;
2100 }
2101
2102 HRESULT CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y)
2103 {
2104 ::TrackPopupMenu(popup, 0, x, y, 0, m_menuOwner, NULL);
2105 return S_OK;
2106 }
2107
2108 HRESULT CMenuBand::_GetTopLevelWindow(HWND*topLevel)
2109 {
2110 *topLevel = m_topLevelWindow;
2111 return S_OK;
2112 }
2113
2114 HRESULT CMenuBand::_OnHotItemChanged(CMenuToolbarBase * tb, INT id)
2115 {
2116 if (m_hotBar && m_hotBar != tb)
2117 m_hotBar->ChangeHotItem(-1);
2118 m_hotBar = tb;
2119 m_hotItem = id;
2120 return S_OK;
2121 }
2122
2123 HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
2124 {
2125 HRESULT hr;
2126
2127 if (changeType == VK_DOWN)
2128 {
2129 if (m_SFToolbar && (m_hotBar == m_SFToolbar || m_hotBar == NULL))
2130 {
2131 hr = m_SFToolbar->ChangeHotItem(VK_DOWN);
2132 if (hr == S_FALSE)
2133 {
2134 if (m_staticToolbar)
2135 return m_staticToolbar->ChangeHotItem(VK_HOME);
2136 else
2137 return m_SFToolbar->ChangeHotItem(VK_HOME);
2138 }
2139 return hr;
2140 }
2141 else if (m_staticToolbar && m_hotBar == m_staticToolbar)
2142 {
2143 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2144 if (hr == S_FALSE)
2145 {
2146 if (m_SFToolbar)
2147 return m_SFToolbar->ChangeHotItem(VK_HOME);
2148 else
2149 return m_staticToolbar->ChangeHotItem(VK_HOME);
2150 }
2151 return hr;
2152 }
2153 }
2154 else if (changeType == VK_UP)
2155 {
2156 if (m_staticToolbar && (m_hotBar == m_staticToolbar || m_hotBar == NULL))
2157 {
2158 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2159 if (hr == S_FALSE)
2160 {
2161 if (m_SFToolbar)
2162 return m_SFToolbar->ChangeHotItem(VK_END);
2163 else
2164 return m_staticToolbar->ChangeHotItem(VK_END);
2165 }
2166 return hr;
2167 }
2168 else if (m_SFToolbar && m_hotBar == m_SFToolbar)
2169 {
2170 hr = m_SFToolbar->ChangeHotItem(VK_UP);
2171 if (hr == S_FALSE)
2172 {
2173 if (m_staticToolbar)
2174 return m_staticToolbar->ChangeHotItem(VK_END);
2175 else
2176 return m_SFToolbar->ChangeHotItem(VK_END);
2177 }
2178 return hr;
2179 }
2180 }
2181 else
2182 {
2183 CComPtr<IMenuPopup> pmp;
2184 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp));
2185 if (FAILED(hr))
2186 return hr;
2187 pmp->OnSelect(changeType);
2188 }
2189 return S_OK;
2190 }
2191
2192
2193 HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup)
2194 {
2195 if (m_childMenu)
2196 {
2197 HRESULT hr = m_childMenu->OnSelect(MPOS_CANCELLEVEL);
2198 if (FAILED(hr))
2199 return hr;
2200 }
2201 m_childMenu = popup;
2202 if (m_childMenu)
2203 {
2204 return m_childMenu->SetSubMenu(this, TRUE);
2205 }
2206 return S_OK;
2207 }