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>
25 #include "CMenuBand.h"
26 #include "CMenuToolbars.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(CMenuToolbars
);
31 HRESULT WINAPI
SHGetImageList(
37 // FIXME: Enable if/when wine comctl supports this flag properly
38 //#define TBSTYLE_EX_VERTICAL 4
40 #define TIMERID_HOTTRACK 1
41 #define SUBCLASS_ID_MENUBAND 1
43 HRESULT
CMenuToolbarBase::OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
50 NMTBCUSTOMDRAW
* cdraw
;
56 COLORREF clrTextHighlight
;
64 return OnCommand(wParam
, lParam
, theResult
);
67 hdr
= reinterpret_cast<LPNMHDR
>(lParam
);
71 csize
= reinterpret_cast<LPNMPGCALCSIZE
>(hdr
);
74 if (csize
->dwFlag
== PGF_CALCHEIGHT
)
76 csize
->iHeight
= tbs
.cy
;
78 else if (csize
->dwFlag
== PGF_CALCWIDTH
)
80 csize
->iHeight
= tbs
.cx
;
85 wParam
= reinterpret_cast<LPNMTOOLBAR
>(hdr
)->iItem
;
86 return OnCommand(wParam
, 0, theResult
);
88 case TBN_HOTITEMCHANGE
:
89 hot
= reinterpret_cast<LPNMTBHOTITEM
>(hdr
);
90 return OnHotItemChange(hot
);
93 rclick
= reinterpret_cast<LPNMMOUSE
>(hdr
);
95 return OnContextMenu(rclick
);
98 cdraw
= reinterpret_cast<LPNMTBCUSTOMDRAW
>(hdr
);
99 switch (cdraw
->nmcd
.dwDrawStage
)
102 *theResult
= CDRF_NOTIFYITEMDRAW
;
105 case CDDS_ITEMPREPAINT
:
107 clrText
= GetSysColor(COLOR_MENUTEXT
);
108 clrTextHighlight
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
110 bgBrush
= GetSysColorBrush(COLOR_MENU
);
111 hotBrush
= GetSysColorBrush(m_useFlatMenus
? COLOR_MENUHILIGHT
: COLOR_HIGHLIGHT
);
114 hdc
= cdraw
->nmcd
.hdc
;
116 isHot
= m_hotBar
== this && m_hotItem
== static_cast<INT
>(cdraw
->nmcd
.dwItemSpec
);
117 isPopup
= m_popupBar
== this && m_popupItem
== static_cast<INT
>(cdraw
->nmcd
.dwItemSpec
);
119 if (isHot
|| (m_hotItem
< 0 && isPopup
))
121 cdraw
->nmcd
.uItemState
|= CDIS_HOT
;
125 cdraw
->nmcd
.uItemState
&= ~CDIS_HOT
;
128 if (cdraw
->nmcd
.uItemState
&CDIS_HOT
)
130 FillRect(hdc
, &rc
, hotBrush
);
131 SetTextColor(hdc
, clrTextHighlight
);
132 cdraw
->clrText
= clrTextHighlight
;
136 FillRect(hdc
, &rc
, bgBrush
);
137 SetTextColor(hdc
, clrText
);
138 cdraw
->clrText
= clrText
;
141 cdraw
->iListGap
+= 4;
143 *theResult
= CDRF_NOTIFYPOSTPAINT
| TBCDRF_NOBACKGROUND
| TBCDRF_NOEDGES
| TBCDRF_NOOFFSET
| TBCDRF_NOMARK
| 0x00800000; // FIXME: the last bit is Vista+, for debugging only
146 case CDDS_ITEMPOSTPAINT
:
147 btni
.cbSize
= sizeof(btni
);
148 btni
.dwMask
= TBIF_STYLE
;
149 SendMessage(hWnd
, TB_GETBUTTONINFO
, cdraw
->nmcd
.dwItemSpec
, reinterpret_cast<LPARAM
>(&btni
));
150 if (btni
.fsStyle
& BTNS_DROPDOWN
)
152 SelectObject(cdraw
->nmcd
.hdc
, m_marlett
);
154 SetBkMode(cdraw
->nmcd
.hdc
, TRANSPARENT
);
155 RECT rc
= cdraw
->nmcd
.rc
;
157 DrawTextEx(cdraw
->nmcd
.hdc
, text
, 1, &rc
, DT_NOCLIP
| DT_VCENTER
| DT_RIGHT
| DT_SINGLELINE
, NULL
);
170 CMenuToolbarBase::CMenuToolbarBase(CMenuBand
*menuBand
, BOOL usePager
) :
172 m_useFlatMenus(FALSE
),
174 m_menuBand(menuBand
),
177 m_hasIdealSize(FALSE
),
178 m_usePager(usePager
),
182 m_marlett
= CreateFont(
183 0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET
,
184 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
,
185 DEFAULT_QUALITY
, FF_DONTCARE
, L
"Marlett");
188 CMenuToolbarBase::~CMenuToolbarBase()
190 DeleteObject(m_marlett
);
193 HRESULT
CMenuToolbarBase::IsWindowOwner(HWND hwnd
)
195 return (m_hwnd
&& m_hwnd
== hwnd
) ||
196 (m_hwndToolbar
&& m_hwndToolbar
== hwnd
) ? S_OK
: S_FALSE
;
199 void CMenuToolbarBase::InvalidateDraw()
201 InvalidateRect(m_hwnd
, NULL
, FALSE
);
204 HRESULT
CMenuToolbarBase::ShowWindow(BOOL fShow
)
206 ::ShowWindow(m_hwnd
, fShow
? SW_SHOW
: SW_HIDE
);
210 SystemParametersInfo(SPI_GETFLATMENU
, 0, &m_useFlatMenus
, 0);
215 HRESULT
CMenuToolbarBase::UpdateImageLists()
218 if (m_menuBand
->UseBigIcons())
221 SendMessageW(m_hwndToolbar
, TB_SETPADDING
, 0, MAKELPARAM(4, 0));
226 SendMessageW(m_hwndToolbar
, TB_SETPADDING
, 0, MAKELPARAM(4, 4));
230 HRESULT hr
= SHGetImageList(shiml
, IID_PPV_ARG(IImageList
, &piml
));
233 SendMessageW(m_hwndToolbar
, TB_SETIMAGELIST
, 0, reinterpret_cast<LPARAM
>(piml
));
237 SendMessageW(m_hwndToolbar
, TB_SETIMAGELIST
, 0, 0);
242 HRESULT
CMenuToolbarBase::Close()
244 DestroyWindow(m_hwndToolbar
);
245 if (m_hwndToolbar
!= m_hwnd
)
246 DestroyWindow(m_hwnd
);
247 m_hwndToolbar
= NULL
;
252 HRESULT
CMenuToolbarBase::CreateToolbar(HWND hwndParent
, DWORD dwFlags
)
254 LONG tbStyles
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
255 TBSTYLE_TOOLTIPS
| TBSTYLE_TRANSPARENT
| TBSTYLE_REGISTERDROP
| TBSTYLE_LIST
| TBSTYLE_FLAT
| TBSTYLE_CUSTOMERASE
|
256 CCS_NODIVIDER
| CCS_NOPARENTALIGN
| CCS_NORESIZE
| CCS_TOP
;
257 LONG tbExStyles
= TBSTYLE_EX_DOUBLEBUFFER
;
259 if (dwFlags
& SMINIT_VERTICAL
)
261 tbStyles
|= CCS_VERT
;
263 #ifdef TBSTYLE_EX_VERTICAL
264 // FIXME: Use when it works in ros (?)
265 tbExStyles
|= TBSTYLE_EX_VERTICAL
| WS_EX_TOOLWINDOW
;
271 if (!::GetClientRect(hwndParent
, &rc
) || (rc
.left
== rc
.right
) || (rc
.top
== rc
.bottom
))
279 HWND hwndToolbar
= CreateWindowEx(
280 tbExStyles
, TOOLBARCLASSNAMEW
, NULL
,
281 tbStyles
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
282 hwndParent
, NULL
, _AtlBaseModule
.GetModuleInstance(), 0);
284 if (hwndToolbar
== NULL
)
289 LONG pgStyles
= PGS_VERT
| WS_CHILD
| WS_VISIBLE
;
292 HWND hwndPager
= CreateWindowEx(
293 pgExStyles
, WC_PAGESCROLLER
, NULL
,
294 pgStyles
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
295 hwndParent
, NULL
, _AtlBaseModule
.GetModuleInstance(), 0);
297 ::SetParent(hwndToolbar
, hwndPager
);
298 ::SetParent(hwndPager
, hwndParent
);
300 SendMessage(hwndPager
, PGM_SETCHILD
, 0, reinterpret_cast<LPARAM
>(hwndToolbar
));
301 m_hwndToolbar
= hwndToolbar
;
306 ::SetParent(hwndToolbar
, hwndParent
);
307 m_hwndToolbar
= hwndToolbar
;
308 m_hwnd
= hwndToolbar
;
311 /* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */
312 SendMessageW(hwndToolbar
, TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0);
314 //if (dwFlags & SMINIT_TOPLEVEL)
316 // /* Hide the placeholders for the button images */
317 // SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0);
321 SetWindowLongPtr(hwndToolbar
, GWLP_USERDATA
, reinterpret_cast<LONG_PTR
>(this));
322 m_SubclassOld
= (WNDPROC
) SetWindowLongPtr(hwndToolbar
, GWLP_WNDPROC
, reinterpret_cast<LONG_PTR
>(CMenuToolbarBase::s_SubclassProc
));
329 HRESULT
CMenuToolbarBase::GetIdealSize(SIZE
& size
)
331 size
.cx
= size
.cy
= 0;
333 if (m_hwndToolbar
&& !m_hasIdealSize
)
335 SendMessageW(m_hwndToolbar
, TB_AUTOSIZE
, 0, 0);
336 SendMessageW(m_hwndToolbar
, TB_GETMAXSIZE
, 0, reinterpret_cast<LPARAM
>(&m_idealSize
));
337 m_hasIdealSize
= TRUE
;
345 HRESULT
CMenuToolbarBase::SetPosSize(int x
, int y
, int cx
, int cy
)
347 if (m_hwnd
!= m_hwndToolbar
)
349 SetWindowPos(m_hwndToolbar
, NULL
, x
, y
, cx
, m_idealSize
.cy
, 0);
351 SetWindowPos(m_hwnd
, NULL
, x
, y
, cx
, cy
, 0);
352 DWORD btnSize
= SendMessage(m_hwndToolbar
, TB_GETBUTTONSIZE
, 0, 0);
353 SendMessage(m_hwndToolbar
, TB_SETBUTTONSIZE
, 0, MAKELPARAM(cx
, HIWORD(btnSize
)));
357 HRESULT
CMenuToolbarBase::GetWindow(HWND
*phwnd
)
367 LRESULT CALLBACK
CMenuToolbarBase::s_SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
369 CMenuToolbarBase
* pthis
= reinterpret_cast<CMenuToolbarBase
*>(GetWindowLongPtr(hWnd
, GWLP_USERDATA
));
370 return pthis
->SubclassProc(hWnd
, uMsg
, wParam
, lParam
);
373 LRESULT
CMenuToolbarBase::SubclassProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
378 if (wParam
== TIMERID_HOTTRACK
)
380 KillTimer(hWnd
, TIMERID_HOTTRACK
);
382 m_menuBand
->_OnPopupSubMenu(NULL
, NULL
, NULL
, NULL
, -1);
384 if (HasSubMenu(m_hotItem
) == S_OK
)
386 PopupItem(m_hotItem
);
391 return m_SubclassOld(hWnd
, uMsg
, wParam
, lParam
);
394 HRESULT
CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM
* hot
)
396 if (hot
->dwFlags
& HICF_LEAVING
)
398 KillTimer(m_hwndToolbar
, TIMERID_HOTTRACK
);
400 m_menuBand
->_OnHotItemChanged(NULL
, -1);
401 m_menuBand
->_MenuItemHotTrack(MPOS_CHILDTRACKING
);
403 else if (m_hotItem
!= hot
->idNew
)
406 SystemParametersInfo(SPI_GETMENUSHOWDELAY
, 0, &elapsed
, 0);
407 SetTimer(m_hwndToolbar
, TIMERID_HOTTRACK
, elapsed
, NULL
);
409 m_hotItem
= hot
->idNew
;
410 m_menuBand
->_OnHotItemChanged(this, m_hotItem
);
411 m_menuBand
->_MenuItemHotTrack(MPOS_CHILDTRACKING
);
416 HRESULT
CMenuToolbarBase::OnHotItemChanged(CMenuToolbarBase
* toolbar
, INT item
)
424 HRESULT
CMenuToolbarBase::OnPopupItemChanged(CMenuToolbarBase
* toolbar
, INT item
)
426 m_popupBar
= toolbar
;
432 HRESULT
CMenuToolbarBase::PopupSubMenu(UINT uItem
, UINT index
, IShellMenu
* childShellMenu
)
434 IBandSite
* pBandSite
;
440 if (!SendMessage(m_hwndToolbar
, TB_GETITEMRECT
, index
, reinterpret_cast<LPARAM
>(&rc
)))
443 POINT a
= { rc
.left
, rc
.top
};
444 POINT b
= { rc
.right
, rc
.bottom
};
446 ClientToScreen(m_hwndToolbar
, &a
);
447 ClientToScreen(m_hwndToolbar
, &b
);
449 POINTL pt
= { b
.x
- 3, a
.y
- 3 };
450 RECTL rcl
= { a
.x
, a
.y
, b
.x
, b
.y
}; // maybe-TODO: fetch client area of deskbar?
452 #if USE_SYSTEM_MENUSITE
453 hr
= CoCreateInstance(CLSID_MenuBandSite
,
455 CLSCTX_INPROC_SERVER
,
456 IID_PPV_ARG(IBandSite
, &pBandSite
));
458 hr
= CMenuSite_Constructor(IID_PPV_ARG(IBandSite
, &pBandSite
));
463 hr
= CMenuSite_Wrapper(pBandSite
, IID_PPV_ARG(IBandSite
, &pBandSite
));
468 #if USE_SYSTEM_MENUDESKBAR
469 hr
= CoCreateInstance(CLSID_MenuDeskBar
,
471 CLSCTX_INPROC_SERVER
,
472 IID_PPV_ARG(IDeskBar
, &pDeskBar
));
474 hr
= CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar
, &pDeskBar
));
479 hr
= CMenuDeskBar_Wrapper(pDeskBar
, IID_PPV_ARG(IDeskBar
, &pDeskBar
));
484 hr
= pDeskBar
->SetClient(pBandSite
);
488 hr
= pBandSite
->AddBand(childShellMenu
);
492 CComPtr
<IMenuPopup
> popup
;
493 hr
= pDeskBar
->QueryInterface(IID_PPV_ARG(IMenuPopup
, &popup
));
497 m_menuBand
->_OnPopupSubMenu(popup
, &pt
, &rcl
, this, m_popupItem
);
502 HRESULT
CMenuToolbarBase::PopupSubMenu(UINT index
, HMENU menu
)
506 if (!SendMessage(m_hwndToolbar
, TB_GETITEMRECT
, index
, reinterpret_cast<LPARAM
>(&rc
)))
509 POINT b
= { rc
.right
, rc
.bottom
};
511 ClientToScreen(m_hwndToolbar
, &b
);
513 HMENU popup
= GetSubMenu(menu
, index
);
515 m_menuBand
->_TrackSubMenuUsingTrackPopupMenu(popup
, b
.x
, b
.y
);
520 HRESULT
CMenuToolbarBase::DoContextMenu(IContextMenu
* contextMenu
)
523 HMENU hPopup
= CreatePopupMenu();
528 hr
= contextMenu
->QueryContextMenu(hPopup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
535 DWORD dwPos
= GetMessagePos();
536 UINT uCommand
= ::TrackPopupMenu(hPopup
, TPM_RETURNCMD
, GET_X_LPARAM(dwPos
), GET_Y_LPARAM(dwPos
), 0, m_hwnd
, NULL
);
540 CMINVOKECOMMANDINFO cmi
= { 0 };
541 cmi
.cbSize
= sizeof(cmi
);
542 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
544 hr
= contextMenu
->InvokeCommand(&cmi
);
550 HRESULT
CMenuToolbarBase::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
553 if (HasSubMenu(wParam
) == S_OK
)
555 KillTimer(m_hwndToolbar
, TIMERID_HOTTRACK
);
559 return m_menuBand
->_MenuItemHotTrack(MPOS_EXECUTE
);
562 HRESULT
CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType
)
564 int prev
= m_hotItem
;
567 if (dwSelectType
!= 0xFFFFFFFF)
569 int count
= SendMessage(m_hwndToolbar
, TB_BUTTONCOUNT
, 0, 0);
573 TBBUTTONINFO info
= { 0 };
574 info
.cbSize
= sizeof(TBBUTTONINFO
);
576 index
= SendMessage(m_hwndToolbar
, TB_GETBUTTONINFO
, m_hotItem
, reinterpret_cast<LPARAM
>(&info
));
579 if (dwSelectType
== VK_HOME
)
582 dwSelectType
= VK_DOWN
;
584 else if (dwSelectType
== VK_END
)
587 dwSelectType
= VK_UP
;
591 if (dwSelectType
== VK_UP
)
595 else if (dwSelectType
== VK_DOWN
)
602 if (dwSelectType
== VK_UP
)
606 else if (dwSelectType
== VK_DOWN
)
612 TBBUTTON btn
= { 0 };
613 while (index
>= 0 && index
< count
)
615 DWORD res
= SendMessage(m_hwndToolbar
, TB_GETBUTTON
, index
, reinterpret_cast<LPARAM
>(&btn
));
621 m_hotItem
= btn
.idCommand
;
622 if (prev
!= m_hotItem
)
624 SendMessage(m_hwndToolbar
, TB_SETHOTITEM
, index
, 0);
625 return m_menuBand
->_OnHotItemChanged(this, m_hotItem
);
630 if (dwSelectType
== VK_UP
)
634 else if (dwSelectType
== VK_DOWN
)
642 if (prev
!= m_hotItem
)
644 SendMessage(m_hwndToolbar
, TB_SETHOTITEM
, -1, 0);
645 m_menuBand
->_OnHotItemChanged(NULL
, -1);
650 HRESULT
CMenuToolbarBase::AddButton(DWORD commandId
, LPCWSTR caption
, BOOL hasSubMenu
, INT iconId
, DWORD_PTR buttonData
, BOOL last
)
652 TBBUTTON tbb
= { 0 };
654 tbb
.fsState
= TBSTATE_ENABLED
;
655 #ifndef TBSTYLE_EX_VERTICAL
657 tbb
.fsState
|= TBSTATE_WRAP
;
662 tbb
.fsStyle
|= BTNS_DROPDOWN
;
664 tbb
.iString
= (INT_PTR
) caption
;
665 tbb
.idCommand
= commandId
;
667 tbb
.iBitmap
= iconId
;
668 tbb
.dwData
= buttonData
;
670 SendMessageW(m_hwndToolbar
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
675 HRESULT
CMenuToolbarBase::AddSeparator(BOOL last
)
677 TBBUTTON tbb
= { 0 };
679 tbb
.fsState
= TBSTATE_ENABLED
;
680 #ifndef TBSTYLE_EX_VERTICAL
682 tbb
.fsState
|= TBSTATE_WRAP
;
684 tbb
.fsStyle
= BTNS_SEP
;
687 SendMessageW(m_hwndToolbar
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
692 HRESULT
CMenuToolbarBase::AddPlaceholder()
694 TBBUTTON tbb
= { 0 };
695 PCWSTR MenuString
= L
"(Empty)";
699 tbb
.iString
= (INT_PTR
) MenuString
;
702 SendMessageW(m_hwndToolbar
, TB_ADDBUTTONS
, 1, reinterpret_cast<LPARAM
>(&tbb
));
707 HRESULT
CMenuToolbarBase::GetDataFromId(INT uItem
, INT
* pIndex
, DWORD_PTR
* pData
)
709 TBBUTTONINFO info
= { 0 };
710 info
.cbSize
= sizeof(TBBUTTONINFO
);
712 int index
= SendMessage(m_hwndToolbar
, TB_GETBUTTONINFO
, uItem
, reinterpret_cast<LPARAM
>(&info
));
721 TBBUTTON btn
= { 0 };
722 if (!SendMessage(m_hwndToolbar
, TB_GETBUTTON
, index
, reinterpret_cast<LPARAM
>(&btn
)))
731 HRESULT
CMenuToolbarBase::PopupItem(INT uItem
)
736 GetDataFromId(uItem
, &index
, &dwData
);
738 return InternalPopupItem(uItem
, index
, dwData
);
741 HRESULT
CMenuToolbarBase::HasSubMenu(INT uItem
)
746 GetDataFromId(uItem
, &index
, &dwData
);
748 return InternalHasSubMenu(uItem
, index
, dwData
);
751 CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand
*menuBand
) :
752 CMenuToolbarBase(menuBand
, FALSE
),
757 HRESULT
CMenuStaticToolbar::GetMenu(
764 *pdwFlags
= m_dwMenuFlags
;
769 HRESULT
CMenuStaticToolbar::SetMenu(
775 m_dwMenuFlags
= dwFlags
;
780 HRESULT
CMenuStaticToolbar::FillToolbar()
783 int ic
= GetMenuItemCount(m_hmenu
);
785 for (i
= 0; i
< ic
; i
++)
787 BOOL last
= i
+ 1 == ic
;
791 info
.cbSize
= sizeof(info
);
792 info
.dwTypeData
= NULL
;
793 info
.fMask
= MIIM_FTYPE
| MIIM_STRING
;
795 GetMenuItemInfoW(m_hmenu
, i
, TRUE
, &info
);
797 if (info
.fType
== MFT_STRING
)
800 info
.dwTypeData
= (PWSTR
) HeapAlloc(GetProcessHeap(), 0, (info
.cch
+ 1) * sizeof(WCHAR
));
802 info
.fMask
= MIIM_STRING
| MIIM_SUBMENU
| MIIM_ID
;
803 GetMenuItemInfoW(m_hmenu
, i
, TRUE
, &info
);
805 SMINFO
* sminfo
= new SMINFO();
806 sminfo
->dwMask
= SMIM_ICON
| SMIM_FLAGS
;
807 // FIXME: remove before deleting the toolbar or it will leak
809 HRESULT hr
= m_menuBand
->_CallCBWithItemId(info
.wID
, SMC_GETINFO
, 0, reinterpret_cast<LPARAM
>(sminfo
));
813 AddButton(info
.wID
, info
.dwTypeData
, info
.hSubMenu
!= NULL
, sminfo
->iIcon
, reinterpret_cast<DWORD_PTR
>(sminfo
), last
);
815 HeapFree(GetProcessHeap(), 0, info
.dwTypeData
);
826 HRESULT
CMenuStaticToolbar::OnContextMenu(NMMOUSE
* rclick
)
828 CComPtr
<IContextMenu
> contextMenu
;
829 HRESULT hr
= m_menuBand
->_CallCBWithItemId(rclick
->dwItemSpec
, SMC_GETOBJECT
, reinterpret_cast<WPARAM
>(&IID_IContextMenu
), reinterpret_cast<LPARAM
>(&contextMenu
));
833 return DoContextMenu(contextMenu
);
836 HRESULT
CMenuStaticToolbar::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
839 hr
= CMenuToolbarBase::OnCommand(wParam
, lParam
, theResult
);
843 // in case the clicked item has a submenu, we do not need to execute the item
847 return m_menuBand
->_CallCBWithItemId(wParam
, SMC_EXEC
, 0, 0);
850 HRESULT
CMenuStaticToolbar::InternalPopupItem(INT uItem
, INT index
, DWORD_PTR dwData
)
852 SMINFO
* nfo
= reinterpret_cast<SMINFO
*>(dwData
);
856 if (nfo
->dwFlags
&SMIF_TRACKPOPUP
)
858 return PopupSubMenu(index
, m_hmenu
);
862 CComPtr
<IShellMenu
> shellMenu
;
863 HRESULT hr
= m_menuBand
->_CallCBWithItemId(uItem
, SMC_GETOBJECT
, reinterpret_cast<WPARAM
>(&IID_IShellMenu
), reinterpret_cast<LPARAM
>(&shellMenu
));
867 return PopupSubMenu(uItem
, index
, shellMenu
);
871 HRESULT
CMenuStaticToolbar::InternalHasSubMenu(INT uItem
, INT index
, DWORD_PTR dwData
)
873 return ::GetSubMenu(m_hmenu
, index
) ? S_OK
: S_FALSE
;
876 CMenuSFToolbar::CMenuSFToolbar(CMenuBand
* menuBand
) :
877 CMenuToolbarBase(menuBand
, TRUE
),
882 CMenuSFToolbar::~CMenuSFToolbar()
886 HRESULT
CMenuSFToolbar::FillToolbar()
893 m_shellFolder
->EnumObjects(m_hwndToolbar
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
, &eidl
);
895 LPITEMIDLIST item
= static_cast<LPITEMIDLIST
>(CoTaskMemAlloc(sizeof(ITEMIDLIST
)));
897 hr
= eidl
->Next(1, &item
, &fetched
);
898 while (SUCCEEDED(hr
) && fetched
> 0)
903 STRRET sr
= { STRRET_CSTR
, { 0 } };
905 hr
= m_shellFolder
->GetDisplayNameOf(item
, SIGDN_NORMALDISPLAY
, &sr
);
909 StrRetToStr(&sr
, NULL
, &MenuString
);
911 index
= SHMapPIDLToSystemImageListIndex(m_shellFolder
, item
, &indexOpen
);
913 LPCITEMIDLIST itemc
= item
;
915 SFGAOF attrs
= SFGAO_FOLDER
;
916 hr
= m_shellFolder
->GetAttributesOf(1, &itemc
, &attrs
);
918 DWORD_PTR dwData
= reinterpret_cast<DWORD_PTR
>(ILClone(item
));
919 // FIXME: remove before deleting the toolbar or it will leak
921 // Fetch next item already, so we know if the current one is the last
922 hr
= eidl
->Next(1, &item
, &fetched
);
924 AddButton(++i
, MenuString
, attrs
& SFGAO_FOLDER
, index
, dwData
, SUCCEEDED(hr
) && fetched
> 0);
926 CoTaskMemFree(MenuString
);
930 // If no items were added, show the "empty" placeholder
933 return AddPlaceholder();
939 HRESULT
CMenuSFToolbar::SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
)
942 m_idList
= pidlFolder
;
944 m_dwMenuFlags
= dwFlags
;
948 HRESULT
CMenuSFToolbar::GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
)
952 hr
= m_shellFolder
->QueryInterface(riid
, ppv
);
957 *pdwFlags
= m_dwMenuFlags
;
961 LPITEMIDLIST pidl
= NULL
;
965 pidl
= ILClone(m_idList
);
968 (*(IUnknown
**) ppv
)->Release();
979 HRESULT
CMenuSFToolbar::OnContextMenu(NMMOUSE
* rclick
)
982 CComPtr
<IContextMenu
> contextMenu
;
983 LPCITEMIDLIST pidl
= reinterpret_cast<LPCITEMIDLIST
>(rclick
->dwItemData
);
985 hr
= m_shellFolder
->GetUIObjectOf(m_hwndToolbar
, 1, &pidl
, IID_IContextMenu
, NULL
, reinterpret_cast<VOID
**>(&contextMenu
));
989 return DoContextMenu(contextMenu
);
992 HRESULT
CMenuSFToolbar::OnCommand(WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
995 hr
= CMenuToolbarBase::OnCommand(wParam
, lParam
, theResult
);
999 // in case the clicked item has a submenu, we do not need to execute the item
1004 GetDataFromId(wParam
, NULL
, &data
);
1006 return m_menuBand
->_CallCBWithItemPidl(reinterpret_cast<LPITEMIDLIST
>(data
), SMC_SFEXEC
, 0, 0);
1009 HRESULT
CMenuSFToolbar::InternalPopupItem(INT uItem
, INT index
, DWORD_PTR dwData
)
1015 CComPtr
<IShellMenuCallback
> psmc
;
1016 CComPtr
<IShellMenu
> shellMenu
;
1018 LPITEMIDLIST pidl
= reinterpret_cast<LPITEMIDLIST
>(dwData
);
1023 #if USE_SYSTEM_MENUBAND
1024 hr
= CoCreateInstance(CLSID_MenuBand
,
1026 CLSCTX_INPROC_SERVER
,
1027 IID_PPV_ARG(IShellMenu
, &shellMenu
));
1029 hr
= CMenuBand_Constructor(IID_PPV_ARG(IShellMenu
, &shellMenu
));
1034 hr
= CMenuBand_Wrapper(shellMenu
, IID_PPV_ARG(IShellMenu
, &shellMenu
));
1039 m_menuBand
->GetMenuInfo(&psmc
, &uId
, &uIdAncestor
, &flags
);
1041 // FIXME: not sure what to use as uId/uIdAncestor here
1042 hr
= shellMenu
->Initialize(psmc
, 0, uId
, SMINIT_VERTICAL
);
1046 CComPtr
<IShellFolder
> childFolder
;
1047 hr
= m_shellFolder
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &childFolder
));
1051 hr
= shellMenu
->SetShellFolder(childFolder
, NULL
, NULL
, 0);
1055 return PopupSubMenu(uItem
, index
, shellMenu
);
1058 HRESULT
CMenuSFToolbar::InternalHasSubMenu(INT uItem
, INT index
, DWORD_PTR dwData
)
1061 LPCITEMIDLIST pidl
= reinterpret_cast<LPITEMIDLIST
>(dwData
);
1063 SFGAOF attrs
= SFGAO_FOLDER
;
1064 hr
= m_shellFolder
->GetAttributesOf(1, &pidl
, &attrs
);
1068 return (attrs
& SFGAO_FOLDER
) ? S_OK
: S_FALSE
;