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->AppendMenuW(&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 return hr; 96 97 return hr; 98 } 99 100 HRESULT OnGetInfo(LPSMDATA psmd, SMINFO *psminfo) 101 { 102 int iconIndex = 0; 103 104 switch (psmd->uId) 105 { 106 // Smaller "24x24" icons used for the start menu 107 // The bitmaps are still 32x32, but the image is centered 108 case IDM_FAVORITES: iconIndex = -IDI_SHELL_FAVOTITES; break; 109 case IDM_SEARCH: iconIndex = -IDI_SHELL_SEARCH1; break; 110 case IDM_HELPANDSUPPORT: iconIndex = -IDI_SHELL_HELP2; break; 111 case IDM_LOGOFF: iconIndex = -IDI_SHELL_LOGOFF1; break; 112 case IDM_PROGRAMS: iconIndex = -IDI_SHELL_PROGRAMS_FOLDER1; break; 113 case IDM_DOCUMENTS: iconIndex = -IDI_SHELL_RECENT_DOCUMENTS1; break; 114 case IDM_RUN: iconIndex = -IDI_SHELL_RUN1; break; 115 case IDM_SHUTDOWN: iconIndex = -IDI_SHELL_SHUTDOWN1; break; 116 case IDM_SETTINGS: iconIndex = -IDI_SHELL_CONTROL_PANEL1; break; 117 case IDM_MYDOCUMENTS: iconIndex = -IDI_SHELL_MY_DOCUMENTS; break; 118 case IDM_MYPICTURES: iconIndex = -IDI_SHELL_MY_PICTURES; break; 119 120 case IDM_CONTROLPANEL: iconIndex = -IDI_SHELL_CONTROL_PANEL; break; 121 case IDM_NETWORKCONNECTIONS: iconIndex = -IDI_SHELL_NETWORK_CONNECTIONS2; break; 122 case IDM_PRINTERSANDFAXES: iconIndex = -IDI_SHELL_PRINTER2; break; 123 case IDM_TASKBARANDSTARTMENU: iconIndex = -IDI_SHELL_TSKBAR_STARTMENU; break; 124 //case IDM_SECURITY: iconIndex = -21; break; 125 //case IDM_SYNCHRONIZE: iconIndex = -21; break; 126 //case IDM_DISCONNECT: iconIndex = -21; break; 127 //case IDM_UNDOCKCOMPUTER: iconIndex = -21; break; 128 default: 129 return S_FALSE; 130 } 131 132 if (iconIndex) 133 { 134 if ((psminfo->dwMask & SMIM_TYPE) != 0) 135 psminfo->dwType = SMIT_STRING; 136 if ((psminfo->dwMask & SMIM_ICON) != 0) 137 psminfo->iIcon = Shell_GetCachedImageIndex(L"shell32.dll", iconIndex, FALSE); 138 if ((psminfo->dwMask & SMIM_FLAGS) != 0) 139 psminfo->dwFlags |= SMIF_ICON; 140 #ifdef TEST_TRACKPOPUPMENU_SUBMENUS 141 if ((psminfo->dwMask & SMIM_FLAGS) != 0) 142 psminfo->dwFlags |= SMIF_TRACKPOPUP; 143 #endif 144 } 145 else 146 { 147 if ((psminfo->dwMask & SMIM_TYPE) != 0) 148 psminfo->dwType = SMIT_SEPARATOR; 149 } 150 return S_OK; 151 } 152 153 void InsertRecentItem(HMENU hMenu, UINT nID, INT csidl, BOOL bExpand) const 154 { 155 WCHAR szPath[MAX_PATH]; 156 if (!SHGetSpecialFolderPathW(NULL, szPath, csidl, FALSE)) 157 { 158 ERR("SHGetSpecialFolderPathW failed\n"); 159 return; 160 } 161 162 LPWSTR pszText = PathFindFileNameW(szPath); 163 if (bExpand) 164 { 165 MENUITEMINFOW mii = { sizeof(mii), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU }; 166 mii.fType = MFT_STRING; 167 mii.wID = nID; 168 mii.hSubMenu = ::CreatePopupMenu(); 169 mii.dwTypeData = pszText; 170 mii.cch = lstrlenW(pszText); 171 InsertMenuItemW(hMenu, GetMenuItemCount(hMenu), TRUE, &mii); 172 } 173 else 174 { 175 AppendMenuW(hMenu, MF_STRING | MF_ENABLED, nID, pszText); 176 } 177 } 178 179 HMENU CreateRecentMenu(BOOL bExpandMyDocuments, BOOL bExpandMyPictures) const 180 { 181 HMENU hMenu = ::CreateMenu(); 182 InsertRecentItem(hMenu, IDM_MYDOCUMENTS, CSIDL_MYDOCUMENTS, bExpandMyDocuments); 183 InsertRecentItem(hMenu, IDM_MYPICTURES, CSIDL_MYPICTURES, bExpandMyPictures); 184 AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL); 185 return hMenu; 186 } 187 188 HRESULT OnGetSubMenu(LPSMDATA psmd, REFIID iid, void ** pv) 189 { 190 HRESULT hr; 191 int csidl = 0; 192 IShellMenu *pShellMenu; 193 194 hr = CMenuBand_CreateInstance(IID_PPV_ARG(IShellMenu, &pShellMenu)); 195 if (FAILED_UNEXPECTEDLY(hr)) 196 return hr; 197 198 hr = pShellMenu->Initialize(this, 0, ANCESTORDEFAULT, SMINIT_VERTICAL); 199 if (FAILED_UNEXPECTEDLY(hr)) 200 return hr; 201 202 switch (psmd->uId) 203 { 204 case IDM_PROGRAMS: csidl = CSIDL_PROGRAMS; break; 205 case IDM_FAVORITES: csidl = CSIDL_FAVORITES; break; 206 case IDM_DOCUMENTS: csidl = CSIDL_RECENT; break; 207 case IDM_MYDOCUMENTS: csidl = CSIDL_MYDOCUMENTS; break; 208 case IDM_MYPICTURES: csidl = CSIDL_MYPICTURES; break; 209 } 210 211 if (csidl) 212 { 213 IShellFolder *psfStartMenu; 214 DWORD dwFlags = SMSET_TOP; 215 216 if (csidl == CSIDL_PROGRAMS && m_psfPrograms) 217 { 218 psfStartMenu = m_psfPrograms; 219 } 220 else 221 { 222 if (csidl == CSIDL_RECENT) 223 { 224 BOOL bExpandMyDocuments = FALSE; /* FIXME: Get value from registry */ 225 BOOL bExpandMyPictures = FALSE; /* FIXME: Get value from registry */ 226 HMENU hMenu = CreateRecentMenu(bExpandMyDocuments, bExpandMyPictures); 227 if (hMenu == NULL) 228 ERR("CreateRecentMenu failed\n"); 229 230 hr = pShellMenu->SetMenu(hMenu, NULL, SMSET_BOTTOM); 231 if (FAILED_UNEXPECTEDLY(hr)) 232 return hr; 233 234 dwFlags = SMSET_BOTTOM; 235 } 236 237 LPITEMIDLIST pidlStartMenu; 238 IShellFolder *psfDestop; 239 hr = SHGetFolderLocation(NULL, csidl, 0, 0, &pidlStartMenu); 240 if (FAILED_UNEXPECTEDLY(hr)) 241 return hr; 242 243 hr = SHGetDesktopFolder(&psfDestop); 244 if (FAILED_UNEXPECTEDLY(hr)) 245 return hr; 246 247 hr = psfDestop->BindToObject(pidlStartMenu, NULL, IID_PPV_ARG(IShellFolder, &psfStartMenu)); 248 if (FAILED_UNEXPECTEDLY(hr)) 249 return hr; 250 } 251 252 hr = pShellMenu->SetShellFolder(psfStartMenu, NULL, NULL, dwFlags); 253 if (FAILED_UNEXPECTEDLY(hr)) 254 return hr; 255 } 256 else 257 { 258 MENUITEMINFO mii; 259 mii.cbSize = sizeof(mii); 260 mii.fMask = MIIM_SUBMENU; 261 if (GetMenuItemInfoW(psmd->hmenu, psmd->uId, FALSE, &mii)) 262 { 263 hr = pShellMenu->SetMenu(mii.hSubMenu, NULL, SMSET_BOTTOM); 264 if (FAILED_UNEXPECTEDLY(hr)) 265 return hr; 266 } 267 } 268 return pShellMenu->QueryInterface(iid, pv); 269 } 270 271 HRESULT OnGetContextMenu(LPSMDATA psmd, REFIID iid, void ** pv) 272 { 273 if (psmd->uId == IDM_PROGRAMS || 274 psmd->uId == IDM_CONTROLPANEL || 275 psmd->uId == IDM_NETWORKCONNECTIONS || 276 psmd->uId == IDM_PRINTERSANDFAXES) 277 { 278 //UNIMPLEMENTED 279 } 280 281 return S_FALSE; 282 } 283 284 HRESULT OnGetObject(LPSMDATA psmd, REFIID iid, void ** pv) 285 { 286 if (IsEqualIID(iid, IID_IShellMenu)) 287 return OnGetSubMenu(psmd, iid, pv); 288 else if (IsEqualIID(iid, IID_IContextMenu)) 289 return OnGetContextMenu(psmd, iid, pv); 290 291 return S_FALSE; 292 } 293 294 HRESULT OnExec(LPSMDATA psmd) 295 { 296 WCHAR szPath[MAX_PATH]; 297 298 // HACK: Because our ShellExecute can't handle CLSID components in paths, we can't launch the paths using the "open" verb. 299 // FIXME: Change this back to using the path as the filename and the "open" verb, once ShellExecute can handle CLSID path components. 300 301 if (psmd->uId == IDM_CONTROLPANEL) 302 ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL, SW_SHOWNORMAL); 303 else if (psmd->uId == IDM_NETWORKCONNECTIONS) 304 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); 305 else if (psmd->uId == IDM_PRINTERSANDFAXES) 306 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); 307 else if (psmd->uId == IDM_MYDOCUMENTS) 308 { 309 if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_PERSONAL, FALSE)) 310 ShellExecuteW(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL); 311 else 312 ERR("SHGetSpecialFolderPathW failed\n"); 313 } 314 else if (psmd->uId == IDM_MYPICTURES) 315 { 316 if (SHGetSpecialFolderPathW(NULL, szPath, CSIDL_MYPICTURES, FALSE)) 317 ShellExecuteW(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL); 318 else 319 ERR("SHGetSpecialFolderPathW failed\n"); 320 } 321 else 322 PostMessageW(m_hwndTray, WM_COMMAND, psmd->uId, 0); 323 324 return S_OK; 325 } 326 327 public: 328 329 DECLARE_NOT_AGGREGATABLE(CShellMenuCallback) 330 DECLARE_PROTECT_FINAL_CONSTRUCT() 331 BEGIN_COM_MAP(CShellMenuCallback) 332 COM_INTERFACE_ENTRY_IID(IID_IShellMenuCallback, IShellMenuCallback) 333 END_COM_MAP() 334 335 void Initialize( 336 IShellMenu* pShellMenu, 337 IBandSite* pBandSite, 338 IDeskBar* pDeskBar) 339 { 340 m_pShellMenu = pShellMenu; 341 m_pBandSite = pBandSite; 342 m_pDeskBar = pDeskBar; 343 } 344 345 ~CShellMenuCallback() 346 { 347 } 348 349 HRESULT _SetProgramsFolder(IShellFolder * psf, LPITEMIDLIST pidl) 350 { 351 m_psfPrograms = psf; 352 m_pidlPrograms = pidl; 353 return S_OK; 354 } 355 356 HRESULT STDMETHODCALLTYPE CallbackSM( 357 LPSMDATA psmd, 358 UINT uMsg, 359 WPARAM wParam, 360 LPARAM lParam) 361 { 362 switch (uMsg) 363 { 364 case SMC_INITMENU: 365 return OnInitMenu(); 366 case SMC_GETINFO: 367 return OnGetInfo(psmd, reinterpret_cast<SMINFO*>(lParam)); 368 case SMC_GETOBJECT: 369 return OnGetObject(psmd, *reinterpret_cast<IID *>(wParam), reinterpret_cast<void **>(lParam)); 370 case SMC_EXEC: 371 return OnExec(psmd); 372 case SMC_SFEXEC: 373 m_pTrayPriv->Execute(psmd->psf, psmd->pidlItem); 374 break; 375 case 0x10000000: // _FilterPIDL from CMenuSFToolbar 376 if (psmd->psf->CompareIDs(0, psmd->pidlItem, m_pidlPrograms) == 0) 377 return S_OK; 378 return S_FALSE; 379 } 380 381 return S_FALSE; 382 } 383 }; 384 385 HRESULT BindToDesktop(LPCITEMIDLIST pidl, IShellFolder ** ppsfResult) 386 { 387 HRESULT hr; 388 CComPtr<IShellFolder> psfDesktop; 389 390 *ppsfResult = NULL; 391 392 hr = SHGetDesktopFolder(&psfDesktop); 393 if (FAILED(hr)) 394 return hr; 395 396 hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, ppsfResult)); 397 398 return hr; 399 } 400 401 static HRESULT GetMergedFolder(int folder1, int folder2, IShellFolder ** ppsfStartMenu) 402 { 403 HRESULT hr; 404 LPITEMIDLIST pidlUserStartMenu; 405 LPITEMIDLIST pidlCommonStartMenu; 406 CComPtr<IShellFolder> psfUserStartMenu; 407 CComPtr<IShellFolder> psfCommonStartMenu; 408 CComPtr<IAugmentedShellFolder> pasf; 409 410 *ppsfStartMenu = NULL; 411 412 hr = SHGetSpecialFolderLocation(NULL, folder1, &pidlUserStartMenu); 413 if (FAILED(hr)) 414 { 415 WARN("Failed to get the USER start menu folder. Trying to run with just the COMMON one.\n"); 416 417 hr = SHGetSpecialFolderLocation(NULL, folder2, &pidlCommonStartMenu); 418 if (FAILED_UNEXPECTEDLY(hr)) 419 return hr; 420 421 TRACE("COMMON start menu obtained.\n"); 422 hr = BindToDesktop(pidlCommonStartMenu, ppsfStartMenu); 423 ILFree(pidlCommonStartMenu); 424 return hr; 425 } 426 #if MERGE_FOLDERS 427 hr = SHGetSpecialFolderLocation(NULL, folder2, &pidlCommonStartMenu); 428 if (FAILED_UNEXPECTEDLY(hr)) 429 #else 430 else 431 #endif 432 { 433 WARN("Failed to get the COMMON start menu folder. Will use only the USER contents.\n"); 434 hr = BindToDesktop(pidlUserStartMenu, ppsfStartMenu); 435 ILFree(pidlUserStartMenu); 436 return hr; 437 } 438 439 TRACE("Both COMMON and USER statr menu folders obtained, merging them...\n"); 440 441 hr = BindToDesktop(pidlUserStartMenu, &psfUserStartMenu); 442 if (FAILED_UNEXPECTEDLY(hr)) 443 return hr; 444 445 hr = BindToDesktop(pidlCommonStartMenu, &psfCommonStartMenu); 446 if (FAILED_UNEXPECTEDLY(hr)) 447 return hr; 448 449 hr = CMergedFolder_CreateInstance(IID_PPV_ARG(IAugmentedShellFolder, &pasf)); 450 if (FAILED_UNEXPECTEDLY(hr)) 451 { 452 *ppsfStartMenu = psfUserStartMenu.Detach(); 453 ILFree(pidlCommonStartMenu); 454 ILFree(pidlUserStartMenu); 455 return hr; 456 } 457 458 hr = pasf->AddNameSpace(NULL, psfUserStartMenu, pidlUserStartMenu, 0xFF00); 459 if (FAILED_UNEXPECTEDLY(hr)) 460 return hr; 461 462 hr = pasf->AddNameSpace(NULL, psfCommonStartMenu, pidlCommonStartMenu, 0); 463 if (FAILED_UNEXPECTEDLY(hr)) 464 return hr; 465 466 hr = pasf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsfStartMenu)); 467 pasf.Release(); 468 469 ILFree(pidlCommonStartMenu); 470 ILFree(pidlUserStartMenu); 471 472 return hr; 473 } 474 475 static HRESULT GetStartMenuFolder(IShellFolder ** ppsfStartMenu) 476 { 477 return GetMergedFolder(CSIDL_STARTMENU, CSIDL_COMMON_STARTMENU, ppsfStartMenu); 478 } 479 480 static HRESULT GetProgramsFolder(IShellFolder ** ppsfStartMenu) 481 { 482 return GetMergedFolder(CSIDL_PROGRAMS, CSIDL_COMMON_PROGRAMS, ppsfStartMenu); 483 } 484 485 extern "C" 486 HRESULT WINAPI 487 RSHELL_CStartMenu_CreateInstance(REFIID riid, void **ppv) 488 { 489 CComPtr<IShellMenu> pShellMenu; 490 CComPtr<IBandSite> pBandSite; 491 CComPtr<IDeskBar> pDeskBar; 492 493 HRESULT hr; 494 IShellFolder * psf; 495 496 LPITEMIDLIST pidlProgramsAbsolute; 497 LPITEMIDLIST pidlPrograms; 498 CComPtr<IShellFolder> psfPrograms; 499 500 hr = CMenuBand_CreateInstance(IID_PPV_ARG(IShellMenu, &pShellMenu)); 501 if (FAILED_UNEXPECTEDLY(hr)) 502 return hr; 503 504 hr = CMenuSite_CreateInstance(IID_PPV_ARG(IBandSite, &pBandSite)); 505 if (FAILED_UNEXPECTEDLY(hr)) 506 return hr; 507 508 hr = CMenuDeskBar_CreateInstance(IID_PPV_ARG(IDeskBar, &pDeskBar)); 509 if (FAILED_UNEXPECTEDLY(hr)) 510 return hr; 511 512 CComObject<CShellMenuCallback> *pCallback; 513 hr = CComObject<CShellMenuCallback>::CreateInstance(&pCallback); 514 if (FAILED_UNEXPECTEDLY(hr)) 515 return hr; 516 517 pCallback->AddRef(); // CreateInstance returns object with 0 ref count */ 518 pCallback->Initialize(pShellMenu, pBandSite, pDeskBar); 519 520 hr = pShellMenu->Initialize(pCallback, (UINT) -1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL); 521 if (FAILED_UNEXPECTEDLY(hr)) 522 return hr; 523 524 hr = GetStartMenuFolder(&psf); 525 if (FAILED_UNEXPECTEDLY(hr)) 526 return hr; 527 528 /* psf is a merged folder, so now we want to get the pidl of the programs item from the merged folder */ 529 { 530 hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAMS, &pidlProgramsAbsolute); 531 if (FAILED_UNEXPECTEDLY(hr)) 532 { 533 WARN("USER Programs folder not found.\n"); 534 hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlProgramsAbsolute); 535 if (FAILED_UNEXPECTEDLY(hr)) 536 return hr; 537 } 538 539 LPCITEMIDLIST pcidlPrograms; 540 CComPtr<IShellFolder> psfParent; 541 STRRET str; 542 TCHAR szDisplayName[MAX_PATH]; 543 544 hr = SHBindToParent(pidlProgramsAbsolute, IID_PPV_ARG(IShellFolder, &psfParent), &pcidlPrograms); 545 if (FAILED_UNEXPECTEDLY(hr)) 546 return hr; 547 548 hr = psfParent->GetDisplayNameOf(pcidlPrograms, SHGDN_FORPARSING | SHGDN_INFOLDER, &str); 549 if (FAILED_UNEXPECTEDLY(hr)) 550 return hr; 551 552 StrRetToBuf(&str, pcidlPrograms, szDisplayName, _countof(szDisplayName)); 553 ILFree(pidlProgramsAbsolute); 554 555 /* We got the display name from the fs folder and we parse it with the merged folder here */ 556 hr = psf->ParseDisplayName(NULL, NULL, szDisplayName, NULL, &pidlPrograms, NULL); 557 if (FAILED_UNEXPECTEDLY(hr)) 558 return hr; 559 } 560 561 hr = GetProgramsFolder(&psfPrograms); 562 if (FAILED_UNEXPECTEDLY(hr)) 563 return hr; 564 565 hr = pCallback->_SetProgramsFolder(psfPrograms, pidlPrograms); 566 if (FAILED_UNEXPECTEDLY(hr)) 567 return hr; 568 569 hr = pShellMenu->SetShellFolder(psf, NULL, NULL, SMSET_TOP); 570 if (FAILED_UNEXPECTEDLY(hr)) 571 return hr; 572 573 hr = pDeskBar->SetClient(pBandSite); 574 if (FAILED_UNEXPECTEDLY(hr)) 575 return hr; 576 577 hr = pBandSite->AddBand(pShellMenu); 578 if (FAILED_UNEXPECTEDLY(hr)) 579 return hr; 580 581 return pDeskBar->QueryInterface(riid, ppv); 582 } 583