- Improve filebrowser a bit and add some FIXMEs to show what should be done later
[reactos.git] / base / shell / rshell / CStartMenu.cpp
1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2014 Giannis Adamopoulos
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "precomp.h"
22
23 /* NOTE: The following constants may *NOT* be changed because
24 they're hardcoded and need to be the exact values
25 in order to get the start menu to work! */
26 #define IDM_PROGRAMS 504
27 #define IDM_FAVORITES 507
28 #define IDM_DOCUMENTS 501
29 #define IDM_SETTINGS 508
30 #define IDM_CONTROLPANEL 505
31 #define IDM_SECURITY 5001
32 #define IDM_NETWORKCONNECTIONS 557
33 #define IDM_PRINTERSANDFAXES 510
34 #define IDM_TASKBARANDSTARTMENU 413
35 #define IDM_SEARCH 520
36 #define IDM_HELPANDSUPPORT 503
37 #define IDM_RUN 401
38 #define IDM_SYNCHRONIZE 553
39 #define IDM_LOGOFF 402
40 #define IDM_DISCONNECT 5000
41 #define IDM_UNDOCKCOMPUTER 410
42 #define IDM_SHUTDOWN 506
43 #define IDM_LASTSTARTMENU_SEPARATOR 450
44
45 /*
46 * TODO:
47 * 1. append the start menu contents from all users
48 * 2. implement the context menu for start menu entries (programs, control panel, network connetions, printers)
49 * 3. filter out programs folder from the shell folder part of the start menu
50 */
51
52 class CShellMenuCallback :
53 public CComObjectRootEx<CComMultiThreadModelNoCS>,
54 public IShellMenuCallback
55 {
56 private:
57
58 HWND m_hwndTray;
59 CComPtr<IShellMenu> m_pShellMenu;
60 CComPtr<IBandSite> m_pBandSite;
61 CComPtr<IDeskBar> m_pDeskBar;
62 CComPtr<ITrayPriv> m_pTrayPriv;
63
64 HRESULT OnInitMenu()
65 {
66 HMENU hmenu;
67 HRESULT hr;
68
69 if (m_pTrayPriv.p)
70 return S_OK;
71
72 hr = IUnknown_GetSite(m_pDeskBar, IID_PPV_ARG(ITrayPriv, &m_pTrayPriv));
73 hr = IUnknown_GetWindow(m_pTrayPriv, &m_hwndTray);
74 hr = m_pTrayPriv->AppendMenuW(&hmenu);
75 hr = m_pShellMenu->SetMenu(hmenu, NULL, SMSET_BOTTOM);
76
77 return hr;
78 }
79
80 HRESULT OnGetInfo(LPSMDATA psmd, SMINFO *psminfo)
81 {
82 int iconIndex = 0;
83
84 switch (psmd->uId)
85 {
86 case IDM_PROGRAMS: iconIndex = -20; break;
87 case IDM_FAVORITES: iconIndex = -173; break;
88 case IDM_DOCUMENTS: iconIndex = -21; break;
89 case IDM_SETTINGS: iconIndex = -22; break;
90 case IDM_CONTROLPANEL: iconIndex = -22; break;
91 //case IDM_SECURITY: iconIndex = -21; break;
92 case IDM_NETWORKCONNECTIONS: iconIndex = -257; break;
93 case IDM_PRINTERSANDFAXES: iconIndex = -138; break;
94 case IDM_TASKBARANDSTARTMENU: iconIndex = -40; break;
95 case IDM_SEARCH: iconIndex = -23; break;
96 case IDM_HELPANDSUPPORT: iconIndex = -24; break;
97 case IDM_RUN: iconIndex = -25; break;
98 //case IDM_SYNCHRONIZE: iconIndex = -21; break;
99 case IDM_LOGOFF: iconIndex = -45; break;
100 //case IDM_DISCONNECT: iconIndex = -21; break;
101 //case IDM_UNDOCKCOMPUTER: iconIndex = -21; break;
102 case IDM_SHUTDOWN: iconIndex = -28; break;
103 default:
104 return S_FALSE;
105 }
106
107 if (iconIndex)
108 {
109 psminfo->dwMask = SMIM_ICON;
110 psminfo->iIcon = Shell_GetCachedImageIndex(L"shell32.dll", iconIndex, FALSE);
111 }
112 return S_OK;
113 }
114
115 HRESULT OnGetSubMenu(LPSMDATA psmd, REFIID iid, void ** pv)
116 {
117 HRESULT hr;
118 int csidl = 0;
119 IShellMenu *pShellMenu;
120
121 switch (psmd->uId)
122 {
123 case IDM_PROGRAMS: csidl = CSIDL_PROGRAMS; break;
124 case IDM_FAVORITES: csidl = CSIDL_FAVORITES; break;
125 case IDM_DOCUMENTS: csidl = CSIDL_RECENT; break;
126 }
127
128 hr = CoCreateInstance(CLSID_MenuBand,
129 NULL,
130 CLSCTX_INPROC_SERVER,
131 IID_PPV_ARG(IShellMenu,&pShellMenu));
132
133 hr = pShellMenu->Initialize(this, 0, ANCESTORDEFAULT, SMINIT_VERTICAL);
134
135 if (csidl)
136 {
137 LPITEMIDLIST pidlStartMenu;
138 IShellFolder *psfDestop, *psfStartMenu;
139
140 hr = SHGetFolderLocation(NULL, csidl, 0, 0, &pidlStartMenu);
141 hr = SHGetDesktopFolder(&psfDestop);
142 hr = psfDestop->BindToObject(pidlStartMenu, NULL, IID_PPV_ARG(IShellFolder, &psfStartMenu));
143
144 hr = pShellMenu->SetShellFolder(psfStartMenu, NULL, NULL, 0);
145 }
146 else
147 {
148 MENUITEMINFO mii;
149 mii.cbSize = sizeof(mii);
150 mii.fMask = MIIM_SUBMENU;
151 if (GetMenuItemInfoW( psmd->hmenu, psmd->uId, FALSE, &mii))
152 {
153 hr = pShellMenu->SetMenu(mii.hSubMenu, NULL, SMSET_BOTTOM);
154 }
155 }
156 return pShellMenu->QueryInterface(iid, pv);
157 }
158
159 HRESULT OnGetContextMenu(LPSMDATA psmd, REFIID iid, void ** pv)
160 {
161 if (psmd->uId == IDM_PROGRAMS ||
162 psmd->uId == IDM_CONTROLPANEL ||
163 psmd->uId == IDM_NETWORKCONNECTIONS ||
164 psmd->uId == IDM_PRINTERSANDFAXES)
165 {
166 //UNIMPLEMENTED
167 }
168
169 return S_FALSE;
170 }
171
172 HRESULT OnGetObject(LPSMDATA psmd, REFIID iid, void ** pv)
173 {
174 if (IsEqualIID(iid , IID_IShellMenu))
175 return OnGetSubMenu(psmd, iid, pv);
176 else if (IsEqualIID( iid, IID_IContextMenu))
177 return OnGetContextMenu(psmd, iid, pv);
178
179 return S_FALSE;
180 }
181
182 HRESULT OnExec(LPSMDATA psmd)
183 {
184 if(psmd->uId == IDM_CONTROLPANEL)
185 ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL,NULL, 1);
186 else if(psmd->uId == IDM_NETWORKCONNECTIONS)
187 ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", NULL,NULL, 1);
188 else if(psmd->uId == IDM_PRINTERSANDFAXES)
189 ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}", NULL,NULL, 1);
190 else
191 PostMessageW( m_hwndTray, WM_COMMAND, psmd->uId, 0);
192
193 return S_OK;
194 }
195
196 public:
197
198 DECLARE_NOT_AGGREGATABLE(CShellMenuCallback)
199 DECLARE_PROTECT_FINAL_CONSTRUCT()
200 BEGIN_COM_MAP(CShellMenuCallback)
201 COM_INTERFACE_ENTRY_IID(IID_IShellMenuCallback, IShellMenuCallback)
202 END_COM_MAP()
203
204 void Initialize(
205 IShellMenu* pShellMenu,
206 IBandSite* pBandSite,
207 IDeskBar* pDeskBar)
208 {
209 m_pShellMenu.Attach(pShellMenu);
210 m_pBandSite.Attach(pBandSite);
211 m_pDeskBar.Attach(pDeskBar);
212 }
213
214 ~CShellMenuCallback()
215 {
216 m_pShellMenu.Release();
217 m_pBandSite.Release();
218 m_pDeskBar.Release();
219 }
220
221 HRESULT STDMETHODCALLTYPE CallbackSM(
222 LPSMDATA psmd,
223 UINT uMsg,
224 WPARAM wParam,
225 LPARAM lParam)
226 {
227 switch (uMsg)
228 {
229 case SMC_INITMENU:
230 return OnInitMenu();
231 case SMC_GETINFO:
232 return OnGetInfo(psmd, reinterpret_cast<SMINFO*>(lParam));
233 case SMC_GETOBJECT:
234 return OnGetObject(psmd, *reinterpret_cast<IID *>(wParam), reinterpret_cast<void **>(lParam));
235 case SMC_EXEC:
236 return OnExec(psmd);
237 case SMC_SFEXEC:
238 m_pTrayPriv->Execute(psmd->psf, psmd->pidlItem);
239 break;
240 }
241
242 return S_FALSE;
243 }
244 };
245
246 extern "C"
247 HRESULT
248 CStartMenu_Constructor(
249 REFIID riid,
250 void **ppv)
251 {
252 IShellMenu* pShellMenu;
253 IBandSite* pBandSite;
254 IDeskBar* pDeskBar;
255 IShellMenuCallback* callback;
256 LPITEMIDLIST pidlStartMenu;
257
258 HRESULT hr;
259 IShellFolder *shellFolder;
260 IShellFolder *psfStartMenu;
261
262 hr = CoCreateInstance(CLSID_MenuBand,
263 NULL,
264 CLSCTX_INPROC_SERVER,
265 IID_PPV_ARG(IShellMenu, &pShellMenu));
266 if (FAILED(hr))
267 return NULL;
268
269 #if 1
270 hr = CoCreateInstance(CLSID_MenuBandSite,
271 NULL,
272 CLSCTX_INPROC_SERVER,
273 IID_PPV_ARG(IBandSite, &pBandSite));
274 #else
275 hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
276 #endif
277 if (FAILED(hr))
278 return NULL;
279
280 hr = CoCreateInstance(CLSID_MenuDeskBar,
281 NULL,
282 CLSCTX_INPROC_SERVER,
283 IID_PPV_ARG(IDeskBar, &pDeskBar));
284 if (FAILED(hr))
285 return NULL;
286
287 CComObject<CShellMenuCallback> *pCallback;
288 hr = CComObject<CShellMenuCallback>::CreateInstance(&pCallback);
289 if (FAILED(hr))
290 return FALSE;
291 pCallback->AddRef(); // CreateInstance returns object with 0 ref count */
292 pCallback->Initialize(pShellMenu, pBandSite, pDeskBar);
293 callback = pCallback;
294
295 hr = CShellMenuCallback::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellMenuCallback, &callback));
296 if (FAILED(hr))
297 return NULL;
298
299 pShellMenu->Initialize(pCallback, -1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL);
300 if (FAILED(hr))
301 return NULL;
302
303 /* FIXME: Use CLSID_MergedFolder class and IID_IAugmentedShellFolder2 interface here */
304 /* CLSID_MergedFolder 26fdc864-be88-46e7-9235-032d8ea5162e */
305 /* IID_IAugmentedShellFolder2 8db3b3f4-6cfe-11d1-8ae9-00c04fd918d0 */
306 hr = SHGetFolderLocation(NULL, CSIDL_STARTMENU, 0, 0, &pidlStartMenu);
307 hr = SHGetDesktopFolder(&shellFolder);
308 hr = shellFolder->BindToObject(pidlStartMenu, NULL, IID_IShellFolder, (void**)&psfStartMenu);
309
310 hr = pShellMenu->SetShellFolder(psfStartMenu, NULL, NULL, 0);
311
312 hr = pDeskBar->SetClient(pBandSite);
313 if (FAILED(hr))
314 return NULL;
315
316 hr = pBandSite->AddBand(pShellMenu);
317 if (FAILED(hr))
318 return NULL;
319
320 return pDeskBar->QueryInterface(riid, ppv);
321 }