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 <CommonControls.h>
23 #include <shlwapi_undoc.h>
26 HRESULT WINAPI
SHGetImageList(
33 #define TBSTYLE_EX_VERTICAL 4
35 WINE_DEFAULT_DEBUG_CHANNEL(CMenuBand
);
37 #define TIMERID_HOTTRACK 1
38 #define SUBCLASS_ID_MENUBAND 1
40 extern "C" BOOL WINAPI
Shell_GetImageLists(HIMAGELIST
* lpBigList
, HIMAGELIST
* lpSmallList
);
43 class CMenuFocusManager
;
45 class CMenuToolbarBase
48 HWND m_hwnd
; // May be the pager
51 CMenuBand
* m_menuBand
;
55 WNDPROC m_SubclassOld
;
61 static LRESULT CALLBACK
s_SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
64 CMenuToolbarBase(CMenuBand
*menuBand
, BOOL usePager
);
65 virtual ~CMenuToolbarBase() {}
67 HRESULT
IsWindowOwner(HWND hwnd
);
68 HRESULT
CreateToolbar(HWND hwndParent
, DWORD dwFlags
);
69 HRESULT
GetWindow(HWND
*phwnd
);
70 HRESULT
ShowWindow(BOOL fShow
);
73 virtual HRESULT
FillToolbar() = 0;
74 virtual HRESULT
PopupItem(UINT uItem
) = 0;
75 virtual HRESULT
HasSubMenu(UINT uItem
) = 0;
76 virtual HRESULT
OnContextMenu(NMMOUSE
* rclick
) = 0;
77 virtual HRESULT
OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
);
79 HRESULT
PopupSubMenu(UINT itemId
, UINT index
, IShellMenu
* childShellMenu
);
80 HRESULT
PopupSubMenu(UINT index
, HMENU menu
);
81 HRESULT
DoContextMenu(IContextMenu
* contextMenu
);
83 HRESULT
ChangeHotItem(DWORD changeType
);
84 HRESULT
OnHotItemChange(const NMTBHOTITEM
* hot
);
86 HRESULT
GetIdealSize(SIZE
& size
);
87 HRESULT
SetPosSize(int x
, int y
, int cx
, int cy
);
89 void InvalidateDraw();
92 LRESULT CALLBACK
SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
95 class CMenuStaticToolbar
:
96 public CMenuToolbarBase
102 CMenuStaticToolbar(CMenuBand
*menuBand
);
103 virtual ~CMenuStaticToolbar() {}
105 HRESULT
SetMenu(HMENU hmenu
, HWND hwnd
, DWORD dwFlags
);
106 HRESULT
GetMenu(HMENU
*phmenu
, HWND
*phwnd
, DWORD
*pdwFlags
);
108 virtual HRESULT
FillToolbar();
109 virtual HRESULT
PopupItem(UINT uItem
);
110 virtual HRESULT
HasSubMenu(UINT uItem
);
111 virtual HRESULT
OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
);
112 virtual HRESULT
OnContextMenu(NMMOUSE
* rclick
);
116 class CMenuSFToolbar
:
117 public CMenuToolbarBase
120 IShellFolder
* m_shellFolder
;
121 LPCITEMIDLIST m_idList
;
125 CMenuSFToolbar(CMenuBand
*menuBand
);
126 virtual ~CMenuSFToolbar();
128 HRESULT
SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
);
129 HRESULT
GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
);
131 virtual HRESULT
FillToolbar();
132 virtual HRESULT
PopupItem(UINT uItem
);
133 virtual HRESULT
HasSubMenu(UINT uItem
);
134 virtual HRESULT
OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
);
135 virtual HRESULT
OnContextMenu(NMMOUSE
* rclick
);
138 LPITEMIDLIST
GetPidlFromId(UINT uItem
, INT
* pIndex
= NULL
);
142 public CComCoClass
<CMenuBand
>,
143 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
145 public IObjectWithSite
,
147 public IPersistStream
,
148 public IOleCommandTarget
,
149 public IServiceProvider
,
153 public IWinEventHandler
,
157 CMenuFocusManager
* m_focusManager
;
158 CMenuStaticToolbar
* m_staticToolbar
;
159 CMenuSFToolbar
* m_SFToolbar
;
161 CComPtr
<IOleWindow
> m_site
;
162 CComPtr
<IShellMenuCallback
> m_psmc
;
163 CComPtr
<IMenuPopup
> m_subMenuChild
;
164 CComPtr
<IMenuPopup
> m_subMenuParent
;
174 HWND m_topLevelWindow
;
176 CMenuToolbarBase
* m_hotBar
;
186 DECLARE_NOT_AGGREGATABLE(CMenuBand
)
187 DECLARE_PROTECT_FINAL_CONSTRUCT()
189 BEGIN_COM_MAP(CMenuBand
)
190 COM_INTERFACE_ENTRY_IID(IID_IDeskBar
, IMenuPopup
)
191 COM_INTERFACE_ENTRY_IID(IID_IShellMenu
, IShellMenu
)
192 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget
, IOleCommandTarget
)
193 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IDeskBand
)
194 COM_INTERFACE_ENTRY_IID(IID_IDockingWindow
, IDockingWindow
)
195 COM_INTERFACE_ENTRY_IID(IID_IDeskBand
, IDeskBand
)
196 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite
, IObjectWithSite
)
197 COM_INTERFACE_ENTRY_IID(IID_IInputObject
, IInputObject
)
198 COM_INTERFACE_ENTRY_IID(IID_IPersistStream
, IPersistStream
)
199 COM_INTERFACE_ENTRY_IID(IID_IPersist
, IPersistStream
)
200 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider
, IServiceProvider
)
201 COM_INTERFACE_ENTRY_IID(IID_IMenuPopup
, IMenuPopup
)
202 COM_INTERFACE_ENTRY_IID(IID_IMenuBand
, IMenuBand
)
203 COM_INTERFACE_ENTRY_IID(IID_IShellMenu2
, IShellMenu2
)
204 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler
, IWinEventHandler
)
205 COM_INTERFACE_ENTRY_IID(IID_IShellMenuAcc
, IShellMenuAcc
)
208 // *** IDeskBand methods ***
209 virtual HRESULT STDMETHODCALLTYPE
GetBandInfo(DWORD dwBandID
, DWORD dwViewMode
, DESKBANDINFO
*pdbi
);
211 // *** IDockingWindow methods ***
212 virtual HRESULT STDMETHODCALLTYPE
ShowDW(BOOL fShow
);
213 virtual HRESULT STDMETHODCALLTYPE
CloseDW(DWORD dwReserved
);
214 virtual HRESULT STDMETHODCALLTYPE
ResizeBorderDW(LPCRECT prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
);
216 // *** IOleWindow methods ***
217 virtual HRESULT STDMETHODCALLTYPE
GetWindow(HWND
*phwnd
);
218 virtual HRESULT STDMETHODCALLTYPE
ContextSensitiveHelp(BOOL fEnterMode
);
220 // *** IObjectWithSite methods ***
221 virtual HRESULT STDMETHODCALLTYPE
SetSite(IUnknown
*pUnkSite
);
222 virtual HRESULT STDMETHODCALLTYPE
GetSite(REFIID riid
, PVOID
*ppvSite
);
224 // *** IInputObject methods ***
225 virtual HRESULT STDMETHODCALLTYPE
UIActivateIO(BOOL fActivate
, LPMSG lpMsg
);
226 virtual HRESULT STDMETHODCALLTYPE
HasFocusIO();
227 virtual HRESULT STDMETHODCALLTYPE
TranslateAcceleratorIO(LPMSG lpMsg
);
229 // *** IPersistStream methods ***
230 virtual HRESULT STDMETHODCALLTYPE
IsDirty();
231 virtual HRESULT STDMETHODCALLTYPE
Load(IStream
*pStm
);
232 virtual HRESULT STDMETHODCALLTYPE
Save(IStream
*pStm
, BOOL fClearDirty
);
233 virtual HRESULT STDMETHODCALLTYPE
GetSizeMax(ULARGE_INTEGER
*pcbSize
);
235 // *** IPersist methods ***
236 virtual HRESULT STDMETHODCALLTYPE
GetClassID(CLSID
*pClassID
);
238 // *** IOleCommandTarget methods ***
239 virtual HRESULT STDMETHODCALLTYPE
QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
);
240 virtual HRESULT STDMETHODCALLTYPE
Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
);
242 // *** IServiceProvider methods ***
243 virtual HRESULT STDMETHODCALLTYPE
QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
);
245 // *** IMenuPopup methods ***
246 virtual HRESULT STDMETHODCALLTYPE
Popup(POINTL
*ppt
, RECTL
*prcExclude
, MP_POPUPFLAGS dwFlags
);
247 virtual HRESULT STDMETHODCALLTYPE
OnSelect(DWORD dwSelectType
);
248 virtual HRESULT STDMETHODCALLTYPE
SetSubMenu(IMenuPopup
*pmp
, BOOL fSet
);
250 // *** IDeskBar methods ***
251 virtual HRESULT STDMETHODCALLTYPE
SetClient(IUnknown
*punkClient
);
252 virtual HRESULT STDMETHODCALLTYPE
GetClient(IUnknown
**ppunkClient
);
253 virtual HRESULT STDMETHODCALLTYPE
OnPosRectChangeDB(RECT
*prc
);
255 // *** IMenuBand methods ***
256 virtual HRESULT STDMETHODCALLTYPE
IsMenuMessage(MSG
*pmsg
);
257 virtual HRESULT STDMETHODCALLTYPE
TranslateMenuMessage(MSG
*pmsg
, LRESULT
*plRet
);
259 // *** IShellMenu methods ***
260 virtual HRESULT STDMETHODCALLTYPE
Initialize(IShellMenuCallback
*psmc
, UINT uId
, UINT uIdAncestor
, DWORD dwFlags
);
261 virtual HRESULT STDMETHODCALLTYPE
GetMenuInfo(IShellMenuCallback
**ppsmc
, UINT
*puId
, UINT
*puIdAncestor
, DWORD
*pdwFlags
);
262 virtual HRESULT STDMETHODCALLTYPE
SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
);
263 virtual HRESULT STDMETHODCALLTYPE
GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
);
264 virtual HRESULT STDMETHODCALLTYPE
SetMenu(HMENU hmenu
, HWND hwnd
, DWORD dwFlags
);
265 virtual HRESULT STDMETHODCALLTYPE
GetMenu(HMENU
*phmenu
, HWND
*phwnd
, DWORD
*pdwFlags
);
266 virtual HRESULT STDMETHODCALLTYPE
InvalidateItem(LPSMDATA psmd
, DWORD dwFlags
);
267 virtual HRESULT STDMETHODCALLTYPE
GetState(LPSMDATA psmd
);
268 virtual HRESULT STDMETHODCALLTYPE
SetMenuToolbar(IUnknown
*punk
, DWORD dwFlags
);
270 // *** IWinEventHandler methods ***
271 virtual HRESULT STDMETHODCALLTYPE
OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
);
272 virtual HRESULT STDMETHODCALLTYPE
IsWindowOwner(HWND hWnd
);
274 // *** IShellMenu2 methods ***
275 virtual HRESULT STDMETHODCALLTYPE
GetSubMenu(THIS
);
276 virtual HRESULT STDMETHODCALLTYPE
SetToolbar(THIS
);
277 virtual HRESULT STDMETHODCALLTYPE
SetMinWidth(THIS
);
278 virtual HRESULT STDMETHODCALLTYPE
SetNoBorder(THIS
);
279 virtual HRESULT STDMETHODCALLTYPE
SetTheme(THIS
);
281 // *** IShellMenuAcc methods ***
282 virtual HRESULT STDMETHODCALLTYPE
GetTop(THIS
);
283 virtual HRESULT STDMETHODCALLTYPE
GetBottom(THIS
);
284 virtual HRESULT STDMETHODCALLTYPE
GetTracked(THIS
);
285 virtual HRESULT STDMETHODCALLTYPE
GetParentSite(THIS
);
286 virtual HRESULT STDMETHODCALLTYPE
GetState(THIS
);
287 virtual HRESULT STDMETHODCALLTYPE
DoDefaultAction(THIS
);
288 virtual HRESULT STDMETHODCALLTYPE
IsEmpty(THIS
);
290 HRESULT
_CallCBWithItemId(UINT Id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
291 HRESULT
_CallCBWithItemPidl(LPITEMIDLIST pidl
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
292 HRESULT
_TrackSubMenuUsingTrackPopupMenu(HMENU popup
, INT x
, INT y
);
293 HRESULT
_GetTopLevelWindow(HWND
*topLevel
);
294 HRESULT
_OnHotItemChanged(CMenuToolbarBase
* tb
, INT id
);
295 HRESULT
_MenuItemHotTrack(DWORD changeType
);
296 HRESULT
_OnPopupSubMenu(INT popupItem
, IMenuPopup
* popup
, POINTL
* pAt
, RECTL
* pExclude
);
300 return m_useBigIcons
;
304 HRESULT
_CallCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT id
= 0, LPITEMIDLIST pidl
= NULL
);
307 class CMenuFocusManager
:
308 public CComCoClass
<CMenuFocusManager
>,
309 public CComObjectRootEx
<CComMultiThreadModelNoCS
>
312 static DWORD TlsIndex
;
314 static CMenuFocusManager
* GetManager()
316 return reinterpret_cast<CMenuFocusManager
*>(TlsGetValue(TlsIndex
));
320 static CMenuFocusManager
* AcquireManager()
322 CMenuFocusManager
* obj
= NULL
;
326 if ((TlsIndex
= TlsAlloc()) == TLS_OUT_OF_INDEXES
)
334 obj
= new CComObject
<CMenuFocusManager
>();
335 TlsSetValue(TlsIndex
, obj
);
343 static void ReleaseManager(CMenuFocusManager
* obj
)
347 TlsSetValue(TlsIndex
, NULL
);
352 static LRESULT CALLBACK
s_GetMsgHook(INT nCode
, WPARAM wParam
, LPARAM lParam
)
354 return GetManager()->GetMsgHook(nCode
, wParam
, lParam
);
358 CMenuBand
* m_currentBand
;
363 // TODO: make dynamic
364 #define MAX_RECURSE 20
365 CMenuBand
* m_bandStack
[MAX_RECURSE
];
368 HRESULT
PushToArray(CMenuBand
* item
)
370 if (m_bandCount
>= MAX_RECURSE
)
371 return E_OUTOFMEMORY
;
373 m_bandStack
[m_bandCount
++] = item
;
377 HRESULT
PopFromArray(CMenuBand
** pItem
)
382 if (m_bandCount
<= 0)
388 *pItem
= m_bandStack
[m_bandCount
];
390 m_bandStack
[m_bandCount
] = NULL
;
395 HRESULT
PeekArray(CMenuBand
** pItem
)
402 if (m_bandCount
<= 0)
405 *pItem
= m_bandStack
[m_bandCount
- 1];
411 CMenuFocusManager() :
413 m_currentFocus(NULL
),
416 m_threadId
= GetCurrentThreadId();
425 DECLARE_NOT_AGGREGATABLE(CMenuFocusManager
)
426 DECLARE_PROTECT_FINAL_CONSTRUCT()
427 BEGIN_COM_MAP(CMenuFocusManager
)
430 LRESULT
GetMsgHook(INT nCode
, WPARAM wParam
, LPARAM lParam
)
433 return CallNextHookEx(m_hHook
, nCode
, wParam
, lParam
);
435 if (nCode
== HC_ACTION
)
437 BOOL callNext
= TRUE
;
438 MSG
* msg
= reinterpret_cast<MSG
*>(lParam
);
440 // Do whatever is necessary here
442 switch (msg
->message
)
453 m_currentBand
->_MenuItemHotTrack(MPOS_FULLCANCEL
);
456 m_currentBand
->_MenuItemHotTrack(MPOS_SELECTLEFT
);
459 m_currentBand
->_MenuItemHotTrack(MPOS_SELECTRIGHT
);
462 m_currentBand
->_MenuItemHotTrack(VK_UP
);
465 m_currentBand
->_MenuItemHotTrack(VK_DOWN
);
470 //if (msg->wParam >= 'a' && msg->wParam <= 'z')
473 // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam);
482 return CallNextHookEx(m_hHook
, nCode
, wParam
, lParam
);
485 HRESULT
PlaceHooks(HWND window
)
487 //SetCapture(window);
488 m_hHook
= SetWindowsHookEx(WH_GETMESSAGE
, s_GetMsgHook
, NULL
, m_threadId
);
492 HRESULT
RemoveHooks(HWND window
)
494 UnhookWindowsHookEx(m_hHook
);
499 HRESULT
UpdateFocus(CMenuBand
* newBand
)
506 hr
= RemoveHooks(m_currentFocus
);
507 m_currentFocus
= NULL
;
508 m_currentBand
= NULL
;
512 hr
= newBand
->_GetTopLevelWindow(&newFocus
);
518 hr
= PlaceHooks(newFocus
);
523 m_currentFocus
= newFocus
;
524 m_currentBand
= newBand
;
530 HRESULT
PushMenu(CMenuBand
* mb
)
534 hr
= PushToArray(mb
);
538 return UpdateFocus(mb
);
541 HRESULT
PopMenu(CMenuBand
* mb
)
546 hr
= PopFromArray(&mbc
);
553 hr
= PeekArray(&mbc
);
555 return UpdateFocus(mbc
);
559 DWORD
CMenuFocusManager::TlsIndex
= 0;
562 HRESULT
CMenuBand_Constructor(REFIID riid
, LPVOID
*ppv
)
566 CMenuBand
* site
= new CComObject
<CMenuBand
>();
569 return E_OUTOFMEMORY
;
571 HRESULT hr
= site
->QueryInterface(riid
, ppv
);
579 CMenuToolbarBase::CMenuToolbarBase(CMenuBand
*menuBand
, BOOL usePager
) :
581 m_menuBand(menuBand
),
584 m_hasIdealSize(FALSE
)
588 HRESULT
CMenuToolbarBase::IsWindowOwner(HWND hwnd
)
590 return (m_hwnd
&& m_hwnd
== hwnd
) ||
591 (m_hwndToolbar
&& m_hwndToolbar
== hwnd
) ? S_OK
: S_FALSE
;
594 void CMenuToolbarBase::InvalidateDraw()
596 InvalidateRect(m_hwnd
, NULL
, FALSE
);
599 HRESULT
CMenuToolbarBase::ShowWindow(BOOL fShow
)
601 ::ShowWindow(m_hwnd
, fShow
? SW_SHOW
: SW_HIDE
);
603 HIMAGELIST ilBig
, ilSmall
;
604 Shell_GetImageLists(&ilBig
, &ilSmall
);
606 if (m_menuBand
->UseBigIcons())
608 SendMessageW(m_hwndToolbar
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(ilBig
));
612 SendMessageW(m_hwndToolbar
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(ilSmall
));
618 HRESULT
CMenuToolbarBase::Close()
620 DestroyWindow(m_hwndToolbar
);
621 if (m_hwndToolbar
!= m_hwnd
)
622 DestroyWindow(m_hwnd
);
623 m_hwndToolbar
= NULL
;
628 HRESULT
CMenuToolbarBase::CreateToolbar(HWND hwndParent
, DWORD dwFlags
)
630 LONG tbStyles
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
631 TBSTYLE_TOOLTIPS
| TBSTYLE_TRANSPARENT
| TBSTYLE_REGISTERDROP
| TBSTYLE_LIST
| TBSTYLE_FLAT
| TBSTYLE_CUSTOMERASE
|
632 CCS_NODIVIDER
| CCS_NOPARENTALIGN
| CCS_NORESIZE
| CCS_TOP
;
633 LONG tbExStyles
= TBSTYLE_EX_DOUBLEBUFFER
;
635 if (dwFlags
& SMINIT_VERTICAL
)
637 tbStyles
|= CCS_VERT
;
638 tbExStyles
|= TBSTYLE_EX_VERTICAL
| WS_EX_TOOLWINDOW
;
643 if (!::GetClientRect(hwndParent
, &rc
) || (rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
))
651 HWND hwndToolbar
= CreateWindowEx(
652 tbExStyles
, TOOLBARCLASSNAMEW
, NULL
,
653 tbStyles
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
654 hwndParent
, NULL
, _AtlBaseModule
.GetModuleInstance(), 0);
656 if (hwndToolbar
== NULL
)
661 LONG pgStyles
= PGS_VERT
| WS_CHILD
| WS_VISIBLE
;
664 HWND hwndPager
= CreateWindowEx(
665 pgExStyles
, WC_PAGESCROLLER
, NULL
,
666 pgStyles
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
667 hwndParent
, NULL
, _AtlBaseModule
.GetModuleInstance(), 0);
669 ::SetParent(hwndToolbar
, hwndPager
);
670 ::SetParent(hwndPager
, hwndParent
);
672 SendMessage(hwndPager
, PGM_SETCHILD
, 0, reinterpret_cast<LPARAM
>(hwndToolbar
));
673 m_hwndToolbar
= hwndToolbar
;
678 ::SetParent(hwndToolbar
, hwndParent
);
679 m_hwndToolbar
= hwndToolbar
;
680 m_hwnd
= hwndToolbar
;
683 /* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */
684 SendMessageW(hwndToolbar
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
686 //if (dwFlags & SMINIT_TOPLEVEL)
688 // /* Hide the placeholders for the button images */
689 // SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0);
693 if (m_menuBand
->UseBigIcons())
696 SendMessageW(hwndToolbar
, TB_SETPADDING
, 0, MAKELPARAM(0, 0));
704 HRESULT hr
= SHGetImageList(shiml
, IID_PPV_ARG(IImageList
, &piml
));
707 SendMessageW(hwndToolbar
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(piml
));
711 SendMessageW(hwndToolbar
, TB_SETIMAGELIST
, 0, 0);
714 SetWindowLongPtr(hwndToolbar
, GWLP_USERDATA
, reinterpret_cast<LONG_PTR
>(this));
715 m_SubclassOld
= (WNDPROC
) SetWindowLongPtr(hwndToolbar
, GWLP_WNDPROC
, reinterpret_cast<LONG_PTR
>(CMenuToolbarBase::s_SubclassProc
));
720 HRESULT
CMenuToolbarBase::GetIdealSize(SIZE
& size
)
722 size
.cx
= size
.cy
= 0;
724 if (m_hwndToolbar
&& !m_hasIdealSize
)
726 SendMessageW(m_hwndToolbar
, TB_AUTOSIZE
, 0, 0);
727 SendMessageW(m_hwndToolbar
, TB_GETMAXSIZE
, 0, reinterpret_cast<LPARAM
>(&m_idealSize
));
728 m_hasIdealSize
= TRUE
;
736 HRESULT
CMenuToolbarBase::SetPosSize(int x
, int y
, int cx
, int cy
)
738 if (m_hwnd
!= m_hwndToolbar
)
740 SetWindowPos(m_hwndToolbar
, NULL
, x
, y
, cx
, m_idealSize
.cy
, 0);
742 SetWindowPos(m_hwnd
, NULL
, x
, y
, cx
, cy
, 0);
743 DWORD btnSize
= SendMessage(m_hwndToolbar
, TB_GETBUTTONSIZE
, 0, 0);
744 SendMessage(m_hwndToolbar
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(cx
, HIWORD(btnSize
)));
748 HRESULT
CMenuToolbarBase::GetWindow(HWND
*phwnd
)
758 LRESULT CALLBACK
CMenuToolbarBase::s_SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
760 CMenuToolbarBase
* pthis
= reinterpret_cast<CMenuToolbarBase
*>(GetWindowLongPtr(hWnd
, GWLP_USERDATA
));
761 return pthis
->SubclassProc(hWnd
, uMsg
, wParam
, lParam
);
764 LRESULT
CMenuToolbarBase::SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
769 if (wParam
== TIMERID_HOTTRACK
)
771 KillTimer(hWnd
, TIMERID_HOTTRACK
);
773 m_menuBand
->_OnPopupSubMenu(-1, NULL
, NULL
, NULL
);
775 if (HasSubMenu(m_hotItem
) == S_OK
)
777 PopupItem(m_hotItem
);
782 return m_SubclassOld(hWnd
, uMsg
, wParam
, lParam
);
785 HRESULT
CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM
* hot
)
787 if (hot
->dwFlags
& HICF_LEAVING
)
789 KillTimer(m_hwndToolbar
, TIMERID_HOTTRACK
);
791 m_menuBand
->_OnHotItemChanged(NULL
, -1);
792 m_menuBand
->_MenuItemHotTrack(MPOS_CHILDTRACKING
);
794 else if (m_hotItem
!= hot
->idNew
)
797 SystemParametersInfo(SPI_GETMENUSHOWDELAY
, 0, &elapsed
, 0);
798 SetTimer(m_hwndToolbar
, TIMERID_HOTTRACK
, elapsed
, NULL
);
800 m_hotItem
= hot
->idNew
;
801 m_menuBand
->_OnHotItemChanged(this, m_hotItem
);
802 m_menuBand
->_MenuItemHotTrack(MPOS_CHILDTRACKING
);
807 HRESULT
CMenuToolbarBase::PopupSubMenu(UINT itemId
, UINT index
, IShellMenu
* childShellMenu
)
809 IBandSite
* pBandSite
;
815 if (!SendMessage(m_hwndToolbar
, TB_GETITEMRECT
, index
, reinterpret_cast<LPARAM
>(&rc
)))
818 POINT a
= { rc
.left
, rc
.top
};
819 POINT b
= { rc
.right
, rc
.bottom
};
821 ClientToScreen(m_hwndToolbar
, &a
);
822 ClientToScreen(m_hwndToolbar
, &b
);
824 POINTL pt
= { b
.x
, a
.y
};
825 RECTL rcl
= { a
.x
, a
.y
, b
.x
, b
.y
}; // maybe-TODO: fetch client area of deskbar?
828 #if USE_SYSTEM_MENUSITE
829 hr
= CoCreateInstance(CLSID_MenuBandSite
,
831 CLSCTX_INPROC_SERVER
,
832 IID_PPV_ARG(IBandSite
, &pBandSite
));
834 hr
= CMenuSite_Constructor(IID_PPV_ARG(IBandSite
, &pBandSite
));
839 hr
= CMenuSite_Wrapper(pBandSite
, IID_PPV_ARG(IBandSite
, &pBandSite
));
844 #if USE_SYSTEM_MENUDESKBAR
845 hr
= CoCreateInstance(CLSID_MenuDeskBar
,
847 CLSCTX_INPROC_SERVER
,
848 IID_PPV_ARG(IDeskBar
, &pDeskBar
));
850 hr
= CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar
, &pDeskBar
));
855 hr
= CMenuDeskBar_Wrapper(pDeskBar
, IID_PPV_ARG(IDeskBar
, &pDeskBar
));
860 hr
= pDeskBar
->SetClient(pBandSite
);
864 hr
= pBandSite
->AddBand(childShellMenu
);
868 CComPtr
<IMenuPopup
> popup
;
869 hr
= pDeskBar
->QueryInterface(IID_PPV_ARG(IMenuPopup
, &popup
));
873 m_menuBand
->_OnPopupSubMenu(itemId
, popup
, &pt
, &rcl
);
878 HRESULT
CMenuToolbarBase::PopupSubMenu(UINT index
, HMENU menu
)
882 if (!SendMessage(m_hwndToolbar
, TB_GETITEMRECT
, index
, reinterpret_cast<LPARAM
>(&rc
)))
885 POINT b
= { rc
.right
, rc
.bottom
};
887 ClientToScreen(m_hwndToolbar
, &b
);
889 HMENU popup
= GetSubMenu(menu
, index
);
891 m_menuBand
->_TrackSubMenuUsingTrackPopupMenu(popup
, b
.x
, b
.y
);
896 HRESULT
CMenuToolbarBase::DoContextMenu(IContextMenu
* contextMenu
)
899 HMENU hPopup
= CreatePopupMenu();
904 hr
= contextMenu
->QueryContextMenu(hPopup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
911 DWORD dwPos
= GetMessagePos();
912 UINT uCommand
= ::TrackPopupMenu(hPopup
, TPM_RETURNCMD
, GET_X_LPARAM(dwPos
), GET_Y_LPARAM(dwPos
), 0, m_hwnd
, NULL
);
916 CMINVOKECOMMANDINFO cmi
= { 0 };
917 cmi
.cbSize
= sizeof(cmi
);
918 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
920 hr
= contextMenu
->InvokeCommand(&cmi
);
926 HRESULT
CMenuToolbarBase::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
929 if (HasSubMenu(wParam
) == S_OK
)
931 KillTimer(m_hwndToolbar
, TIMERID_HOTTRACK
);
935 return m_menuBand
->_MenuItemHotTrack(MPOS_EXECUTE
);
938 HRESULT
CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType
)
940 int prev
= m_hotItem
;
943 if (dwSelectType
!= 0xFFFFFFFF)
945 int count
= SendMessage(m_hwndToolbar
, TB_BUTTONCOUNT
, 0, 0);
949 TBBUTTONINFO info
= { 0 };
950 info
.cbSize
= sizeof(TBBUTTONINFO
);
952 index
= SendMessage(m_hwndToolbar
, TB_GETBUTTONINFO
, m_hotItem
, reinterpret_cast<LPARAM
>(&info
));
955 if (dwSelectType
== VK_HOME
)
958 dwSelectType
= VK_DOWN
;
960 else if (dwSelectType
== VK_END
)
963 dwSelectType
= VK_UP
;
967 if (dwSelectType
== VK_UP
)
971 else if (dwSelectType
== VK_DOWN
)
978 if (dwSelectType
== VK_UP
)
982 else if (dwSelectType
== VK_DOWN
)
988 TBBUTTON btn
= { 0 };
989 while (index
>= 0 && index
< count
)
991 DWORD res
= SendMessage(m_hwndToolbar
, TB_GETBUTTON
, index
, reinterpret_cast<LPARAM
>(&btn
));
997 m_hotItem
= btn
.idCommand
;
998 if (prev
!= m_hotItem
)
1000 SendMessage(m_hwndToolbar
, TB_SETHOTITEM
, index
, 0);
1001 return m_menuBand
->_OnHotItemChanged(this, m_hotItem
);
1006 if (dwSelectType
== VK_UP
)
1010 else if (dwSelectType
== VK_DOWN
)
1018 if (prev
!= m_hotItem
)
1020 SendMessage(m_hwndToolbar
, TB_SETHOTITEM
, -1, 0);
1021 m_menuBand
->_OnHotItemChanged(NULL
, -1);
1027 AllocAndGetMenuString(HMENU hMenu
, UINT ItemIDByPosition
, WCHAR
** String
)
1031 Length
= GetMenuStringW(hMenu
, ItemIDByPosition
, NULL
, 0, MF_BYPOSITION
);
1036 /* Also allocate space for the terminating NULL character */
1038 *String
= (PWSTR
) HeapAlloc(GetProcessHeap(), 0, Length
* sizeof(WCHAR
));
1040 GetMenuStringW(hMenu
, ItemIDByPosition
, *String
, Length
, MF_BYPOSITION
);
1045 CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand
*menuBand
) :
1046 CMenuToolbarBase(menuBand
, FALSE
),
1051 HRESULT
CMenuStaticToolbar::GetMenu(
1058 *pdwFlags
= m_dwMenuFlags
;
1063 HRESULT
CMenuStaticToolbar::SetMenu(
1069 m_dwMenuFlags
= dwFlags
;
1074 HRESULT
CMenuStaticToolbar::FillToolbar()
1077 int ic
= GetMenuItemCount(m_hmenu
);
1079 for (i
= 0; i
< ic
; i
++)
1082 TBBUTTON tbb
= { 0 };
1083 PWSTR MenuString
= NULL
;
1085 tbb
.fsState
= TBSTATE_ENABLED
;
1088 info
.cbSize
= sizeof(info
);
1089 info
.fMask
= MIIM_FTYPE
| MIIM_ID
;
1091 GetMenuItemInfoW(m_hmenu
, i
, TRUE
, &info
);
1093 if (info
.fType
== MFT_STRING
)
1095 if (!AllocAndGetMenuString(m_hmenu
, i
, &MenuString
))
1096 return E_OUTOFMEMORY
;
1097 if (::GetSubMenu(m_hmenu
, i
) != NULL
)
1098 tbb
.fsStyle
|= BTNS_DROPDOWN
;
1099 tbb
.iString
= (INT_PTR
) MenuString
;
1100 tbb
.idCommand
= info
.wID
;
1102 SMINFO
* sminfo
= new SMINFO();
1103 sminfo
->dwMask
= SMIM_ICON
| SMIM_FLAGS
;
1104 if (SUCCEEDED(m_menuBand
->_CallCBWithItemId(info
.wID
, SMC_GETINFO
, 0, reinterpret_cast<LPARAM
>(sminfo
))))
1106 tbb
.iBitmap
= sminfo
->iIcon
;
1107 tbb
.dwData
= reinterpret_cast<DWORD_PTR
>(sminfo
);
1108 // FIXME: remove before deleting the toolbar or it will leak
1113 tbb
.fsStyle
|= BTNS_SEP
;
1116 SendMessageW(m_hwndToolbar
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
1119 HeapFree(GetProcessHeap(), 0, MenuString
);
1125 HRESULT
CMenuStaticToolbar::OnContextMenu(NMMOUSE
* rclick
)
1127 CComPtr
<IContextMenu
> contextMenu
;
1128 HRESULT hr
= m_menuBand
->_CallCBWithItemId(rclick
->dwItemSpec
, SMC_GETOBJECT
, reinterpret_cast<WPARAM
>(&IID_IContextMenu
), reinterpret_cast<LPARAM
>(&contextMenu
));
1132 return DoContextMenu(contextMenu
);
1135 HRESULT
CMenuStaticToolbar::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
1138 hr
= CMenuToolbarBase::OnCommand(wParam
, lParam
, theResult
);
1142 // in case the clicked item has a submenu, we do not need to execute the item
1146 return m_menuBand
->_CallCBWithItemId(wParam
, SMC_EXEC
, 0, 0);
1149 HRESULT
CMenuStaticToolbar::PopupItem(UINT uItem
)
1151 TBBUTTONINFO info
= { 0 };
1152 info
.cbSize
= sizeof(TBBUTTONINFO
);
1154 int index
= SendMessage(m_hwndToolbar
, TB_GETBUTTONINFO
, uItem
, reinterpret_cast<LPARAM
>(&info
));
1158 TBBUTTON btn
= { 0 };
1159 SendMessage(m_hwndToolbar
, TB_GETBUTTON
, index
, reinterpret_cast<LPARAM
>(&btn
));
1161 SMINFO
* nfo
= reinterpret_cast<SMINFO
*>(btn
.dwData
);
1165 if (nfo
->dwFlags
&SMIF_TRACKPOPUP
)
1167 return PopupSubMenu(index
, m_hmenu
);
1171 CComPtr
<IShellMenu
> shellMenu
;
1172 HRESULT hr
= m_menuBand
->_CallCBWithItemId(uItem
, SMC_GETOBJECT
, reinterpret_cast<WPARAM
>(&IID_IShellMenu
), reinterpret_cast<LPARAM
>(&shellMenu
));
1176 return PopupSubMenu(uItem
, index
, shellMenu
);
1180 HRESULT
CMenuStaticToolbar::HasSubMenu(UINT uItem
)
1182 TBBUTTONINFO info
= { 0 };
1183 info
.cbSize
= sizeof(TBBUTTONINFO
);
1185 int index
= SendMessage(m_hwndToolbar
, TB_GETBUTTONINFO
, uItem
, reinterpret_cast<LPARAM
>(&info
));
1188 return ::GetSubMenu(m_hmenu
, index
) ? S_OK
: S_FALSE
;
1191 CMenuSFToolbar::CMenuSFToolbar(CMenuBand
* menuBand
) :
1192 CMenuToolbarBase(menuBand
, TRUE
),
1197 CMenuSFToolbar::~CMenuSFToolbar()
1201 HRESULT
CMenuSFToolbar::FillToolbar()
1208 m_shellFolder
->EnumObjects(m_hwndToolbar
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
, &eidl
);
1210 LPITEMIDLIST item
= static_cast<LPITEMIDLIST
>(CoTaskMemAlloc(sizeof(ITEMIDLIST
)));
1212 while ((hr
= eidl
->Next(1, &item
, &fetched
)) == S_OK
)
1217 TBBUTTON tbb
= { 0 };
1218 tbb
.fsState
= TBSTATE_ENABLED
;
1221 CComPtr
<IShellItem
> psi
;
1222 hr
= SHCreateShellItem(NULL
, m_shellFolder
, item
, &psi
);
1226 hr
= psi
->GetDisplayName(SIGDN_NORMALDISPLAY
, &MenuString
);
1230 index
= SHMapPIDLToSystemImageListIndex(m_shellFolder
, item
, &indexOpen
);
1233 hr
= psi
->GetAttributes(SFGAO_FOLDER
, &attrs
);
1237 tbb
.fsStyle
|= BTNS_DROPDOWN
;
1240 tbb
.idCommand
= ++i
;
1241 tbb
.iString
= (INT_PTR
) MenuString
;
1242 tbb
.iBitmap
= index
;
1243 tbb
.dwData
= reinterpret_cast<DWORD_PTR
>(ILClone(item
));
1244 // FIXME: remove before deleting the toolbar or it will leak
1246 SendMessageW(m_hwndToolbar
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
1247 HeapFree(GetProcessHeap(), 0, MenuString
);
1250 CoTaskMemFree(item
);
1252 // If no items were added, show the "empty" placeholder
1255 TBBUTTON tbb
= { 0 };
1256 PCWSTR MenuString
= L
"(Empty)";
1258 tbb
.fsState
= 0/*TBSTATE_DISABLED*/;
1260 tbb
.iString
= (INT_PTR
) MenuString
;
1263 SendMessageW(m_hwndToolbar
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
1271 HRESULT
CMenuSFToolbar::SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
)
1273 m_shellFolder
= psf
;
1274 m_idList
= pidlFolder
;
1276 m_dwMenuFlags
= dwFlags
;
1280 HRESULT
CMenuSFToolbar::GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
)
1284 hr
= m_shellFolder
->QueryInterface(riid
, ppv
);
1289 *pdwFlags
= m_dwMenuFlags
;
1293 LPITEMIDLIST pidl
= NULL
;
1297 pidl
= ILClone(m_idList
);
1300 (*(IUnknown
**) ppv
)->Release();
1311 LPITEMIDLIST
CMenuSFToolbar::GetPidlFromId(UINT uItem
, INT
* pIndex
)
1313 TBBUTTONINFO info
= { 0 };
1314 info
.cbSize
= sizeof(TBBUTTONINFO
);
1316 int index
= SendMessage(m_hwndToolbar
, TB_GETBUTTONINFO
, uItem
, reinterpret_cast<LPARAM
>(&info
));
1323 TBBUTTON btn
= { 0 };
1324 if (!SendMessage(m_hwndToolbar
, TB_GETBUTTON
, index
, reinterpret_cast<LPARAM
>(&btn
)))
1327 return reinterpret_cast<LPITEMIDLIST
>(btn
.dwData
);
1330 HRESULT
CMenuSFToolbar::OnContextMenu(NMMOUSE
* rclick
)
1333 CComPtr
<IContextMenu
> contextMenu
;
1334 LPCITEMIDLIST pidl
= reinterpret_cast<LPCITEMIDLIST
>(rclick
->dwItemData
);
1336 hr
= m_shellFolder
->GetUIObjectOf(m_hwndToolbar
, 1, &pidl
, IID_IContextMenu
, NULL
, reinterpret_cast<VOID
**>(&contextMenu
));
1340 return DoContextMenu(contextMenu
);
1343 HRESULT
CMenuSFToolbar::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
1346 hr
= CMenuToolbarBase::OnCommand(wParam
, lParam
, theResult
);
1350 // in case the clicked item has a submenu, we do not need to execute the item
1354 return m_menuBand
->_CallCBWithItemPidl(GetPidlFromId(wParam
), SMC_SFEXEC
, 0, 0);
1357 HRESULT
CMenuSFToolbar::PopupItem(UINT uItem
)
1364 CComPtr
<IShellMenuCallback
> psmc
;
1365 CComPtr
<IShellMenu
> shellMenu
;
1367 LPITEMIDLIST pidl
= GetPidlFromId(uItem
, &index
);
1372 #if USE_SYSTEM_MENUBAND
1373 hr
= CoCreateInstance(CLSID_MenuBand
,
1375 CLSCTX_INPROC_SERVER
,
1376 IID_PPV_ARG(IShellMenu
, &shellMenu
));
1378 hr
= CMenuBand_Constructor(IID_PPV_ARG(IShellMenu
, &shellMenu
));
1383 hr
= CMenuBand_Wrapper(shellMenu
, IID_PPV_ARG(IShellMenu
, &shellMenu
));
1388 m_menuBand
->GetMenuInfo(&psmc
, &uId
, &uIdAncestor
, &flags
);
1390 // FIXME: not sure what to use as uId/uIdAncestor here
1391 hr
= shellMenu
->Initialize(psmc
, 0, uId
, SMINIT_VERTICAL
);
1395 CComPtr
<IShellFolder
> childFolder
;
1396 hr
= m_shellFolder
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &childFolder
));
1400 hr
= shellMenu
->SetShellFolder(childFolder
, NULL
, NULL
, 0);
1404 return PopupSubMenu(uItem
, index
, shellMenu
);
1407 HRESULT
CMenuSFToolbar::HasSubMenu(UINT uItem
)
1410 CComPtr
<IShellItem
> psi
;
1411 hr
= SHCreateShellItem(NULL
, m_shellFolder
, GetPidlFromId(uItem
), &psi
);
1416 hr
= psi
->GetAttributes(SFGAO_FOLDER
, &attrs
);
1420 return (attrs
!= 0) ? S_OK
: S_FALSE
;
1423 CMenuBand::CMenuBand() :
1424 m_staticToolbar(NULL
),
1428 m_subMenuChild(NULL
),
1429 m_useBigIcons(FALSE
),
1434 m_focusManager
= CMenuFocusManager::AcquireManager();
1436 m_marlett
= CreateFont(
1437 0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET
,
1438 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
,
1439 DEFAULT_QUALITY
, FF_DONTCARE
, L
"Marlett");
1442 CMenuBand::~CMenuBand()
1444 CMenuFocusManager::ReleaseManager(m_focusManager
);
1446 if (m_staticToolbar
)
1447 delete m_staticToolbar
;
1452 DeleteObject(m_marlett
);
1455 HRESULT STDMETHODCALLTYPE
CMenuBand::Initialize(
1456 IShellMenuCallback
*psmc
,
1464 m_uIdAncestor
= uIdAncestor
;
1465 m_dwFlags
= dwFlags
;
1469 _CallCB(SMC_CREATE
, 0, reinterpret_cast<LPARAM
>(&m_UserData
));
1475 HRESULT STDMETHODCALLTYPE
CMenuBand::GetMenuInfo(
1476 IShellMenuCallback
**ppsmc
,
1481 if (!pdwFlags
) // maybe?
1482 return E_INVALIDARG
;
1491 *puIdAncestor
= m_uIdAncestor
;
1493 *pdwFlags
= m_dwFlags
;
1498 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMenu(
1503 if (m_staticToolbar
== NULL
)
1505 m_staticToolbar
= new CMenuStaticToolbar(this);
1510 HRESULT hr
= m_staticToolbar
->SetMenu(hmenu
, hwnd
, dwFlags
);
1518 hr
= m_site
->GetWindow(&hwndParent
);
1522 hr
= m_staticToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
1526 hr
= m_staticToolbar
->FillToolbar();
1532 HRESULT STDMETHODCALLTYPE
CMenuBand::GetMenu(
1537 if (m_staticToolbar
== NULL
)
1540 return m_staticToolbar
->GetMenu(phmenu
, phwnd
, pdwFlags
);
1543 HRESULT STDMETHODCALLTYPE
CMenuBand::SetSite(IUnknown
*pUnkSite
)
1550 if (pUnkSite
== NULL
)
1554 hr
= pUnkSite
->QueryInterface(IID_PPV_ARG(IOleWindow
, &m_site
));
1558 hr
= m_site
->GetWindow(&hwndParent
);
1562 if (!::IsWindow(hwndParent
))
1565 if (m_staticToolbar
!= NULL
)
1567 hr
= m_staticToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
1571 hr
= m_staticToolbar
->FillToolbar();
1576 if (m_SFToolbar
!= NULL
)
1578 hr
= m_SFToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
1582 hr
= m_SFToolbar
->FillToolbar();
1587 hr
= IUnknown_QueryService(m_site
, SID_SMenuPopup
, IID_PPV_ARG(IMenuPopup
, &m_subMenuParent
));
1591 CComPtr
<IOleWindow
> pTopLevelWindow
;
1592 hr
= IUnknown_QueryService(m_site
, SID_STopLevelBrowser
, IID_PPV_ARG(IOleWindow
, &pTopLevelWindow
));
1596 return pTopLevelWindow
->GetWindow(&m_topLevelWindow
);
1599 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSite(REFIID riid
, PVOID
*ppvSite
)
1604 return m_site
->QueryInterface(riid
, ppvSite
);
1607 HRESULT STDMETHODCALLTYPE
CMenuBand::GetWindow(
1610 if (m_SFToolbar
!= NULL
)
1611 return m_SFToolbar
->GetWindow(phwnd
);
1613 if (m_staticToolbar
!= NULL
)
1614 return m_staticToolbar
->GetWindow(phwnd
);
1619 HRESULT STDMETHODCALLTYPE
CMenuBand::OnPosRectChangeDB(RECT
*prc
)
1621 SIZE sizeStatic
= { 0 };
1622 SIZE sizeShlFld
= { 0 };
1625 if (m_staticToolbar
!= NULL
)
1626 hr
= m_staticToolbar
->GetIdealSize(sizeStatic
);
1630 if (m_SFToolbar
!= NULL
)
1631 hr
= m_SFToolbar
->GetIdealSize(sizeShlFld
);
1635 if (m_staticToolbar
== NULL
&& m_SFToolbar
== NULL
)
1638 int sy
= min(prc
->bottom
- prc
->top
, sizeStatic
.cy
+ sizeShlFld
.cy
);
1640 int syStatic
= sizeStatic
.cy
;
1641 int syShlFld
= sy
- syStatic
;
1645 m_SFToolbar
->SetPosSize(
1648 prc
->right
- prc
->left
,
1651 if (m_staticToolbar
)
1653 m_staticToolbar
->SetPosSize(
1655 prc
->top
+ syShlFld
,
1656 prc
->right
- prc
->left
,
1662 HRESULT STDMETHODCALLTYPE
CMenuBand::GetBandInfo(
1667 SIZE sizeStatic
= { 0 };
1668 SIZE sizeShlFld
= { 0 };
1672 if (m_staticToolbar
!= NULL
)
1673 hr
= m_staticToolbar
->GetIdealSize(sizeStatic
);
1677 if (m_SFToolbar
!= NULL
)
1678 hr
= m_SFToolbar
->GetIdealSize(sizeShlFld
);
1682 if (m_staticToolbar
== NULL
&& m_SFToolbar
== NULL
)
1685 pdbi
->ptMaxSize
.x
= max(sizeStatic
.cx
, sizeShlFld
.cx
) + 20;
1686 pdbi
->ptMaxSize
.y
= sizeStatic
.cy
+ sizeShlFld
.cy
;
1691 /* IDockingWindow */
1692 HRESULT STDMETHODCALLTYPE
CMenuBand::ShowDW(BOOL fShow
)
1696 if (m_staticToolbar
!= NULL
)
1697 hr
= m_staticToolbar
->ShowWindow(fShow
);
1700 if (m_SFToolbar
!= NULL
)
1701 hr
= m_SFToolbar
->ShowWindow(fShow
);
1707 hr
= _CallCB(SMC_INITMENU
, 0, 0);
1713 hr
= m_focusManager
->PushMenu(this);
1715 hr
= m_focusManager
->PopMenu(this);
1720 HRESULT STDMETHODCALLTYPE
CMenuBand::CloseDW(DWORD dwReserved
)
1724 if (m_staticToolbar
!= NULL
)
1725 return m_staticToolbar
->Close();
1727 if (m_SFToolbar
!= NULL
)
1728 return m_SFToolbar
->Close();
1732 HRESULT STDMETHODCALLTYPE
CMenuBand::ResizeBorderDW(LPCRECT prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
)
1738 HRESULT STDMETHODCALLTYPE
CMenuBand::ContextSensitiveHelp(BOOL fEnterMode
)
1744 HRESULT STDMETHODCALLTYPE
CMenuBand::UIActivateIO(BOOL fActivate
, LPMSG lpMsg
)
1748 hr
= m_subMenuParent
->SetSubMenu(this, fActivate
);
1754 CComPtr
<IOleWindow
> pTopLevelWindow
;
1755 hr
= IUnknown_QueryService(m_site
, SID_SMenuPopup
, IID_PPV_ARG(IOleWindow
, &pTopLevelWindow
));
1759 hr
= pTopLevelWindow
->GetWindow(&m_topLevelWindow
);
1765 m_topLevelWindow
= NULL
;
1771 HRESULT STDMETHODCALLTYPE
CMenuBand::HasFocusIO()
1777 HRESULT STDMETHODCALLTYPE
CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg
)
1783 HRESULT STDMETHODCALLTYPE
CMenuBand::IsDirty()
1789 HRESULT STDMETHODCALLTYPE
CMenuBand::Load(IStream
*pStm
)
1795 HRESULT STDMETHODCALLTYPE
CMenuBand::Save(IStream
*pStm
, BOOL fClearDirty
)
1801 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSizeMax(ULARGE_INTEGER
*pcbSize
)
1807 HRESULT STDMETHODCALLTYPE
CMenuBand::GetClassID(CLSID
*pClassID
)
1813 HRESULT STDMETHODCALLTYPE
CMenuBand::QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
1819 HRESULT STDMETHODCALLTYPE
CMenuBand::Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
1824 if (IsEqualGUID(*pguidCmdGroup
, CLSID_MenuBand
))
1826 if (nCmdID
== 16) // set (big) icon size
1828 this->m_useBigIcons
= nCmdexecopt
== 2;
1831 else if (nCmdID
== 19) // popup-related
1841 HRESULT STDMETHODCALLTYPE
CMenuBand::QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
)
1843 if (IsEqualIID(guidService
, SID_SMenuBandChild
) ||
1844 IsEqualIID(guidService
, SID_SMenuBandBottom
) ||
1845 IsEqualIID(guidService
, SID_SMenuBandBottomSelected
))
1846 return this->QueryInterface(riid
, ppvObject
);
1847 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService
));
1848 return E_NOINTERFACE
;
1851 HRESULT STDMETHODCALLTYPE
CMenuBand::Popup(POINTL
*ppt
, RECTL
*prcExclude
, MP_POPUPFLAGS dwFlags
)
1857 HRESULT STDMETHODCALLTYPE
CMenuBand::OnSelect(DWORD dwSelectType
)
1859 switch (dwSelectType
)
1861 case MPOS_CHILDTRACKING
:
1862 // TODO: Cancel timers?
1863 return m_subMenuParent
->OnSelect(dwSelectType
);
1864 case MPOS_SELECTLEFT
:
1866 m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
1867 return m_subMenuParent
->OnSelect(dwSelectType
);
1868 case MPOS_SELECTRIGHT
:
1869 if (m_hotBar
&& m_hotItem
>= 0)
1871 // TODO: popup the current child if it has subitems, otherwise spread up.
1873 return m_subMenuParent
->OnSelect(dwSelectType
);
1875 case MPOS_FULLCANCEL
:
1877 m_subMenuChild
->OnSelect(dwSelectType
);
1878 return m_subMenuParent
->OnSelect(dwSelectType
);
1879 case MPOS_CANCELLEVEL
:
1881 m_subMenuChild
->OnSelect(dwSelectType
);
1887 HRESULT STDMETHODCALLTYPE
CMenuBand::SetSubMenu(IMenuPopup
*pmp
, BOOL fSet
)
1893 HRESULT STDMETHODCALLTYPE
CMenuBand::SetClient(IUnknown
*punkClient
)
1899 HRESULT STDMETHODCALLTYPE
CMenuBand::GetClient(IUnknown
**ppunkClient
)
1901 // HACK, so I can test for a submenu in the DeskBar
1906 *ppunkClient
= m_subMenuChild
;
1908 *ppunkClient
= NULL
;
1913 HRESULT STDMETHODCALLTYPE
CMenuBand::IsMenuMessage(MSG
*pmsg
)
1921 HRESULT STDMETHODCALLTYPE
CMenuBand::TranslateMenuMessage(MSG
*pmsg
, LRESULT
*plRet
)
1927 HRESULT STDMETHODCALLTYPE
CMenuBand::SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
)
1929 if (m_SFToolbar
== NULL
)
1931 m_SFToolbar
= new CMenuSFToolbar(this);
1934 HRESULT hr
= m_SFToolbar
->SetShellFolder(psf
, pidlFolder
, hKey
, dwFlags
);
1942 hr
= m_site
->GetWindow(&hwndParent
);
1946 hr
= m_SFToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
1950 hr
= m_SFToolbar
->FillToolbar();
1956 HRESULT STDMETHODCALLTYPE
CMenuBand::GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
)
1959 return m_SFToolbar
->GetShellFolder(pdwFlags
, ppidl
, riid
, ppv
);
1963 HRESULT STDMETHODCALLTYPE
CMenuBand::InvalidateItem(LPSMDATA psmd
, DWORD dwFlags
)
1969 HRESULT STDMETHODCALLTYPE
CMenuBand::GetState(LPSMDATA psmd
)
1975 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMenuToolbar(IUnknown
*punk
, DWORD dwFlags
)
1981 HRESULT STDMETHODCALLTYPE
CMenuBand::OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
1993 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
1995 return m_staticToolbar
->OnCommand(wParam
, lParam
, theResult
);
1998 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2000 return m_SFToolbar
->OnCommand(wParam
, lParam
, theResult
);
2006 NMHDR
* hdr
= reinterpret_cast<LPNMHDR
>(lParam
);
2007 NMTBCUSTOMDRAW
* cdraw
;
2010 NMPGCALCSIZE
* csize
;
2015 csize
= reinterpret_cast<LPNMPGCALCSIZE
>(hdr
);
2017 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2020 m_staticToolbar
->GetIdealSize(tbs
);
2021 if (csize
->dwFlag
== PGF_CALCHEIGHT
)
2023 csize
->iHeight
= tbs
.cy
;
2025 else if (csize
->dwFlag
== PGF_CALCWIDTH
)
2027 csize
->iHeight
= tbs
.cx
;
2031 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2034 m_SFToolbar
->GetIdealSize(tbs
);
2035 if (csize
->dwFlag
== PGF_CALCHEIGHT
)
2037 csize
->iHeight
= tbs
.cy
;
2039 else if (csize
->dwFlag
== PGF_CALCWIDTH
)
2041 csize
->iHeight
= tbs
.cx
;
2048 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2050 WPARAM wp
= reinterpret_cast<LPNMTOOLBAR
>(hdr
)->iItem
;
2051 return m_staticToolbar
->OnCommand(wp
, 0, theResult
);
2054 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2056 WPARAM wp
= reinterpret_cast<LPNMTOOLBAR
>(hdr
)->iItem
;
2057 return m_SFToolbar
->OnCommand(wp
, 0, theResult
);
2062 case TBN_HOTITEMCHANGE
:
2063 hot
= reinterpret_cast<LPNMTBHOTITEM
>(hdr
);
2065 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2067 return m_staticToolbar
->OnHotItemChange(hot
);
2070 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2072 return m_SFToolbar
->OnHotItemChange(hot
);
2078 rclick
= reinterpret_cast<LPNMMOUSE
>(hdr
);
2080 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2082 return m_staticToolbar
->OnContextMenu(rclick
);
2085 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2087 return m_SFToolbar
->OnContextMenu(rclick
);
2093 cdraw
= reinterpret_cast<LPNMTBCUSTOMDRAW
>(hdr
);
2094 switch (cdraw
->nmcd
.dwDrawStage
)
2097 *theResult
= CDRF_NOTIFYITEMDRAW
;
2100 case CDDS_ITEMPREPAINT
:
2102 cdraw
->clrBtnFace
= GetSysColor(COLOR_MENU
);
2103 cdraw
->clrBtnHighlight
= GetSysColor(COLOR_MENUHILIGHT
);
2105 cdraw
->clrText
= GetSysColor(COLOR_MENUTEXT
);
2106 cdraw
->clrTextHighlight
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
2107 cdraw
->clrHighlightHotTrack
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
2109 bgBrush
= GetSysColorBrush(COLOR_MENU
);
2110 hotBrush
= GetSysColorBrush(COLOR_MENUHILIGHT
);
2112 rc
= cdraw
->nmcd
.rc
;
2113 hdc
= cdraw
->nmcd
.hdc
;
2115 if (cdraw
->nmcd
.uItemState
!= CDIS_DISABLED
&&
2116 ((INT
)cdraw
->nmcd
.dwItemSpec
== m_hotItem
||
2117 (m_hotItem
< 0 && (INT
)cdraw
->nmcd
.dwItemSpec
== m_popupItem
)))
2119 cdraw
->nmcd
.uItemState
= CDIS_HOT
;
2122 switch (cdraw
->nmcd
.uItemState
)
2126 FillRect(hdc
, &rc
, hotBrush
);
2129 FillRect(hdc
, &rc
, bgBrush
);
2133 *theResult
= CDRF_NOTIFYPOSTPAINT
| TBCDRF_NOBACKGROUND
| TBCDRF_NOEDGES
| TBCDRF_NOOFFSET
| TBCDRF_NOMARK
| 0x00800000; // FIXME: the last bit is Vista+, for debugging only
2136 case CDDS_ITEMPOSTPAINT
:
2137 btni
.cbSize
= sizeof(btni
);
2138 btni
.dwMask
= TBIF_STYLE
;
2139 SendMessage(hWnd
, TB_GETBUTTONINFO
, cdraw
->nmcd
.dwItemSpec
, reinterpret_cast<LPARAM
>(&btni
));
2140 if (btni
.fsStyle
& BTNS_DROPDOWN
)
2142 SelectObject(cdraw
->nmcd
.hdc
, m_marlett
);
2143 WCHAR text
[] = L
"8";
2144 SetBkMode(cdraw
->nmcd
.hdc
, TRANSPARENT
);
2145 DrawTextEx(cdraw
->nmcd
.hdc
, text
, 1, &cdraw
->nmcd
.rc
, DT_NOCLIP
| DT_VCENTER
| DT_RIGHT
| DT_SINGLELINE
, NULL
);
2158 HRESULT STDMETHODCALLTYPE
CMenuBand::IsWindowOwner(HWND hWnd
)
2160 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2163 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
2169 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSubMenu(THIS
)
2175 HRESULT STDMETHODCALLTYPE
CMenuBand::SetToolbar(THIS
)
2181 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMinWidth(THIS
)
2187 HRESULT STDMETHODCALLTYPE
CMenuBand::SetNoBorder(THIS
)
2193 HRESULT STDMETHODCALLTYPE
CMenuBand::SetTheme(THIS
)
2199 HRESULT STDMETHODCALLTYPE
CMenuBand::GetTop(THIS
)
2205 HRESULT STDMETHODCALLTYPE
CMenuBand::GetBottom(THIS
)
2211 HRESULT STDMETHODCALLTYPE
CMenuBand::GetTracked(THIS
)
2217 HRESULT STDMETHODCALLTYPE
CMenuBand::GetParentSite(THIS
)
2223 HRESULT STDMETHODCALLTYPE
CMenuBand::GetState(THIS
)
2229 HRESULT STDMETHODCALLTYPE
CMenuBand::DoDefaultAction(THIS
)
2235 HRESULT STDMETHODCALLTYPE
CMenuBand::IsEmpty(THIS
)
2241 HRESULT
CMenuBand::_CallCBWithItemId(UINT id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
2243 return _CallCB(uMsg
, wParam
, lParam
, id
);
2246 HRESULT
CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
2248 return _CallCB(uMsg
, wParam
, lParam
, 0, pidl
);
2251 HRESULT
CMenuBand::_CallCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT id
, LPITEMIDLIST pidl
)
2259 SMDATA smData
= { 0 };
2260 smData
.punk
= static_cast<IShellMenu2
*>(this);
2262 smData
.uIdParent
= m_uId
;
2263 smData
.uIdAncestor
= m_uIdAncestor
;
2265 smData
.pidlItem
= pidl
;
2266 if (m_staticToolbar
)
2268 smData
.hmenu
= m_hmenu
;
2270 smData
.pvUserData
= NULL
;
2272 m_SFToolbar
->GetShellFolder(NULL
, &smData
.pidlFolder
, IID_PPV_ARG(IShellFolder
, &smData
.psf
));
2273 HRESULT hr
= m_psmc
->CallbackSM(&smData
, uMsg
, wParam
, lParam
);
2274 ILFree(smData
.pidlFolder
);
2276 smData
.psf
->Release();
2280 HRESULT
CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup
, INT x
, INT y
)
2282 ::TrackPopupMenu(popup
, 0, x
, y
, 0, m_menuOwner
, NULL
);
2286 HRESULT
CMenuBand::_GetTopLevelWindow(HWND
*topLevel
)
2288 *topLevel
= m_topLevelWindow
;
2292 HRESULT
CMenuBand::_OnHotItemChanged(CMenuToolbarBase
* tb
, INT id
)
2294 if (m_hotBar
&& m_hotBar
!= tb
)
2295 m_hotBar
->ChangeHotItem(-1);
2298 if (m_staticToolbar
) m_staticToolbar
->InvalidateDraw();
2299 if (m_SFToolbar
) m_SFToolbar
->InvalidateDraw();
2303 HRESULT
CMenuBand::_MenuItemHotTrack(DWORD changeType
)
2307 if (changeType
== VK_DOWN
)
2309 if (m_SFToolbar
&& (m_hotBar
== m_SFToolbar
|| m_hotBar
== NULL
))
2311 hr
= m_SFToolbar
->ChangeHotItem(VK_DOWN
);
2314 if (m_staticToolbar
)
2315 return m_staticToolbar
->ChangeHotItem(VK_HOME
);
2317 return m_SFToolbar
->ChangeHotItem(VK_HOME
);
2321 else if (m_staticToolbar
&& m_hotBar
== m_staticToolbar
)
2323 hr
= m_staticToolbar
->ChangeHotItem(VK_DOWN
);
2327 return m_SFToolbar
->ChangeHotItem(VK_HOME
);
2329 return m_staticToolbar
->ChangeHotItem(VK_HOME
);
2334 else if (changeType
== VK_UP
)
2336 if (m_staticToolbar
&& (m_hotBar
== m_staticToolbar
|| m_hotBar
== NULL
))
2338 hr
= m_staticToolbar
->ChangeHotItem(VK_DOWN
);
2342 return m_SFToolbar
->ChangeHotItem(VK_END
);
2344 return m_staticToolbar
->ChangeHotItem(VK_END
);
2348 else if (m_SFToolbar
&& m_hotBar
== m_SFToolbar
)
2350 hr
= m_SFToolbar
->ChangeHotItem(VK_UP
);
2353 if (m_staticToolbar
)
2354 return m_staticToolbar
->ChangeHotItem(VK_END
);
2356 return m_SFToolbar
->ChangeHotItem(VK_END
);
2363 m_subMenuParent
->OnSelect(changeType
);
2368 HRESULT
CMenuBand::_OnPopupSubMenu(INT popupItem
, IMenuPopup
* popup
, POINTL
* pAt
, RECTL
* pExclude
)
2372 HRESULT hr
= m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
2376 m_popupItem
= popupItem
;
2377 m_subMenuChild
= popup
;
2380 IUnknown_SetSite(popup
, m_subMenuParent
);
2381 popup
->Popup(pAt
, pExclude
, MPPF_RIGHT
);
2383 if (m_staticToolbar
) m_staticToolbar
->InvalidateDraw();
2384 if (m_SFToolbar
) m_SFToolbar
->InvalidateDraw();