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