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 #include "shellmenu.h"
21
22 #include "CMergedFolder.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(CStartMenu);
25
26 //#define TEST_TRACKPOPUPMENU_SUBMENUS
27
28
29 /* NOTE: The following constants *MUST NOT* be changed because
30 they're hardcoded and need to be the exact values
31 in order to get the start menu to work! */
32 #define IDM_RUN 401
33 #define IDM_LOGOFF 402
34 #define IDM_UNDOCKCOMPUTER 410
35 #define IDM_TASKBARANDSTARTMENU 413
36 #define IDM_LASTSTARTMENU_SEPARATOR 450
37 #define IDM_DOCUMENTS 501
38 #define IDM_HELPANDSUPPORT 503
39 #define IDM_PROGRAMS 504
40 #define IDM_CONTROLPANEL 505
41 #define IDM_SHUTDOWN 506
42 #define IDM_FAVORITES 507
43 #define IDM_SETTINGS 508
44 #define IDM_PRINTERSANDFAXES 510
45 #define IDM_SEARCH 520
46 #define IDM_SYNCHRONIZE 553
47 #define IDM_NETWORKCONNECTIONS 557
48 #define IDM_DISCONNECT 5000
49 #define IDM_SECURITY 5001
50
51 /*
52 * TODO:
53 * 1. append the start menu contents from all users
54 * 2. implement the context menu for start menu entries (programs, control panel, network connetions, printers)
55 * 3. filter out programs folder from the shell folder part of the start menu
56 * 4. showing the programs start menu is SLOW compared to windows. this needs some investigation
57 */
58
59 class CShellMenuCallback :
60 public CComObjectRootEx<CComMultiThreadModelNoCS>,
61 public IShellMenuCallback
62 {
63 private:
64 HWND m_hwndTray;
65 CComPtr<IShellMenu> m_pShellMenu;
66 CComPtr<IBandSite> m_pBandSite;
67 CComPtr<IDeskBar> m_pDeskBar;
68 CComPtr<ITrayPriv> m_pTrayPriv;
69 CComPtr<IShellFolder> m_psfPrograms;
70
71 LPITEMIDLIST m_pidlPrograms;
72
OnInitMenu()73 HRESULT OnInitMenu()
74 {
75 HMENU hmenu;
76 HRESULT hr;
77
78 if (m_pTrayPriv.p)
79 return S_OK;
80
81 hr = IUnknown_GetSite(m_pDeskBar, IID_PPV_ARG(ITrayPriv, &m_pTrayPriv));
82 if (FAILED_UNEXPECTEDLY(hr))
83 return hr;
84
85 hr = IUnknown_GetWindow(m_pTrayPriv, &m_hwndTray);
86 if (FAILED_UNEXPECTEDLY(hr))
87 return hr;
88
89 hr = m_pTrayPriv->AppendMenu(&hmenu);
90 if (FAILED_UNEXPECTEDLY(hr))
91 return hr;
92
93 hr = m_pShellMenu->SetMenu(hmenu, NULL, SMSET_BOTTOM);
94 if (FAILED_UNEXPECTEDLY(hr))
95 {
96 DestroyMenu(hmenu);
97 return hr;
98 }
99
100 return hr;
101 }
102
OnGetInfo(LPSMDATA psmd,SMINFO * psminfo)103 HRESULT OnGetInfo(LPSMDATA psmd, SMINFO *psminfo)
104 {
105 int iconIndex = 0;
106
107 switch (psmd->uId)
108 {
109 // Smaller "24x24" icons used for the start menu
110 // The bitmaps are still 32x32, but the image is centered
111 case IDM_FAVORITES: iconIndex = -IDI_SHELL_FAVOTITES; break;
112 case IDM_SEARCH: iconIndex = -IDI_SHELL_SEARCH1; break;
113 case IDM_HELPANDSUPPORT: iconIndex = -IDI_SHELL_HELP2; break;
114 case IDM_LOGOFF: iconIndex = -IDI_SHELL_LOGOFF1; break;
115 case IDM_PROGRAMS: iconIndex = -IDI_SHELL_PROGRAMS_FOLDER1; break;
116 case IDM_DOCUMENTS: iconIndex = -IDI_SHELL_RECENT_DOCUMENTS1; break;
117 case IDM_RUN: iconIndex = -IDI_SHELL_RUN1; break;
118 case IDM_SHUTDOWN: iconIndex = -IDI_SHELL_SHUTDOWN1; break;
119 case IDM_SETTINGS: iconIndex = -IDI_SHELL_CONTROL_PANEL1; break;
120 case IDM_MYDOCUMENTS: iconIndex = -IDI_SHELL_MY_DOCUMENTS; break;
121 case IDM_MYPICTURES: iconIndex = -IDI_SHELL_MY_PICTURES; break;
122
123 case IDM_CONTROLPANEL: iconIndex = -IDI_SHELL_CONTROL_PANEL; break;
124 case IDM_NETWORKCONNECTIONS: iconIndex = -IDI_SHELL_NETWORK_CONNECTIONS2; break;
125 case IDM_PRINTERSANDFAXES: iconIndex = -IDI_SHELL_PRINTER2; break;
126 case IDM_TASKBARANDSTARTMENU: iconIndex = -IDI_SHELL_TSKBAR_STARTMENU; break;
127 //case IDM_SECURITY: iconIndex = -21; break;
128 //case IDM_SYNCHRONIZE: iconIndex = -21; break;
129 //case IDM_DISCONNECT: iconIndex = -21; break;
130 //case IDM_UNDOCKCOMPUTER: iconIndex = -21; break;
131 default:
132 return S_FALSE;
133 }
134
135 if (iconIndex)
136 {
137 if ((psminfo->dwMask & SMIM_TYPE) != 0)
138 psminfo->dwType = SMIT_STRING;
139 if ((psminfo->dwMask & SMIM_ICON) != 0)
140 psminfo->iIcon = Shell_GetCachedImageIndex(L"shell32.dll", iconIndex, FALSE);
141 if ((psminfo->dwMask & SMIM_FLAGS) != 0)
142 psminfo->dwFlags |= SMIF_ICON;
143 #ifdef TEST_TRACKPOPUPMENU_SUBMENUS
144 if ((psminfo->dwMask & SMIM_FLAGS) != 0)
145 psminfo->dwFlags |= SMIF_TRACKPOPUP;
146 #endif
147 }
148 else
149 {
150 if ((psminfo->dwMask & SMIM_TYPE) != 0)
151 psminfo->dwType = SMIT_SEPARATOR;
152 }
153 return S_OK;
154 }
155
AddOrSetMenuItem(HMENU hMenu,UINT nID,INT csidl,BOOL bExpand,BOOL bAdd=TRUE,BOOL bSetText=TRUE) const156 void AddOrSetMenuItem(HMENU hMenu, UINT nID, INT csidl, BOOL bExpand,
157 BOOL bAdd = TRUE, BOOL bSetText = TRUE) const
158 {
159 MENUITEMINFOW mii = { sizeof(mii), MIIM_ID | MIIM_SUBMENU };
160 mii.wID = nID;
161
162 SHFILEINFOW fileInfo = { 0 };
163 if (bAdd || bSetText)
164 {
165 LPITEMIDLIST pidl;
166 if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) != S_OK)
167 {
168 ERR("SHGetSpecialFolderLocation failed\n");
169 return;
170 }
171
172 SHGetFileInfoW((LPWSTR)pidl, 0, &fileInfo, sizeof(fileInfo),
173 SHGFI_PIDL | SHGFI_DISPLAYNAME);
174 CoTaskMemFree(pidl);
175
176 mii.fMask |= MIIM_TYPE;
177 mii.fType = MFT_STRING;
178 mii.dwTypeData = fileInfo.szDisplayName;
179 }
180
181 if (bExpand)
182 mii.hSubMenu = ::CreatePopupMenu();
183
184 if (bAdd)
185 InsertMenuItemW(hMenu, GetMenuItemCount(hMenu), TRUE, &mii);
186 else
187 SetMenuItemInfoW(hMenu, nID, FALSE, &mii);
188 }
189
GetAdvancedValue(LPCWSTR pszName,BOOL bDefault=FALSE) const190 BOOL GetAdvancedValue(LPCWSTR pszName, BOOL bDefault = FALSE) const
191 {
192 return SHRegGetBoolUSValueW(
193 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
194 pszName, FALSE, bDefault);
195 }
196
CreateRecentMenu() const197 HMENU CreateRecentMenu() const
198 {
199 HMENU hMenu = ::CreateMenu();
200 BOOL bAdded = FALSE;
201
202 // My Documents
203 if (!SHRestricted(REST_NOSMMYDOCS) &&
204 GetAdvancedValue(L"Start_ShowMyDocs", TRUE))
205 {
206 BOOL bExpand = GetAdvancedValue(L"CascadeMyDocuments", FALSE);
207 AddOrSetMenuItem(hMenu, IDM_MYDOCUMENTS, CSIDL_MYDOCUMENTS, bExpand);
208 bAdded = TRUE;
209 }
210
211 // My Pictures
212 if (!SHRestricted(REST_NOSMMYPICS) &&
213 GetAdvancedValue(L"Start_ShowMyPics", TRUE))
214 {
215 BOOL bExpand = GetAdvancedValue(L"CascadeMyPictures", FALSE);
216 AddOrSetMenuItem(hMenu, IDM_MYPICTURES, CSIDL_MYPICTURES, bExpand);
217 bAdded = TRUE;
218 }
219
220 if (bAdded)
221 AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
222
223 return hMenu;
224 }
225
UpdateSettingsMenu(HMENU hMenu)226 void UpdateSettingsMenu(HMENU hMenu)
227 {
228 BOOL bExpand;
229
230 bExpand = GetAdvancedValue(L"CascadeControlPanel");
231 AddOrSetMenuItem(hMenu, IDM_CONTROLPANEL, CSIDL_CONTROLS, bExpand, FALSE, FALSE);
232
233 bExpand = GetAdvancedValue(L"CascadeNetworkConnections");
234 AddOrSetMenuItem(hMenu, IDM_NETWORKCONNECTIONS, CSIDL_NETWORK, bExpand, FALSE, FALSE);
235
236 bExpand = GetAdvancedValue(L"CascadePrinters");
237 AddOrSetMenuItem(hMenu, IDM_PRINTERSANDFAXES, CSIDL_PRINTERS, bExpand, FALSE, FALSE);
238 }
239
AddStartMenuItems(IShellMenu * pShellMenu,INT csidl,DWORD dwFlags,IShellFolder * psf=NULL)240 HRESULT AddStartMenuItems(IShellMenu *pShellMenu, INT csidl, DWORD dwFlags, IShellFolder *psf = NULL)
241 {
242 CComHeapPtr<ITEMIDLIST> pidlFolder;
243 CComPtr<IShellFolder> psfDesktop;
244 CComPtr<IShellFolder> pShellFolder;
245 HRESULT hr;
246
247 hr = SHGetFolderLocation(NULL, csidl, 0, 0, &pidlFolder);
248 if (FAILED_UNEXPECTEDLY(hr))
249 return hr;
250
251 if (psf)
252 {
253 pShellFolder = psf;
254 }
255 else
256 {
257 hr = SHGetDesktopFolder(&psfDesktop);
258 if (FAILED_UNEXPECTEDLY(hr))
259 return hr;
260
261 hr = psfDesktop->BindToObject(pidlFolder, NULL, IID_PPV_ARG(IShellFolder, &pShellFolder));
262 if (FAILED_UNEXPECTEDLY(hr))
263 return hr;
264 }
265
266 hr = pShellMenu->SetShellFolder(pShellFolder, pidlFolder, NULL, dwFlags);
267 if (FAILED_UNEXPECTEDLY(hr))
268 return hr;
269
270 return hr;
271 }
272
OnGetSubMenu(LPSMDATA psmd,REFIID iid,void ** pv)273 HRESULT OnGetSubMenu(LPSMDATA psmd, REFIID iid, void ** pv)
274 {
275 HRESULT hr;
276 CComPtr<IShellMenu> pShellMenu;
277
278 hr = CMenuBand_CreateInstance(IID_PPV_ARG(IShellMenu, &pShellMenu));
279 if (FAILED_UNEXPECTEDLY(hr))
280 return hr;
281
282 hr = pShellMenu->Initialize(this, 0, ANCESTORDEFAULT, SMINIT_VERTICAL);
283 if (FAILED_UNEXPECTEDLY(hr))
284 return hr;
285
286 hr = E_FAIL;
287 switch (psmd->uId)
288 {
289 case IDM_PROGRAMS:
290 {
291 hr = AddStartMenuItems(pShellMenu, CSIDL_PROGRAMS, SMSET_TOP, m_psfPrograms);
292 break;
293 }
294 case IDM_FAVORITES:
295 case IDM_MYDOCUMENTS:
296 case IDM_MYPICTURES:
297 case IDM_CONTROLPANEL:
298 case IDM_NETWORKCONNECTIONS:
299 case IDM_PRINTERSANDFAXES:
300 {
301 hr = AddStartMenuItems(pShellMenu, CSIDLFromID(psmd->uId), SMSET_TOP);
302 break;
303 }
304 case IDM_DOCUMENTS:
305 {
306 HMENU hMenu = CreateRecentMenu();
307 if (hMenu == NULL)
308 ERR("CreateRecentMenu failed\n");
309
310 hr = pShellMenu->SetMenu(hMenu, NULL, SMSET_BOTTOM);
311 if (FAILED_UNEXPECTEDLY(hr))
312 return hr;
313
314 hr = AddStartMenuItems(pShellMenu, CSIDL_RECENT, SMSET_BOTTOM);
315 break;
316 }
317 case IDM_SETTINGS:
318 {
319 MENUITEMINFOW mii = { sizeof(mii), MIIM_SUBMENU };
320 if (GetMenuItemInfoW(psmd->hmenu, psmd->uId, FALSE, &mii))
321 {
322 UpdateSettingsMenu(mii.hSubMenu);
323
324 hr = pShellMenu->SetMenu(mii.hSubMenu, NULL, SMSET_BOTTOM);
325 if (FAILED_UNEXPECTEDLY(hr))
326 return hr;
327 }
328 break;
329 }
330 default:
331 {
332 MENUITEMINFOW mii = { sizeof(mii), MIIM_SUBMENU };
333 if (GetMenuItemInfoW(psmd->hmenu, psmd->uId, FALSE, &mii))
334 {
335 hr = pShellMenu->SetMenu(mii.hSubMenu, NULL, SMSET_BOTTOM);
336 if (FAILED_UNEXPECTEDLY(hr))
337 return hr;
338 }
339 }
340 }
341
342 if (FAILED(hr))
343 return hr;
344
345 hr = pShellMenu->QueryInterface(iid, pv);
346 pShellMenu.Detach();
347 return hr;
348 }
349
CSIDLFromID(UINT uId) const350 INT CSIDLFromID(UINT uId) const
351 {
352 switch (uId)
353 {
354 case IDM_PROGRAMS: return CSIDL_PROGRAMS;
355 case IDM_FAVORITES: return CSIDL_FAVORITES;
356 case IDM_DOCUMENTS: return CSIDL_RECENT;
357 case IDM_MYDOCUMENTS: return CSIDL_MYDOCUMENTS;
358 case IDM_MYPICTURES: return CSIDL_MYPICTURES;
359 case IDM_CONTROLPANEL: return CSIDL_CONTROLS;
360 case IDM_NETWORKCONNECTIONS: return CSIDL_NETWORK;
361 case IDM_PRINTERSANDFAXES: return CSIDL_PRINTERS;
362 default: return 0;
363 }
364 }
365
OnGetContextMenu(LPSMDATA psmd,REFIID iid,void ** pv)366 HRESULT OnGetContextMenu(LPSMDATA psmd, REFIID iid, void ** pv)
367 {
368 INT csidl = CSIDLFromID(psmd->uId);
369 if (!csidl)
370 return S_FALSE;
371
372 TRACE("csidl: 0x%X\n", csidl);
373
374 if (csidl == CSIDL_CONTROLS || csidl == CSIDL_NETWORK || csidl == CSIDL_PRINTERS)
375 FIXME("This CSIDL %d wrongly opens My Computer. CORE-19477\n", csidl);
376
377 CComHeapPtr<ITEMIDLIST> pidl;
378 SHGetSpecialFolderLocation(NULL, csidl, &pidl);
379
380 CComPtr<IShellFolder> pSF;
381 LPCITEMIDLIST pidlChild = NULL;
382 HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&pSF, &pidlChild);
383 if (FAILED(hr))
384 return hr;
385
386 return pSF->GetUIObjectOf(NULL, 1, &pidlChild, IID_IContextMenu, NULL, pv);
387 }
388
OnGetObject(LPSMDATA psmd,REFIID iid,void ** pv)389 HRESULT OnGetObject(LPSMDATA psmd, REFIID iid, void ** pv)
390 {
391 if (IsEqualIID(iid, IID_IShellMenu))
392 return OnGetSubMenu(psmd, iid, pv);
393 else if (IsEqualIID(iid, IID_IContextMenu))
394 return OnGetContextMenu(psmd, iid, pv);
395
396 return S_FALSE;
397 }
398
OnExec(LPSMDATA psmd)399 HRESULT OnExec(LPSMDATA psmd)
400 {
401 WCHAR szPath[MAX_PATH];
402
403 // HACK: Because our ShellExecute can't handle CLSID components in paths, we can't launch the paths using the "open" verb.
404 // FIXME: Change this back to using the path as the filename and the "open" verb, once ShellExecute can handle CLSID path components.
405
406 if (psmd->uId == IDM_CONTROLPANEL)
407 ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL, SW_SHOWNORMAL);
408 else if (psmd->uId == IDM_NETWORKCONNECTIONS)
409 ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", NULL, SW_SHOWNORMAL);
410 else if (psmd->uId == IDM_PRINTERSANDFAXES)
411 ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}", NULL, SW_SHOWNORMAL);
412 else if (psmd->uId == IDM_MYDOCUMENTS)
413 {
414 if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_PERSONAL, FALSE))
415 ShellExecuteW(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);
416 else
417 ERR("SHGetSpecialFolderPathW failed\n");
418 }
419 else if (psmd->uId == IDM_MYPICTURES)
420 {
421 if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_MYPICTURES, FALSE))
422 ShellExecuteW(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);
423 else
424 ERR("SHGetSpecialFolderPathW failed\n");
425 }
426 else
427 PostMessageW(m_hwndTray, WM_COMMAND, psmd->uId, 0);
428
429 return S_OK;
430 }
431
432 public:
433
434 DECLARE_NOT_AGGREGATABLE(CShellMenuCallback)
DECLARE_PROTECT_FINAL_CONSTRUCT()435 DECLARE_PROTECT_FINAL_CONSTRUCT()
436 BEGIN_COM_MAP(CShellMenuCallback)
437 COM_INTERFACE_ENTRY_IID(IID_IShellMenuCallback, IShellMenuCallback)
438 END_COM_MAP()
439
440 void Initialize(
441 IShellMenu* pShellMenu,
442 IBandSite* pBandSite,
443 IDeskBar* pDeskBar)
444 {
445 m_pShellMenu = pShellMenu;
446 m_pBandSite = pBandSite;
447 m_pDeskBar = pDeskBar;
448 }
449
~CShellMenuCallback()450 ~CShellMenuCallback()
451 {
452 }
453
_SetProgramsFolder(IShellFolder * psf,LPITEMIDLIST pidl)454 HRESULT _SetProgramsFolder(IShellFolder * psf, LPITEMIDLIST pidl)
455 {
456 m_psfPrograms = psf;
457 m_pidlPrograms = pidl;
458 return S_OK;
459 }
460
CallbackSM(LPSMDATA psmd,UINT uMsg,WPARAM wParam,LPARAM lParam)461 HRESULT STDMETHODCALLTYPE CallbackSM(
462 LPSMDATA psmd,
463 UINT uMsg,
464 WPARAM wParam,
465 LPARAM lParam)
466 {
467 switch (uMsg)
468 {
469 case SMC_INITMENU:
470 return OnInitMenu();
471 case SMC_GETINFO:
472 return OnGetInfo(psmd, reinterpret_cast<SMINFO*>(lParam));
473 case SMC_GETOBJECT:
474 return OnGetObject(psmd, *reinterpret_cast<IID *>(wParam), reinterpret_cast<void **>(lParam));
475 case SMC_EXEC:
476 return OnExec(psmd);
477 case SMC_SFEXEC:
478 m_pTrayPriv->Execute(psmd->psf, psmd->pidlItem);
479 break;
480 case 0x10000000: // _FilterPIDL from CMenuSFToolbar
481 if (psmd->psf->CompareIDs(0, psmd->pidlItem, m_pidlPrograms) == 0)
482 return S_OK;
483 return S_FALSE;
484 }
485
486 return S_FALSE;
487 }
488 };
489
BindToDesktop(LPCITEMIDLIST pidl,IShellFolder ** ppsfResult)490 HRESULT BindToDesktop(LPCITEMIDLIST pidl, IShellFolder ** ppsfResult)
491 {
492 HRESULT hr;
493 CComPtr<IShellFolder> psfDesktop;
494
495 *ppsfResult = NULL;
496
497 hr = SHGetDesktopFolder(&psfDesktop);
498 if (FAILED(hr))
499 return hr;
500
501 hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, ppsfResult));
502
503 return hr;
504 }
505
GetMergedFolder(int folder1,int folder2,IShellFolder ** ppsfStartMenu)506 static HRESULT GetMergedFolder(int folder1, int folder2, IShellFolder ** ppsfStartMenu)
507 {
508 HRESULT hr;
509 LPITEMIDLIST pidlUserStartMenu;
510 LPITEMIDLIST pidlCommonStartMenu;
511 CComPtr<IShellFolder> psfUserStartMenu;
512 CComPtr<IShellFolder> psfCommonStartMenu;
513 CComPtr<IAugmentedShellFolder> pasf;
514
515 *ppsfStartMenu = NULL;
516
517 hr = SHGetSpecialFolderLocation(NULL, folder1, &pidlUserStartMenu);
518 if (FAILED(hr))
519 {
520 WARN("Failed to get the USER start menu folder. Trying to run with just the COMMON one.\n");
521
522 hr = SHGetSpecialFolderLocation(NULL, folder2, &pidlCommonStartMenu);
523 if (FAILED_UNEXPECTEDLY(hr))
524 return hr;
525
526 TRACE("COMMON start menu obtained.\n");
527 hr = BindToDesktop(pidlCommonStartMenu, ppsfStartMenu);
528 ILFree(pidlCommonStartMenu);
529 return hr;
530 }
531 #if MERGE_FOLDERS
532 hr = SHGetSpecialFolderLocation(NULL, folder2, &pidlCommonStartMenu);
533 if (FAILED_UNEXPECTEDLY(hr))
534 #else
535 else
536 #endif
537 {
538 WARN("Failed to get the COMMON start menu folder. Will use only the USER contents.\n");
539 hr = BindToDesktop(pidlUserStartMenu, ppsfStartMenu);
540 ILFree(pidlUserStartMenu);
541 return hr;
542 }
543
544 TRACE("Both COMMON and USER statr menu folders obtained, merging them...\n");
545
546 hr = BindToDesktop(pidlUserStartMenu, &psfUserStartMenu);
547 if (FAILED_UNEXPECTEDLY(hr))
548 return hr;
549
550 hr = BindToDesktop(pidlCommonStartMenu, &psfCommonStartMenu);
551 if (FAILED_UNEXPECTEDLY(hr))
552 return hr;
553
554 hr = CMergedFolder_CreateInstance(IID_PPV_ARG(IAugmentedShellFolder, &pasf));
555 if (FAILED_UNEXPECTEDLY(hr))
556 {
557 *ppsfStartMenu = psfUserStartMenu.Detach();
558 ILFree(pidlCommonStartMenu);
559 ILFree(pidlUserStartMenu);
560 return hr;
561 }
562
563 hr = pasf->AddNameSpace(NULL, psfUserStartMenu, pidlUserStartMenu, 0xFF00);
564 if (FAILED_UNEXPECTEDLY(hr))
565 return hr;
566
567 hr = pasf->AddNameSpace(NULL, psfCommonStartMenu, pidlCommonStartMenu, 0);
568 if (FAILED_UNEXPECTEDLY(hr))
569 return hr;
570
571 hr = pasf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsfStartMenu));
572 pasf.Release();
573
574 ILFree(pidlCommonStartMenu);
575 ILFree(pidlUserStartMenu);
576
577 return hr;
578 }
579
GetStartMenuFolder(IShellFolder ** ppsfStartMenu)580 static HRESULT GetStartMenuFolder(IShellFolder ** ppsfStartMenu)
581 {
582 return GetMergedFolder(CSIDL_STARTMENU, CSIDL_COMMON_STARTMENU, ppsfStartMenu);
583 }
584
GetProgramsFolder(IShellFolder ** ppsfStartMenu)585 static HRESULT GetProgramsFolder(IShellFolder ** ppsfStartMenu)
586 {
587 return GetMergedFolder(CSIDL_PROGRAMS, CSIDL_COMMON_PROGRAMS, ppsfStartMenu);
588 }
589
590 extern "C"
591 HRESULT WINAPI
RSHELL_CStartMenu_CreateInstance(REFIID riid,void ** ppv)592 RSHELL_CStartMenu_CreateInstance(REFIID riid, void **ppv)
593 {
594 CComPtr<IShellMenu> pShellMenu;
595 CComPtr<IBandSite> pBandSite;
596 CComPtr<IDeskBar> pDeskBar;
597
598 HRESULT hr;
599 IShellFolder * psf;
600
601 LPITEMIDLIST pidlProgramsAbsolute;
602 LPITEMIDLIST pidlPrograms;
603 CComPtr<IShellFolder> psfPrograms;
604
605 hr = CMenuBand_CreateInstance(IID_PPV_ARG(IShellMenu, &pShellMenu));
606 if (FAILED_UNEXPECTEDLY(hr))
607 return hr;
608
609 hr = CMenuSite_CreateInstance(IID_PPV_ARG(IBandSite, &pBandSite));
610 if (FAILED_UNEXPECTEDLY(hr))
611 return hr;
612
613 hr = CMenuDeskBar_CreateInstance(IID_PPV_ARG(IDeskBar, &pDeskBar));
614 if (FAILED_UNEXPECTEDLY(hr))
615 return hr;
616
617 CComObject<CShellMenuCallback> *pCallback;
618 hr = CComObject<CShellMenuCallback>::CreateInstance(&pCallback);
619 if (FAILED_UNEXPECTEDLY(hr))
620 return hr;
621
622 pCallback->AddRef(); // CreateInstance returns object with 0 ref count */
623 pCallback->Initialize(pShellMenu, pBandSite, pDeskBar);
624
625 hr = pShellMenu->Initialize(pCallback, (UINT) -1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL);
626 if (FAILED_UNEXPECTEDLY(hr))
627 return hr;
628
629 hr = GetStartMenuFolder(&psf);
630 if (FAILED_UNEXPECTEDLY(hr))
631 return hr;
632
633 /* psf is a merged folder, so now we want to get the pidl of the programs item from the merged folder */
634 {
635 hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAMS, &pidlProgramsAbsolute);
636 if (FAILED_UNEXPECTEDLY(hr))
637 {
638 WARN("USER Programs folder not found\n");
639 hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlProgramsAbsolute);
640 if (FAILED_UNEXPECTEDLY(hr))
641 return hr;
642 }
643
644 LPCITEMIDLIST pcidlPrograms;
645 CComPtr<IShellFolder> psfParent;
646 STRRET str;
647 TCHAR szDisplayName[MAX_PATH];
648
649 hr = SHBindToParent(pidlProgramsAbsolute, IID_PPV_ARG(IShellFolder, &psfParent), &pcidlPrograms);
650 if (FAILED_UNEXPECTEDLY(hr))
651 return hr;
652
653 hr = psfParent->GetDisplayNameOf(pcidlPrograms, SHGDN_FORPARSING | SHGDN_INFOLDER, &str);
654 if (FAILED_UNEXPECTEDLY(hr))
655 return hr;
656
657 StrRetToBuf(&str, pcidlPrograms, szDisplayName, _countof(szDisplayName));
658 ILFree(pidlProgramsAbsolute);
659
660 /* We got the display name from the fs folder and we parse it with the merged folder here */
661 hr = psf->ParseDisplayName(NULL, NULL, szDisplayName, NULL, &pidlPrograms, NULL);
662 if (FAILED_UNEXPECTEDLY(hr))
663 return hr;
664 }
665
666 hr = GetProgramsFolder(&psfPrograms);
667 if (FAILED_UNEXPECTEDLY(hr))
668 return hr;
669
670 hr = pCallback->_SetProgramsFolder(psfPrograms, pidlPrograms);
671 if (FAILED_UNEXPECTEDLY(hr))
672 return hr;
673
674 hr = pShellMenu->SetShellFolder(psf, NULL, NULL, SMSET_TOP);
675 if (FAILED_UNEXPECTEDLY(hr))
676 return hr;
677
678 hr = pDeskBar->SetClient(pBandSite);
679 if (FAILED_UNEXPECTEDLY(hr))
680 return hr;
681
682 hr = pBandSite->AddBand(pShellMenu);
683 if (FAILED_UNEXPECTEDLY(hr))
684 return hr;
685
686 return pDeskBar->QueryInterface(riid, ppv);
687 }
688