[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 HRESULT hr;
1293
1294 CComPtr<IMenuPopup> pmp;
1295
1296 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp));
1297 if (FAILED(hr))
1298 return hr;
1299
1300 hr = pmp->SetSubMenu(this, TRUE);
1301 if (FAILED(hr))
1302 return hr;
1303
1304 CComPtr<IOleWindow> pTopLevelWindow;
1305 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
1306 if (FAILED(hr))
1307 return hr;
1308
1309 hr = pTopLevelWindow->GetWindow(&m_topLevelWindow);
1310 if (FAILED(hr))
1311 return hr;
1312
1313 return S_FALSE;
1314 }
1315
1316 HRESULT STDMETHODCALLTYPE CMenuBand::HasFocusIO()
1317 {
1318 UNIMPLEMENTED;
1319 return S_OK;
1320 }
1321
1322 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg)
1323 {
1324 UNIMPLEMENTED;
1325 return S_OK;
1326 }
1327
1328 HRESULT STDMETHODCALLTYPE CMenuBand::IsDirty()
1329 {
1330 UNIMPLEMENTED;
1331 return S_OK;
1332 }
1333
1334 HRESULT STDMETHODCALLTYPE CMenuBand::Load(IStream *pStm)
1335 {
1336 UNIMPLEMENTED;
1337 return S_OK;
1338 }
1339
1340 HRESULT STDMETHODCALLTYPE CMenuBand::Save(IStream *pStm, BOOL fClearDirty)
1341 {
1342 UNIMPLEMENTED;
1343 return S_OK;
1344 }
1345
1346 HRESULT STDMETHODCALLTYPE CMenuBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
1347 {
1348 UNIMPLEMENTED;
1349 return S_OK;
1350 }
1351
1352 HRESULT STDMETHODCALLTYPE CMenuBand::GetClassID(CLSID *pClassID)
1353 {
1354 UNIMPLEMENTED;
1355 return S_OK;
1356 }
1357
1358 HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
1359 {
1360 UNIMPLEMENTED;
1361 return S_OK;
1362 }
1363
1364 HRESULT STDMETHODCALLTYPE CMenuBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1365 {
1366 if (!pguidCmdGroup)
1367 return E_FAIL;
1368
1369 if (IsEqualGUID(*pguidCmdGroup, CLSID_MenuBand))
1370 {
1371 if (nCmdID == 16) // set (big) icon size
1372 {
1373 this->m_useBigIcons = TRUE;
1374 return S_OK;
1375 }
1376 else if (nCmdID == 19) // popup-related
1377 {
1378 return S_FALSE;
1379 }
1380 }
1381
1382 UNIMPLEMENTED;
1383 return S_OK;
1384 }
1385
1386 HRESULT STDMETHODCALLTYPE CMenuBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
1387 {
1388 if (IsEqualIID(guidService, SID_SMenuBandChild) ||
1389 IsEqualIID(guidService, SID_SMenuBandBottom) ||
1390 IsEqualIID(guidService, SID_SMenuBandBottomSelected))
1391 return this->QueryInterface(riid, ppvObject);
1392 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService));
1393 return E_NOINTERFACE;
1394 }
1395
1396 HRESULT STDMETHODCALLTYPE CMenuBand::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
1397 {
1398 UNIMPLEMENTED;
1399 return S_OK;
1400 }
1401
1402 HRESULT STDMETHODCALLTYPE CMenuBand::OnSelect(DWORD dwSelectType)
1403 {
1404 CComPtr<IMenuPopup> pmp;
1405 HRESULT hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp));
1406 if (FAILED(hr))
1407 return hr;
1408 pmp->OnSelect(dwSelectType);
1409 return S_OK;
1410 }
1411
1412 HRESULT STDMETHODCALLTYPE CMenuBand::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
1413 {
1414 UNIMPLEMENTED;
1415 return S_OK;
1416 }
1417
1418 HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
1419 {
1420 UNIMPLEMENTED;
1421 return S_OK;
1422 }
1423
1424 HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
1425 {
1426 UNIMPLEMENTED;
1427 return S_OK;
1428 }
1429
1430 HRESULT STDMETHODCALLTYPE CMenuBand::IsMenuMessage(MSG *pmsg)
1431 {
1432 //UNIMPLEMENTED;
1433 //return S_OK;
1434 return S_FALSE;
1435 //return E_NOTIMPL;
1436 }
1437
1438 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet)
1439 {
1440 //UNIMPLEMENTED;
1441 return S_FALSE;
1442 }
1443
1444 HRESULT STDMETHODCALLTYPE CMenuBand::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
1445 {
1446 if (m_SFToolbar == NULL)
1447 {
1448 m_SFToolbar = new CMenuSFToolbar(this);
1449 }
1450
1451 HRESULT hr = m_SFToolbar->SetShellFolder(psf, pidlFolder, hKey, dwFlags);
1452 if (FAILED(hr))
1453 return hr;
1454
1455 if (m_site)
1456 {
1457 HWND hwndParent;
1458
1459 hr = m_site->GetWindow(&hwndParent);
1460 if (FAILED(hr))
1461 return hr;
1462
1463 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
1464 if (FAILED(hr))
1465 return hr;
1466
1467 hr = m_SFToolbar->FillToolbar();
1468 }
1469
1470 return hr;
1471 }
1472
1473 HRESULT STDMETHODCALLTYPE CMenuBand::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
1474 {
1475 if (m_SFToolbar)
1476 return m_SFToolbar->GetShellFolder(pdwFlags, ppidl, riid, ppv);
1477 return E_FAIL;
1478 }
1479
1480 HRESULT STDMETHODCALLTYPE CMenuBand::InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
1481 {
1482 UNIMPLEMENTED;
1483 return S_OK;
1484 }
1485
1486 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(LPSMDATA psmd)
1487 {
1488 UNIMPLEMENTED;
1489 return S_OK;
1490 }
1491
1492 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenuToolbar(IUnknown *punk, DWORD dwFlags)
1493 {
1494 UNIMPLEMENTED;
1495 return S_OK;
1496 }
1497
1498 HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
1499 {
1500 *theResult = 0;
1501 switch (uMsg)
1502 {
1503 case WM_COMMAND:
1504
1505 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd))
1506 {
1507 return m_staticToolbar->OnCommand(wParam, lParam, theResult);
1508 }
1509
1510 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd))
1511 {
1512 return m_SFToolbar->OnCommand(wParam, lParam, theResult);
1513 }
1514
1515 return S_OK;
1516
1517 case WM_NOTIFY:
1518 NMHDR * hdr = reinterpret_cast<LPNMHDR>(lParam);
1519 NMTBCUSTOMDRAW * cdraw;
1520 NMTBHOTITEM * hot;
1521 NMMOUSE * rclick;
1522 switch (hdr->code)
1523 {
1524 case TBN_HOTITEMCHANGE:
1525 hot = reinterpret_cast<LPNMTBHOTITEM>(hdr);
1526
1527 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd))
1528 {
1529 return m_staticToolbar->OnHotItemChange(hot);
1530 }
1531
1532 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd))
1533 {
1534 return m_SFToolbar->OnHotItemChange(hot);
1535 }
1536
1537 return S_OK;
1538
1539 case NM_RCLICK:
1540 rclick = reinterpret_cast<LPNMMOUSE>(hdr);
1541
1542 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd))
1543 {
1544 return m_staticToolbar->OnContextMenu(rclick);
1545 }
1546
1547 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd))
1548 {
1549 return m_SFToolbar->OnContextMenu(rclick);
1550 }
1551
1552 return S_OK;
1553 case NM_CUSTOMDRAW:
1554 cdraw = reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr);
1555 switch (cdraw->nmcd.dwDrawStage)
1556 {
1557 case CDDS_PREPAINT:
1558 *theResult = CDRF_NOTIFYITEMDRAW;
1559 return S_OK;
1560
1561 case CDDS_ITEMPREPAINT:
1562
1563 cdraw->clrBtnFace = GetSysColor(COLOR_MENU);
1564 cdraw->clrBtnHighlight = GetSysColor(COLOR_MENUHILIGHT);
1565
1566 cdraw->clrText = GetSysColor(COLOR_MENUTEXT);
1567 cdraw->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
1568 cdraw->clrHighlightHotTrack = GetSysColor(COLOR_HIGHLIGHTTEXT);
1569
1570 RECT rc = cdraw->nmcd.rc;
1571 HDC hdc = cdraw->nmcd.hdc;
1572
1573 HBRUSH bgBrush = GetSysColorBrush(COLOR_MENU);
1574 HBRUSH hotBrush = GetSysColorBrush(COLOR_MENUHILIGHT);
1575
1576 switch (cdraw->nmcd.uItemState)
1577 {
1578 case CDIS_HOT:
1579 case CDIS_FOCUS:
1580 FillRect(hdc, &rc, hotBrush);
1581 break;
1582 default:
1583 FillRect(hdc, &rc, bgBrush);
1584 break;
1585 }
1586
1587 *theResult = TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOETCHEDEFFECT | TBCDRF_HILITEHOTTRACK | TBCDRF_NOOFFSET;
1588 return S_OK;
1589 }
1590 return S_OK;
1591 }
1592 return S_OK;
1593 }
1594
1595 return S_FALSE;
1596 }
1597
1598 HRESULT STDMETHODCALLTYPE CMenuBand::IsWindowOwner(HWND hWnd)
1599 {
1600 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd))
1601 return S_OK;
1602
1603 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd))
1604 return S_OK;
1605
1606 return S_FALSE;
1607 }
1608
1609 HRESULT STDMETHODCALLTYPE CMenuBand::GetSubMenu(THIS)
1610 {
1611 UNIMPLEMENTED;
1612 return S_OK;
1613 }
1614
1615 HRESULT STDMETHODCALLTYPE CMenuBand::SetToolbar(THIS)
1616 {
1617 UNIMPLEMENTED;
1618 return S_OK;
1619 }
1620
1621 HRESULT STDMETHODCALLTYPE CMenuBand::SetMinWidth(THIS)
1622 {
1623 UNIMPLEMENTED;
1624 return S_OK;
1625 }
1626
1627 HRESULT STDMETHODCALLTYPE CMenuBand::SetNoBorder(THIS)
1628 {
1629 UNIMPLEMENTED;
1630 return S_OK;
1631 }
1632
1633 HRESULT STDMETHODCALLTYPE CMenuBand::SetTheme(THIS)
1634 {
1635 UNIMPLEMENTED;
1636 return S_OK;
1637 }
1638
1639 HRESULT STDMETHODCALLTYPE CMenuBand::GetTop(THIS)
1640 {
1641 UNIMPLEMENTED;
1642 return S_OK;
1643 }
1644
1645 HRESULT STDMETHODCALLTYPE CMenuBand::GetBottom(THIS)
1646 {
1647 UNIMPLEMENTED;
1648 return S_OK;
1649 }
1650
1651 HRESULT STDMETHODCALLTYPE CMenuBand::GetTracked(THIS)
1652 {
1653 UNIMPLEMENTED;
1654 return S_OK;
1655 }
1656
1657 HRESULT STDMETHODCALLTYPE CMenuBand::GetParentSite(THIS)
1658 {
1659 UNIMPLEMENTED;
1660 return S_OK;
1661 }
1662
1663 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(THIS)
1664 {
1665 UNIMPLEMENTED;
1666 return S_OK;
1667 }
1668
1669 HRESULT STDMETHODCALLTYPE CMenuBand::DoDefaultAction(THIS)
1670 {
1671 UNIMPLEMENTED;
1672 return S_OK;
1673 }
1674
1675 HRESULT STDMETHODCALLTYPE CMenuBand::IsEmpty(THIS)
1676 {
1677 UNIMPLEMENTED;
1678 return S_OK;
1679 }
1680
1681 HRESULT CMenuBand::CallCBWithId(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam)
1682 {
1683 return _CallCB(uMsg, wParam, lParam, id);
1684 }
1685
1686 HRESULT CMenuBand::CallCBWithPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam)
1687 {
1688 return _CallCB(uMsg, wParam, lParam, 0, pidl);
1689 }
1690
1691 HRESULT CMenuBand::_CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id, LPITEMIDLIST pidl)
1692 {
1693 if (!m_psmc)
1694 return S_FALSE;
1695
1696 HWND hwnd;
1697 GetWindow(&hwnd);
1698
1699 SMDATA smData = { 0 };
1700 smData.punk = static_cast<IShellMenu2*>(this);
1701 smData.uId = id;
1702 smData.uIdParent = m_uId;
1703 smData.uIdAncestor = m_uIdAncestor;
1704 smData.hwnd = hwnd;
1705 smData.pidlItem = pidl;
1706 if (m_staticToolbar)
1707 {
1708 smData.hmenu = m_hmenu;
1709 }
1710 smData.pvUserData = NULL;
1711 if (m_SFToolbar)
1712 m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf));
1713 HRESULT hr = m_psmc->CallbackSM(&smData, uMsg, wParam, lParam);
1714 ILFree(smData.pidlFolder);
1715 if (smData.psf)
1716 smData.psf->Release();
1717 return hr;
1718 }
1719
1720 HRESULT CMenuBand::TrackPopup(HMENU popup, INT x, INT y)
1721 {
1722 ::TrackPopupMenu(popup, 0, x, y, 0, m_menuOwner, NULL);
1723 return S_OK;
1724 }