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 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 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 156 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 190 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 197 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 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 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 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 350 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 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 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 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) 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 450 ~CShellMenuCallback() 451 { 452 } 453 454 HRESULT _SetProgramsFolder(IShellFolder * psf, LPITEMIDLIST pidl) 455 { 456 m_psfPrograms = psf; 457 m_pidlPrograms = pidl; 458 return S_OK; 459 } 460 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 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 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 580 static HRESULT GetStartMenuFolder(IShellFolder ** ppsfStartMenu) 581 { 582 return GetMergedFolder(CSIDL_STARTMENU, CSIDL_COMMON_STARTMENU, ppsfStartMenu); 583 } 584 585 static HRESULT GetProgramsFolder(IShellFolder ** ppsfStartMenu) 586 { 587 return GetMergedFolder(CSIDL_PROGRAMS, CSIDL_COMMON_PROGRAMS, ppsfStartMenu); 588 } 589 590 extern "C" 591 HRESULT WINAPI 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