[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, a.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 #define MIN_WIDTH 220
1584
1585 if (pdbi->dwMask & DBIM_MINSIZE)
1586 {
1587 SIZE sizeStatic = { 0 };
1588 SIZE sizeShlFld = { 0 };
1589
1590 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStatic));
1591 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFld));
1592
1593 pdbi->ptMinSize.x = MIN_WIDTH;
1594 pdbi->ptMinSize.y = sizeStatic.cy + sizeShlFld.cy;
1595 }
1596 if (pdbi->dwMask & DBIM_MAXSIZE)
1597 {
1598 SIZE sizeStatic = { 0 };
1599 SIZE sizeShlFld = { 0 };
1600
1601 if (hwndStatic) SendMessageW(hwndStatic, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeStatic));
1602 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeShlFld));
1603
1604 pdbi->ptMaxSize.x = max(MIN_WIDTH, max(sizeStatic.cx, sizeShlFld.cx)); // ignored
1605 pdbi->ptMaxSize.y = sizeStatic.cy + sizeShlFld.cy;
1606 }
1607 if (pdbi->dwMask & DBIM_INTEGRAL)
1608 {
1609 pdbi->ptIntegral.x = 0;
1610 pdbi->ptIntegral.y = 0;
1611 }
1612 if (pdbi->dwMask & DBIM_ACTUAL)
1613 {
1614 SIZE sizeStatic = { 0 };
1615 SIZE sizeShlFld = { 0 };
1616
1617 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&sizeStatic));
1618 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&sizeShlFld));
1619 pdbi->ptActual.x = max(sizeStatic.cx, sizeShlFld.cx);
1620
1621 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStatic));
1622 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFld));
1623 pdbi->ptActual.y = sizeStatic.cy + sizeShlFld.cy;
1624 }
1625 if (pdbi->dwMask & DBIM_TITLE)
1626 wcscpy(pdbi->wszTitle, L"");
1627 if (pdbi->dwMask & DBIM_MODEFLAGS)
1628 pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
1629 if (pdbi->dwMask & DBIM_BKCOLOR)
1630 pdbi->crBkgnd = 0;
1631 return S_OK;
1632 }
1633
1634 /* IDockingWindow */
1635 HRESULT STDMETHODCALLTYPE CMenuBand::ShowDW(BOOL fShow)
1636 {
1637 HRESULT hr = S_OK;
1638
1639 if (m_staticToolbar != NULL)
1640 hr = m_staticToolbar->ShowWindow(fShow);
1641 if (FAILED(hr))
1642 return hr;
1643 if (m_SFToolbar != NULL)
1644 hr = m_SFToolbar->ShowWindow(fShow);
1645 if (FAILED(hr))
1646 return hr;
1647
1648 if (fShow)
1649 {
1650 hr = _CallCB(SMC_INITMENU, 0, 0);
1651 if (FAILED(hr))
1652 return hr;
1653 }
1654
1655 if (fShow)
1656 hr = m_focusManager->PushMenu(this);
1657 else
1658 hr = m_focusManager->PopMenu(this);
1659
1660 return S_OK;
1661 }
1662
1663 HRESULT STDMETHODCALLTYPE CMenuBand::CloseDW(DWORD dwReserved)
1664 {
1665 ShowDW(FALSE);
1666
1667 if (m_staticToolbar != NULL)
1668 return m_staticToolbar->Close();
1669
1670 if (m_SFToolbar != NULL)
1671 return m_SFToolbar->Close();
1672
1673 return S_OK;
1674 }
1675 HRESULT STDMETHODCALLTYPE CMenuBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
1676 {
1677 UNIMPLEMENTED;
1678 return S_OK;
1679 }
1680
1681 HRESULT STDMETHODCALLTYPE CMenuBand::ContextSensitiveHelp(BOOL fEnterMode)
1682 {
1683 UNIMPLEMENTED;
1684 return S_OK;
1685 }
1686
1687 HRESULT STDMETHODCALLTYPE CMenuBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
1688 {
1689 HRESULT hr;
1690
1691 hr = m_subMenuParent->SetSubMenu(this, fActivate);
1692 if (FAILED(hr))
1693 return hr;
1694
1695 if (fActivate)
1696 {
1697 CComPtr<IOleWindow> pTopLevelWindow;
1698 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1699 if (FAILED(hr))
1700 return hr;
1701
1702 hr = pTopLevelWindow->GetWindow(&m_topLevelWindow);
1703 if (FAILED(hr))
1704 return hr;
1705 }
1706 else
1707 {
1708 m_topLevelWindow = NULL;
1709 }
1710
1711 return S_FALSE;
1712 }
1713
1714 HRESULT STDMETHODCALLTYPE CMenuBand::HasFocusIO()
1715 {
1716 UNIMPLEMENTED;
1717 return S_OK;
1718 }
1719
1720 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg)
1721 {
1722 UNIMPLEMENTED;
1723 return S_OK;
1724 }
1725
1726 HRESULT STDMETHODCALLTYPE CMenuBand::IsDirty()
1727 {
1728 UNIMPLEMENTED;
1729 return S_OK;
1730 }
1731
1732 HRESULT STDMETHODCALLTYPE CMenuBand::Load(IStream *pStm)
1733 {
1734 UNIMPLEMENTED;
1735 return S_OK;
1736 }
1737
1738 HRESULT STDMETHODCALLTYPE CMenuBand::Save(IStream *pStm, BOOL fClearDirty)
1739 {
1740 UNIMPLEMENTED;
1741 return S_OK;
1742 }
1743
1744 HRESULT STDMETHODCALLTYPE CMenuBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
1745 {
1746 UNIMPLEMENTED;
1747 return S_OK;
1748 }
1749
1750 HRESULT STDMETHODCALLTYPE CMenuBand::GetClassID(CLSID *pClassID)
1751 {
1752 UNIMPLEMENTED;
1753 return S_OK;
1754 }
1755
1756 HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
1757 {
1758 UNIMPLEMENTED;
1759 return S_OK;
1760 }
1761
1762 HRESULT STDMETHODCALLTYPE CMenuBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1763 {
1764 if (!pguidCmdGroup)
1765 return E_FAIL;
1766
1767 if (IsEqualGUID(*pguidCmdGroup, CLSID_MenuBand))
1768 {
1769 if (nCmdID == 16) // set (big) icon size
1770 {
1771 this->m_useBigIcons = TRUE;
1772 return S_OK;
1773 }
1774 else if (nCmdID == 19) // popup-related
1775 {
1776 return S_FALSE;
1777 }
1778 }
1779
1780 UNIMPLEMENTED;
1781 return S_OK;
1782 }
1783
1784 HRESULT STDMETHODCALLTYPE CMenuBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
1785 {
1786 if (IsEqualIID(guidService, SID_SMenuBandChild) ||
1787 IsEqualIID(guidService, SID_SMenuBandBottom) ||
1788 IsEqualIID(guidService, SID_SMenuBandBottomSelected))
1789 return this->QueryInterface(riid, ppvObject);
1790 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService));
1791 return E_NOINTERFACE;
1792 }
1793
1794 HRESULT STDMETHODCALLTYPE CMenuBand::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
1795 {
1796 UNIMPLEMENTED;
1797 return S_OK;
1798 }
1799
1800 HRESULT STDMETHODCALLTYPE CMenuBand::OnSelect(DWORD dwSelectType)
1801 {
1802 switch (dwSelectType)
1803 {
1804 case MPOS_CHILDTRACKING:
1805 // TODO: Cancel timers?
1806 return m_subMenuParent->OnSelect(dwSelectType);
1807 case MPOS_SELECTLEFT:
1808 if (m_subMenuChild)
1809 m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
1810 return m_subMenuParent->OnSelect(dwSelectType);
1811 case MPOS_SELECTRIGHT:
1812 if (m_hotBar && m_hotItem >= 0)
1813 {
1814 // TODO: popup the current child if it has subitems, otherwise spread up.
1815 }
1816 return m_subMenuParent->OnSelect(dwSelectType);
1817 case MPOS_EXECUTE:
1818 case MPOS_FULLCANCEL:
1819 if (m_subMenuChild)
1820 m_subMenuChild->OnSelect(dwSelectType);
1821 return m_subMenuParent->OnSelect(dwSelectType);
1822 case MPOS_CANCELLEVEL:
1823 if (m_subMenuChild)
1824 m_subMenuChild->OnSelect(dwSelectType);
1825 break;
1826 }
1827 return S_FALSE;
1828 }
1829
1830 HRESULT STDMETHODCALLTYPE CMenuBand::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
1831 {
1832 UNIMPLEMENTED;
1833 return S_OK;
1834 }
1835
1836 HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
1837 {
1838 UNIMPLEMENTED;
1839 return S_OK;
1840 }
1841
1842 HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
1843 {
1844 // HACK, so I can test for a submenu in the DeskBar
1845 //UNIMPLEMENTED;
1846 if (ppunkClient)
1847 {
1848 if (m_subMenuChild)
1849 *ppunkClient = m_subMenuChild;
1850 else
1851 *ppunkClient = NULL;
1852 }
1853 return S_OK;
1854 }
1855
1856 HRESULT STDMETHODCALLTYPE CMenuBand::IsMenuMessage(MSG *pmsg)
1857 {
1858 //UNIMPLEMENTED;
1859 //return S_OK;
1860 return S_FALSE;
1861 //return E_NOTIMPL;
1862 }
1863
1864 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet)
1865 {
1866 //UNIMPLEMENTED;
1867 return S_FALSE;
1868 }
1869
1870 HRESULT STDMETHODCALLTYPE CMenuBand::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1871 {
1872 if (m_SFToolbar == NULL)
1873 {
1874 m_SFToolbar = new CMenuSFToolbar(this);
1875 }
1876
1877 HRESULT hr = m_SFToolbar->SetShellFolder(psf, pidlFolder, hKey, dwFlags);
1878 if (FAILED(hr))
1879 return hr;
1880
1881 if (m_site)
1882 {
1883 HWND hwndParent;
1884
1885 hr = m_site->GetWindow(&hwndParent);
1886 if (FAILED(hr))
1887 return hr;
1888
1889 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1890 if (FAILED(hr))
1891 return hr;
1892
1893 hr = m_SFToolbar->FillToolbar();
1894 }
1895
1896 return hr;
1897 }
1898
1899 HRESULT STDMETHODCALLTYPE CMenuBand::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1900 {
1901 if (m_SFToolbar)
1902 return m_SFToolbar->GetShellFolder(pdwFlags, ppidl, riid, ppv);
1903 return E_FAIL;
1904 }
1905
1906 HRESULT STDMETHODCALLTYPE CMenuBand::InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
1907 {
1908 UNIMPLEMENTED;
1909 return S_OK;
1910 }
1911
1912 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(LPSMDATA psmd)
1913 {
1914 UNIMPLEMENTED;
1915 return S_OK;
1916 }
1917
1918 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenuToolbar(IUnknown *punk, DWORD dwFlags)
1919 {
1920 UNIMPLEMENTED;
1921 return S_OK;
1922 }
1923
1924 HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1925 {
1926 *theResult = 0;
1927 switch (uMsg)
1928 {
1929 case WM_COMMAND:
1930
1931 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1932 {
1933 return m_staticToolbar->OnCommand(wParam, lParam, theResult);
1934 }
1935
1936 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1937 {
1938 return m_SFToolbar->OnCommand(wParam, lParam, theResult);
1939 }
1940
1941 return S_OK;
1942
1943 case WM_NOTIFY:
1944 NMHDR * hdr = reinterpret_cast<LPNMHDR>(lParam);
1945 NMTBCUSTOMDRAW * cdraw;
1946 NMTBHOTITEM * hot;
1947 NMMOUSE * rclick;
1948 switch (hdr->code)
1949 {
1950 case TBN_HOTITEMCHANGE:
1951 hot = reinterpret_cast<LPNMTBHOTITEM>(hdr);
1952
1953 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1954 {
1955 return m_staticToolbar->OnHotItemChange(hot);
1956 }
1957
1958 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1959 {
1960 return m_SFToolbar->OnHotItemChange(hot);
1961 }
1962
1963 return S_OK;
1964
1965 case NM_RCLICK:
1966 rclick = reinterpret_cast<LPNMMOUSE>(hdr);
1967
1968 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1969 {
1970 return m_staticToolbar->OnContextMenu(rclick);
1971 }
1972
1973 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1974 {
1975 return m_SFToolbar->OnContextMenu(rclick);
1976 }
1977
1978 return S_OK;
1979 case NM_CUSTOMDRAW:
1980 cdraw = reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr);
1981 switch (cdraw->nmcd.dwDrawStage)
1982 {
1983 case CDDS_PREPAINT:
1984 *theResult = CDRF_NOTIFYITEMDRAW;
1985 return S_OK;
1986
1987 case CDDS_ITEMPREPAINT:
1988
1989 cdraw->clrBtnFace = GetSysColor(COLOR_MENU);
1990 cdraw->clrBtnHighlight = GetSysColor(COLOR_MENUHILIGHT);
1991
1992 cdraw->clrText = GetSysColor(COLOR_MENUTEXT);
1993 cdraw->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
1994 cdraw->clrHighlightHotTrack = GetSysColor(COLOR_HIGHLIGHTTEXT);
1995
1996 RECT rc = cdraw->nmcd.rc;
1997 HDC hdc = cdraw->nmcd.hdc;
1998
1999 HBRUSH bgBrush = GetSysColorBrush(COLOR_MENU);
2000 HBRUSH hotBrush = GetSysColorBrush(COLOR_MENUHILIGHT);
2001
2002 switch (cdraw->nmcd.uItemState)
2003 {
2004 case CDIS_HOT:
2005 case CDIS_FOCUS:
2006 FillRect(hdc, &rc, hotBrush);
2007 break;
2008 default:
2009 FillRect(hdc, &rc, bgBrush);
2010 break;
2011 }
2012
2013 *theResult = TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOETCHEDEFFECT | TBCDRF_HILITEHOTTRACK | TBCDRF_NOOFFSET;
2014 return S_OK;
2015 }
2016 return S_OK;
2017 }
2018 return S_OK;
2019 }
2020
2021 return S_FALSE;
2022 }
2023
2024 HRESULT STDMETHODCALLTYPE CMenuBand::IsWindowOwner(HWND hWnd)
2025 {
2026 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
2027 return S_OK;
2028
2029 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
2030 return S_OK;
2031
2032 return S_FALSE;
2033 }
2034
2035 HRESULT STDMETHODCALLTYPE CMenuBand::GetSubMenu(THIS)
2036 {
2037 UNIMPLEMENTED;
2038 return S_OK;
2039 }
2040
2041 HRESULT STDMETHODCALLTYPE CMenuBand::SetToolbar(THIS)
2042 {
2043 UNIMPLEMENTED;
2044 return S_OK;
2045 }
2046
2047 HRESULT STDMETHODCALLTYPE CMenuBand::SetMinWidth(THIS)
2048 {
2049 UNIMPLEMENTED;
2050 return S_OK;
2051 }
2052
2053 HRESULT STDMETHODCALLTYPE CMenuBand::SetNoBorder(THIS)
2054 {
2055 UNIMPLEMENTED;
2056 return S_OK;
2057 }
2058
2059 HRESULT STDMETHODCALLTYPE CMenuBand::SetTheme(THIS)
2060 {
2061 UNIMPLEMENTED;
2062 return S_OK;
2063 }
2064
2065 HRESULT STDMETHODCALLTYPE CMenuBand::GetTop(THIS)
2066 {
2067 UNIMPLEMENTED;
2068 return S_OK;
2069 }
2070
2071 HRESULT STDMETHODCALLTYPE CMenuBand::GetBottom(THIS)
2072 {
2073 UNIMPLEMENTED;
2074 return S_OK;
2075 }
2076
2077 HRESULT STDMETHODCALLTYPE CMenuBand::GetTracked(THIS)
2078 {
2079 UNIMPLEMENTED;
2080 return S_OK;
2081 }
2082
2083 HRESULT STDMETHODCALLTYPE CMenuBand::GetParentSite(THIS)
2084 {
2085 UNIMPLEMENTED;
2086 return S_OK;
2087 }
2088
2089 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(THIS)
2090 {
2091 UNIMPLEMENTED;
2092 return S_OK;
2093 }
2094
2095 HRESULT STDMETHODCALLTYPE CMenuBand::DoDefaultAction(THIS)
2096 {
2097 UNIMPLEMENTED;
2098 return S_OK;
2099 }
2100
2101 HRESULT STDMETHODCALLTYPE CMenuBand::IsEmpty(THIS)
2102 {
2103 UNIMPLEMENTED;
2104 return S_OK;
2105 }
2106
2107 HRESULT CMenuBand::_CallCBWithItemId(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam)
2108 {
2109 return _CallCB(uMsg, wParam, lParam, id);
2110 }
2111
2112 HRESULT CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam)
2113 {
2114 return _CallCB(uMsg, wParam, lParam, 0, pidl);
2115 }
2116
2117 HRESULT CMenuBand::_CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id, LPITEMIDLIST pidl)
2118 {
2119 if (!m_psmc)
2120 return S_FALSE;
2121
2122 HWND hwnd;
2123 GetWindow(&hwnd);
2124
2125 SMDATA smData = { 0 };
2126 smData.punk = static_cast<IShellMenu2*>(this);
2127 smData.uId = id;
2128 smData.uIdParent = m_uId;
2129 smData.uIdAncestor = m_uIdAncestor;
2130 smData.hwnd = hwnd;
2131 smData.pidlItem = pidl;
2132 if (m_staticToolbar)
2133 {
2134 smData.hmenu = m_hmenu;
2135 }
2136 smData.pvUserData = NULL;
2137 if (m_SFToolbar)
2138 m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf));
2139 HRESULT hr = m_psmc->CallbackSM(&smData, uMsg, wParam, lParam);
2140 ILFree(smData.pidlFolder);
2141 if (smData.psf)
2142 smData.psf->Release();
2143 return hr;
2144 }
2145
2146 HRESULT CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y)
2147 {
2148 ::TrackPopupMenu(popup, 0, x, y, 0, m_menuOwner, NULL);
2149 return S_OK;
2150 }
2151
2152 HRESULT CMenuBand::_GetTopLevelWindow(HWND*topLevel)
2153 {
2154 *topLevel = m_topLevelWindow;
2155 return S_OK;
2156 }
2157
2158 HRESULT CMenuBand::_OnHotItemChanged(CMenuToolbarBase * tb, INT id)
2159 {
2160 if (m_hotBar && m_hotBar != tb)
2161 m_hotBar->ChangeHotItem(-1);
2162 m_hotBar = tb;
2163 m_hotItem = id;
2164 return S_OK;
2165 }
2166
2167 HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
2168 {
2169 HRESULT hr;
2170
2171 if (changeType == VK_DOWN)
2172 {
2173 if (m_SFToolbar && (m_hotBar == m_SFToolbar || m_hotBar == NULL))
2174 {
2175 hr = m_SFToolbar->ChangeHotItem(VK_DOWN);
2176 if (hr == S_FALSE)
2177 {
2178 if (m_staticToolbar)
2179 return m_staticToolbar->ChangeHotItem(VK_HOME);
2180 else
2181 return m_SFToolbar->ChangeHotItem(VK_HOME);
2182 }
2183 return hr;
2184 }
2185 else if (m_staticToolbar && m_hotBar == m_staticToolbar)
2186 {
2187 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2188 if (hr == S_FALSE)
2189 {
2190 if (m_SFToolbar)
2191 return m_SFToolbar->ChangeHotItem(VK_HOME);
2192 else
2193 return m_staticToolbar->ChangeHotItem(VK_HOME);
2194 }
2195 return hr;
2196 }
2197 }
2198 else if (changeType == VK_UP)
2199 {
2200 if (m_staticToolbar && (m_hotBar == m_staticToolbar || m_hotBar == NULL))
2201 {
2202 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2203 if (hr == S_FALSE)
2204 {
2205 if (m_SFToolbar)
2206 return m_SFToolbar->ChangeHotItem(VK_END);
2207 else
2208 return m_staticToolbar->ChangeHotItem(VK_END);
2209 }
2210 return hr;
2211 }
2212 else if (m_SFToolbar && m_hotBar == m_SFToolbar)
2213 {
2214 hr = m_SFToolbar->ChangeHotItem(VK_UP);
2215 if (hr == S_FALSE)
2216 {
2217 if (m_staticToolbar)
2218 return m_staticToolbar->ChangeHotItem(VK_END);
2219 else
2220 return m_SFToolbar->ChangeHotItem(VK_END);
2221 }
2222 return hr;
2223 }
2224 }
2225 else
2226 {
2227 m_subMenuParent->OnSelect(changeType);
2228 }
2229 return S_OK;
2230 }
2231
2232 HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude)
2233 {
2234 if (m_subMenuChild)
2235 {
2236 HRESULT hr = m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
2237 if (FAILED(hr))
2238 return hr;
2239 }
2240 m_subMenuChild = popup;
2241 if (popup)
2242 {
2243 IUnknown_SetSite(popup, m_subMenuParent);
2244 popup->Popup(pAt, pExclude, MPPF_RIGHT);
2245 }
2246 return S_OK;
2247 }