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