[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 KillTimer(hWnd, TIMERID_HOTTRACK);
680
681 m_menuBand->_OnPopupSubMenu(NULL, NULL, NULL);
682
683 if (HasSubMenu(m_hotItem) == S_OK)
684 {
685 PopupItem(m_hotItem);
686 }
687 }
688 }
689
690 return m_SubclassOld(hWnd, uMsg, wParam, lParam);
691 }
692
693 HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot)
694 {
695 if (hot->dwFlags & HICF_LEAVING)
696 {
697 KillTimer(m_hwnd, TIMERID_HOTTRACK);
698 m_hotItem = -1;
699 m_menuBand->_OnHotItemChanged(NULL, -1);
700 m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
701 }
702 else if (m_hotItem != hot->idNew)
703 {
704 DWORD elapsed = 0;
705 SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0);
706 SetTimer(m_hwnd, TIMERID_HOTTRACK, elapsed, NULL);
707
708 m_hotItem = hot->idNew;
709 m_menuBand->_OnHotItemChanged(this, m_hotItem);
710 m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
711 }
712 return S_OK;
713 }
714
715 HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, IShellMenu* childShellMenu)
716 {
717 IBandSite* pBandSite;
718 IDeskBar* pDeskBar;
719
720 HRESULT hr = 0;
721 RECT rc = { 0 };
722
723 if (!SendMessage(m_hwnd, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
724 return E_FAIL;
725
726 POINT a = { rc.left, rc.top };
727 POINT b = { rc.right, rc.bottom };
728
729 ClientToScreen(m_hwnd, &a);
730 ClientToScreen(m_hwnd, &b);
731
732 POINTL pt = { b.x, a.y };
733 RECTL rcl = { a.x, a.y, b.x, b.y }; // maybe-TODO: fetch client area of deskbar?
734
735
736 #if USE_SYSTEM_MENUSITE
737 hr = CoCreateInstance(CLSID_MenuBandSite,
738 NULL,
739 CLSCTX_INPROC_SERVER,
740 IID_PPV_ARG(IBandSite, &pBandSite));
741 #else
742 hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
743 #endif
744 if (FAILED(hr))
745 return hr;
746 #if WRAP_MENUSITE
747 hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite));
748 if (FAILED(hr))
749 return hr;
750 #endif
751
752 #if USE_SYSTEM_MENUDESKBAR
753 hr = CoCreateInstance(CLSID_MenuDeskBar,
754 NULL,
755 CLSCTX_INPROC_SERVER,
756 IID_PPV_ARG(IDeskBar, &pDeskBar));
757 #else
758 hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar));
759 #endif
760 if (FAILED(hr))
761 return hr;
762 #if WRAP_MENUDESKBAR
763 hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar));
764 if (FAILED(hr))
765 return hr;
766 #endif
767
768 hr = pDeskBar->SetClient(pBandSite);
769 if (FAILED(hr))
770 return hr;
771
772 hr = pBandSite->AddBand(childShellMenu);
773 if (FAILED(hr))
774 return hr;
775
776 CComPtr<IMenuPopup> popup;
777 hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup));
778 if (FAILED(hr))
779 return hr;
780
781 m_menuBand->_OnPopupSubMenu(popup, &pt, &rcl);
782
783 return S_OK;
784 }
785
786 HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, HMENU menu)
787 {
788 RECT rc = { 0 };
789
790 if (!SendMessage(m_hwnd, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
791 return E_FAIL;
792
793 POINT b = { rc.right, rc.bottom };
794
795 ClientToScreen(m_hwnd, &b);
796
797 HMENU popup = GetSubMenu(menu, index);
798
799 m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, b.x, b.y);
800
801 return S_OK;
802 }
803
804 HRESULT CMenuToolbarBase::DoContextMenu(IContextMenu* contextMenu)
805 {
806 HRESULT hr;
807 HMENU hPopup = CreatePopupMenu();
808
809 if (hPopup == NULL)
810 return E_FAIL;
811
812 hr = contextMenu->QueryContextMenu(hPopup, 0, 0, UINT_MAX, CMF_NORMAL);
813 if (FAILED(hr))
814 {
815 DestroyMenu(hPopup);
816 return hr;
817 }
818
819 DWORD dwPos = GetMessagePos();
820 UINT uCommand = ::TrackPopupMenu(hPopup, TPM_RETURNCMD, GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), 0, m_hwnd, NULL);
821 if (uCommand == 0)
822 return S_FALSE;
823
824 CMINVOKECOMMANDINFO cmi = { 0 };
825 cmi.cbSize = sizeof(cmi);
826 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
827 cmi.hwnd = m_hwnd;
828 hr = contextMenu->InvokeCommand(&cmi);
829
830 DestroyMenu(hPopup);
831 return hr;
832 }
833
834 HRESULT CMenuToolbarBase::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
835 {
836 theResult = 0;
837 return m_menuBand->_MenuItemHotTrack(MPOS_EXECUTE);
838 }
839
840
841 HRESULT CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType)
842 {
843 int prev = m_hotItem;
844 int index = -1;
845
846 if (dwSelectType != 0xFFFFFFFF)
847 {
848 int count = SendMessage(m_hwnd, TB_BUTTONCOUNT, 0, 0);
849
850 if (m_hotItem >= 0)
851 {
852 TBBUTTONINFO info = { 0 };
853 info.cbSize = sizeof(TBBUTTONINFO);
854 info.dwMask = 0;
855 index = SendMessage(m_hwnd, TB_GETBUTTONINFO, m_hotItem, reinterpret_cast<LPARAM>(&info));
856 }
857
858 if (dwSelectType == VK_HOME)
859 {
860 index = 0;
861 dwSelectType = VK_DOWN;
862 }
863 else if (dwSelectType == VK_END)
864 {
865 index = count - 1;
866 dwSelectType = VK_UP;
867 }
868 else if (index < 0)
869 {
870 if (dwSelectType == VK_UP)
871 {
872 index = count - 1;
873 }
874 else if (dwSelectType == VK_DOWN)
875 {
876 index = 0;
877 }
878 }
879 else
880 {
881 if (dwSelectType == VK_UP)
882 {
883 index--;
884 }
885 else if (dwSelectType == VK_DOWN)
886 {
887 index++;
888 }
889 }
890
891 TBBUTTON btn = { 0 };
892 while (index >= 0 && index < count)
893 {
894 DWORD res = SendMessage(m_hwnd, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
895 if (!res)
896 return E_FAIL;
897
898 if (btn.dwData)
899 {
900 m_hotItem = btn.idCommand;
901 if (prev != m_hotItem)
902 {
903 SendMessage(m_hwnd, TB_SETHOTITEM, index, 0);
904 return m_menuBand->_OnHotItemChanged(this, m_hotItem);
905 }
906 return S_OK;
907 }
908
909 if (dwSelectType == VK_UP)
910 {
911 index--;
912 }
913 else if (dwSelectType == VK_DOWN)
914 {
915 index++;
916 }
917 }
918 }
919
920 m_hotItem = -1;
921 if (prev != m_hotItem)
922 {
923 SendMessage(m_hwnd, TB_SETHOTITEM, -1, 0);
924 m_menuBand->_OnHotItemChanged(NULL, -1);
925 }
926 return S_FALSE;
927 }
928
929 BOOL
930 AllocAndGetMenuString(HMENU hMenu, UINT ItemIDByPosition, WCHAR** String)
931 {
932 int Length;
933
934 Length = GetMenuStringW(hMenu, ItemIDByPosition, NULL, 0, MF_BYPOSITION);
935
936 if (!Length)
937 return FALSE;
938
939 /* Also allocate space for the terminating NULL character */
940 ++Length;
941 *String = (PWSTR) HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR));
942
943 GetMenuStringW(hMenu, ItemIDByPosition, *String, Length, MF_BYPOSITION);
944
945 return TRUE;
946 }
947
948 CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand *menuBand) :
949 CMenuToolbarBase(menuBand),
950 m_hmenu(NULL)
951 {
952 }
953
954 HRESULT CMenuStaticToolbar::GetMenu(
955 HMENU *phmenu,
956 HWND *phwnd,
957 DWORD *pdwFlags)
958 {
959 *phmenu = m_hmenu;
960 *phwnd = NULL;
961 *pdwFlags = m_dwMenuFlags;
962
963 return S_OK;
964 }
965
966 HRESULT CMenuStaticToolbar::SetMenu(
967 HMENU hmenu,
968 HWND hwnd,
969 DWORD dwFlags)
970 {
971 m_hmenu = hmenu;
972 m_dwMenuFlags = dwFlags;
973
974 return S_OK;
975 }
976
977 HRESULT CMenuStaticToolbar::FillToolbar()
978 {
979 int i;
980 int ic = GetMenuItemCount(m_hmenu);
981
982 for (i = 0; i < ic; i++)
983 {
984 MENUITEMINFOW info;
985 TBBUTTON tbb = { 0 };
986 PWSTR MenuString = NULL;
987
988 tbb.fsState = TBSTATE_ENABLED;
989 tbb.fsStyle = 0;
990
991 info.cbSize = sizeof(info);
992 info.fMask = MIIM_FTYPE | MIIM_ID;
993
994 GetMenuItemInfoW(m_hmenu, i, TRUE, &info);
995
996 if (info.fType == MFT_STRING)
997 {
998 if (!AllocAndGetMenuString(m_hmenu, i, &MenuString))
999 return E_OUTOFMEMORY;
1000 if (::GetSubMenu(m_hmenu, i) != NULL)
1001 tbb.fsStyle |= BTNS_DROPDOWN;
1002 tbb.iString = (INT_PTR) MenuString;
1003 tbb.idCommand = info.wID;
1004
1005 SMINFO * sminfo = new SMINFO();
1006 sminfo->dwMask = SMIM_ICON | SMIM_FLAGS;
1007 if (SUCCEEDED(m_menuBand->_CallCBWithItemId(info.wID, SMC_GETINFO, 0, reinterpret_cast<LPARAM>(sminfo))))
1008 {
1009 tbb.iBitmap = sminfo->iIcon;
1010 tbb.dwData = reinterpret_cast<DWORD_PTR>(sminfo);
1011 // FIXME: remove before deleting the toolbar or it will leak
1012 }
1013 }
1014 else
1015 {
1016 tbb.fsStyle |= BTNS_SEP;
1017 }
1018
1019 SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1020
1021 if (MenuString)
1022 HeapFree(GetProcessHeap(), 0, MenuString);
1023 }
1024
1025 return S_OK;
1026 }
1027
1028 HRESULT CMenuStaticToolbar::OnContextMenu(NMMOUSE * rclick)
1029 {
1030 CComPtr<IContextMenu> contextMenu;
1031 HRESULT hr = m_menuBand->_CallCBWithItemId(rclick->dwItemSpec, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IContextMenu), reinterpret_cast<LPARAM>(&contextMenu));
1032 if (hr != S_OK)
1033 return hr;
1034
1035 return DoContextMenu(contextMenu);
1036 }
1037
1038 HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1039 {
1040 HRESULT hr;
1041 hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1042 if (FAILED(hr))
1043 return hr;
1044
1045 return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0);
1046 }
1047
1048 HRESULT CMenuStaticToolbar::PopupItem(UINT uItem)
1049 {
1050 TBBUTTONINFO info = { 0 };
1051 info.cbSize = sizeof(TBBUTTONINFO);
1052 info.dwMask = 0;
1053 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1054 if (index < 0)
1055 return E_FAIL;
1056
1057 TBBUTTON btn = { 0 };
1058 SendMessage(m_hwnd, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
1059
1060 SMINFO * nfo = reinterpret_cast<SMINFO*>(btn.dwData);
1061 if (!nfo)
1062 return E_FAIL;
1063
1064 if (nfo->dwFlags&SMIF_TRACKPOPUP)
1065 {
1066 return PopupSubMenu(index, m_hmenu);
1067 }
1068 else
1069 {
1070 CComPtr<IShellMenu> shellMenu;
1071 HRESULT hr = m_menuBand->_CallCBWithItemId(uItem, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IShellMenu), reinterpret_cast<LPARAM>(&shellMenu));
1072 if (FAILED(hr))
1073 return hr;
1074
1075 return PopupSubMenu(index, shellMenu);
1076 }
1077 }
1078
1079 HRESULT CMenuStaticToolbar::HasSubMenu(UINT uItem)
1080 {
1081 TBBUTTONINFO info = { 0 };
1082 info.cbSize = sizeof(TBBUTTONINFO);
1083 info.dwMask = 0;
1084 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1085 if (index < 0)
1086 return E_FAIL;
1087 return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE;
1088 }
1089
1090 CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) :
1091 CMenuToolbarBase(menuBand),
1092 m_shellFolder(NULL)
1093 {
1094 }
1095
1096 CMenuSFToolbar::~CMenuSFToolbar()
1097 {
1098 }
1099
1100 HRESULT CMenuSFToolbar::FillToolbar()
1101 {
1102 HRESULT hr;
1103 int i = 0;
1104 PWSTR MenuString;
1105
1106 IEnumIDList * eidl;
1107 m_shellFolder->EnumObjects(m_hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &eidl);
1108
1109 LPITEMIDLIST item = static_cast<LPITEMIDLIST>(CoTaskMemAlloc(sizeof(ITEMIDLIST)));
1110 ULONG fetched;
1111 while ((hr = eidl->Next(1, &item, &fetched)) == S_OK)
1112 {
1113 INT index = 0;
1114 INT indexOpen = 0;
1115
1116 TBBUTTON tbb = { 0 };
1117 tbb.fsState = TBSTATE_ENABLED;
1118 tbb.fsStyle = 0;
1119
1120 CComPtr<IShellItem> psi;
1121 SHCreateShellItem(NULL, m_shellFolder, item, &psi);
1122
1123 hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &MenuString);
1124 if (FAILED(hr))
1125 return hr;
1126
1127 index = SHMapPIDLToSystemImageListIndex(m_shellFolder, item, &indexOpen);
1128
1129 SFGAOF attrs;
1130 hr = psi->GetAttributes(SFGAO_FOLDER, &attrs);
1131
1132 if (attrs != 0)
1133 {
1134 tbb.fsStyle |= BTNS_DROPDOWN;
1135 }
1136
1137 tbb.idCommand = ++i;
1138 tbb.iString = (INT_PTR) MenuString;
1139 tbb.iBitmap = index;
1140 tbb.dwData = reinterpret_cast<DWORD_PTR>(ILClone(item));
1141 // FIXME: remove before deleting the toolbar or it will leak
1142
1143 SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1144 HeapFree(GetProcessHeap(), 0, MenuString);
1145
1146 }
1147 CoTaskMemFree(item);
1148
1149 // If no items were added, show the "empty" placeholder
1150 if (i == 0)
1151 {
1152 TBBUTTON tbb = { 0 };
1153 PWSTR MenuString = L"(Empty)";
1154
1155 tbb.fsState = 0/*TBSTATE_DISABLED*/;
1156 tbb.fsStyle = 0;
1157 tbb.iString = (INT_PTR) MenuString;
1158 tbb.iBitmap = -1;
1159
1160 SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
1161
1162 return S_OK;
1163 }
1164
1165 return hr;
1166 }
1167
1168 HRESULT CMenuSFToolbar::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1169 {
1170 m_shellFolder = psf;
1171 m_idList = pidlFolder;
1172 m_hKey = hKey;
1173 m_dwMenuFlags = dwFlags;
1174 return S_OK;
1175 }
1176
1177 HRESULT CMenuSFToolbar::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1178 {
1179 HRESULT hr;
1180
1181 hr = m_shellFolder->QueryInterface(riid, ppv);
1182 if (FAILED(hr))
1183 return hr;
1184
1185 if (pdwFlags)
1186 *pdwFlags = m_dwMenuFlags;
1187
1188 if (ppidl)
1189 {
1190 LPITEMIDLIST pidl = NULL;
1191
1192 if (m_idList)
1193 {
1194 pidl = ILClone(m_idList);
1195 if (!pidl)
1196 {
1197 (*(IUnknown**) ppv)->Release();
1198 return E_FAIL;
1199 }
1200 }
1201
1202 *ppidl = pidl;
1203 }
1204
1205 return hr;
1206 }
1207
1208 LPITEMIDLIST CMenuSFToolbar::GetPidlFromId(UINT uItem, INT* pIndex)
1209 {
1210 TBBUTTONINFO info = { 0 };
1211 info.cbSize = sizeof(TBBUTTONINFO);
1212 info.dwMask = 0;
1213 int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
1214 if (index < 0)
1215 return NULL;
1216
1217 if (pIndex)
1218 *pIndex = index;
1219
1220 TBBUTTON btn = { 0 };
1221 if (!SendMessage(m_hwnd, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn)))
1222 return NULL;
1223
1224 return reinterpret_cast<LPITEMIDLIST>(btn.dwData);
1225 }
1226
1227 HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick)
1228 {
1229 HRESULT hr;
1230 CComPtr<IContextMenu> contextMenu;
1231 LPCITEMIDLIST pidl = reinterpret_cast<LPCITEMIDLIST>(rclick->dwItemData);
1232
1233 hr = m_shellFolder->GetUIObjectOf(m_hwnd, 1, &pidl, IID_IContextMenu, NULL, reinterpret_cast<VOID **>(&contextMenu));
1234 if (hr != S_OK)
1235 return hr;
1236
1237 return DoContextMenu(contextMenu);
1238 }
1239
1240 HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1241 {
1242 HRESULT hr;
1243 hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
1244 if (FAILED(hr))
1245 return hr;
1246
1247 return m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0);
1248 }
1249
1250 HRESULT CMenuSFToolbar::PopupItem(UINT uItem)
1251 {
1252 HRESULT hr;
1253 UINT uId;
1254 UINT uIdAncestor;
1255 DWORD flags;
1256 int index;
1257 CComPtr<IShellMenuCallback> psmc;
1258 CComPtr<IShellMenu> shellMenu;
1259
1260 LPITEMIDLIST pidl = GetPidlFromId(uItem, &index);
1261
1262 if (!pidl)
1263 return E_FAIL;
1264
1265 #if USE_SYSTEM_MENUBAND
1266 hr = CoCreateInstance(CLSID_MenuBand,
1267 NULL,
1268 CLSCTX_INPROC_SERVER,
1269 IID_PPV_ARG(IShellMenu, &shellMenu));
1270 #else
1271 hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &shellMenu));
1272 #endif
1273 if (FAILED(hr))
1274 return hr;
1275 #if WRAP_MENUBAND
1276 hr = CMenuBand_Wrapper(shellMenu, IID_PPV_ARG(IShellMenu, &shellMenu));
1277 if (FAILED(hr))
1278 return hr;
1279 #endif
1280
1281 m_menuBand->GetMenuInfo(&psmc, &uId, &uIdAncestor, &flags);
1282
1283 // FIXME: not sure waht to use as uId/uIdAncestor here
1284 hr = shellMenu->Initialize(psmc, 0, uId, SMINIT_VERTICAL);
1285 if (FAILED(hr))
1286 return hr;
1287
1288 CComPtr<IShellFolder> childFolder;
1289 hr = m_shellFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &childFolder));
1290 if (FAILED(hr))
1291 return hr;
1292
1293 hr = shellMenu->SetShellFolder(childFolder, NULL, NULL, 0);
1294 if (FAILED(hr))
1295 return hr;
1296
1297 return PopupSubMenu(index, shellMenu);
1298 }
1299
1300 HRESULT CMenuSFToolbar::HasSubMenu(UINT uItem)
1301 {
1302 HRESULT hr;
1303 CComPtr<IShellItem> psi;
1304 SHCreateShellItem(NULL, m_shellFolder, GetPidlFromId(uItem), &psi);
1305
1306 SFGAOF attrs;
1307 hr = psi->GetAttributes(SFGAO_FOLDER, &attrs);
1308 if (FAILED(hr))
1309 return hr;
1310
1311 return (attrs != 0) ? S_OK : S_FALSE;
1312 }
1313
1314 CMenuBand::CMenuBand() :
1315 m_site(NULL),
1316 m_psmc(NULL),
1317 m_staticToolbar(NULL),
1318 m_SFToolbar(NULL),
1319 m_useBigIcons(FALSE),
1320 m_hotBar(NULL),
1321 m_hotItem(-1),
1322 m_subMenuChild(NULL)
1323 {
1324 m_focusManager = CMenuFocusManager::AcquireManager();
1325 }
1326
1327 CMenuBand::~CMenuBand()
1328 {
1329 CMenuFocusManager::ReleaseManager(m_focusManager);
1330
1331 if (m_staticToolbar)
1332 delete m_staticToolbar;
1333
1334 if (m_SFToolbar)
1335 delete m_SFToolbar;
1336 }
1337
1338 HRESULT STDMETHODCALLTYPE CMenuBand::Initialize(
1339 IShellMenuCallback *psmc,
1340 UINT uId,
1341 UINT uIdAncestor,
1342 DWORD dwFlags)
1343 {
1344 if (m_psmc != psmc)
1345 m_psmc = psmc;
1346 m_uId = uId;
1347 m_uIdAncestor = uIdAncestor;
1348 m_dwFlags = dwFlags;
1349
1350 if (m_psmc)
1351 {
1352 _CallCB(SMC_CREATE, 0, reinterpret_cast<LPARAM>(&m_UserData));
1353 }
1354
1355 return S_OK;
1356 }
1357
1358 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenuInfo(
1359 IShellMenuCallback **ppsmc,
1360 UINT *puId,
1361 UINT *puIdAncestor,
1362 DWORD *pdwFlags)
1363 {
1364 if (!pdwFlags) // maybe?
1365 return E_INVALIDARG;
1366
1367 if (ppsmc)
1368 *ppsmc = m_psmc;
1369
1370 if (puId)
1371 *puId = m_uId;
1372
1373 if (puIdAncestor)
1374 *puIdAncestor = m_uIdAncestor;
1375
1376 *pdwFlags = m_dwFlags;
1377
1378 return S_OK;
1379 }
1380
1381 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenu(
1382 HMENU hmenu,
1383 HWND hwnd,
1384 DWORD dwFlags)
1385 {
1386 if (m_staticToolbar == NULL)
1387 {
1388 m_staticToolbar = new CMenuStaticToolbar(this);
1389 }
1390 m_hmenu = hmenu;
1391 m_menuOwner;
1392
1393 HRESULT hr = m_staticToolbar->SetMenu(hmenu, hwnd, dwFlags);
1394 if (FAILED(hr))
1395 return hr;
1396
1397 if (m_site)
1398 {
1399 HWND hwndParent;
1400
1401 hr = m_site->GetWindow(&hwndParent);
1402 if (FAILED(hr))
1403 return hr;
1404
1405 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
1406 if (FAILED(hr))
1407 return hr;
1408
1409 hr = m_staticToolbar->FillToolbar();
1410 }
1411
1412 return hr;
1413 }
1414
1415 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenu(
1416 HMENU *phmenu,
1417 HWND *phwnd,
1418 DWORD *pdwFlags)
1419 {
1420 if (m_staticToolbar == NULL)
1421 return E_FAIL;
1422
1423 return m_staticToolbar->GetMenu(phmenu, phwnd, pdwFlags);
1424 }
1425
1426 HRESULT STDMETHODCALLTYPE CMenuBand::SetSite(IUnknown *pUnkSite)
1427 {
1428 HWND hwndParent;
1429 HRESULT hr;
1430
1431 m_site = NULL;
1432
1433 if (pUnkSite == NULL)
1434 return S_OK;
1435
1436 hwndParent = NULL;
1437 hr = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &m_site));
1438 if (FAILED(hr))
1439 return hr;
1440
1441 hr = m_site->GetWindow(&hwndParent);
1442 if (FAILED(hr))
1443 return hr;
1444
1445 if (!::IsWindow(hwndParent))
1446 return E_FAIL;
1447
1448 if (m_staticToolbar != NULL)
1449 {
1450 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
1451 if (FAILED(hr))
1452 return hr;
1453
1454 hr = m_staticToolbar->FillToolbar();
1455 if (FAILED(hr))
1456 return hr;
1457 }
1458
1459 if (m_SFToolbar != NULL)
1460 {
1461 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1462 if (FAILED(hr))
1463 return hr;
1464
1465 hr = m_SFToolbar->FillToolbar();
1466 if (FAILED(hr))
1467 return hr;
1468 }
1469
1470 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_subMenuParent));
1471 if (FAILED(hr))
1472 return hr;
1473
1474 CComPtr<IOleWindow> pTopLevelWindow;
1475 hr = IUnknown_QueryService(m_site, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1476 if (FAILED(hr))
1477 return hr;
1478
1479 return pTopLevelWindow->GetWindow(&m_topLevelWindow);
1480 }
1481
1482 HRESULT STDMETHODCALLTYPE CMenuBand::GetSite(REFIID riid, PVOID *ppvSite)
1483 {
1484 if (m_site == NULL)
1485 return E_FAIL;
1486
1487 return m_site->QueryInterface(riid, ppvSite);
1488 }
1489
1490 HRESULT STDMETHODCALLTYPE CMenuBand::GetWindow(
1491 HWND *phwnd)
1492 {
1493 if (m_SFToolbar != NULL)
1494 return m_SFToolbar->GetWindow(phwnd);
1495
1496 if (m_staticToolbar != NULL)
1497 return m_staticToolbar->GetWindow(phwnd);
1498
1499 return E_FAIL;
1500 }
1501
1502 HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc)
1503 {
1504 SIZE sizeStaticY = { 0 };
1505 SIZE sizeShlFldY = { 0 };
1506 HWND hwndStatic = NULL;
1507 HWND hwndShlFld = NULL;
1508 HRESULT hr = S_OK;
1509
1510 if (m_staticToolbar != NULL)
1511 hr = m_staticToolbar->GetWindow(&hwndStatic);
1512 if (FAILED(hr))
1513 return hr;
1514
1515 if (m_SFToolbar != NULL)
1516 hr = m_SFToolbar->GetWindow(&hwndShlFld);
1517 if (FAILED(hr))
1518 return hr;
1519
1520 if (hwndStatic == NULL && hwndShlFld == NULL)
1521 return E_FAIL;
1522
1523 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStaticY));
1524 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFldY));
1525
1526 int sy = min(prc->bottom - prc->top, sizeStaticY.cy + sizeShlFldY.cy);
1527
1528 int syStatic = sizeStaticY.cy;
1529 int syShlFld = sy - syStatic;
1530
1531 if (hwndShlFld)
1532 {
1533 SetWindowPos(hwndShlFld, NULL,
1534 prc->left,
1535 prc->top,
1536 prc->right - prc->left,
1537 syShlFld,
1538 0);
1539 DWORD btnSize = SendMessage(hwndShlFld, TB_GETBUTTONSIZE, 0, 0);
1540 SendMessage(hwndShlFld, TB_SETBUTTONSIZE, 0, MAKELPARAM(prc->right - prc->left, HIWORD(btnSize)));
1541 }
1542 if (hwndStatic)
1543 {
1544 SetWindowPos(hwndStatic, hwndShlFld,
1545 prc->left,
1546 prc->top + syShlFld,
1547 prc->right - prc->left,
1548 syStatic,
1549 0);
1550 DWORD btnSize = SendMessage(hwndStatic, TB_GETBUTTONSIZE, 0, 0);
1551 SendMessage(hwndStatic, TB_SETBUTTONSIZE, 0, MAKELPARAM(prc->right - prc->left, HIWORD(btnSize)));
1552 }
1553
1554 return S_OK;
1555 }
1556
1557 HRESULT STDMETHODCALLTYPE CMenuBand::GetBandInfo(
1558 DWORD dwBandID,
1559 DWORD dwViewMode,
1560 DESKBANDINFO *pdbi)
1561 {
1562 HWND hwndStatic = NULL;
1563 HWND hwndShlFld = NULL;
1564 HRESULT hr = S_OK;
1565
1566 if (m_staticToolbar != NULL)
1567 hr = m_staticToolbar->GetWindow(&hwndStatic);
1568 if (FAILED(hr))
1569 return hr;
1570
1571 if (m_SFToolbar != NULL)
1572 hr = m_SFToolbar->GetWindow(&hwndShlFld);
1573 if (FAILED(hr))
1574 return hr;
1575
1576 if (hwndStatic == NULL && hwndShlFld == NULL)
1577 return E_FAIL;
1578
1579 // HACK (?)
1580 if (pdbi->dwMask == 0)
1581 {
1582 pdbi->dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
1583 }
1584
1585 #define MIN_WIDTH 220
1586
1587 if (pdbi->dwMask & DBIM_MINSIZE)
1588 {
1589 SIZE sizeStatic = { 0 };
1590 SIZE sizeShlFld = { 0 };
1591
1592 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStatic));
1593 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFld));
1594
1595 pdbi->ptMinSize.x = MIN_WIDTH;
1596 pdbi->ptMinSize.y = sizeStatic.cy + sizeShlFld.cy;
1597 }
1598 if (pdbi->dwMask & DBIM_MAXSIZE)
1599 {
1600 SIZE sizeStatic = { 0 };
1601 SIZE sizeShlFld = { 0 };
1602
1603 if (hwndStatic) SendMessageW(hwndStatic, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeStatic));
1604 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeShlFld));
1605
1606 pdbi->ptMaxSize.x = max(MIN_WIDTH, max(sizeStatic.cx, sizeShlFld.cx)); // ignored
1607 pdbi->ptMaxSize.y = sizeStatic.cy + sizeShlFld.cy;
1608 }
1609 if (pdbi->dwMask & DBIM_INTEGRAL)
1610 {
1611 pdbi->ptIntegral.x = 0;
1612 pdbi->ptIntegral.y = 0;
1613 }
1614 if (pdbi->dwMask & DBIM_ACTUAL)
1615 {
1616 SIZE sizeStatic = { 0 };
1617 SIZE sizeShlFld = { 0 };
1618
1619 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&sizeStatic));
1620 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&sizeShlFld));
1621 pdbi->ptActual.x = max(sizeStatic.cx, sizeShlFld.cx);
1622
1623 if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeStatic));
1624 if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast<LPARAM>(&sizeShlFld));
1625 pdbi->ptActual.y = sizeStatic.cy + sizeShlFld.cy;
1626 }
1627 if (pdbi->dwMask & DBIM_TITLE)
1628 wcscpy(pdbi->wszTitle, L"");
1629 if (pdbi->dwMask & DBIM_MODEFLAGS)
1630 pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
1631 if (pdbi->dwMask & DBIM_BKCOLOR)
1632 pdbi->crBkgnd = 0;
1633 return S_OK;
1634 }
1635
1636 /* IDockingWindow */
1637 HRESULT STDMETHODCALLTYPE CMenuBand::ShowDW(BOOL fShow)
1638 {
1639 HRESULT hr = S_OK;
1640
1641 if (m_staticToolbar != NULL)
1642 hr = m_staticToolbar->ShowWindow(fShow);
1643 if (FAILED(hr))
1644 return hr;
1645 if (m_SFToolbar != NULL)
1646 hr = m_SFToolbar->ShowWindow(fShow);
1647 if (FAILED(hr))
1648 return hr;
1649
1650 if (fShow)
1651 {
1652 hr = _CallCB(SMC_INITMENU, 0, 0);
1653 if (FAILED(hr))
1654 return hr;
1655 }
1656
1657 if (fShow)
1658 hr = m_focusManager->PushMenu(this);
1659 else
1660 hr = m_focusManager->PopMenu(this);
1661
1662 return S_OK;
1663 }
1664
1665 HRESULT STDMETHODCALLTYPE CMenuBand::CloseDW(DWORD dwReserved)
1666 {
1667 ShowDW(FALSE);
1668
1669 if (m_staticToolbar != NULL)
1670 return m_staticToolbar->Close();
1671
1672 if (m_SFToolbar != NULL)
1673 return m_SFToolbar->Close();
1674
1675 return S_OK;
1676 }
1677 HRESULT STDMETHODCALLTYPE CMenuBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
1678 {
1679 UNIMPLEMENTED;
1680 return S_OK;
1681 }
1682
1683 HRESULT STDMETHODCALLTYPE CMenuBand::ContextSensitiveHelp(BOOL fEnterMode)
1684 {
1685 UNIMPLEMENTED;
1686 return S_OK;
1687 }
1688
1689 HRESULT STDMETHODCALLTYPE CMenuBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
1690 {
1691 HRESULT hr;
1692
1693 hr = m_subMenuParent->SetSubMenu(this, fActivate);
1694 if (FAILED(hr))
1695 return hr;
1696
1697 if (fActivate)
1698 {
1699 CComPtr<IOleWindow> pTopLevelWindow;
1700 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1701 if (FAILED(hr))
1702 return hr;
1703
1704 hr = pTopLevelWindow->GetWindow(&m_topLevelWindow);
1705 if (FAILED(hr))
1706 return hr;
1707 }
1708 else
1709 {
1710 m_topLevelWindow = NULL;
1711 }
1712
1713 return S_FALSE;
1714 }
1715
1716 HRESULT STDMETHODCALLTYPE CMenuBand::HasFocusIO()
1717 {
1718 UNIMPLEMENTED;
1719 return S_OK;
1720 }
1721
1722 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg)
1723 {
1724 UNIMPLEMENTED;
1725 return S_OK;
1726 }
1727
1728 HRESULT STDMETHODCALLTYPE CMenuBand::IsDirty()
1729 {
1730 UNIMPLEMENTED;
1731 return S_OK;
1732 }
1733
1734 HRESULT STDMETHODCALLTYPE CMenuBand::Load(IStream *pStm)
1735 {
1736 UNIMPLEMENTED;
1737 return S_OK;
1738 }
1739
1740 HRESULT STDMETHODCALLTYPE CMenuBand::Save(IStream *pStm, BOOL fClearDirty)
1741 {
1742 UNIMPLEMENTED;
1743 return S_OK;
1744 }
1745
1746 HRESULT STDMETHODCALLTYPE CMenuBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
1747 {
1748 UNIMPLEMENTED;
1749 return S_OK;
1750 }
1751
1752 HRESULT STDMETHODCALLTYPE CMenuBand::GetClassID(CLSID *pClassID)
1753 {
1754 UNIMPLEMENTED;
1755 return S_OK;
1756 }
1757
1758 HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
1759 {
1760 UNIMPLEMENTED;
1761 return S_OK;
1762 }
1763
1764 HRESULT STDMETHODCALLTYPE CMenuBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1765 {
1766 if (!pguidCmdGroup)
1767 return E_FAIL;
1768
1769 if (IsEqualGUID(*pguidCmdGroup, CLSID_MenuBand))
1770 {
1771 if (nCmdID == 16) // set (big) icon size
1772 {
1773 this->m_useBigIcons = TRUE;
1774 return S_OK;
1775 }
1776 else if (nCmdID == 19) // popup-related
1777 {
1778 return S_FALSE;
1779 }
1780 }
1781
1782 UNIMPLEMENTED;
1783 return S_OK;
1784 }
1785
1786 HRESULT STDMETHODCALLTYPE CMenuBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
1787 {
1788 if (IsEqualIID(guidService, SID_SMenuBandChild) ||
1789 IsEqualIID(guidService, SID_SMenuBandBottom) ||
1790 IsEqualIID(guidService, SID_SMenuBandBottomSelected))
1791 return this->QueryInterface(riid, ppvObject);
1792 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService));
1793 return E_NOINTERFACE;
1794 }
1795
1796 HRESULT STDMETHODCALLTYPE CMenuBand::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
1797 {
1798 UNIMPLEMENTED;
1799 return S_OK;
1800 }
1801
1802 HRESULT STDMETHODCALLTYPE CMenuBand::OnSelect(DWORD dwSelectType)
1803 {
1804 switch (dwSelectType)
1805 {
1806 case MPOS_CHILDTRACKING:
1807 // TODO: Cancel timers?
1808 return m_subMenuParent->OnSelect(dwSelectType);
1809 case MPOS_SELECTLEFT:
1810 if (m_subMenuChild)
1811 m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
1812 return m_subMenuParent->OnSelect(dwSelectType);
1813 case MPOS_SELECTRIGHT:
1814 if (m_hotBar && m_hotItem >= 0)
1815 {
1816 // TODO: popup the current child if it has subitems, otherwise spread up.
1817 }
1818 return m_subMenuParent->OnSelect(dwSelectType);
1819 case MPOS_EXECUTE:
1820 case MPOS_FULLCANCEL:
1821 if (m_subMenuChild)
1822 m_subMenuChild->OnSelect(dwSelectType);
1823 return m_subMenuParent->OnSelect(dwSelectType);
1824 case MPOS_CANCELLEVEL:
1825 if (m_subMenuChild)
1826 m_subMenuChild->OnSelect(dwSelectType);
1827 break;
1828 }
1829 return S_FALSE;
1830 }
1831
1832 HRESULT STDMETHODCALLTYPE CMenuBand::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
1833 {
1834 UNIMPLEMENTED;
1835 return S_OK;
1836 }
1837
1838 HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
1839 {
1840 UNIMPLEMENTED;
1841 return S_OK;
1842 }
1843
1844 HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
1845 {
1846 // HACK, so I can test for a submenu in the DeskBar
1847 //UNIMPLEMENTED;
1848 if (ppunkClient)
1849 {
1850 if (m_subMenuChild)
1851 *ppunkClient = m_subMenuChild;
1852 else
1853 *ppunkClient = NULL;
1854 }
1855 return S_OK;
1856 }
1857
1858 HRESULT STDMETHODCALLTYPE CMenuBand::IsMenuMessage(MSG *pmsg)
1859 {
1860 //UNIMPLEMENTED;
1861 //return S_OK;
1862 return S_FALSE;
1863 //return E_NOTIMPL;
1864 }
1865
1866 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet)
1867 {
1868 //UNIMPLEMENTED;
1869 return S_FALSE;
1870 }
1871
1872 HRESULT STDMETHODCALLTYPE CMenuBand::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1873 {
1874 if (m_SFToolbar == NULL)
1875 {
1876 m_SFToolbar = new CMenuSFToolbar(this);
1877 }
1878
1879 HRESULT hr = m_SFToolbar->SetShellFolder(psf, pidlFolder, hKey, dwFlags);
1880 if (FAILED(hr))
1881 return hr;
1882
1883 if (m_site)
1884 {
1885 HWND hwndParent;
1886
1887 hr = m_site->GetWindow(&hwndParent);
1888 if (FAILED(hr))
1889 return hr;
1890
1891 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1892 if (FAILED(hr))
1893 return hr;
1894
1895 hr = m_SFToolbar->FillToolbar();
1896 }
1897
1898 return hr;
1899 }
1900
1901 HRESULT STDMETHODCALLTYPE CMenuBand::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1902 {
1903 if (m_SFToolbar)
1904 return m_SFToolbar->GetShellFolder(pdwFlags, ppidl, riid, ppv);
1905 return E_FAIL;
1906 }
1907
1908 HRESULT STDMETHODCALLTYPE CMenuBand::InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
1909 {
1910 UNIMPLEMENTED;
1911 return S_OK;
1912 }
1913
1914 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(LPSMDATA psmd)
1915 {
1916 UNIMPLEMENTED;
1917 return S_OK;
1918 }
1919
1920 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenuToolbar(IUnknown *punk, DWORD dwFlags)
1921 {
1922 UNIMPLEMENTED;
1923 return S_OK;
1924 }
1925
1926 HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1927 {
1928 *theResult = 0;
1929 switch (uMsg)
1930 {
1931 case WM_COMMAND:
1932
1933 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1934 {
1935 return m_staticToolbar->OnCommand(wParam, lParam, theResult);
1936 }
1937
1938 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1939 {
1940 return m_SFToolbar->OnCommand(wParam, lParam, theResult);
1941 }
1942
1943 return S_OK;
1944
1945 case WM_NOTIFY:
1946 NMHDR * hdr = reinterpret_cast<LPNMHDR>(lParam);
1947 NMTBCUSTOMDRAW * cdraw;
1948 NMTBHOTITEM * hot;
1949 NMMOUSE * rclick;
1950 switch (hdr->code)
1951 {
1952 case TBN_HOTITEMCHANGE:
1953 hot = reinterpret_cast<LPNMTBHOTITEM>(hdr);
1954
1955 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1956 {
1957 return m_staticToolbar->OnHotItemChange(hot);
1958 }
1959
1960 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1961 {
1962 return m_SFToolbar->OnHotItemChange(hot);
1963 }
1964
1965 return S_OK;
1966
1967 case NM_RCLICK:
1968 rclick = reinterpret_cast<LPNMMOUSE>(hdr);
1969
1970 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
1971 {
1972 return m_staticToolbar->OnContextMenu(rclick);
1973 }
1974
1975 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
1976 {
1977 return m_SFToolbar->OnContextMenu(rclick);
1978 }
1979
1980 return S_OK;
1981 case NM_CUSTOMDRAW:
1982 cdraw = reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr);
1983 switch (cdraw->nmcd.dwDrawStage)
1984 {
1985 case CDDS_PREPAINT:
1986 *theResult = CDRF_NOTIFYITEMDRAW;
1987 return S_OK;
1988
1989 case CDDS_ITEMPREPAINT:
1990
1991 cdraw->clrBtnFace = GetSysColor(COLOR_MENU);
1992 cdraw->clrBtnHighlight = GetSysColor(COLOR_MENUHILIGHT);
1993
1994 cdraw->clrText = GetSysColor(COLOR_MENUTEXT);
1995 cdraw->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
1996 cdraw->clrHighlightHotTrack = GetSysColor(COLOR_HIGHLIGHTTEXT);
1997
1998 RECT rc = cdraw->nmcd.rc;
1999 HDC hdc = cdraw->nmcd.hdc;
2000
2001 HBRUSH bgBrush = GetSysColorBrush(COLOR_MENU);
2002 HBRUSH hotBrush = GetSysColorBrush(COLOR_MENUHILIGHT);
2003
2004 switch (cdraw->nmcd.uItemState)
2005 {
2006 case CDIS_HOT:
2007 case CDIS_FOCUS:
2008 FillRect(hdc, &rc, hotBrush);
2009 break;
2010 default:
2011 FillRect(hdc, &rc, bgBrush);
2012 break;
2013 }
2014
2015 *theResult = TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOETCHEDEFFECT | TBCDRF_HILITEHOTTRACK | TBCDRF_NOOFFSET;
2016 return S_OK;
2017 }
2018 return S_OK;
2019 }
2020 return S_OK;
2021 }
2022
2023 return S_FALSE;
2024 }
2025
2026 HRESULT STDMETHODCALLTYPE CMenuBand::IsWindowOwner(HWND hWnd)
2027 {
2028 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
2029 return S_OK;
2030
2031 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
2032 return S_OK;
2033
2034 return S_FALSE;
2035 }
2036
2037 HRESULT STDMETHODCALLTYPE CMenuBand::GetSubMenu(THIS)
2038 {
2039 UNIMPLEMENTED;
2040 return S_OK;
2041 }
2042
2043 HRESULT STDMETHODCALLTYPE CMenuBand::SetToolbar(THIS)
2044 {
2045 UNIMPLEMENTED;
2046 return S_OK;
2047 }
2048
2049 HRESULT STDMETHODCALLTYPE CMenuBand::SetMinWidth(THIS)
2050 {
2051 UNIMPLEMENTED;
2052 return S_OK;
2053 }
2054
2055 HRESULT STDMETHODCALLTYPE CMenuBand::SetNoBorder(THIS)
2056 {
2057 UNIMPLEMENTED;
2058 return S_OK;
2059 }
2060
2061 HRESULT STDMETHODCALLTYPE CMenuBand::SetTheme(THIS)
2062 {
2063 UNIMPLEMENTED;
2064 return S_OK;
2065 }
2066
2067 HRESULT STDMETHODCALLTYPE CMenuBand::GetTop(THIS)
2068 {
2069 UNIMPLEMENTED;
2070 return S_OK;
2071 }
2072
2073 HRESULT STDMETHODCALLTYPE CMenuBand::GetBottom(THIS)
2074 {
2075 UNIMPLEMENTED;
2076 return S_OK;
2077 }
2078
2079 HRESULT STDMETHODCALLTYPE CMenuBand::GetTracked(THIS)
2080 {
2081 UNIMPLEMENTED;
2082 return S_OK;
2083 }
2084
2085 HRESULT STDMETHODCALLTYPE CMenuBand::GetParentSite(THIS)
2086 {
2087 UNIMPLEMENTED;
2088 return S_OK;
2089 }
2090
2091 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(THIS)
2092 {
2093 UNIMPLEMENTED;
2094 return S_OK;
2095 }
2096
2097 HRESULT STDMETHODCALLTYPE CMenuBand::DoDefaultAction(THIS)
2098 {
2099 UNIMPLEMENTED;
2100 return S_OK;
2101 }
2102
2103 HRESULT STDMETHODCALLTYPE CMenuBand::IsEmpty(THIS)
2104 {
2105 UNIMPLEMENTED;
2106 return S_OK;
2107 }
2108
2109 HRESULT CMenuBand::_CallCBWithItemId(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam)
2110 {
2111 return _CallCB(uMsg, wParam, lParam, id);
2112 }
2113
2114 HRESULT CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam)
2115 {
2116 return _CallCB(uMsg, wParam, lParam, 0, pidl);
2117 }
2118
2119 HRESULT CMenuBand::_CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id, LPITEMIDLIST pidl)
2120 {
2121 if (!m_psmc)
2122 return S_FALSE;
2123
2124 HWND hwnd;
2125 GetWindow(&hwnd);
2126
2127 SMDATA smData = { 0 };
2128 smData.punk = static_cast<IShellMenu2*>(this);
2129 smData.uId = id;
2130 smData.uIdParent = m_uId;
2131 smData.uIdAncestor = m_uIdAncestor;
2132 smData.hwnd = hwnd;
2133 smData.pidlItem = pidl;
2134 if (m_staticToolbar)
2135 {
2136 smData.hmenu = m_hmenu;
2137 }
2138 smData.pvUserData = NULL;
2139 if (m_SFToolbar)
2140 m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf));
2141 HRESULT hr = m_psmc->CallbackSM(&smData, uMsg, wParam, lParam);
2142 ILFree(smData.pidlFolder);
2143 if (smData.psf)
2144 smData.psf->Release();
2145 return hr;
2146 }
2147
2148 HRESULT CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y)
2149 {
2150 ::TrackPopupMenu(popup, 0, x, y, 0, m_menuOwner, NULL);
2151 return S_OK;
2152 }
2153
2154 HRESULT CMenuBand::_GetTopLevelWindow(HWND*topLevel)
2155 {
2156 *topLevel = m_topLevelWindow;
2157 return S_OK;
2158 }
2159
2160 HRESULT CMenuBand::_OnHotItemChanged(CMenuToolbarBase * tb, INT id)
2161 {
2162 if (m_hotBar && m_hotBar != tb)
2163 m_hotBar->ChangeHotItem(-1);
2164 m_hotBar = tb;
2165 m_hotItem = id;
2166 return S_OK;
2167 }
2168
2169 HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
2170 {
2171 HRESULT hr;
2172
2173 if (changeType == VK_DOWN)
2174 {
2175 if (m_SFToolbar && (m_hotBar == m_SFToolbar || m_hotBar == NULL))
2176 {
2177 hr = m_SFToolbar->ChangeHotItem(VK_DOWN);
2178 if (hr == S_FALSE)
2179 {
2180 if (m_staticToolbar)
2181 return m_staticToolbar->ChangeHotItem(VK_HOME);
2182 else
2183 return m_SFToolbar->ChangeHotItem(VK_HOME);
2184 }
2185 return hr;
2186 }
2187 else if (m_staticToolbar && m_hotBar == m_staticToolbar)
2188 {
2189 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2190 if (hr == S_FALSE)
2191 {
2192 if (m_SFToolbar)
2193 return m_SFToolbar->ChangeHotItem(VK_HOME);
2194 else
2195 return m_staticToolbar->ChangeHotItem(VK_HOME);
2196 }
2197 return hr;
2198 }
2199 }
2200 else if (changeType == VK_UP)
2201 {
2202 if (m_staticToolbar && (m_hotBar == m_staticToolbar || m_hotBar == NULL))
2203 {
2204 hr = m_staticToolbar->ChangeHotItem(VK_DOWN);
2205 if (hr == S_FALSE)
2206 {
2207 if (m_SFToolbar)
2208 return m_SFToolbar->ChangeHotItem(VK_END);
2209 else
2210 return m_staticToolbar->ChangeHotItem(VK_END);
2211 }
2212 return hr;
2213 }
2214 else if (m_SFToolbar && m_hotBar == m_SFToolbar)
2215 {
2216 hr = m_SFToolbar->ChangeHotItem(VK_UP);
2217 if (hr == S_FALSE)
2218 {
2219 if (m_staticToolbar)
2220 return m_staticToolbar->ChangeHotItem(VK_END);
2221 else
2222 return m_SFToolbar->ChangeHotItem(VK_END);
2223 }
2224 return hr;
2225 }
2226 }
2227 else
2228 {
2229 m_subMenuParent->OnSelect(changeType);
2230 }
2231 return S_OK;
2232 }
2233
2234 HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude)
2235 {
2236 if (m_subMenuChild)
2237 {
2238 HRESULT hr = m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
2239 if (FAILED(hr))
2240 return hr;
2241 }
2242 m_subMenuChild = popup;
2243 if (popup)
2244 {
2245 IUnknown_SetSite(popup, m_subMenuParent);
2246 popup->Popup(pAt, pExclude, MPPF_RIGHT);
2247 }
2248 return S_OK;
2249 }