Reactos
at master 636 lines 20 kB view raw
1/* 2 * Shell Folder stuff 3 * 4 * Copyright 1997 Marcus Meissner 5 * Copyright 1998, 1999, 2002 Juergen Schmied 6 * Copyright 2018 Katayama Hirofumi MZ 7 * 8 * IShellFolder2 and related interfaces 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 23 */ 24 25#include "precomp.h" 26 27WINE_DEFAULT_DEBUG_CHANNEL(shell); 28 29SHCONTF SHELL_GetDefaultFolderEnumSHCONTF() 30{ 31 SHCONTF Flags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS; 32 SHELLSTATE ss; 33 SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS | SSF_SHOWSUPERHIDDEN, FALSE); 34 if (ss.fShowAllObjects) 35 Flags |= SHCONTF_INCLUDEHIDDEN; 36 if (ss.fShowSuperHidden) 37 Flags |= SHCONTF_INCLUDESUPERHIDDEN; 38 return Flags; 39} 40 41BOOL SHELL_IncludeItemInFolderEnum(IShellFolder *pSF, PCUITEMID_CHILD pidl, SFGAOF Query, SHCONTF Flags) 42{ 43 if (SUCCEEDED(pSF->GetAttributesOf(1, &pidl, &Query))) 44 { 45 if (Query & SFGAO_NONENUMERATED) 46 return FALSE; 47 if ((Query & SFGAO_HIDDEN) && !(Flags & SHCONTF_INCLUDEHIDDEN)) 48 return FALSE; 49 if ((Query & (SFGAO_HIDDEN | SFGAO_SYSTEM)) == (SFGAO_HIDDEN | SFGAO_SYSTEM) && !(Flags & SHCONTF_INCLUDESUPERHIDDEN)) 50 return FALSE; 51 if ((Flags & (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS)) != (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS)) 52 return (Flags & SHCONTF_FOLDERS) ? (Query & SFGAO_FOLDER) : !(Query & SFGAO_FOLDER); 53 } 54 return TRUE; 55} 56 57static HRESULT 58MapSCIDToShell32FsColumn(const SHCOLUMNID *pscid, VARTYPE &vt) 59{ 60 if (pscid->fmtid == FMTID_Storage) 61 { 62 switch (pscid->pid) 63 { 64 case PID_STG_NAME: vt = VT_BSTR; return SHFSF_COL_NAME; 65 case PID_STG_SIZE: vt = VT_UI8; return SHFSF_COL_SIZE; 66 case PID_STG_STORAGETYPE: vt = VT_BSTR; return SHFSF_COL_TYPE; 67 case PID_STG_ATTRIBUTES: vt = VT_BSTR; return SHFSF_COL_FATTS; 68 case PID_STG_WRITETIME: vt = VT_DATE; return SHFSF_COL_MDATE; 69 } 70 } 71 if (pscid->fmtid == FMTID_SummaryInformation && pscid->pid == PIDSI_COMMENTS) 72 { 73 vt = VT_BSTR; 74 return SHFSF_COL_COMMENT; 75 } 76 return E_INVALIDARG; 77} 78 79HRESULT 80SHELL_MapSCIDToColumn(IShellFolder2 *pSF, const SHCOLUMNID *pscid) 81{ 82 for (UINT i = 0; i <= SHCIDS_COLUMNMASK; ++i) 83 { 84 SHCOLUMNID scid; 85 HRESULT hr = pSF->MapColumnToSCID(i, &scid); 86 if (FAILED(hr)) 87 break; 88 if (IsEqualPropertyKey(scid, *pscid)) 89 return i; 90 } 91 return E_FAIL; 92} 93 94HRESULT 95SHELL_GetDetailsOfAsStringVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARIANT *pVar) 96{ 97 V_VT(pVar) = VT_EMPTY; 98 SHELLDETAILS sd; 99 sd.str.uType = STRRET_CSTR; 100 HRESULT hr = pSF->GetDetailsOf(pidl, Column, &sd); 101 if (FAILED(hr)) 102 return hr; 103 if (FAILED(hr = StrRetToBSTR(&sd.str, pidl, &V_BSTR(pVar)))) 104 return hr; 105 V_VT(pVar) = VT_BSTR; 106 return hr; 107} 108 109HRESULT 110SHELL_GetDetailsOfColumnAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, UINT Column, VARTYPE vt, VARIANT *pVar) 111{ 112 HRESULT hr = SHELL_GetDetailsOfAsStringVariant(pSF, pidl, Column, pVar); 113 if (FAILED(hr)) 114 return hr; 115 if (vt == VT_EMPTY) 116 { 117 SHCOLSTATEF state; 118 if (FAILED(pSF->GetDefaultColumnState(Column, &state))) 119 state = SHCOLSTATE_TYPE_STR; 120 if ((state & SHCOLSTATE_TYPEMASK) == SHCOLSTATE_TYPE_INT) 121 vt = VT_I8; 122 else if ((state & SHCOLSTATE_TYPEMASK) == SHCOLSTATE_TYPE_DATE) 123 vt = VT_DATE; 124 else 125 vt = VT_BSTR; 126 } 127 if (vt != VT_BSTR) 128 VariantChangeType(pVar, pVar, 0, vt); 129 return hr; 130} 131 132HRESULT 133SH32_GetDetailsOfPKeyAsVariant(IShellFolder2 *pSF, PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pVar, BOOL UseFsColMap) 134{ 135 // CFSFolder and CRegFolder uses the SHFSF_COL columns and can use the faster and better version, 136 // everyone else must ask the folder to map the SCID to a column. 137 VARTYPE vt = VT_EMPTY; 138 HRESULT hr = UseFsColMap ? MapSCIDToShell32FsColumn(pscid, vt) : SHELL_MapSCIDToColumn(pSF, pscid); 139 return SUCCEEDED(hr) ? SHELL_GetDetailsOfColumnAsVariant(pSF, pidl, hr, vt, pVar) : hr; 140} 141 142HRESULT SHELL_CreateAbsolutePidl(IShellFolder *pSF, PCUIDLIST_RELATIVE pidlChild, PIDLIST_ABSOLUTE *ppPidl) 143{ 144 PIDLIST_ABSOLUTE pidlFolder; 145 HRESULT hr = SHGetIDListFromObject(pSF, &pidlFolder); 146 if (SUCCEEDED(hr)) 147 { 148 hr = SHILCombine(pidlFolder, pidlChild, ppPidl); 149 ILFree(pidlFolder); 150 } 151 return hr; 152} 153 154HRESULT 155Shell_NextElement( 156 _Inout_ LPWSTR *ppch, 157 _Out_ LPWSTR pszOut, 158 _In_ INT cchOut, 159 _In_ BOOL bValidate) 160{ 161 *pszOut = UNICODE_NULL; 162 163 if (!*ppch) 164 return S_FALSE; 165 166 HRESULT hr; 167 LPWSTR pchNext = wcschr(*ppch, L'\\'); 168 if (pchNext) 169 { 170 if (*ppch < pchNext) 171 { 172 /* Get an element */ 173 StringCchCopyNW(pszOut, cchOut, *ppch, pchNext - *ppch); 174 ++pchNext; 175 176 if (!*pchNext) 177 pchNext = NULL; /* No next */ 178 179 hr = S_OK; 180 } 181 else /* Double backslashes found? */ 182 { 183 pchNext = NULL; 184 hr = E_INVALIDARG; 185 } 186 } 187 else /* No more next */ 188 { 189 StringCchCopyW(pszOut, cchOut, *ppch); 190 hr = S_OK; 191 } 192 193 *ppch = pchNext; /* Go next */ 194 195 if (hr == S_OK && bValidate && !PathIsValidElement(pszOut)) 196 { 197 *pszOut = UNICODE_NULL; 198 hr = E_INVALIDARG; 199 } 200 201 return hr; 202} 203 204HRESULT SHELL32_ParseNextElement (IShellFolder2 * psf, HWND hwndOwner, LPBC pbc, 205 LPITEMIDLIST * pidlInOut, LPOLESTR szNext, DWORD * pEaten, DWORD * pdwAttributes) 206{ 207 HRESULT hr = E_INVALIDARG; 208 LPITEMIDLIST pidlIn = pidlInOut ? *pidlInOut : NULL; 209 LPITEMIDLIST pidlOut = NULL; 210 LPITEMIDLIST pidlTemp = NULL; 211 CComPtr<IShellFolder> psfChild; 212 213 TRACE ("(%p, %p, %p, %s)\n", psf, pbc, pidlIn, debugstr_w (szNext)); 214 215 /* get the shellfolder for the child pidl and let it analyse further */ 216 hr = psf->BindToObject(pidlIn, pbc, IID_PPV_ARG(IShellFolder, &psfChild)); 217 if (FAILED(hr)) 218 return hr; 219 220 hr = psfChild->ParseDisplayName(hwndOwner, pbc, szNext, pEaten, &pidlOut, pdwAttributes); 221 if (FAILED(hr)) 222 return hr; 223 224 pidlTemp = ILCombine (pidlIn, pidlOut); 225 if (!pidlTemp) 226 { 227 hr = E_OUTOFMEMORY; 228 if (pidlOut) 229 ILFree(pidlOut); 230 return hr; 231 } 232 233 if (pidlOut) 234 ILFree (pidlOut); 235 236 if (pidlIn) 237 ILFree (pidlIn); 238 239 *pidlInOut = pidlTemp; 240 241 TRACE ("-- pidl=%p ret=0x%08x\n", pidlInOut ? *pidlInOut : NULL, hr); 242 return S_OK; 243} 244 245/*********************************************************************** 246 * SHELL32_CoCreateInitSF 247 * 248 * Creates a shell folder and initializes it with a pidl and a root folder 249 * via IPersistFolder3 or IPersistFolder. 250 * 251 * NOTES 252 * pathRoot can be NULL for Folders being a drive. 253 * In this case the absolute path is built from pidlChild (eg. C:) 254 */ 255HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, PERSIST_FOLDER_TARGET_INFO* ppfti, 256 LPCITEMIDLIST pidlChild, const GUID* clsid, REFIID riid, LPVOID *ppvOut) 257{ 258 HRESULT hr; 259 CComPtr<IShellFolder> pShellFolder; 260 261 hr = SHCoCreateInstance(NULL, clsid, NULL, IID_PPV_ARG(IShellFolder, &pShellFolder)); 262 if (FAILED(hr)) 263 return hr; 264 265 LPITEMIDLIST pidlAbsolute = ILCombine (pidlRoot, pidlChild); 266 CComPtr<IPersistFolder> ppf; 267 CComPtr<IPersistFolder3> ppf3; 268 269 if (ppfti && SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf3)))) 270 { 271 ppf3->InitializeEx(NULL, pidlAbsolute, ppfti); 272 } 273 else if (SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder, &ppf)))) 274 { 275 ppf->Initialize(pidlAbsolute); 276 } 277 ILFree (pidlAbsolute); 278 279 return pShellFolder->QueryInterface(riid, ppvOut); 280} 281 282HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, const GUID* clsid, 283 int csidl, REFIID riid, LPVOID *ppvOut) 284{ 285 /* fill the PERSIST_FOLDER_TARGET_INFO */ 286 PERSIST_FOLDER_TARGET_INFO pfti = {0}; 287 pfti.dwAttributes = -1; 288 pfti.csidl = csidl; 289 290 return SHELL32_CoCreateInitSF(pidlRoot, &pfti, NULL, clsid, riid, ppvOut); 291} 292 293HRESULT SHELL32_BindToSF (LPCITEMIDLIST pidlRoot, PERSIST_FOLDER_TARGET_INFO* ppfti, 294 LPCITEMIDLIST pidl, const GUID* clsid, REFIID riid, LPVOID *ppvOut) 295{ 296 PITEMID_CHILD pidlChild = ILCloneFirst (pidl); 297 if (!pidlChild) 298 return E_FAIL; 299 300 CComPtr<IShellFolder> psf; 301 HRESULT hr = SHELL32_CoCreateInitSF(pidlRoot, 302 ppfti, 303 pidlChild, 304 clsid, 305 IID_PPV_ARG(IShellFolder, &psf)); 306 ILFree(pidlChild); 307 308 if (FAILED_UNEXPECTEDLY(hr)) 309 return hr; 310 311 if (_ILIsPidlSimple (pidl)) 312 return psf->QueryInterface(riid, ppvOut); 313 else 314 return psf->BindToObject(ILGetNext (pidl), NULL, riid, ppvOut); 315} 316 317/*********************************************************************** 318 * SHELL32_GetDisplayNameOfChild 319 * 320 * Retrieves the display name of a child object of a shellfolder. 321 * 322 * For a pidl eg. [subpidl1][subpidl2][subpidl3]: 323 * - it binds to the child shellfolder [subpidl1] 324 * - asks it for the displayname of [subpidl2][subpidl3] 325 * 326 * Is possible the pidl is a simple pidl. In this case it asks the 327 * subfolder for the displayname of an empty pidl. The subfolder 328 * returns the own displayname eg. "::{guid}". This is used for 329 * virtual folders with the registry key WantsFORPARSING set. 330 */ 331HRESULT SHELL32_GetDisplayNameOfChild (IShellFolder2 * psf, 332 LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet) 333{ 334 LPITEMIDLIST pidlFirst = ILCloneFirst(pidl); 335 if (!pidlFirst) 336 return E_OUTOFMEMORY; 337 338 CComPtr<IShellFolder> psfChild; 339 HRESULT hr = psf->BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 340 if (SUCCEEDED (hr)) 341 { 342 hr = psfChild->GetDisplayNameOf(ILGetNext (pidl), dwFlags, strRet); 343 } 344 ILFree (pidlFirst); 345 346 return hr; 347} 348 349HRESULT SHELL32_CompareChildren(IShellFolder2* psf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) 350{ 351 PUIDLIST_RELATIVE nextpidl1 = ILGetNext (pidl1); 352 PUIDLIST_RELATIVE nextpidl2 = ILGetNext (pidl2); 353 354 bool isEmpty1 = _ILIsDesktop(nextpidl1); 355 bool isEmpty2 = _ILIsDesktop(nextpidl2); 356 if (isEmpty1 || isEmpty2) 357 return MAKE_COMPARE_HRESULT(isEmpty2 - isEmpty1); 358 359 PITEMID_CHILD firstpidl = ILCloneFirst (pidl1); 360 if (!firstpidl) 361 return E_OUTOFMEMORY; 362 363 CComPtr<IShellFolder> psf2; 364 HRESULT hr = psf->BindToObject(firstpidl, 0, IID_PPV_ARG(IShellFolder, &psf2)); 365 ILFree(firstpidl); 366 if (FAILED(hr)) 367 return MAKE_COMPARE_HRESULT(0); 368 369 return psf2->CompareIDs(lParam, nextpidl1, nextpidl2); 370} 371 372HRESULT SHELL32_CompareDetails(IShellFolder2* isf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) 373{ 374 SHELLDETAILS sd; 375 WCHAR wszItem1[MAX_PATH], wszItem2[MAX_PATH]; 376 HRESULT hres; 377 UINT col = LOWORD(lParam); // Column index without SHCIDS_* flags 378 379 hres = isf->GetDetailsOf(pidl1, col, &sd); 380 if (FAILED(hres)) 381 return MAKE_COMPARE_HRESULT(1); 382 383 hres = StrRetToBufW(&sd.str, pidl1, wszItem1, MAX_PATH); 384 if (FAILED(hres)) 385 return MAKE_COMPARE_HRESULT(1); 386 387 hres = isf->GetDetailsOf(pidl2, col, &sd); 388 if (FAILED(hres)) 389 return MAKE_COMPARE_HRESULT(1); 390 391 hres = StrRetToBufW(&sd.str, pidl2, wszItem2, MAX_PATH); 392 if (FAILED(hres)) 393 return MAKE_COMPARE_HRESULT(1); 394 395 int ret = CFSFolder::CompareUiStrings(wszItem1, wszItem2, lParam); 396 if (ret == 0) 397 return SHELL32_CompareChildren(isf, lParam, pidl1, pidl2); 398 399 return MAKE_COMPARE_HRESULT(ret); 400} 401 402void CloseRegKeyArray(HKEY* array, UINT cKeys) 403{ 404 for (UINT i = 0; i < cKeys; ++i) 405 RegCloseKey(array[i]); 406} 407 408LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys) 409{ 410 if (*cKeys >= 16) 411 return ERROR_MORE_DATA; 412 413 HKEY hkey; 414 LSTATUS result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, KEY_READ | KEY_QUERY_VALUE, &hkey); 415 if (result == ERROR_SUCCESS) 416 { 417 array[*cKeys] = hkey; 418 *cKeys += 1; 419 } 420 return result; 421} 422 423LSTATUS AddClsidKeyToArray(REFCLSID clsid, HKEY* array, UINT* cKeys) 424{ 425 WCHAR path[6 + 38 + 1] = L"CLSID\\"; 426 StringFromGUID2(clsid, path + 6, 38 + 1); 427 return AddClassKeyToArray(path, array, cKeys); 428} 429 430void AddFSClassKeysToArray(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, HKEY* array, UINT* cKeys) 431{ 432 // This function opens the association array keys in canonical order for filesystem items. 433 // The order is documented: learn.microsoft.com/en-us/windows/win32/shell/fa-associationarray 434 435 ASSERT(cidl >= 1 && apidl); 436 PCUITEMID_CHILD pidl = apidl[0]; 437 if (_ILIsValue(pidl)) 438 { 439 WCHAR buf[MAX_PATH]; 440 PWSTR name; 441 FileStructW* pFileData = _ILGetFileStructW(pidl); 442 if (pFileData) 443 { 444 name = pFileData->wszName; 445 } 446 else 447 { 448 _ILSimpleGetTextW(pidl, buf, _countof(buf)); 449 name = buf; 450 } 451 LPCWSTR extension = PathFindExtension(name); 452 453 if (extension) 454 { 455 WCHAR wszClass[MAX_PATH], wszSFA[23 + _countof(wszClass)]; 456 DWORD dwSize = sizeof(wszClass); 457 if (RegGetValueW(HKEY_CLASSES_ROOT, extension, NULL, RRF_RT_REG_SZ, NULL, wszClass, &dwSize) != ERROR_SUCCESS || 458 !*wszClass || AddClassKeyToArray(wszClass, array, cKeys) != ERROR_SUCCESS) 459 { 460 // Only add the extension key if the ProgId is not valid 461 AddClassKeyToArray(extension, array, cKeys); 462 463 // "Open With" becomes the default when there are no verbs in the above keys 464 if (cidl == 1) 465 AddClassKeyToArray(L"Unknown", array, cKeys); 466 } 467 468 swprintf(wszSFA, L"SystemFileAssociations\\%s", extension); 469 AddClassKeyToArray(wszSFA, array, cKeys); 470 471 dwSize = sizeof(wszClass); 472 if (RegGetValueW(HKEY_CLASSES_ROOT, extension, L"PerceivedType", RRF_RT_REG_SZ, NULL, wszClass, &dwSize) == ERROR_SUCCESS) 473 { 474 swprintf(wszSFA, L"SystemFileAssociations\\%s", wszClass); 475 AddClassKeyToArray(wszSFA, array, cKeys); 476 } 477 } 478 479 AddClassKeyToArray(L"*", array, cKeys); 480 AddClassKeyToArray(L"AllFilesystemObjects", array, cKeys); 481 } 482 else if (_ILIsFolder(pidl)) 483 { 484 // FIXME: Directory > Folder > AFO is the correct order and it's 485 // the order Windows reports in its undocumented association array 486 // but it is somehow not the order Windows adds the items to its menu! 487 // Until the correct algorithm in CDefaultContextMenu can be determined, 488 // we add the folder keys in "menu order". 489 AddClassKeyToArray(L"Folder", array, cKeys); 490 AddClassKeyToArray(L"AllFilesystemObjects", array, cKeys); 491 AddClassKeyToArray(L"Directory", array, cKeys); 492 } 493 else if (_ILIsDrive(pidl)) 494 { 495 AddClassKeyToArray(L"Drive", array, cKeys); 496 AddClassKeyToArray(L"Folder", array, cKeys); 497 } 498 else 499 { 500 ERR("Got non FS pidl\n"); 501 } 502} 503 504void AddPidlClassKeysToArray(LPCITEMIDLIST pidl, HKEY* array, UINT* cKeys) 505{ 506 if ((pidl = ILFindLastID(pidl)) != NULL) 507 AddFSClassKeysToArray(1, &pidl, array, cKeys); 508} 509 510HRESULT SH_GetApidlFromDataObject(IDataObject *pDataObject, PIDLIST_ABSOLUTE* ppidlfolder, PUITEMID_CHILD **apidlItems, UINT *pcidl) 511{ 512 CDataObjectHIDA cida(pDataObject); 513 514 if (FAILED_UNEXPECTEDLY(cida.hr())) 515 return cida.hr(); 516 517 /* convert the data into pidl */ 518 LPITEMIDLIST pidl; 519 LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, cida); 520 if (!apidl) 521 { 522 return E_OUTOFMEMORY; 523 } 524 525 *ppidlfolder = pidl; 526 *apidlItems = apidl; 527 *pcidl = cida->cidl; 528 529 return S_OK; 530} 531 532/*********************************************************************** 533 * SHCreateLinks 534 * 535 * Undocumented. 536 */ 537HRESULT WINAPI SHCreateLinks( HWND hWnd, LPCSTR lpszDir, IDataObject * lpDataObject, 538 UINT uFlags, LPITEMIDLIST *lppidlLinks) 539{ 540 FIXME("%p %s %p %08x %p\n", hWnd, lpszDir, lpDataObject, uFlags, lppidlLinks); 541 return E_NOTIMPL; 542} 543 544/*********************************************************************** 545 * SHOpenFolderAndSelectItems 546 * 547 * Unimplemented. 548 */ 549EXTERN_C HRESULT 550WINAPI 551SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE pidlFolder, 552 UINT cidl, 553 PCUITEMID_CHILD_ARRAY apidl, 554 DWORD dwFlags) 555{ 556 ERR("SHOpenFolderAndSelectItems() is hackplemented\n"); 557 CComHeapPtr<ITEMIDLIST> freeItem; 558 PCIDLIST_ABSOLUTE pidlItem; 559 if (cidl) 560 { 561 /* Firefox sends a full pidl here dispite the fact it is a PCUITEMID_CHILD_ARRAY -_- */ 562 if (!ILIsSingle(apidl[0])) 563 { 564 pidlItem = apidl[0]; 565 } 566 else 567 { 568 HRESULT hr = SHILCombine(pidlFolder, apidl[0], &pidlItem); 569 if (FAILED_UNEXPECTEDLY(hr)) 570 return hr; 571 freeItem.Attach(const_cast<PIDLIST_ABSOLUTE>(pidlItem)); 572 } 573 } 574 else 575 { 576 pidlItem = pidlFolder; 577 } 578 579 CComPtr<IShellFolder> psfDesktop; 580 581 HRESULT hr = SHGetDesktopFolder(&psfDesktop); 582 if (FAILED_UNEXPECTEDLY(hr)) 583 return hr; 584 585 STRRET strret; 586 hr = psfDesktop->GetDisplayNameOf(pidlItem, SHGDN_FORPARSING, &strret); 587 if (FAILED_UNEXPECTEDLY(hr)) 588 return hr; 589 590 WCHAR wszBuf[MAX_PATH]; 591 hr = StrRetToBufW(&strret, pidlItem, wszBuf, _countof(wszBuf)); 592 if (FAILED_UNEXPECTEDLY(hr)) 593 return hr; 594 595 WCHAR wszParams[MAX_PATH]; 596 wcscpy(wszParams, L"/select,"); 597 wcscat(wszParams, wszBuf); 598 599 SHELLEXECUTEINFOW sei; 600 memset(&sei, 0, sizeof sei); 601 sei.cbSize = sizeof sei; 602 sei.fMask = SEE_MASK_WAITFORINPUTIDLE; 603 sei.lpFile = L"explorer.exe"; 604 sei.lpParameters = wszParams; 605 606 if (ShellExecuteExW(&sei)) 607 return S_OK; 608 else 609 return E_FAIL; 610} 611 612/* 613 * for internal use 614 */ 615HRESULT 616SHELL32_ShowPropertiesDialog(IDataObject *pdtobj) 617{ 618 if (!pdtobj) 619 return E_INVALIDARG; 620 return SHELL32_ShowFilesystemItemsPropertiesDialogAsync(NULL, pdtobj); 621} 622 623HRESULT 624SHELL32_DefaultContextMenuCallBack(IShellFolder *psf, IDataObject *pdo, UINT msg) 625{ 626 switch (msg) 627 { 628 case DFM_MERGECONTEXTMENU: 629 return S_OK; // Yes, I want verbs 630 case DFM_INVOKECOMMAND: 631 return S_FALSE; // Do it for me please 632 case DFM_GETDEFSTATICID: 633 return S_FALSE; // Supposedly "required for Windows 7 to pick a default" 634 } 635 return E_NOTIMPL; 636}