Reactos
at listview 684 lines 23 kB view raw
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 24WINE_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 59class CShellMenuCallback : 60 public CComObjectRootEx<CComMultiThreadModelNoCS>, 61 public IShellMenuCallback 62{ 63private: 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_CONNECTIONS; 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 CComHeapPtr<ITEMIDLIST> pidl; 375 SHGetSpecialFolderLocation(NULL, csidl, &pidl); 376 377 CComPtr<IShellFolder> pSF; 378 LPCITEMIDLIST pidlChild = NULL; 379 HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&pSF, &pidlChild); 380 if (FAILED(hr)) 381 return hr; 382 383 return pSF->GetUIObjectOf(NULL, 1, &pidlChild, IID_IContextMenu, NULL, pv); 384 } 385 386 HRESULT OnGetObject(LPSMDATA psmd, REFIID iid, void ** pv) 387 { 388 if (IsEqualIID(iid, IID_IShellMenu)) 389 return OnGetSubMenu(psmd, iid, pv); 390 else if (IsEqualIID(iid, IID_IContextMenu)) 391 return OnGetContextMenu(psmd, iid, pv); 392 393 return S_FALSE; 394 } 395 396 HRESULT OnExec(LPSMDATA psmd) 397 { 398 WCHAR szPath[MAX_PATH]; 399 400 // HACK: Because our ShellExecute can't handle CLSID components in paths, we can't launch the paths using the "open" verb. 401 // FIXME: Change this back to using the path as the filename and the "open" verb, once ShellExecute can handle CLSID path components. 402 403 if (psmd->uId == IDM_CONTROLPANEL) 404 ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL, SW_SHOWNORMAL); 405 else if (psmd->uId == IDM_NETWORKCONNECTIONS) 406 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); 407 else if (psmd->uId == IDM_PRINTERSANDFAXES) 408 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); 409 else if (psmd->uId == IDM_MYDOCUMENTS) 410 { 411 if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_PERSONAL, FALSE)) 412 ShellExecuteW(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL); 413 else 414 ERR("SHGetSpecialFolderPathW failed\n"); 415 } 416 else if (psmd->uId == IDM_MYPICTURES) 417 { 418 if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_MYPICTURES, FALSE)) 419 ShellExecuteW(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL); 420 else 421 ERR("SHGetSpecialFolderPathW failed\n"); 422 } 423 else 424 PostMessageW(m_hwndTray, WM_COMMAND, psmd->uId, 0); 425 426 return S_OK; 427 } 428 429public: 430 431 DECLARE_NOT_AGGREGATABLE(CShellMenuCallback) 432 DECLARE_PROTECT_FINAL_CONSTRUCT() 433 BEGIN_COM_MAP(CShellMenuCallback) 434 COM_INTERFACE_ENTRY_IID(IID_IShellMenuCallback, IShellMenuCallback) 435 END_COM_MAP() 436 437 void Initialize( 438 IShellMenu* pShellMenu, 439 IBandSite* pBandSite, 440 IDeskBar* pDeskBar) 441 { 442 m_pShellMenu = pShellMenu; 443 m_pBandSite = pBandSite; 444 m_pDeskBar = pDeskBar; 445 } 446 447 ~CShellMenuCallback() 448 { 449 } 450 451 HRESULT _SetProgramsFolder(IShellFolder * psf, LPITEMIDLIST pidl) 452 { 453 m_psfPrograms = psf; 454 m_pidlPrograms = pidl; 455 return S_OK; 456 } 457 458 HRESULT STDMETHODCALLTYPE CallbackSM( 459 LPSMDATA psmd, 460 UINT uMsg, 461 WPARAM wParam, 462 LPARAM lParam) 463 { 464 switch (uMsg) 465 { 466 case SMC_INITMENU: 467 return OnInitMenu(); 468 case SMC_GETINFO: 469 return OnGetInfo(psmd, reinterpret_cast<SMINFO*>(lParam)); 470 case SMC_GETOBJECT: 471 return OnGetObject(psmd, *reinterpret_cast<IID *>(wParam), reinterpret_cast<void **>(lParam)); 472 case SMC_EXEC: 473 return OnExec(psmd); 474 case SMC_SFEXEC: 475 m_pTrayPriv->Execute(psmd->psf, psmd->pidlItem); 476 break; 477 case 0x10000000: // _FilterPIDL from CMenuSFToolbar 478 if (psmd->psf->CompareIDs(0, psmd->pidlItem, m_pidlPrograms) == 0) 479 return S_OK; 480 return S_FALSE; 481 } 482 483 return S_FALSE; 484 } 485}; 486 487HRESULT BindToDesktop(LPCITEMIDLIST pidl, IShellFolder ** ppsfResult) 488{ 489 HRESULT hr; 490 CComPtr<IShellFolder> psfDesktop; 491 492 *ppsfResult = NULL; 493 494 hr = SHGetDesktopFolder(&psfDesktop); 495 if (FAILED(hr)) 496 return hr; 497 498 hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, ppsfResult)); 499 500 return hr; 501} 502 503static HRESULT GetMergedFolder(int folder1, int folder2, IShellFolder ** ppsfStartMenu) 504{ 505 HRESULT hr; 506 LPITEMIDLIST pidlUserStartMenu; 507 LPITEMIDLIST pidlCommonStartMenu; 508 CComPtr<IShellFolder> psfUserStartMenu; 509 CComPtr<IShellFolder> psfCommonStartMenu; 510 CComPtr<IAugmentedShellFolder> pasf; 511 512 *ppsfStartMenu = NULL; 513 514 hr = SHGetSpecialFolderLocation(NULL, folder1, &pidlUserStartMenu); 515 if (FAILED(hr)) 516 { 517 WARN("Failed to get the USER start menu folder. Trying to run with just the COMMON one.\n"); 518 519 hr = SHGetSpecialFolderLocation(NULL, folder2, &pidlCommonStartMenu); 520 if (FAILED_UNEXPECTEDLY(hr)) 521 return hr; 522 523 TRACE("COMMON start menu obtained.\n"); 524 hr = BindToDesktop(pidlCommonStartMenu, ppsfStartMenu); 525 ILFree(pidlCommonStartMenu); 526 return hr; 527 } 528#if MERGE_FOLDERS 529 hr = SHGetSpecialFolderLocation(NULL, folder2, &pidlCommonStartMenu); 530 if (FAILED_UNEXPECTEDLY(hr)) 531#else 532 else 533#endif 534 { 535 WARN("Failed to get the COMMON start menu folder. Will use only the USER contents.\n"); 536 hr = BindToDesktop(pidlUserStartMenu, ppsfStartMenu); 537 ILFree(pidlUserStartMenu); 538 return hr; 539 } 540 541 TRACE("Both COMMON and USER statr menu folders obtained, merging them...\n"); 542 543 hr = BindToDesktop(pidlUserStartMenu, &psfUserStartMenu); 544 if (FAILED_UNEXPECTEDLY(hr)) 545 return hr; 546 547 hr = BindToDesktop(pidlCommonStartMenu, &psfCommonStartMenu); 548 if (FAILED_UNEXPECTEDLY(hr)) 549 return hr; 550 551 hr = CMergedFolder_CreateInstance(IID_PPV_ARG(IAugmentedShellFolder, &pasf)); 552 if (FAILED_UNEXPECTEDLY(hr)) 553 { 554 *ppsfStartMenu = psfUserStartMenu.Detach(); 555 ILFree(pidlCommonStartMenu); 556 ILFree(pidlUserStartMenu); 557 return hr; 558 } 559 560 hr = pasf->AddNameSpace(NULL, psfUserStartMenu, pidlUserStartMenu, 0xFF00); 561 if (FAILED_UNEXPECTEDLY(hr)) 562 return hr; 563 564 hr = pasf->AddNameSpace(NULL, psfCommonStartMenu, pidlCommonStartMenu, 0); 565 if (FAILED_UNEXPECTEDLY(hr)) 566 return hr; 567 568 hr = pasf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsfStartMenu)); 569 pasf.Release(); 570 571 ILFree(pidlCommonStartMenu); 572 ILFree(pidlUserStartMenu); 573 574 return hr; 575} 576 577static HRESULT GetStartMenuFolder(IShellFolder ** ppsfStartMenu) 578{ 579 return GetMergedFolder(CSIDL_STARTMENU, CSIDL_COMMON_STARTMENU, ppsfStartMenu); 580} 581 582static HRESULT GetProgramsFolder(IShellFolder ** ppsfStartMenu) 583{ 584 return GetMergedFolder(CSIDL_PROGRAMS, CSIDL_COMMON_PROGRAMS, ppsfStartMenu); 585} 586 587extern "C" 588HRESULT WINAPI 589RSHELL_CStartMenu_CreateInstance(REFIID riid, void **ppv) 590{ 591 CComPtr<IShellMenu> pShellMenu; 592 CComPtr<IBandSite> pBandSite; 593 CComPtr<IDeskBar> pDeskBar; 594 595 HRESULT hr; 596 IShellFolder * psf; 597 598 LPITEMIDLIST pidlProgramsAbsolute; 599 LPITEMIDLIST pidlPrograms; 600 CComPtr<IShellFolder> psfPrograms; 601 602 hr = CMenuBand_CreateInstance(IID_PPV_ARG(IShellMenu, &pShellMenu)); 603 if (FAILED_UNEXPECTEDLY(hr)) 604 return hr; 605 606 hr = CMenuSite_CreateInstance(IID_PPV_ARG(IBandSite, &pBandSite)); 607 if (FAILED_UNEXPECTEDLY(hr)) 608 return hr; 609 610 hr = CMenuDeskBar_CreateInstance(IID_PPV_ARG(IDeskBar, &pDeskBar)); 611 if (FAILED_UNEXPECTEDLY(hr)) 612 return hr; 613 614 CComObject<CShellMenuCallback> *pCallback; 615 hr = CComObject<CShellMenuCallback>::CreateInstance(&pCallback); 616 if (FAILED_UNEXPECTEDLY(hr)) 617 return hr; 618 619 pCallback->AddRef(); // CreateInstance returns object with 0 ref count */ 620 pCallback->Initialize(pShellMenu, pBandSite, pDeskBar); 621 622 hr = pShellMenu->Initialize(pCallback, (UINT) -1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL); 623 if (FAILED_UNEXPECTEDLY(hr)) 624 return hr; 625 626 hr = GetStartMenuFolder(&psf); 627 if (FAILED_UNEXPECTEDLY(hr)) 628 return hr; 629 630 /* psf is a merged folder, so now we want to get the pidl of the programs item from the merged folder */ 631 { 632 hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAMS, &pidlProgramsAbsolute); 633 if (FAILED_UNEXPECTEDLY(hr)) 634 { 635 WARN("USER Programs folder not found\n"); 636 hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlProgramsAbsolute); 637 if (FAILED_UNEXPECTEDLY(hr)) 638 return hr; 639 } 640 641 LPCITEMIDLIST pcidlPrograms; 642 CComPtr<IShellFolder> psfParent; 643 STRRET str; 644 TCHAR szDisplayName[MAX_PATH]; 645 646 hr = SHBindToParent(pidlProgramsAbsolute, IID_PPV_ARG(IShellFolder, &psfParent), &pcidlPrograms); 647 if (FAILED_UNEXPECTEDLY(hr)) 648 return hr; 649 650 hr = psfParent->GetDisplayNameOf(pcidlPrograms, SHGDN_FORPARSING | SHGDN_INFOLDER, &str); 651 if (FAILED_UNEXPECTEDLY(hr)) 652 return hr; 653 654 StrRetToBuf(&str, pcidlPrograms, szDisplayName, _countof(szDisplayName)); 655 ILFree(pidlProgramsAbsolute); 656 657 /* We got the display name from the fs folder and we parse it with the merged folder here */ 658 hr = psf->ParseDisplayName(NULL, NULL, szDisplayName, NULL, &pidlPrograms, NULL); 659 if (FAILED_UNEXPECTEDLY(hr)) 660 return hr; 661 } 662 663 hr = GetProgramsFolder(&psfPrograms); 664 if (FAILED_UNEXPECTEDLY(hr)) 665 return hr; 666 667 hr = pCallback->_SetProgramsFolder(psfPrograms, pidlPrograms); 668 if (FAILED_UNEXPECTEDLY(hr)) 669 return hr; 670 671 hr = pShellMenu->SetShellFolder(psf, NULL, NULL, SMSET_TOP); 672 if (FAILED_UNEXPECTEDLY(hr)) 673 return hr; 674 675 hr = pDeskBar->SetClient(pBandSite); 676 if (FAILED_UNEXPECTEDLY(hr)) 677 return hr; 678 679 hr = pBandSite->AddBand(pShellMenu); 680 if (FAILED_UNEXPECTEDLY(hr)) 681 return hr; 682 683 return pDeskBar->QueryInterface(riid, ppv); 684}