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