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