4 * Copyright 2014 David Quintana
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.
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.
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
22 #include <shlwapi_undoc.h>
24 #define TBSTYLE_EX_VERTICAL 4
26 WINE_DEFAULT_DEBUG_CHANNEL(CMenuBand
);
28 #define TIMERID_HOTTRACK 1
29 #define SUBCLASS_ID_MENUBAND 1
31 extern "C" BOOL WINAPI
Shell_GetImageLists(HIMAGELIST
* lpBigList
, HIMAGELIST
* lpSmallList
);
34 class CMenuFocusManager
;
36 class CMenuToolbarBase
39 CMenuBand
* m_menuBand
;
43 WNDPROC m_SubclassOld
;
46 static LRESULT CALLBACK
s_SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
49 CMenuToolbarBase(CMenuBand
*menuBand
);
50 virtual ~CMenuToolbarBase() {}
52 HRESULT
IsWindowOwner(HWND hwnd
);
53 HRESULT
CreateToolbar(HWND hwndParent
, DWORD dwFlags
);
54 HRESULT
GetWindow(HWND
*phwnd
);
55 HRESULT
ShowWindow(BOOL fShow
);
58 virtual HRESULT
FillToolbar() = 0;
59 virtual HRESULT
PopupItem(UINT uItem
) = 0;
60 virtual HRESULT
HasSubMenu(UINT uItem
) = 0;
61 virtual HRESULT
OnContextMenu(NMMOUSE
* rclick
) = 0;
62 virtual HRESULT
OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
);
64 HRESULT
PopupSubMenu(UINT index
, IShellMenu
* childShellMenu
);
65 HRESULT
PopupSubMenu(UINT index
, HMENU menu
);
66 HRESULT
DoContextMenu(IContextMenu
* contextMenu
);
68 HRESULT
ChangeHotItem(DWORD changeType
);
69 HRESULT
OnHotItemChange(const NMTBHOTITEM
* hot
);
72 LRESULT CALLBACK
SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
75 class CMenuStaticToolbar
:
76 public CMenuToolbarBase
82 CMenuStaticToolbar(CMenuBand
*menuBand
);
83 virtual ~CMenuStaticToolbar() {}
85 HRESULT
SetMenu(HMENU hmenu
, HWND hwnd
, DWORD dwFlags
);
86 HRESULT
GetMenu(HMENU
*phmenu
, HWND
*phwnd
, DWORD
*pdwFlags
);
88 virtual HRESULT
FillToolbar();
89 virtual HRESULT
PopupItem(UINT uItem
);
90 virtual HRESULT
HasSubMenu(UINT uItem
);
91 virtual HRESULT
OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
);
92 virtual HRESULT
OnContextMenu(NMMOUSE
* rclick
);
96 class CMenuSFToolbar
:
97 public CMenuToolbarBase
100 IShellFolder
* m_shellFolder
;
101 LPCITEMIDLIST m_idList
;
105 CMenuSFToolbar(CMenuBand
*menuBand
);
106 virtual ~CMenuSFToolbar();
108 HRESULT
SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
);
109 HRESULT
GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
);
111 virtual HRESULT
FillToolbar();
112 virtual HRESULT
PopupItem(UINT uItem
);
113 virtual HRESULT
HasSubMenu(UINT uItem
);
114 virtual HRESULT
OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
);
115 virtual HRESULT
OnContextMenu(NMMOUSE
* rclick
);
118 LPITEMIDLIST
GetPidlFromId(UINT uItem
, INT
* pIndex
= NULL
);
122 public CComCoClass
<CMenuBand
>,
123 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
125 public IObjectWithSite
,
127 public IPersistStream
,
128 public IOleCommandTarget
,
129 public IServiceProvider
,
133 public IWinEventHandler
,
137 CMenuFocusManager
* m_focusManager
;
138 CMenuStaticToolbar
* m_staticToolbar
;
139 CMenuSFToolbar
* m_SFToolbar
;
141 CComPtr
<IOleWindow
> m_site
;
142 CComPtr
<IShellMenuCallback
> m_psmc
;
143 CComPtr
<IMenuPopup
> m_subMenuChild
;
144 CComPtr
<IMenuPopup
> m_subMenuParent
;
154 HWND m_topLevelWindow
;
156 CMenuToolbarBase
* m_hotBar
;
163 DECLARE_NOT_AGGREGATABLE(CMenuBand
)
164 DECLARE_PROTECT_FINAL_CONSTRUCT()
166 BEGIN_COM_MAP(CMenuBand
)
167 COM_INTERFACE_ENTRY_IID(IID_IDeskBar
, IMenuPopup
)
168 COM_INTERFACE_ENTRY_IID(IID_IShellMenu
, IShellMenu
)
169 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget
, IOleCommandTarget
)
170 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IDeskBand
)
171 COM_INTERFACE_ENTRY_IID(IID_IDockingWindow
, IDockingWindow
)
172 COM_INTERFACE_ENTRY_IID(IID_IDeskBand
, IDeskBand
)
173 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite
, IObjectWithSite
)
174 COM_INTERFACE_ENTRY_IID(IID_IInputObject
, IInputObject
)
175 COM_INTERFACE_ENTRY_IID(IID_IPersistStream
, IPersistStream
)
176 COM_INTERFACE_ENTRY_IID(IID_IPersist
, IPersistStream
)
177 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider
, IServiceProvider
)
178 COM_INTERFACE_ENTRY_IID(IID_IMenuPopup
, IMenuPopup
)
179 COM_INTERFACE_ENTRY_IID(IID_IMenuBand
, IMenuBand
)
180 COM_INTERFACE_ENTRY_IID(IID_IShellMenu2
, IShellMenu2
)
181 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler
, IWinEventHandler
)
182 COM_INTERFACE_ENTRY_IID(IID_IShellMenuAcc
, IShellMenuAcc
)
185 // *** IDeskBand methods ***
186 virtual HRESULT STDMETHODCALLTYPE
GetBandInfo(DWORD dwBandID
, DWORD dwViewMode
, DESKBANDINFO
*pdbi
);
188 // *** IDockingWindow methods ***
189 virtual HRESULT STDMETHODCALLTYPE
ShowDW(BOOL fShow
);
190 virtual HRESULT STDMETHODCALLTYPE
CloseDW(DWORD dwReserved
);
191 virtual HRESULT STDMETHODCALLTYPE
ResizeBorderDW(LPCRECT prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
);
193 // *** IOleWindow methods ***
194 virtual HRESULT STDMETHODCALLTYPE
GetWindow(HWND
*phwnd
);
195 virtual HRESULT STDMETHODCALLTYPE
ContextSensitiveHelp(BOOL fEnterMode
);
197 // *** IObjectWithSite methods ***
198 virtual HRESULT STDMETHODCALLTYPE
SetSite(IUnknown
*pUnkSite
);
199 virtual HRESULT STDMETHODCALLTYPE
GetSite(REFIID riid
, PVOID
*ppvSite
);
201 // *** IInputObject methods ***
202 virtual HRESULT STDMETHODCALLTYPE
UIActivateIO(BOOL fActivate
, LPMSG lpMsg
);
203 virtual HRESULT STDMETHODCALLTYPE
HasFocusIO();
204 virtual HRESULT STDMETHODCALLTYPE
TranslateAcceleratorIO(LPMSG lpMsg
);
206 // *** IPersistStream methods ***
207 virtual HRESULT STDMETHODCALLTYPE
IsDirty();
208 virtual HRESULT STDMETHODCALLTYPE
Load(IStream
*pStm
);
209 virtual HRESULT STDMETHODCALLTYPE
Save(IStream
*pStm
, BOOL fClearDirty
);
210 virtual HRESULT STDMETHODCALLTYPE
GetSizeMax(ULARGE_INTEGER
*pcbSize
);
212 // *** IPersist methods ***
213 virtual HRESULT STDMETHODCALLTYPE
GetClassID(CLSID
*pClassID
);
215 // *** IOleCommandTarget methods ***
216 virtual HRESULT STDMETHODCALLTYPE
QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
);
217 virtual HRESULT STDMETHODCALLTYPE
Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
);
219 // *** IServiceProvider methods ***
220 virtual HRESULT STDMETHODCALLTYPE
QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
);
222 // *** IMenuPopup methods ***
223 virtual HRESULT STDMETHODCALLTYPE
Popup(POINTL
*ppt
, RECTL
*prcExclude
, MP_POPUPFLAGS dwFlags
);
224 virtual HRESULT STDMETHODCALLTYPE
OnSelect(DWORD dwSelectType
);
225 virtual HRESULT STDMETHODCALLTYPE
SetSubMenu(IMenuPopup
*pmp
, BOOL fSet
);
227 // *** IDeskBar methods ***
228 virtual HRESULT STDMETHODCALLTYPE
SetClient(IUnknown
*punkClient
);
229 virtual HRESULT STDMETHODCALLTYPE
GetClient(IUnknown
**ppunkClient
);
230 virtual HRESULT STDMETHODCALLTYPE
OnPosRectChangeDB(RECT
*prc
);
232 // *** IMenuBand methods ***
233 virtual HRESULT STDMETHODCALLTYPE
IsMenuMessage(MSG
*pmsg
);
234 virtual HRESULT STDMETHODCALLTYPE
TranslateMenuMessage(MSG
*pmsg
, LRESULT
*plRet
);
236 // *** IShellMenu methods ***
237 virtual HRESULT STDMETHODCALLTYPE
Initialize(IShellMenuCallback
*psmc
, UINT uId
, UINT uIdAncestor
, DWORD dwFlags
);
238 virtual HRESULT STDMETHODCALLTYPE
GetMenuInfo(IShellMenuCallback
**ppsmc
, UINT
*puId
, UINT
*puIdAncestor
, DWORD
*pdwFlags
);
239 virtual HRESULT STDMETHODCALLTYPE
SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
);
240 virtual HRESULT STDMETHODCALLTYPE
GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
);
241 virtual HRESULT STDMETHODCALLTYPE
SetMenu(HMENU hmenu
, HWND hwnd
, DWORD dwFlags
);
242 virtual HRESULT STDMETHODCALLTYPE
GetMenu(HMENU
*phmenu
, HWND
*phwnd
, DWORD
*pdwFlags
);
243 virtual HRESULT STDMETHODCALLTYPE
InvalidateItem(LPSMDATA psmd
, DWORD dwFlags
);
244 virtual HRESULT STDMETHODCALLTYPE
GetState(LPSMDATA psmd
);
245 virtual HRESULT STDMETHODCALLTYPE
SetMenuToolbar(IUnknown
*punk
, DWORD dwFlags
);
247 // *** IWinEventHandler methods ***
248 virtual HRESULT STDMETHODCALLTYPE
OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
);
249 virtual HRESULT STDMETHODCALLTYPE
IsWindowOwner(HWND hWnd
);
251 // *** IShellMenu2 methods ***
252 virtual HRESULT STDMETHODCALLTYPE
GetSubMenu(THIS
);
253 virtual HRESULT STDMETHODCALLTYPE
SetToolbar(THIS
);
254 virtual HRESULT STDMETHODCALLTYPE
SetMinWidth(THIS
);
255 virtual HRESULT STDMETHODCALLTYPE
SetNoBorder(THIS
);
256 virtual HRESULT STDMETHODCALLTYPE
SetTheme(THIS
);
258 // *** IShellMenuAcc methods ***
259 virtual HRESULT STDMETHODCALLTYPE
GetTop(THIS
);
260 virtual HRESULT STDMETHODCALLTYPE
GetBottom(THIS
);
261 virtual HRESULT STDMETHODCALLTYPE
GetTracked(THIS
);
262 virtual HRESULT STDMETHODCALLTYPE
GetParentSite(THIS
);
263 virtual HRESULT STDMETHODCALLTYPE
GetState(THIS
);
264 virtual HRESULT STDMETHODCALLTYPE
DoDefaultAction(THIS
);
265 virtual HRESULT STDMETHODCALLTYPE
IsEmpty(THIS
);
267 HRESULT
_CallCBWithItemId(UINT Id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
268 HRESULT
_CallCBWithItemPidl(LPITEMIDLIST pidl
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
269 HRESULT
_TrackSubMenuUsingTrackPopupMenu(HMENU popup
, INT x
, INT y
);
270 HRESULT
_GetTopLevelWindow(HWND
*topLevel
);
271 HRESULT
_OnHotItemChanged(CMenuToolbarBase
* tb
, INT id
);
272 HRESULT
_MenuItemHotTrack(DWORD changeType
);
273 HRESULT
_OnPopupSubMenu(IMenuPopup
* popup
, POINTL
* pAt
, RECTL
* pExclude
);
277 return m_useBigIcons
;
281 HRESULT
_CallCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT id
= 0, LPITEMIDLIST pidl
= NULL
);
284 class CMenuFocusManager
:
285 public CComCoClass
<CMenuFocusManager
>,
286 public CComObjectRootEx
<CComMultiThreadModelNoCS
>
289 static DWORD TlsIndex
;
291 static CMenuFocusManager
* GetManager()
293 return reinterpret_cast<CMenuFocusManager
*>(TlsGetValue(TlsIndex
));
297 static CMenuFocusManager
* AcquireManager()
299 CMenuFocusManager
* obj
= NULL
;
303 if ((TlsIndex
= TlsAlloc()) == TLS_OUT_OF_INDEXES
)
311 obj
= new CComObject
<CMenuFocusManager
>();
312 TlsSetValue(TlsIndex
, obj
);
320 static void ReleaseManager(CMenuFocusManager
* obj
)
324 TlsSetValue(TlsIndex
, NULL
);
329 static LRESULT CALLBACK
s_GetMsgHook(INT nCode
, WPARAM wParam
, LPARAM lParam
)
331 return GetManager()->GetMsgHook(nCode
, wParam
, lParam
);
335 CMenuBand
* m_currentBand
;
340 // TODO: make dynamic
341 #define MAX_RECURSE 20
342 CMenuBand
* m_bandStack
[MAX_RECURSE
];
345 HRESULT
PushToArray(CMenuBand
* item
)
347 if (m_bandCount
>= MAX_RECURSE
)
348 return E_OUTOFMEMORY
;
350 m_bandStack
[m_bandCount
++] = item
;
354 HRESULT
PopFromArray(CMenuBand
** pItem
)
359 if (m_bandCount
<= 0)
365 *pItem
= m_bandStack
[m_bandCount
];
367 m_bandStack
[m_bandCount
] = NULL
;
372 HRESULT
PeekArray(CMenuBand
** pItem
)
379 if (m_bandCount
<= 0)
382 *pItem
= m_bandStack
[m_bandCount
- 1];
388 CMenuFocusManager() :
390 m_currentFocus(NULL
),
393 m_threadId
= GetCurrentThreadId();
402 DECLARE_NOT_AGGREGATABLE(CMenuFocusManager
)
403 DECLARE_PROTECT_FINAL_CONSTRUCT()
404 BEGIN_COM_MAP(CMenuFocusManager
)
407 LRESULT
GetMsgHook(INT nCode
, WPARAM wParam
, LPARAM lParam
)
410 return CallNextHookEx(m_hHook
, nCode
, wParam
, lParam
);
412 if (nCode
== HC_ACTION
)
414 BOOL callNext
= TRUE
;
415 MSG
* msg
= reinterpret_cast<MSG
*>(lParam
);
417 // Do whatever is necessary here
419 switch (msg
->message
)
430 m_currentBand
->_MenuItemHotTrack(MPOS_FULLCANCEL
);
433 m_currentBand
->_MenuItemHotTrack(MPOS_SELECTLEFT
);
436 m_currentBand
->_MenuItemHotTrack(MPOS_SELECTRIGHT
);
439 m_currentBand
->_MenuItemHotTrack(VK_UP
);
442 m_currentBand
->_MenuItemHotTrack(VK_DOWN
);
447 //if (msg->wParam >= 'a' && msg->wParam <= 'z')
450 // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam);
459 return CallNextHookEx(m_hHook
, nCode
, wParam
, lParam
);
462 HRESULT
PlaceHooks(HWND window
)
464 //SetCapture(window);
465 m_hHook
= SetWindowsHookEx(WH_GETMESSAGE
, s_GetMsgHook
, NULL
, m_threadId
);
469 HRESULT
RemoveHooks(HWND window
)
471 UnhookWindowsHookEx(m_hHook
);
476 HRESULT
UpdateFocus(CMenuBand
* newBand
)
483 hr
= RemoveHooks(m_currentFocus
);
484 m_currentFocus
= NULL
;
485 m_currentBand
= NULL
;
489 hr
= newBand
->_GetTopLevelWindow(&newFocus
);
495 hr
= PlaceHooks(newFocus
);
500 m_currentFocus
= newFocus
;
501 m_currentBand
= newBand
;
507 HRESULT
PushMenu(CMenuBand
* mb
)
511 hr
= PushToArray(mb
);
515 return UpdateFocus(mb
);
518 HRESULT
PopMenu(CMenuBand
* mb
)
523 hr
= PopFromArray(&mbc
);
530 hr
= PeekArray(&mbc
);
532 return UpdateFocus(mbc
);
536 DWORD
CMenuFocusManager::TlsIndex
= 0;
539 HRESULT
CMenuBand_Constructor(REFIID riid
, LPVOID
*ppv
)
543 CMenuBand
* site
= new CComObject
<CMenuBand
>();
546 return E_OUTOFMEMORY
;
548 HRESULT hr
= site
->QueryInterface(riid
, ppv
);
556 CMenuToolbarBase::CMenuToolbarBase(CMenuBand
*menuBand
) :
557 m_menuBand(menuBand
),
563 HRESULT
CMenuToolbarBase::IsWindowOwner(HWND hwnd
)
565 return (m_hwnd
&& m_hwnd
== hwnd
) ? S_OK
: S_FALSE
;
568 HRESULT
CMenuToolbarBase::ShowWindow(BOOL fShow
)
570 ::ShowWindow(m_hwnd
, fShow
? SW_SHOW
: SW_HIDE
);
572 HIMAGELIST ilBig
, ilSmall
;
573 Shell_GetImageLists(&ilBig
, &ilSmall
);
575 if (m_menuBand
->UseBigIcons())
577 SendMessageW(m_hwnd
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(ilBig
));
581 SendMessageW(m_hwnd
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(ilSmall
));
587 HRESULT
CMenuToolbarBase::Close()
589 DestroyWindow(m_hwnd
);
594 HRESULT
CMenuToolbarBase::CreateToolbar(HWND hwndParent
, DWORD dwFlags
)
596 LONG tbStyles
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
597 TBSTYLE_TOOLTIPS
| TBSTYLE_TRANSPARENT
| TBSTYLE_REGISTERDROP
| TBSTYLE_LIST
| TBSTYLE_FLAT
| TBSTYLE_CUSTOMERASE
|
598 CCS_NODIVIDER
| CCS_NOPARENTALIGN
| CCS_NORESIZE
| CCS_TOP
;
599 LONG tbExStyles
= TBSTYLE_EX_DOUBLEBUFFER
;
601 if (dwFlags
& SMINIT_VERTICAL
)
603 tbStyles
|= CCS_VERT
;
604 tbExStyles
|= TBSTYLE_EX_VERTICAL
| WS_EX_TOOLWINDOW
;
609 if (!::GetClientRect(hwndParent
, &rc
) || (rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
))
617 HWND hwndToolbar
= CreateWindowEx(
618 tbExStyles
, TOOLBARCLASSNAMEW
, NULL
,
619 tbStyles
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
620 hwndParent
, NULL
, _AtlBaseModule
.GetModuleInstance(), 0);
622 if (hwndToolbar
== NULL
)
625 ::SetParent(hwndToolbar
, hwndParent
);
627 m_hwnd
= hwndToolbar
;
629 /* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */
630 SendMessageW(m_hwnd
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
632 HIMAGELIST ilBig
, ilSmall
;
633 Shell_GetImageLists(&ilBig
, &ilSmall
);
635 //if (dwFlags & SMINIT_TOPLEVEL)
637 // /* Hide the placeholders for the button images */
638 // SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0);
641 if (m_menuBand
->UseBigIcons())
643 SendMessageW(m_hwnd
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(ilBig
));
647 SendMessageW(m_hwnd
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(ilSmall
));
650 SetWindowLongPtr(m_hwnd
, GWLP_USERDATA
, reinterpret_cast<LONG_PTR
>(this));
651 m_SubclassOld
= (WNDPROC
) SetWindowLongPtr(m_hwnd
, GWLP_WNDPROC
, reinterpret_cast<LONG_PTR
>(CMenuToolbarBase::s_SubclassProc
));
656 HRESULT
CMenuToolbarBase::GetWindow(HWND
*phwnd
)
666 LRESULT CALLBACK
CMenuToolbarBase::s_SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
668 CMenuToolbarBase
* pthis
= reinterpret_cast<CMenuToolbarBase
*>(GetWindowLongPtr(hWnd
, GWLP_USERDATA
));
669 return pthis
->SubclassProc(hWnd
, uMsg
, wParam
, lParam
);
672 LRESULT
CMenuToolbarBase::SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
677 if (wParam
== TIMERID_HOTTRACK
)
679 KillTimer(hWnd
, TIMERID_HOTTRACK
);
681 m_menuBand
->_OnPopupSubMenu(NULL
, NULL
, NULL
);
683 if (HasSubMenu(m_hotItem
) == S_OK
)
685 PopupItem(m_hotItem
);
690 return m_SubclassOld(hWnd
, uMsg
, wParam
, lParam
);
693 HRESULT
CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM
* hot
)
695 if (hot
->dwFlags
& HICF_LEAVING
)
697 KillTimer(m_hwnd
, TIMERID_HOTTRACK
);
699 m_menuBand
->_OnHotItemChanged(NULL
, -1);
700 m_menuBand
->_MenuItemHotTrack(MPOS_CHILDTRACKING
);
702 else if (m_hotItem
!= hot
->idNew
)
705 SystemParametersInfo(SPI_GETMENUSHOWDELAY
, 0, &elapsed
, 0);
706 SetTimer(m_hwnd
, TIMERID_HOTTRACK
, elapsed
, NULL
);
708 m_hotItem
= hot
->idNew
;
709 m_menuBand
->_OnHotItemChanged(this, m_hotItem
);
710 m_menuBand
->_MenuItemHotTrack(MPOS_CHILDTRACKING
);
715 HRESULT
CMenuToolbarBase::PopupSubMenu(UINT index
, IShellMenu
* childShellMenu
)
717 IBandSite
* pBandSite
;
723 if (!SendMessage(m_hwnd
, TB_GETITEMRECT
, index
, reinterpret_cast<LPARAM
>(&rc
)))
726 POINT a
= { rc
.left
, rc
.top
};
727 POINT b
= { rc
.right
, rc
.bottom
};
729 ClientToScreen(m_hwnd
, &a
);
730 ClientToScreen(m_hwnd
, &b
);
732 POINTL pt
= { b
.x
, a
.y
};
733 RECTL rcl
= { a
.x
, a
.y
, b
.x
, b
.y
}; // maybe-TODO: fetch client area of deskbar?
736 #if USE_SYSTEM_MENUSITE
737 hr
= CoCreateInstance(CLSID_MenuBandSite
,
739 CLSCTX_INPROC_SERVER
,
740 IID_PPV_ARG(IBandSite
, &pBandSite
));
742 hr
= CMenuSite_Constructor(IID_PPV_ARG(IBandSite
, &pBandSite
));
747 hr
= CMenuSite_Wrapper(pBandSite
, IID_PPV_ARG(IBandSite
, &pBandSite
));
752 #if USE_SYSTEM_MENUDESKBAR
753 hr
= CoCreateInstance(CLSID_MenuDeskBar
,
755 CLSCTX_INPROC_SERVER
,
756 IID_PPV_ARG(IDeskBar
, &pDeskBar
));
758 hr
= CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar
, &pDeskBar
));
763 hr
= CMenuDeskBar_Wrapper(pDeskBar
, IID_PPV_ARG(IDeskBar
, &pDeskBar
));
768 hr
= pDeskBar
->SetClient(pBandSite
);
772 hr
= pBandSite
->AddBand(childShellMenu
);
776 CComPtr
<IMenuPopup
> popup
;
777 hr
= pDeskBar
->QueryInterface(IID_PPV_ARG(IMenuPopup
, &popup
));
781 m_menuBand
->_OnPopupSubMenu(popup
, &pt
, &rcl
);
786 HRESULT
CMenuToolbarBase::PopupSubMenu(UINT index
, HMENU menu
)
790 if (!SendMessage(m_hwnd
, TB_GETITEMRECT
, index
, reinterpret_cast<LPARAM
>(&rc
)))
793 POINT b
= { rc
.right
, rc
.bottom
};
795 ClientToScreen(m_hwnd
, &b
);
797 HMENU popup
= GetSubMenu(menu
, index
);
799 m_menuBand
->_TrackSubMenuUsingTrackPopupMenu(popup
, b
.x
, b
.y
);
804 HRESULT
CMenuToolbarBase::DoContextMenu(IContextMenu
* contextMenu
)
807 HMENU hPopup
= CreatePopupMenu();
812 hr
= contextMenu
->QueryContextMenu(hPopup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
819 DWORD dwPos
= GetMessagePos();
820 UINT uCommand
= ::TrackPopupMenu(hPopup
, TPM_RETURNCMD
, GET_X_LPARAM(dwPos
), GET_Y_LPARAM(dwPos
), 0, m_hwnd
, NULL
);
824 CMINVOKECOMMANDINFO cmi
= { 0 };
825 cmi
.cbSize
= sizeof(cmi
);
826 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
828 hr
= contextMenu
->InvokeCommand(&cmi
);
834 HRESULT
CMenuToolbarBase::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
837 return m_menuBand
->_MenuItemHotTrack(MPOS_EXECUTE
);
841 HRESULT
CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType
)
843 int prev
= m_hotItem
;
846 if (dwSelectType
!= 0xFFFFFFFF)
848 int count
= SendMessage(m_hwnd
, TB_BUTTONCOUNT
, 0, 0);
852 TBBUTTONINFO info
= { 0 };
853 info
.cbSize
= sizeof(TBBUTTONINFO
);
855 index
= SendMessage(m_hwnd
, TB_GETBUTTONINFO
, m_hotItem
, reinterpret_cast<LPARAM
>(&info
));
858 if (dwSelectType
== VK_HOME
)
861 dwSelectType
= VK_DOWN
;
863 else if (dwSelectType
== VK_END
)
866 dwSelectType
= VK_UP
;
870 if (dwSelectType
== VK_UP
)
874 else if (dwSelectType
== VK_DOWN
)
881 if (dwSelectType
== VK_UP
)
885 else if (dwSelectType
== VK_DOWN
)
891 TBBUTTON btn
= { 0 };
892 while (index
>= 0 && index
< count
)
894 DWORD res
= SendMessage(m_hwnd
, TB_GETBUTTON
, index
, reinterpret_cast<LPARAM
>(&btn
));
900 m_hotItem
= btn
.idCommand
;
901 if (prev
!= m_hotItem
)
903 SendMessage(m_hwnd
, TB_SETHOTITEM
, index
, 0);
904 return m_menuBand
->_OnHotItemChanged(this, m_hotItem
);
909 if (dwSelectType
== VK_UP
)
913 else if (dwSelectType
== VK_DOWN
)
921 if (prev
!= m_hotItem
)
923 SendMessage(m_hwnd
, TB_SETHOTITEM
, -1, 0);
924 m_menuBand
->_OnHotItemChanged(NULL
, -1);
930 AllocAndGetMenuString(HMENU hMenu
, UINT ItemIDByPosition
, WCHAR
** String
)
934 Length
= GetMenuStringW(hMenu
, ItemIDByPosition
, NULL
, 0, MF_BYPOSITION
);
939 /* Also allocate space for the terminating NULL character */
941 *String
= (PWSTR
) HeapAlloc(GetProcessHeap(), 0, Length
* sizeof(WCHAR
));
943 GetMenuStringW(hMenu
, ItemIDByPosition
, *String
, Length
, MF_BYPOSITION
);
948 CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand
*menuBand
) :
949 CMenuToolbarBase(menuBand
),
954 HRESULT
CMenuStaticToolbar::GetMenu(
961 *pdwFlags
= m_dwMenuFlags
;
966 HRESULT
CMenuStaticToolbar::SetMenu(
972 m_dwMenuFlags
= dwFlags
;
977 HRESULT
CMenuStaticToolbar::FillToolbar()
980 int ic
= GetMenuItemCount(m_hmenu
);
982 for (i
= 0; i
< ic
; i
++)
985 TBBUTTON tbb
= { 0 };
986 PWSTR MenuString
= NULL
;
988 tbb
.fsState
= TBSTATE_ENABLED
;
991 info
.cbSize
= sizeof(info
);
992 info
.fMask
= MIIM_FTYPE
| MIIM_ID
;
994 GetMenuItemInfoW(m_hmenu
, i
, TRUE
, &info
);
996 if (info
.fType
== MFT_STRING
)
998 if (!AllocAndGetMenuString(m_hmenu
, i
, &MenuString
))
999 return E_OUTOFMEMORY
;
1000 if (::GetSubMenu(m_hmenu
, i
) != NULL
)
1001 tbb
.fsStyle
|= BTNS_DROPDOWN
;
1002 tbb
.iString
= (INT_PTR
) MenuString
;
1003 tbb
.idCommand
= info
.wID
;
1005 SMINFO
* sminfo
= new SMINFO();
1006 sminfo
->dwMask
= SMIM_ICON
| SMIM_FLAGS
;
1007 if (SUCCEEDED(m_menuBand
->_CallCBWithItemId(info
.wID
, SMC_GETINFO
, 0, reinterpret_cast<LPARAM
>(sminfo
))))
1009 tbb
.iBitmap
= sminfo
->iIcon
;
1010 tbb
.dwData
= reinterpret_cast<DWORD_PTR
>(sminfo
);
1011 // FIXME: remove before deleting the toolbar or it will leak
1016 tbb
.fsStyle
|= BTNS_SEP
;
1019 SendMessageW(m_hwnd
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
1022 HeapFree(GetProcessHeap(), 0, MenuString
);
1028 HRESULT
CMenuStaticToolbar::OnContextMenu(NMMOUSE
* rclick
)
1030 CComPtr
<IContextMenu
> contextMenu
;
1031 HRESULT hr
= m_menuBand
->_CallCBWithItemId(rclick
->dwItemSpec
, SMC_GETOBJECT
, reinterpret_cast<WPARAM
>(&IID_IContextMenu
), reinterpret_cast<LPARAM
>(&contextMenu
));
1035 return DoContextMenu(contextMenu
);
1038 HRESULT
CMenuStaticToolbar::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
1041 hr
= CMenuToolbarBase::OnCommand(wParam
, lParam
, theResult
);
1045 return m_menuBand
->_CallCBWithItemId(wParam
, SMC_EXEC
, 0, 0);
1048 HRESULT
CMenuStaticToolbar::PopupItem(UINT uItem
)
1050 TBBUTTONINFO info
= { 0 };
1051 info
.cbSize
= sizeof(TBBUTTONINFO
);
1053 int index
= SendMessage(m_hwnd
, TB_GETBUTTONINFO
, uItem
, reinterpret_cast<LPARAM
>(&info
));
1057 TBBUTTON btn
= { 0 };
1058 SendMessage(m_hwnd
, TB_GETBUTTON
, index
, reinterpret_cast<LPARAM
>(&btn
));
1060 SMINFO
* nfo
= reinterpret_cast<SMINFO
*>(btn
.dwData
);
1064 if (nfo
->dwFlags
&SMIF_TRACKPOPUP
)
1066 return PopupSubMenu(index
, m_hmenu
);
1070 CComPtr
<IShellMenu
> shellMenu
;
1071 HRESULT hr
= m_menuBand
->_CallCBWithItemId(uItem
, SMC_GETOBJECT
, reinterpret_cast<WPARAM
>(&IID_IShellMenu
), reinterpret_cast<LPARAM
>(&shellMenu
));
1075 return PopupSubMenu(index
, shellMenu
);
1079 HRESULT
CMenuStaticToolbar::HasSubMenu(UINT uItem
)
1081 TBBUTTONINFO info
= { 0 };
1082 info
.cbSize
= sizeof(TBBUTTONINFO
);
1084 int index
= SendMessage(m_hwnd
, TB_GETBUTTONINFO
, uItem
, reinterpret_cast<LPARAM
>(&info
));
1087 return ::GetSubMenu(m_hmenu
, index
) ? S_OK
: S_FALSE
;
1090 CMenuSFToolbar::CMenuSFToolbar(CMenuBand
* menuBand
) :
1091 CMenuToolbarBase(menuBand
),
1096 CMenuSFToolbar::~CMenuSFToolbar()
1100 HRESULT
CMenuSFToolbar::FillToolbar()
1107 m_shellFolder
->EnumObjects(m_hwnd
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
, &eidl
);
1109 LPITEMIDLIST item
= static_cast<LPITEMIDLIST
>(CoTaskMemAlloc(sizeof(ITEMIDLIST
)));
1111 while ((hr
= eidl
->Next(1, &item
, &fetched
)) == S_OK
)
1116 TBBUTTON tbb
= { 0 };
1117 tbb
.fsState
= TBSTATE_ENABLED
;
1120 CComPtr
<IShellItem
> psi
;
1121 hr
= SHCreateShellItem(NULL
, m_shellFolder
, item
, &psi
);
1125 hr
= psi
->GetDisplayName(SIGDN_NORMALDISPLAY
, &MenuString
);
1129 index
= SHMapPIDLToSystemImageListIndex(m_shellFolder
, item
, &indexOpen
);
1132 hr
= psi
->GetAttributes(SFGAO_FOLDER
, &attrs
);
1136 tbb
.fsStyle
|= BTNS_DROPDOWN
;
1139 tbb
.idCommand
= ++i
;
1140 tbb
.iString
= (INT_PTR
) MenuString
;
1141 tbb
.iBitmap
= index
;
1142 tbb
.dwData
= reinterpret_cast<DWORD_PTR
>(ILClone(item
));
1143 // FIXME: remove before deleting the toolbar or it will leak
1145 SendMessageW(m_hwnd
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
1146 HeapFree(GetProcessHeap(), 0, MenuString
);
1149 CoTaskMemFree(item
);
1151 // If no items were added, show the "empty" placeholder
1154 TBBUTTON tbb
= { 0 };
1155 PCWSTR MenuString
= L
"(Empty)";
1157 tbb
.fsState
= 0/*TBSTATE_DISABLED*/;
1159 tbb
.iString
= (INT_PTR
) MenuString
;
1162 SendMessageW(m_hwnd
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
1170 HRESULT
CMenuSFToolbar::SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
)
1172 m_shellFolder
= psf
;
1173 m_idList
= pidlFolder
;
1175 m_dwMenuFlags
= dwFlags
;
1179 HRESULT
CMenuSFToolbar::GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
)
1183 hr
= m_shellFolder
->QueryInterface(riid
, ppv
);
1188 *pdwFlags
= m_dwMenuFlags
;
1192 LPITEMIDLIST pidl
= NULL
;
1196 pidl
= ILClone(m_idList
);
1199 (*(IUnknown
**) ppv
)->Release();
1210 LPITEMIDLIST
CMenuSFToolbar::GetPidlFromId(UINT uItem
, INT
* pIndex
)
1212 TBBUTTONINFO info
= { 0 };
1213 info
.cbSize
= sizeof(TBBUTTONINFO
);
1215 int index
= SendMessage(m_hwnd
, TB_GETBUTTONINFO
, uItem
, reinterpret_cast<LPARAM
>(&info
));
1222 TBBUTTON btn
= { 0 };
1223 if (!SendMessage(m_hwnd
, TB_GETBUTTON
, index
, reinterpret_cast<LPARAM
>(&btn
)))
1226 return reinterpret_cast<LPITEMIDLIST
>(btn
.dwData
);
1229 HRESULT
CMenuSFToolbar::OnContextMenu(NMMOUSE
* rclick
)
1232 CComPtr
<IContextMenu
> contextMenu
;
1233 LPCITEMIDLIST pidl
= reinterpret_cast<LPCITEMIDLIST
>(rclick
->dwItemData
);
1235 hr
= m_shellFolder
->GetUIObjectOf(m_hwnd
, 1, &pidl
, IID_IContextMenu
, NULL
, reinterpret_cast<VOID
**>(&contextMenu
));
1239 return DoContextMenu(contextMenu
);
1242 HRESULT
CMenuSFToolbar::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
1245 hr
= CMenuToolbarBase::OnCommand(wParam
, lParam
, theResult
);
1249 return m_menuBand
->_CallCBWithItemPidl(GetPidlFromId(wParam
), SMC_SFEXEC
, 0, 0);
1252 HRESULT
CMenuSFToolbar::PopupItem(UINT uItem
)
1259 CComPtr
<IShellMenuCallback
> psmc
;
1260 CComPtr
<IShellMenu
> shellMenu
;
1262 LPITEMIDLIST pidl
= GetPidlFromId(uItem
, &index
);
1267 #if USE_SYSTEM_MENUBAND
1268 hr
= CoCreateInstance(CLSID_MenuBand
,
1270 CLSCTX_INPROC_SERVER
,
1271 IID_PPV_ARG(IShellMenu
, &shellMenu
));
1273 hr
= CMenuBand_Constructor(IID_PPV_ARG(IShellMenu
, &shellMenu
));
1278 hr
= CMenuBand_Wrapper(shellMenu
, IID_PPV_ARG(IShellMenu
, &shellMenu
));
1283 m_menuBand
->GetMenuInfo(&psmc
, &uId
, &uIdAncestor
, &flags
);
1285 // FIXME: not sure waht to use as uId/uIdAncestor here
1286 hr
= shellMenu
->Initialize(psmc
, 0, uId
, SMINIT_VERTICAL
);
1290 CComPtr
<IShellFolder
> childFolder
;
1291 hr
= m_shellFolder
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &childFolder
));
1295 hr
= shellMenu
->SetShellFolder(childFolder
, NULL
, NULL
, 0);
1299 return PopupSubMenu(index
, shellMenu
);
1302 HRESULT
CMenuSFToolbar::HasSubMenu(UINT uItem
)
1305 CComPtr
<IShellItem
> psi
;
1306 hr
= SHCreateShellItem(NULL
, m_shellFolder
, GetPidlFromId(uItem
), &psi
);
1311 hr
= psi
->GetAttributes(SFGAO_FOLDER
, &attrs
);
1315 return (attrs
!= 0) ? S_OK
: S_FALSE
;
1318 CMenuBand::CMenuBand() :
1319 m_staticToolbar(NULL
),
1323 m_subMenuChild(NULL
),
1324 m_useBigIcons(FALSE
),
1328 m_focusManager
= CMenuFocusManager::AcquireManager();
1331 CMenuBand::~CMenuBand()
1333 CMenuFocusManager::ReleaseManager(m_focusManager
);
1335 if (m_staticToolbar
)
1336 delete m_staticToolbar
;
1342 HRESULT STDMETHODCALLTYPE
CMenuBand::Initialize(
1343 IShellMenuCallback
*psmc
,
1351 m_uIdAncestor
= uIdAncestor
;
1352 m_dwFlags
= dwFlags
;
1356 _CallCB(SMC_CREATE
, 0, reinterpret_cast<LPARAM
>(&m_UserData
));
1362 HRESULT STDMETHODCALLTYPE
CMenuBand::GetMenuInfo(
1363 IShellMenuCallback
**ppsmc
,
1368 if (!pdwFlags
) // maybe?
1369 return E_INVALIDARG
;
1378 *puIdAncestor
= m_uIdAncestor
;
1380 *pdwFlags
= m_dwFlags
;
1385 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMenu(
1390 if (m_staticToolbar
== NULL
)
1392 m_staticToolbar
= new CMenuStaticToolbar(this);
1397 HRESULT hr
= m_staticToolbar
->SetMenu(hmenu
, hwnd
, dwFlags
);
1405 hr
= m_site
->GetWindow(&hwndParent
);
1409 hr
= m_staticToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
1413 hr
= m_staticToolbar
->FillToolbar();
1419 HRESULT STDMETHODCALLTYPE
CMenuBand::GetMenu(
1424 if (m_staticToolbar
== NULL
)
1427 return m_staticToolbar
->GetMenu(phmenu
, phwnd
, pdwFlags
);
1430 HRESULT STDMETHODCALLTYPE
CMenuBand::SetSite(IUnknown
*pUnkSite
)
1437 if (pUnkSite
== NULL
)
1441 hr
= pUnkSite
->QueryInterface(IID_PPV_ARG(IOleWindow
, &m_site
));
1445 hr
= m_site
->GetWindow(&hwndParent
);
1449 if (!::IsWindow(hwndParent
))
1452 if (m_staticToolbar
!= NULL
)
1454 hr
= m_staticToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
1458 hr
= m_staticToolbar
->FillToolbar();
1463 if (m_SFToolbar
!= NULL
)
1465 hr
= m_SFToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
1469 hr
= m_SFToolbar
->FillToolbar();
1474 hr
= IUnknown_QueryService(m_site
, SID_SMenuPopup
, IID_PPV_ARG(IMenuPopup
, &m_subMenuParent
));
1478 CComPtr
<IOleWindow
> pTopLevelWindow
;
1479 hr
= IUnknown_QueryService(m_site
, SID_STopLevelBrowser
, IID_PPV_ARG(IOleWindow
, &pTopLevelWindow
));
1483 return pTopLevelWindow
->GetWindow(&m_topLevelWindow
);
1486 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSite(REFIID riid
, PVOID
*ppvSite
)
1491 return m_site
->QueryInterface(riid
, ppvSite
);
1494 HRESULT STDMETHODCALLTYPE
CMenuBand::GetWindow(
1497 if (m_SFToolbar
!= NULL
)
1498 return m_SFToolbar
->GetWindow(phwnd
);
1500 if (m_staticToolbar
!= NULL
)
1501 return m_staticToolbar
->GetWindow(phwnd
);
1506 HRESULT STDMETHODCALLTYPE
CMenuBand::OnPosRectChangeDB(RECT
*prc
)
1508 SIZE sizeStaticY
= { 0 };
1509 SIZE sizeShlFldY
= { 0 };
1510 HWND hwndStatic
= NULL
;
1511 HWND hwndShlFld
= NULL
;
1514 if (m_staticToolbar
!= NULL
)
1515 hr
= m_staticToolbar
->GetWindow(&hwndStatic
);
1519 if (m_SFToolbar
!= NULL
)
1520 hr
= m_SFToolbar
->GetWindow(&hwndShlFld
);
1524 if (hwndStatic
== NULL
&& hwndShlFld
== NULL
)
1527 if (hwndStatic
) SendMessageW(hwndStatic
, TB_GETIDEALSIZE
, TRUE
, reinterpret_cast<LPARAM
>(&sizeStaticY
));
1528 if (hwndShlFld
) SendMessageW(hwndShlFld
, TB_GETIDEALSIZE
, TRUE
, reinterpret_cast<LPARAM
>(&sizeShlFldY
));
1530 int sy
= min(prc
->bottom
- prc
->top
, sizeStaticY
.cy
+ sizeShlFldY
.cy
);
1532 int syStatic
= sizeStaticY
.cy
;
1533 int syShlFld
= sy
- syStatic
;
1537 SetWindowPos(hwndShlFld
, NULL
,
1540 prc
->right
- prc
->left
,
1543 DWORD btnSize
= SendMessage(hwndShlFld
, TB_GETBUTTONSIZE
, 0, 0);
1544 SendMessage(hwndShlFld
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(prc
->right
- prc
->left
, HIWORD(btnSize
)));
1548 SetWindowPos(hwndStatic
, hwndShlFld
,
1550 prc
->top
+ syShlFld
,
1551 prc
->right
- prc
->left
,
1554 DWORD btnSize
= SendMessage(hwndStatic
, TB_GETBUTTONSIZE
, 0, 0);
1555 SendMessage(hwndStatic
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(prc
->right
- prc
->left
, HIWORD(btnSize
)));
1561 HRESULT STDMETHODCALLTYPE
CMenuBand::GetBandInfo(
1566 HWND hwndStatic
= NULL
;
1567 HWND hwndShlFld
= NULL
;
1570 if (m_staticToolbar
!= NULL
)
1571 hr
= m_staticToolbar
->GetWindow(&hwndStatic
);
1575 if (m_SFToolbar
!= NULL
)
1576 hr
= m_SFToolbar
->GetWindow(&hwndShlFld
);
1580 if (hwndStatic
== NULL
&& hwndShlFld
== NULL
)
1584 if (pdbi
->dwMask
== 0)
1586 pdbi
->dwMask
= DBIM_MINSIZE
| DBIM_MAXSIZE
| DBIM_INTEGRAL
| DBIM_ACTUAL
| DBIM_TITLE
| DBIM_MODEFLAGS
| DBIM_BKCOLOR
;
1589 #define MIN_WIDTH 220
1591 if (pdbi
->dwMask
& DBIM_MINSIZE
)
1593 SIZE sizeStatic
= { 0 };
1594 SIZE sizeShlFld
= { 0 };
1596 if (hwndStatic
) SendMessageW(hwndStatic
, TB_GETIDEALSIZE
, TRUE
, reinterpret_cast<LPARAM
>(&sizeStatic
));
1597 if (hwndShlFld
) SendMessageW(hwndShlFld
, TB_GETIDEALSIZE
, TRUE
, reinterpret_cast<LPARAM
>(&sizeShlFld
));
1599 pdbi
->ptMinSize
.x
= MIN_WIDTH
;
1600 pdbi
->ptMinSize
.y
= sizeStatic
.cy
+ sizeShlFld
.cy
;
1602 if (pdbi
->dwMask
& DBIM_MAXSIZE
)
1604 SIZE sizeStatic
= { 0 };
1605 SIZE sizeShlFld
= { 0 };
1607 if (hwndStatic
) SendMessageW(hwndStatic
, TB_GETMAXSIZE
, 0, reinterpret_cast<LPARAM
>(&sizeStatic
));
1608 if (hwndShlFld
) SendMessageW(hwndShlFld
, TB_GETMAXSIZE
, 0, reinterpret_cast<LPARAM
>(&sizeShlFld
));
1610 pdbi
->ptMaxSize
.x
= max(MIN_WIDTH
, max(sizeStatic
.cx
, sizeShlFld
.cx
)); // ignored
1611 pdbi
->ptMaxSize
.y
= sizeStatic
.cy
+ sizeShlFld
.cy
;
1613 if (pdbi
->dwMask
& DBIM_INTEGRAL
)
1615 pdbi
->ptIntegral
.x
= 0;
1616 pdbi
->ptIntegral
.y
= 0;
1618 if (pdbi
->dwMask
& DBIM_ACTUAL
)
1620 SIZE sizeStatic
= { 0 };
1621 SIZE sizeShlFld
= { 0 };
1623 if (hwndStatic
) SendMessageW(hwndStatic
, TB_GETIDEALSIZE
, FALSE
, reinterpret_cast<LPARAM
>(&sizeStatic
));
1624 if (hwndShlFld
) SendMessageW(hwndShlFld
, TB_GETIDEALSIZE
, FALSE
, reinterpret_cast<LPARAM
>(&sizeShlFld
));
1625 pdbi
->ptActual
.x
= max(sizeStatic
.cx
, sizeShlFld
.cx
);
1627 if (hwndStatic
) SendMessageW(hwndStatic
, TB_GETIDEALSIZE
, TRUE
, reinterpret_cast<LPARAM
>(&sizeStatic
));
1628 if (hwndShlFld
) SendMessageW(hwndShlFld
, TB_GETIDEALSIZE
, TRUE
, reinterpret_cast<LPARAM
>(&sizeShlFld
));
1629 pdbi
->ptActual
.y
= sizeStatic
.cy
+ sizeShlFld
.cy
;
1631 if (pdbi
->dwMask
& DBIM_TITLE
)
1632 wcscpy(pdbi
->wszTitle
, L
"");
1633 if (pdbi
->dwMask
& DBIM_MODEFLAGS
)
1634 pdbi
->dwModeFlags
= DBIMF_UNDELETEABLE
;
1635 if (pdbi
->dwMask
& DBIM_BKCOLOR
)
1640 /* IDockingWindow */
1641 HRESULT STDMETHODCALLTYPE
CMenuBand::ShowDW(BOOL fShow
)
1645 if (m_staticToolbar
!= NULL
)
1646 hr
= m_staticToolbar
->ShowWindow(fShow
);
1649 if (m_SFToolbar
!= NULL
)
1650 hr
= m_SFToolbar
->ShowWindow(fShow
);
1656 hr
= _CallCB(SMC_INITMENU
, 0, 0);
1662 hr
= m_focusManager
->PushMenu(this);
1664 hr
= m_focusManager
->PopMenu(this);
1669 HRESULT STDMETHODCALLTYPE
CMenuBand::CloseDW(DWORD dwReserved
)
1673 if (m_staticToolbar
!= NULL
)
1674 return m_staticToolbar
->Close();
1676 if (m_SFToolbar
!= NULL
)
1677 return m_SFToolbar
->Close();
1681 HRESULT STDMETHODCALLTYPE
CMenuBand::ResizeBorderDW(LPCRECT prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
)
1687 HRESULT STDMETHODCALLTYPE
CMenuBand::ContextSensitiveHelp(BOOL fEnterMode
)
1693 HRESULT STDMETHODCALLTYPE
CMenuBand::UIActivateIO(BOOL fActivate
, LPMSG lpMsg
)
1697 hr
= m_subMenuParent
->SetSubMenu(this, fActivate
);
1703 CComPtr
<IOleWindow
> pTopLevelWindow
;
1704 hr
= IUnknown_QueryService(m_site
, SID_SMenuPopup
, IID_PPV_ARG(IOleWindow
, &pTopLevelWindow
));
1708 hr
= pTopLevelWindow
->GetWindow(&m_topLevelWindow
);
1714 m_topLevelWindow
= NULL
;
1720 HRESULT STDMETHODCALLTYPE
CMenuBand::HasFocusIO()
1726 HRESULT STDMETHODCALLTYPE
CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg
)
1732 HRESULT STDMETHODCALLTYPE
CMenuBand::IsDirty()
1738 HRESULT STDMETHODCALLTYPE
CMenuBand::Load(IStream
*pStm
)
1744 HRESULT STDMETHODCALLTYPE
CMenuBand::Save(IStream
*pStm
, BOOL fClearDirty
)
1750 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSizeMax(ULARGE_INTEGER
*pcbSize
)
1756 HRESULT STDMETHODCALLTYPE
CMenuBand::GetClassID(CLSID
*pClassID
)
1762 HRESULT STDMETHODCALLTYPE
CMenuBand::QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
1768 HRESULT STDMETHODCALLTYPE
CMenuBand::Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
1773 if (IsEqualGUID(*pguidCmdGroup
, CLSID_MenuBand
))
1775 if (nCmdID
== 16) // set (big) icon size
1777 this->m_useBigIcons
= TRUE
;
1780 else if (nCmdID
== 19) // popup-related
1790 HRESULT STDMETHODCALLTYPE
CMenuBand::QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
)
1792 if (IsEqualIID(guidService
, SID_SMenuBandChild
) ||
1793 IsEqualIID(guidService
, SID_SMenuBandBottom
) ||
1794 IsEqualIID(guidService
, SID_SMenuBandBottomSelected
))
1795 return this->QueryInterface(riid
, ppvObject
);
1796 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService
));
1797 return E_NOINTERFACE
;
1800 HRESULT STDMETHODCALLTYPE
CMenuBand::Popup(POINTL
*ppt
, RECTL
*prcExclude
, MP_POPUPFLAGS dwFlags
)
1806 HRESULT STDMETHODCALLTYPE
CMenuBand::OnSelect(DWORD dwSelectType
)
1808 switch (dwSelectType
)
1810 case MPOS_CHILDTRACKING
:
1811 // TODO: Cancel timers?
1812 return m_subMenuParent
->OnSelect(dwSelectType
);
1813 case MPOS_SELECTLEFT
:
1815 m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
1816 return m_subMenuParent
->OnSelect(dwSelectType
);
1817 case MPOS_SELECTRIGHT
:
1818 if (m_hotBar
&& m_hotItem
>= 0)
1820 // TODO: popup the current child if it has subitems, otherwise spread up.
1822 return m_subMenuParent
->OnSelect(dwSelectType
);
1824 case MPOS_FULLCANCEL
:
1826 m_subMenuChild
->OnSelect(dwSelectType
);
1827 return m_subMenuParent
->OnSelect(dwSelectType
);
1828 case MPOS_CANCELLEVEL
:
1830 m_subMenuChild
->OnSelect(dwSelectType
);
1836 HRESULT STDMETHODCALLTYPE
CMenuBand::SetSubMenu(IMenuPopup
*pmp
, BOOL fSet
)
1842 HRESULT STDMETHODCALLTYPE
CMenuBand::SetClient(IUnknown
*punkClient
)
1848 HRESULT STDMETHODCALLTYPE
CMenuBand::GetClient(IUnknown
**ppunkClient
)
1850 // HACK, so I can test for a submenu in the DeskBar
1855 *ppunkClient
= m_subMenuChild
;
1857 *ppunkClient
= NULL
;
1862 HRESULT STDMETHODCALLTYPE
CMenuBand::IsMenuMessage(MSG
*pmsg
)
1870 HRESULT STDMETHODCALLTYPE
CMenuBand::TranslateMenuMessage(MSG
*pmsg
, LRESULT
*plRet
)
1876 HRESULT STDMETHODCALLTYPE
CMenuBand::SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
)
1878 if (m_SFToolbar
== NULL
)
1880 m_SFToolbar
= new CMenuSFToolbar(this);
1883 HRESULT hr
= m_SFToolbar
->SetShellFolder(psf
, pidlFolder
, hKey
, dwFlags
);
1891 hr
= m_site
->GetWindow(&hwndParent
);
1895 hr
= m_SFToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
1899 hr
= m_SFToolbar
->FillToolbar();
1905 HRESULT STDMETHODCALLTYPE
CMenuBand::GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
)
1908 return m_SFToolbar
->GetShellFolder(pdwFlags
, ppidl
, riid
, ppv
);
1912 HRESULT STDMETHODCALLTYPE
CMenuBand::InvalidateItem(LPSMDATA psmd
, DWORD dwFlags
)
1918 HRESULT STDMETHODCALLTYPE
CMenuBand::GetState(LPSMDATA psmd
)
1924 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMenuToolbar(IUnknown
*punk
, DWORD dwFlags
)
1930 HRESULT STDMETHODCALLTYPE
CMenuBand::OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
1937 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
1939 return m_staticToolbar
->OnCommand(wParam
, lParam
, theResult
);
1942 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
1944 return m_SFToolbar
->OnCommand(wParam
, lParam
, theResult
);
1950 NMHDR
* hdr
= reinterpret_cast<LPNMHDR
>(lParam
);
1951 NMTBCUSTOMDRAW
* cdraw
;
1956 case TBN_HOTITEMCHANGE
:
1957 hot
= reinterpret_cast<LPNMTBHOTITEM
>(hdr
);
1959 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
1961 return m_staticToolbar
->OnHotItemChange(hot
);
1964 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
1966 return m_SFToolbar
->OnHotItemChange(hot
);
1972 rclick
= reinterpret_cast<LPNMMOUSE
>(hdr
);
1974 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
1976 return m_staticToolbar
->OnContextMenu(rclick
);
1979 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
1981 return m_SFToolbar
->OnContextMenu(rclick
);
1986 cdraw
= reinterpret_cast<LPNMTBCUSTOMDRAW
>(hdr
);
1987 switch (cdraw
->nmcd
.dwDrawStage
)
1990 *theResult
= CDRF_NOTIFYITEMDRAW
;
1993 case CDDS_ITEMPREPAINT
:
1995 cdraw
->clrBtnFace
= GetSysColor(COLOR_MENU
);
1996 cdraw
->clrBtnHighlight
= GetSysColor(COLOR_MENUHILIGHT
);
1998 cdraw
->clrText
= GetSysColor(COLOR_MENUTEXT
);
1999 cdraw
->clrTextHighlight
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
2000 cdraw
->clrHighlightHotTrack
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
2002 RECT rc
= cdraw
->nmcd
.rc
;
2003 HDC hdc
= cdraw
->nmcd
.hdc
;
2005 HBRUSH bgBrush
= GetSysColorBrush(COLOR_MENU
);
2006 HBRUSH hotBrush
= GetSysColorBrush(COLOR_MENUHILIGHT
);
2008 switch (cdraw
->nmcd
.uItemState
)
2012 FillRect(hdc
, &rc
, hotBrush
);
2015 FillRect(hdc
, &rc
, bgBrush
);
2019 *theResult
= TBCDRF_NOBACKGROUND
| TBCDRF_NOEDGES
| TBCDRF_NOETCHEDEFFECT
| TBCDRF_HILITEHOTTRACK
| TBCDRF_NOOFFSET
;
2030 HRESULT STDMETHODCALLTYPE
CMenuBand::IsWindowOwner(HWND hWnd
)
2032 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2035 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2041 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSubMenu(THIS
)
2047 HRESULT STDMETHODCALLTYPE
CMenuBand::SetToolbar(THIS
)
2053 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMinWidth(THIS
)
2059 HRESULT STDMETHODCALLTYPE
CMenuBand::SetNoBorder(THIS
)
2065 HRESULT STDMETHODCALLTYPE
CMenuBand::SetTheme(THIS
)
2071 HRESULT STDMETHODCALLTYPE
CMenuBand::GetTop(THIS
)
2077 HRESULT STDMETHODCALLTYPE
CMenuBand::GetBottom(THIS
)
2083 HRESULT STDMETHODCALLTYPE
CMenuBand::GetTracked(THIS
)
2089 HRESULT STDMETHODCALLTYPE
CMenuBand::GetParentSite(THIS
)
2095 HRESULT STDMETHODCALLTYPE
CMenuBand::GetState(THIS
)
2101 HRESULT STDMETHODCALLTYPE
CMenuBand::DoDefaultAction(THIS
)
2107 HRESULT STDMETHODCALLTYPE
CMenuBand::IsEmpty(THIS
)
2113 HRESULT
CMenuBand::_CallCBWithItemId(UINT id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
2115 return _CallCB(uMsg
, wParam
, lParam
, id
);
2118 HRESULT
CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
2120 return _CallCB(uMsg
, wParam
, lParam
, 0, pidl
);
2123 HRESULT
CMenuBand::_CallCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT id
, LPITEMIDLIST pidl
)
2131 SMDATA smData
= { 0 };
2132 smData
.punk
= static_cast<IShellMenu2
*>(this);
2134 smData
.uIdParent
= m_uId
;
2135 smData
.uIdAncestor
= m_uIdAncestor
;
2137 smData
.pidlItem
= pidl
;
2138 if (m_staticToolbar
)
2140 smData
.hmenu
= m_hmenu
;
2142 smData
.pvUserData
= NULL
;
2144 m_SFToolbar
->GetShellFolder(NULL
, &smData
.pidlFolder
, IID_PPV_ARG(IShellFolder
, &smData
.psf
));
2145 HRESULT hr
= m_psmc
->CallbackSM(&smData
, uMsg
, wParam
, lParam
);
2146 ILFree(smData
.pidlFolder
);
2148 smData
.psf
->Release();
2152 HRESULT
CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup
, INT x
, INT y
)
2154 ::TrackPopupMenu(popup
, 0, x
, y
, 0, m_menuOwner
, NULL
);
2158 HRESULT
CMenuBand::_GetTopLevelWindow(HWND
*topLevel
)
2160 *topLevel
= m_topLevelWindow
;
2164 HRESULT
CMenuBand::_OnHotItemChanged(CMenuToolbarBase
* tb
, INT id
)
2166 if (m_hotBar
&& m_hotBar
!= tb
)
2167 m_hotBar
->ChangeHotItem(-1);
2173 HRESULT
CMenuBand::_MenuItemHotTrack(DWORD changeType
)
2177 if (changeType
== VK_DOWN
)
2179 if (m_SFToolbar
&& (m_hotBar
== m_SFToolbar
|| m_hotBar
== NULL
))
2181 hr
= m_SFToolbar
->ChangeHotItem(VK_DOWN
);
2184 if (m_staticToolbar
)
2185 return m_staticToolbar
->ChangeHotItem(VK_HOME
);
2187 return m_SFToolbar
->ChangeHotItem(VK_HOME
);
2191 else if (m_staticToolbar
&& m_hotBar
== m_staticToolbar
)
2193 hr
= m_staticToolbar
->ChangeHotItem(VK_DOWN
);
2197 return m_SFToolbar
->ChangeHotItem(VK_HOME
);
2199 return m_staticToolbar
->ChangeHotItem(VK_HOME
);
2204 else if (changeType
== VK_UP
)
2206 if (m_staticToolbar
&& (m_hotBar
== m_staticToolbar
|| m_hotBar
== NULL
))
2208 hr
= m_staticToolbar
->ChangeHotItem(VK_DOWN
);
2212 return m_SFToolbar
->ChangeHotItem(VK_END
);
2214 return m_staticToolbar
->ChangeHotItem(VK_END
);
2218 else if (m_SFToolbar
&& m_hotBar
== m_SFToolbar
)
2220 hr
= m_SFToolbar
->ChangeHotItem(VK_UP
);
2223 if (m_staticToolbar
)
2224 return m_staticToolbar
->ChangeHotItem(VK_END
);
2226 return m_SFToolbar
->ChangeHotItem(VK_END
);
2233 m_subMenuParent
->OnSelect(changeType
);
2238 HRESULT
CMenuBand::_OnPopupSubMenu(IMenuPopup
* popup
, POINTL
* pAt
, RECTL
* pExclude
)
2242 HRESULT hr
= m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
2246 m_subMenuChild
= popup
;
2249 IUnknown_SetSite(popup
, m_subMenuParent
);
2250 popup
->Popup(pAt
, pExclude
, MPPF_RIGHT
);