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