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