4 * Copyright 2014 Giannis Adamopoulos
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //#define TEST_TRACKPOPUPMENU_SUBMENUS
25 /* NOTE: The following constants *MUST NOT* be changed because
26 they're hardcoded and need to be the exact values
27 in order to get the start menu to work! */
29 #define IDM_LOGOFF 402
30 #define IDM_UNDOCKCOMPUTER 410
31 #define IDM_TASKBARANDSTARTMENU 413
32 #define IDM_LASTSTARTMENU_SEPARATOR 450
33 #define IDM_DOCUMENTS 501
34 #define IDM_HELPANDSUPPORT 503
35 #define IDM_PROGRAMS 504
36 #define IDM_CONTROLPANEL 505
37 #define IDM_SHUTDOWN 506
38 #define IDM_FAVORITES 507
39 #define IDM_SETTINGS 508
40 #define IDM_PRINTERSANDFAXES 510
41 #define IDM_SEARCH 520
42 #define IDM_SYNCHRONIZE 553
43 #define IDM_NETWORKCONNECTIONS 557
44 #define IDM_DISCONNECT 5000
45 #define IDM_SECURITY 5001
49 * 1. append the start menu contents from all users
50 * 2. implement the context menu for start menu entries (programs, control panel, network connetions, printers)
51 * 3. filter out programs folder from the shell folder part of the start menu
52 * 4. showing the programs start menu is SLOW compared to windows. this needs some investigation
55 class CShellMenuCallback
:
56 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
57 public IShellMenuCallback
62 CComPtr
<IShellMenu
> m_pShellMenu
;
63 CComPtr
<IBandSite
> m_pBandSite
;
64 CComPtr
<IDeskBar
> m_pDeskBar
;
65 CComPtr
<ITrayPriv
> m_pTrayPriv
;
75 hr
= IUnknown_GetSite(m_pDeskBar
, IID_PPV_ARG(ITrayPriv
, &m_pTrayPriv
));
76 hr
= IUnknown_GetWindow(m_pTrayPriv
, &m_hwndTray
);
77 hr
= m_pTrayPriv
->AppendMenuW(&hmenu
);
78 #ifndef TEST_TRACKPOPUPMENU_SUBMENUS
79 hr
= m_pShellMenu
->SetMenu(hmenu
, NULL
, SMSET_BOTTOM
);
81 hr
= m_pShellMenu
->SetMenu(hmenu
, m_hwndTray
, SMSET_BOTTOM
);
87 HRESULT
OnGetInfo(LPSMDATA psmd
, SMINFO
*psminfo
)
93 // Smaller "24x24" icons used for the start menu
94 // The bitmaps are still 32x32, but the image is centered
95 case IDM_FAVORITES
: iconIndex
= -322; break;
96 case IDM_SEARCH
: iconIndex
= -323; break;
97 case IDM_HELPANDSUPPORT
: iconIndex
= -324; break;
98 case IDM_LOGOFF
: iconIndex
= -325; break;
99 case IDM_PROGRAMS
: iconIndex
= -326; break;
100 case IDM_DOCUMENTS
: iconIndex
= -327; break;
101 case IDM_RUN
: iconIndex
= -328; break;
102 case IDM_SHUTDOWN
: iconIndex
= -329; break;
103 case IDM_SETTINGS
: iconIndex
= -330; break;
105 case IDM_CONTROLPANEL
: iconIndex
= -22; break;
106 case IDM_NETWORKCONNECTIONS
: iconIndex
= -257; break;
107 case IDM_PRINTERSANDFAXES
: iconIndex
= -138; break;
108 case IDM_TASKBARANDSTARTMENU
: iconIndex
= -40; break;
109 //case IDM_SECURITY: iconIndex = -21; break;
110 //case IDM_SYNCHRONIZE: iconIndex = -21; break;
111 //case IDM_DISCONNECT: iconIndex = -21; break;
112 //case IDM_UNDOCKCOMPUTER: iconIndex = -21; break;
119 if ((psminfo
->dwMask
& SMIM_TYPE
) != 0)
120 psminfo
->dwType
= SMIT_STRING
;
121 if ((psminfo
->dwMask
& SMIM_ICON
) != 0)
122 psminfo
->iIcon
= Shell_GetCachedImageIndex(L
"shell32.dll", iconIndex
, FALSE
);
123 if ((psminfo
->dwMask
& SMIM_FLAGS
) != 0)
124 psminfo
->dwFlags
|= SMIF_ICON
;
125 #ifdef TEST_TRACKPOPUPMENU_SUBMENUS
126 if ((psminfo
->dwMask
& SMIM_FLAGS
) != 0)
127 psminfo
->dwFlags
|= SMIF_TRACKPOPUP
;
132 if ((psminfo
->dwMask
& SMIM_TYPE
) != 0)
133 psminfo
->dwType
= SMIT_SEPARATOR
;
138 HRESULT
OnGetSubMenu(LPSMDATA psmd
, REFIID iid
, void ** pv
)
142 IShellMenu
*pShellMenu
;
146 case IDM_PROGRAMS
: csidl
= CSIDL_PROGRAMS
; break;
147 case IDM_FAVORITES
: csidl
= CSIDL_FAVORITES
; break;
148 case IDM_DOCUMENTS
: csidl
= CSIDL_RECENT
; break;
151 #if USE_SYSTEM_MENUBAND
152 hr
= CoCreateInstance(CLSID_MenuBand
,
154 CLSCTX_INPROC_SERVER
,
155 IID_PPV_ARG(IShellMenu
, &pShellMenu
));
157 hr
= CMenuBand_Constructor(IID_PPV_ARG(IShellMenu
, &pShellMenu
));
162 hr
= CMenuBand_Wrapper(pShellMenu
, IID_PPV_ARG(IShellMenu
, &pShellMenu
));
167 hr
= pShellMenu
->Initialize(this, 0, ANCESTORDEFAULT
, SMINIT_VERTICAL
);
171 LPITEMIDLIST pidlStartMenu
;
172 IShellFolder
*psfDestop
, *psfStartMenu
;
174 hr
= SHGetFolderLocation(NULL
, csidl
, 0, 0, &pidlStartMenu
);
175 hr
= SHGetDesktopFolder(&psfDestop
);
176 hr
= psfDestop
->BindToObject(pidlStartMenu
, NULL
, IID_PPV_ARG(IShellFolder
, &psfStartMenu
));
178 hr
= pShellMenu
->SetShellFolder(psfStartMenu
, NULL
, NULL
, 0);
183 mii
.cbSize
= sizeof(mii
);
184 mii
.fMask
= MIIM_SUBMENU
;
185 if (GetMenuItemInfoW(psmd
->hmenu
, psmd
->uId
, FALSE
, &mii
))
187 hr
= pShellMenu
->SetMenu(mii
.hSubMenu
, NULL
, SMSET_BOTTOM
);
190 return pShellMenu
->QueryInterface(iid
, pv
);
193 HRESULT
OnGetContextMenu(LPSMDATA psmd
, REFIID iid
, void ** pv
)
195 if (psmd
->uId
== IDM_PROGRAMS
||
196 psmd
->uId
== IDM_CONTROLPANEL
||
197 psmd
->uId
== IDM_NETWORKCONNECTIONS
||
198 psmd
->uId
== IDM_PRINTERSANDFAXES
)
206 HRESULT
OnGetObject(LPSMDATA psmd
, REFIID iid
, void ** pv
)
208 if (IsEqualIID(iid
, IID_IShellMenu
))
209 return OnGetSubMenu(psmd
, iid
, pv
);
210 else if (IsEqualIID(iid
, IID_IContextMenu
))
211 return OnGetContextMenu(psmd
, iid
, pv
);
216 HRESULT
OnExec(LPSMDATA psmd
)
218 if (psmd
->uId
== IDM_CONTROLPANEL
)
219 ShellExecuteW(NULL
, L
"open", L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL
, NULL
, 1);
220 else if (psmd
->uId
== IDM_NETWORKCONNECTIONS
)
221 ShellExecuteW(NULL
, L
"open", L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", NULL
, NULL
, 1);
222 else if (psmd
->uId
== IDM_PRINTERSANDFAXES
)
223 ShellExecuteW(NULL
, L
"open", L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}", NULL
, NULL
, 1);
225 PostMessageW(m_hwndTray
, WM_COMMAND
, psmd
->uId
, 0);
232 DECLARE_NOT_AGGREGATABLE(CShellMenuCallback
)
233 DECLARE_PROTECT_FINAL_CONSTRUCT()
234 BEGIN_COM_MAP(CShellMenuCallback
)
235 COM_INTERFACE_ENTRY_IID(IID_IShellMenuCallback
, IShellMenuCallback
)
239 IShellMenu
* pShellMenu
,
240 IBandSite
* pBandSite
,
243 m_pShellMenu
.Attach(pShellMenu
);
244 m_pBandSite
.Attach(pBandSite
);
245 m_pDeskBar
.Attach(pDeskBar
);
248 ~CShellMenuCallback()
250 m_pShellMenu
.Release();
251 m_pBandSite
.Release();
252 m_pDeskBar
.Release();
255 HRESULT STDMETHODCALLTYPE
CallbackSM(
266 return OnGetInfo(psmd
, reinterpret_cast<SMINFO
*>(lParam
));
268 return OnGetObject(psmd
, *reinterpret_cast<IID
*>(wParam
), reinterpret_cast<void **>(lParam
));
272 m_pTrayPriv
->Execute(psmd
->psf
, psmd
->pidlItem
);
282 CStartMenu_Constructor(REFIID riid
, void **ppv
)
284 IShellMenu
* pShellMenu
;
285 IBandSite
* pBandSite
;
287 LPITEMIDLIST pidlStartMenu
;
290 IShellFolder
*shellFolder
;
291 IShellFolder
*psfStartMenu
;
293 #if USE_SYSTEM_MENUBAND
294 hr
= CoCreateInstance(CLSID_MenuBand
,
296 CLSCTX_INPROC_SERVER
,
297 IID_PPV_ARG(IShellMenu
, &pShellMenu
));
299 hr
= CMenuBand_Constructor(IID_PPV_ARG(IShellMenu
, &pShellMenu
));
304 hr
= CMenuBand_Wrapper(pShellMenu
, IID_PPV_ARG(IShellMenu
, &pShellMenu
));
309 #if USE_SYSTEM_MENUSITE
310 hr
= CoCreateInstance(CLSID_MenuBandSite
,
312 CLSCTX_INPROC_SERVER
,
313 IID_PPV_ARG(IBandSite
, &pBandSite
));
315 hr
= CMenuSite_Constructor(IID_PPV_ARG(IBandSite
, &pBandSite
));
320 hr
= CMenuSite_Wrapper(pBandSite
, IID_PPV_ARG(IBandSite
, &pBandSite
));
325 #if USE_SYSTEM_MENUDESKBAR
326 hr
= CoCreateInstance(CLSID_MenuDeskBar
,
328 CLSCTX_INPROC_SERVER
,
329 IID_PPV_ARG(IDeskBar
, &pDeskBar
));
331 hr
= CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar
, &pDeskBar
));
336 hr
= CMenuDeskBar_Wrapper(pDeskBar
, IID_PPV_ARG(IDeskBar
, &pDeskBar
));
341 CComObject
<CShellMenuCallback
> *pCallback
;
342 hr
= CComObject
<CShellMenuCallback
>::CreateInstance(&pCallback
);
345 pCallback
->AddRef(); // CreateInstance returns object with 0 ref count */
346 pCallback
->Initialize(pShellMenu
, pBandSite
, pDeskBar
);
348 pShellMenu
->Initialize(pCallback
, (UINT
)-1, 0, SMINIT_TOPLEVEL
| SMINIT_VERTICAL
);
352 /* FIXME: Use CLSID_MergedFolder class and IID_IAugmentedShellFolder2 interface here */
353 /* CLSID_MergedFolder 26fdc864-be88-46e7-9235-032d8ea5162e */
354 /* IID_IAugmentedShellFolder2 8db3b3f4-6cfe-11d1-8ae9-00c04fd918d0 */
355 hr
= SHGetFolderLocation(NULL
, CSIDL_STARTMENU
, 0, 0, &pidlStartMenu
);
356 hr
= SHGetDesktopFolder(&shellFolder
);
357 hr
= shellFolder
->BindToObject(pidlStartMenu
, NULL
, IID_IShellFolder
, (void**) &psfStartMenu
);
359 hr
= pShellMenu
->SetShellFolder(psfStartMenu
, NULL
, NULL
, 0);
361 hr
= pDeskBar
->SetClient(pBandSite
);
365 hr
= pBandSite
->AddBand(pShellMenu
);
369 return pDeskBar
->QueryInterface(riid
, ppv
);