1 /* 2 * ReactOS Shell 3 * 4 * Copyright 2016 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 21 #include <precomp.h> 22 23 WINE_DEFAULT_DEBUG_CHANNEL (shell); 24 25 HRESULT CALLBACK RegFolderContextMenuCallback(IShellFolder *psf, 26 HWND hwnd, 27 IDataObject *pdtobj, 28 UINT uMsg, 29 WPARAM wParam, 30 LPARAM lParam) 31 { 32 if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES) 33 return S_OK; 34 35 PIDLIST_ABSOLUTE pidlFolder; 36 PUITEMID_CHILD *apidl; 37 UINT cidl; 38 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl); 39 if (FAILED_UNEXPECTEDLY(hr)) 40 return hr; 41 42 if (_ILIsMyComputer(apidl[0])) 43 { 44 if (32 >= (UINT_PTR)ShellExecuteW(hwnd, 45 L"open", 46 L"rundll32.exe", 47 L"shell32.dll,Control_RunDLL sysdm.cpl", 48 NULL, 49 SW_SHOWNORMAL)) 50 { 51 hr = E_FAIL; 52 } 53 } 54 else if (_ILIsDesktop(apidl[0])) 55 { 56 if (32 >= (UINT_PTR)ShellExecuteW(hwnd, 57 L"open", 58 L"rundll32.exe", 59 L"shell32.dll,Control_RunDLL desk.cpl", 60 NULL, 61 SW_SHOWNORMAL)) 62 { 63 hr = E_FAIL; 64 } 65 } 66 else if (_ILIsNetHood(apidl[0])) 67 { 68 // FIXME path! 69 if (32 >= (UINT_PTR)ShellExecuteW(NULL, 70 L"open", 71 L"explorer.exe", 72 L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", 73 NULL, 74 SW_SHOWDEFAULT)) 75 { 76 hr = E_FAIL; 77 } 78 } 79 else if (_ILIsBitBucket(apidl[0])) 80 { 81 /* FIXME: detect the drive path of bitbucket if appropiate */ 82 if (!SH_ShowRecycleBinProperties(L'C')) 83 hr = E_FAIL; 84 } 85 else 86 { 87 /* Tell the caller to run the default action */ 88 hr = S_FALSE; 89 } 90 91 SHFree(pidlFolder); 92 _ILFreeaPidl(apidl, cidl); 93 94 return hr; 95 } 96 97 HRESULT CGuidItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, 98 HWND hwnd, 99 UINT cidl, 100 PCUITEMID_CHILD_ARRAY apidl, 101 IShellFolder *psf, 102 IContextMenu **ppcm) 103 { 104 HKEY hKeys[10]; 105 UINT cKeys = 0; 106 107 GUID *pGuid = _ILGetGUIDPointer(apidl[0]); 108 if (pGuid) 109 { 110 LPOLESTR pwszCLSID; 111 WCHAR key[60]; 112 113 wcscpy(key, L"CLSID\\"); 114 HRESULT hr = StringFromCLSID(*pGuid, &pwszCLSID); 115 if (hr == S_OK) 116 { 117 wcscpy(&key[6], pwszCLSID); 118 AddClassKeyToArray(key, hKeys, &cKeys); 119 CoTaskMemFree(pwszCLSID); 120 } 121 } 122 AddClassKeyToArray(L"Folder", hKeys, &cKeys); 123 124 return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, RegFolderContextMenuCallback, cKeys, hKeys, ppcm); 125 } 126 127 HRESULT FormatGUIDKey(LPWSTR KeyName, SIZE_T KeySize, LPCWSTR RegPath, const GUID* riid) 128 { 129 WCHAR xriid[40]; 130 131 if (!StringFromGUID2(*riid, xriid, _countof(xriid) - 1)) 132 return E_FAIL; 133 134 return StringCchPrintfW(KeyName, KeySize, RegPath, xriid); 135 } 136 137 HRESULT CGuidItemExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut) 138 { 139 CComPtr<IDefaultExtractIconInit> initIcon; 140 HRESULT hr; 141 GUID const * riid; 142 int icon_idx; 143 WCHAR wTemp[MAX_PATH]; 144 145 hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon)); 146 if (FAILED(hr)) 147 return hr; 148 149 if (_ILIsDesktop(pidl)) 150 { 151 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DESKTOP); 152 return initIcon->QueryInterface(iid, ppvOut); 153 } 154 155 riid = _ILGetGUIDPointer(pidl); 156 if (!riid) 157 return E_FAIL; 158 159 /* Choose a correct icon for Recycle Bin (full or empty) */ 160 const WCHAR* iconname = NULL; 161 if (_ILIsBitBucket(pidl)) 162 { 163 CComPtr<IEnumIDList> EnumIDList; 164 CoInitialize(NULL); 165 166 CComPtr<IShellFolder2> psfRecycleBin; 167 CComPtr<IShellFolder> psfDesktop; 168 hr = SHGetDesktopFolder(&psfDesktop); 169 170 if (SUCCEEDED(hr)) 171 hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder2, &psfRecycleBin)); 172 if (SUCCEEDED(hr)) 173 hr = psfRecycleBin->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &EnumIDList); 174 175 ULONG itemcount; 176 LPITEMIDLIST pidl = NULL; 177 if (SUCCEEDED(hr) && (hr = EnumIDList->Next(1, &pidl, &itemcount)) == S_OK) 178 { 179 CoTaskMemFree(pidl); 180 iconname = L"Full"; 181 } else { 182 iconname = L"Empty"; 183 } 184 } 185 186 /* Prepare registry path for loading icons of My Computer and other shell extensions */ 187 WCHAR KeyName[MAX_PATH]; 188 189 hr = FormatGUIDKey(KeyName, _countof(KeyName), 190 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", 191 riid); 192 if (FAILED_UNEXPECTEDLY(hr)) 193 return hr; 194 195 /* Load icon for the current user */ 196 BOOL ret = HCU_GetIconW(KeyName, wTemp, iconname, _countof(wTemp), &icon_idx); 197 if (!ret) 198 { 199 /* Failed, load default system-wide icon */ 200 hr = FormatGUIDKey(KeyName, _countof(KeyName), L"CLSID\\%s", riid); 201 if (FAILED_UNEXPECTEDLY(hr)) 202 return hr; 203 204 ret = HCR_GetIconW(KeyName, wTemp, iconname, _countof(wTemp), &icon_idx); 205 } 206 207 if (ret) 208 { 209 /* Success, set loaded icon */ 210 initIcon->SetNormalIcon(wTemp, icon_idx); 211 } 212 else 213 { 214 /* Everything has failed, set blank paper icon */ 215 WARN("Failed to load an icon for the item, setting blank icon\n"); 216 initIcon->SetNormalIcon(swShell32Name, IDI_SHELL_DOCUMENT - 1); 217 } 218 219 return initIcon->QueryInterface(iid, ppvOut); 220 } 221 222 class CRegFolderEnum : 223 public CEnumIDListBase 224 { 225 public: 226 CRegFolderEnum(); 227 ~CRegFolderEnum(); 228 HRESULT Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags); 229 HRESULT AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath); 230 231 BEGIN_COM_MAP(CRegFolderEnum) 232 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 233 END_COM_MAP() 234 }; 235 236 CRegFolderEnum::CRegFolderEnum() 237 { 238 } 239 240 CRegFolderEnum::~CRegFolderEnum() 241 { 242 } 243 244 HRESULT CRegFolderEnum::Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags) 245 { 246 WCHAR KeyName[MAX_PATH]; 247 248 if (!(dwFlags & SHCONTF_FOLDERS)) 249 return S_OK; 250 251 HRESULT hr = StringCchPrintfW(KeyName, MAX_PATH, 252 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\%s\\Namespace", 253 lpszEnumKeyName); 254 if (FAILED_UNEXPECTEDLY(hr)) 255 return hr; 256 257 AddItemsFromKey(HKEY_LOCAL_MACHINE, KeyName); 258 AddItemsFromKey(HKEY_CURRENT_USER, KeyName); 259 260 return S_OK; 261 } 262 263 HRESULT CRegFolderEnum::AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath) 264 { 265 WCHAR name[MAX_PATH]; 266 HKEY hkey; 267 268 if (RegOpenKeyW(hkey_root, szRepPath, &hkey) != ERROR_SUCCESS) 269 return S_FALSE; 270 271 for (int idx = 0; ; idx++) 272 { 273 if (RegEnumKeyW(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS) 274 break; 275 276 /* If the name of the key is not a guid try to get the default value of the key */ 277 if (name[0] != L'{') 278 { 279 DWORD dwSize = sizeof(name); 280 RegGetValueW(hkey, name, NULL, RRF_RT_REG_SZ, NULL, name, &dwSize); 281 } 282 283 if (*name == '{') 284 { 285 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(name); 286 287 if (pidl) 288 AddToEnumList(pidl); 289 } 290 } 291 292 RegCloseKey(hkey); 293 294 return S_OK; 295 } 296 297 /* 298 * These columns try to map to CFSFolder's columns because the CDesktopFolder 299 * displays CFSFolder and CRegFolder items in the same view. 300 */ 301 enum REGFOLDERCOLUMNINDEX 302 { 303 COL_NAME = SHFSF_COL_NAME, 304 COL_TYPE = SHFSF_COL_TYPE, 305 COL_INFOTIP = SHFSF_COL_COMMENT, 306 REGFOLDERCOLUMNCOUNT = max(COL_INFOTIP, COL_TYPE) + 1 307 }; 308 309 class CRegFolder : 310 public CComObjectRootEx<CComMultiThreadModelNoCS>, 311 public IShellFolder2 312 { 313 private: 314 GUID m_guid; 315 CAtlStringW m_rootPath; 316 CAtlStringW m_enumKeyName; 317 CComHeapPtr<ITEMIDLIST> m_pidlRoot; 318 319 HRESULT GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes); 320 BOOL _IsInNameSpace(_In_ LPCITEMIDLIST pidl); 321 322 public: 323 CRegFolder(); 324 ~CRegFolder(); 325 HRESULT WINAPI Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName); 326 327 // IShellFolder 328 STDMETHOD(ParseDisplayName)(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) override; 329 STDMETHOD(EnumObjects)(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) override; 330 STDMETHOD(BindToObject)(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) override; 331 STDMETHOD(BindToStorage)(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) override; 332 STDMETHOD(CompareIDs)(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) override; 333 STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) override; 334 STDMETHOD(GetAttributesOf)(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut) override; 335 STDMETHOD(GetUIObjectOf)(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) override; 336 STDMETHOD(GetDisplayNameOf)(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) override; 337 STDMETHOD(SetNameOf)(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) override; 338 339 /* ShellFolder2 */ 340 STDMETHOD(GetDefaultSearchGUID)(GUID *pguid) override; 341 STDMETHOD(EnumSearches)(IEnumExtraSearch **ppenum) override; 342 STDMETHOD(GetDefaultColumn)(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) override; 343 STDMETHOD(GetDefaultColumnState)(UINT iColumn, DWORD *pcsFlags) override; 344 STDMETHOD(GetDetailsEx)(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) override; 345 STDMETHOD(GetDetailsOf)(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) override; 346 STDMETHOD(MapColumnToSCID)(UINT column, SHCOLUMNID *pscid) override; 347 348 DECLARE_NOT_AGGREGATABLE(CRegFolder) 349 350 DECLARE_PROTECT_FINAL_CONSTRUCT() 351 352 BEGIN_COM_MAP(CRegFolder) 353 COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) 354 COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) 355 END_COM_MAP() 356 }; 357 358 CRegFolder::CRegFolder() 359 { 360 } 361 362 CRegFolder::~CRegFolder() 363 { 364 } 365 366 HRESULT WINAPI CRegFolder::Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName) 367 { 368 memcpy(&m_guid, pGuid, sizeof(m_guid)); 369 370 m_rootPath = lpszPath; 371 if (!m_rootPath) 372 return E_OUTOFMEMORY; 373 374 m_enumKeyName = lpszEnumKeyName; 375 if (!m_enumKeyName) 376 return E_OUTOFMEMORY; 377 378 m_pidlRoot.Attach(ILClone(pidlRoot)); 379 if (!m_pidlRoot) 380 return E_OUTOFMEMORY; 381 382 return S_OK; 383 } 384 385 HRESULT CRegFolder::GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes) 386 { 387 DWORD dwAttributes = *pdwAttributes; 388 389 /* First try to get them from the registry */ 390 if (!HCR_GetFolderAttributes(pidl, pdwAttributes)) 391 { 392 /* We couldn't get anything */ 393 *pdwAttributes = 0; 394 } 395 396 /* Items have more attributes when on desktop */ 397 if (_ILIsDesktop(m_pidlRoot)) 398 { 399 *pdwAttributes |= (dwAttributes & (SFGAO_CANLINK|SFGAO_CANDELETE|SFGAO_CANRENAME|SFGAO_HASPROPSHEET)); 400 } 401 402 /* In any case, links can be created */ 403 if (*pdwAttributes == NULL) 404 { 405 *pdwAttributes |= (dwAttributes & SFGAO_CANLINK); 406 } 407 return S_OK; 408 } 409 410 BOOL CRegFolder::_IsInNameSpace(_In_ LPCITEMIDLIST pidl) 411 { 412 CLSID clsid = *_ILGetGUIDPointer(pidl); 413 if (IsEqualGUID(clsid, CLSID_Printers)) 414 return TRUE; 415 if (IsEqualGUID(clsid, CLSID_ConnectionFolder)) 416 return TRUE; 417 FIXME("Check registry\n"); 418 return TRUE; 419 } 420 421 HRESULT WINAPI CRegFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, 422 ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) 423 { 424 if (!ppidl) 425 return E_INVALIDARG; 426 427 *ppidl = NULL; 428 429 if (!lpszDisplayName) 430 return E_INVALIDARG; 431 432 if (lpszDisplayName[0] != L':' || lpszDisplayName[1] != L':') 433 { 434 FIXME("What should we do here?\n"); 435 return E_FAIL; 436 } 437 438 LPWSTR pch, pchNextOfComma = NULL; 439 for (pch = &lpszDisplayName[2]; *pch && *pch != L'\\'; ++pch) 440 { 441 if (*pch == L',' && !pchNextOfComma) 442 pchNextOfComma = pch + 1; 443 } 444 445 CLSID clsid; 446 if (!GUIDFromStringW(&lpszDisplayName[2], &clsid)) 447 return CO_E_CLASSSTRING; 448 449 if (pchNextOfComma) 450 { 451 FIXME("Delegate folder\n"); 452 return E_FAIL; 453 } 454 455 CComHeapPtr<ITEMIDLIST> pidlTemp(_ILCreateGuid(PT_GUID, clsid)); 456 if (!pidlTemp) 457 return E_OUTOFMEMORY; 458 459 if (!_IsInNameSpace(pidlTemp) && !(BindCtx_GetMode(pbc, 0) & STGM_CREATE)) 460 return E_INVALIDARG; 461 462 *ppidl = pidlTemp.Detach(); 463 464 if (!*pch) 465 { 466 if (pdwAttributes && *pdwAttributes) 467 GetGuidItemAttributes(*ppidl, pdwAttributes); 468 469 return S_OK; 470 } 471 472 HRESULT hr = SHELL32_ParseNextElement(this, hwndOwner, pbc, ppidl, pch + 1, pchEaten, 473 pdwAttributes); 474 if (FAILED(hr)) 475 { 476 ILFree(*ppidl); 477 *ppidl = NULL; 478 } 479 return hr; 480 } 481 482 HRESULT WINAPI CRegFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 483 { 484 return ShellObjectCreatorInit<CRegFolderEnum>(m_enumKeyName, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 485 } 486 487 HRESULT WINAPI CRegFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 488 { 489 CComPtr<IPersistFolder> pFolder; 490 HRESULT hr; 491 492 if (!ppvOut || !pidl || !pidl->mkid.cb) 493 return E_INVALIDARG; 494 495 *ppvOut = NULL; 496 497 GUID *pGUID = _ILGetGUIDPointer(pidl); 498 if (!pGUID) 499 { 500 ERR("CRegFolder::BindToObject called for non guid item!\n"); 501 return E_INVALIDARG; 502 } 503 504 hr = SHELL32_BindToSF(m_pidlRoot, NULL, pidl, pGUID, riid, ppvOut); 505 if (FAILED_UNEXPECTEDLY(hr)) 506 return hr; 507 508 return S_OK; 509 } 510 511 HRESULT WINAPI CRegFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 512 { 513 return E_NOTIMPL; 514 } 515 516 HRESULT WINAPI CRegFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 517 { 518 if (!pidl1 || !pidl2 || pidl1->mkid.cb == 0 || pidl2->mkid.cb == 0) 519 { 520 ERR("Got an empty pidl!\n"); 521 return E_INVALIDARG; 522 } 523 524 GUID const *clsid1 = _ILGetGUIDPointer (pidl1); 525 GUID const *clsid2 = _ILGetGUIDPointer (pidl2); 526 527 if (!clsid1 && !clsid2) 528 { 529 ERR("Got no guid pidl!\n"); 530 return E_INVALIDARG; 531 } 532 else if (clsid1 && clsid2) 533 { 534 if (memcmp(clsid1, clsid2, sizeof(GUID)) == 0) 535 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2); 536 537 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2); 538 } 539 540 /* Guid folders come first compared to everything else */ 541 /* And Drives come before folders in My Computer */ 542 if (_ILIsMyComputer(m_pidlRoot)) 543 { 544 return MAKE_COMPARE_HRESULT(clsid1 ? 1 : -1); 545 } 546 else 547 { 548 return MAKE_COMPARE_HRESULT(clsid1 ? -1 : 1); 549 } 550 } 551 552 HRESULT WINAPI CRegFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) 553 { 554 return E_NOTIMPL; 555 } 556 557 HRESULT WINAPI CRegFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut) 558 { 559 if (!rgfInOut || !cidl || !apidl) 560 return E_INVALIDARG; 561 562 if (*rgfInOut == 0) 563 *rgfInOut = ~0; 564 565 while(cidl > 0 && *apidl) 566 { 567 if (_ILIsSpecialFolder(*apidl)) 568 GetGuidItemAttributes(*apidl, rgfInOut); 569 else 570 ERR("Got unknown pidl\n"); 571 apidl++; 572 cidl--; 573 } 574 575 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 576 *rgfInOut &= ~SFGAO_VALIDATE; 577 578 return S_OK; 579 } 580 581 HRESULT WINAPI CRegFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 582 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) 583 { 584 LPVOID pObj = NULL; 585 HRESULT hr = E_INVALIDARG; 586 587 if (!ppvOut) 588 return hr; 589 590 *ppvOut = NULL; 591 592 if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 593 { 594 hr = CGuidItemExtractIcon_CreateInstance(apidl[0], riid, &pObj); 595 } 596 else if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1)) 597 { 598 if (!_ILGetGUIDPointer (apidl[0])) 599 { 600 ERR("Got non guid item!\n"); 601 return E_FAIL; 602 } 603 604 hr = CGuidItemContextMenu_CreateInstance(m_pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj); 605 } 606 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) 607 { 608 hr = IDataObject_Constructor (hwndOwner, m_pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 609 } 610 else 611 { 612 hr = E_NOINTERFACE; 613 } 614 615 *ppvOut = pObj; 616 return hr; 617 618 } 619 620 HRESULT WINAPI CRegFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 621 { 622 if (!strRet || (!_ILIsSpecialFolder(pidl) && pidl != NULL)) 623 return E_INVALIDARG; 624 625 if (!pidl || !pidl->mkid.cb) 626 { 627 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING)) 628 { 629 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); 630 if (!pszPath) 631 return E_OUTOFMEMORY; 632 633 /* parsing name like ::{...} */ 634 pszPath[0] = ':'; 635 pszPath[1] = ':'; 636 SHELL32_GUIDToStringW(m_guid, &pszPath[2]); 637 638 strRet->uType = STRRET_WSTR; 639 strRet->pOleStr = pszPath; 640 641 return S_OK; 642 } 643 else 644 { 645 BOOL bRet; 646 WCHAR wstrName[MAX_PATH+1]; 647 bRet = HCR_GetClassNameW(m_guid, wstrName, MAX_PATH); 648 if (!bRet) 649 return E_FAIL; 650 651 return SHSetStrRet(strRet, wstrName); 652 653 } 654 } 655 656 HRESULT hr; 657 GUID const *clsid = _ILGetGUIDPointer (pidl); 658 659 /* First of all check if we need to query the name from the child item */ 660 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING && 661 GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) 662 { 663 int bWantsForParsing = FALSE; 664 665 /* 666 * We can only get a filesystem path from a shellfolder if the 667 * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists. 668 * 669 * Exception: The MyComputer folder doesn't have this key, 670 * but any other filesystem backed folder it needs it. 671 */ 672 if (IsEqualIID (*clsid, CLSID_MyComputer)) 673 { 674 bWantsForParsing = TRUE; 675 } 676 else 677 { 678 HKEY hkeyClass; 679 if (HCR_RegOpenClassIDKey(*clsid, &hkeyClass)) 680 { 681 LONG res = SHGetValueW(hkeyClass, L"Shellfolder", L"WantsForParsing", NULL, NULL, NULL); 682 bWantsForParsing = (res == ERROR_SUCCESS); 683 RegCloseKey(hkeyClass); 684 } 685 } 686 687 if (bWantsForParsing) 688 { 689 /* 690 * we need the filesystem path to the destination folder. 691 * Only the folder itself can know it 692 */ 693 return SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags, strRet); 694 } 695 } 696 697 /* Allocate the buffer for the result */ 698 SIZE_T cchPath = MAX_PATH + 1; 699 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc(cchPath * sizeof(WCHAR)); 700 if (!pszPath) 701 return E_OUTOFMEMORY; 702 703 hr = S_OK; 704 705 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING) 706 { 707 SIZE_T pathlen = 0; 708 PWCHAR pItemName = pszPath; // GET_SHGDN_RELATION(dwFlags) == SHGDN_INFOLDER 709 if (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) 710 { 711 hr = StringCchCopyW(pszPath, cchPath, m_rootPath); 712 if (SUCCEEDED(hr)) 713 { 714 pathlen = wcslen(pszPath); 715 pItemName = &pszPath[pathlen]; 716 if (pathlen) 717 { 718 if (++pathlen < cchPath) 719 *pItemName++ = L'\\'; 720 else 721 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 722 } 723 } 724 } 725 726 if (SUCCEEDED(hr) && pathlen + 2 + 38 + 1 < cchPath) 727 { 728 /* parsing name like ::{...} */ 729 pItemName[0] = L':'; 730 pItemName[1] = L':'; 731 SHELL32_GUIDToStringW(*clsid, &pItemName[2]); 732 } 733 else 734 { 735 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 736 } 737 } 738 else 739 { 740 /* user friendly name */ 741 if (!HCR_GetClassNameW(*clsid, pszPath, cchPath)) 742 hr = E_FAIL; 743 } 744 745 if (SUCCEEDED(hr)) 746 { 747 strRet->uType = STRRET_WSTR; 748 strRet->pOleStr = pszPath; 749 } 750 else 751 { 752 CoTaskMemFree(pszPath); 753 } 754 755 return hr; 756 } 757 758 HRESULT WINAPI CRegFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */ 759 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 760 { 761 GUID const *clsid = _ILGetGUIDPointer (pidl); 762 LPOLESTR pStr; 763 HRESULT hr; 764 WCHAR szName[100]; 765 766 if (!clsid) 767 { 768 ERR("Pidl is not reg item!\n"); 769 return E_FAIL; 770 } 771 772 hr = StringFromCLSID(*clsid, &pStr); 773 if (FAILED_UNEXPECTEDLY(hr)) 774 return hr; 775 776 swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr); 777 778 DWORD cbData = (wcslen(lpName) + 1) * sizeof(WCHAR); 779 LONG res = SHSetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, lpName, cbData); 780 781 CoTaskMemFree(pStr); 782 783 if (res == ERROR_SUCCESS) 784 { 785 *pPidlOut = ILClone(pidl); 786 return S_OK; 787 } 788 789 return E_FAIL; 790 } 791 792 793 HRESULT WINAPI CRegFolder::GetDefaultSearchGUID(GUID *pguid) 794 { 795 return E_NOTIMPL; 796 } 797 798 HRESULT WINAPI CRegFolder::EnumSearches(IEnumExtraSearch ** ppenum) 799 { 800 return E_NOTIMPL; 801 } 802 803 HRESULT WINAPI CRegFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 804 { 805 if (pSort) 806 *pSort = 0; 807 if (pDisplay) 808 *pDisplay = 0; 809 810 return S_OK; 811 } 812 813 HRESULT WINAPI CRegFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 814 { 815 if (iColumn >= REGFOLDERCOLUMNCOUNT) 816 return E_INVALIDARG; 817 *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; 818 return S_OK; 819 } 820 821 HRESULT WINAPI CRegFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) 822 { 823 return E_NOTIMPL; 824 } 825 826 HRESULT WINAPI CRegFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 827 { 828 if (!psd) 829 return E_INVALIDARG; 830 831 if (!pidl) 832 { 833 TRACE("CRegFolder has no column info\n"); 834 return E_INVALIDARG; 835 } 836 837 GUID const *clsid = _ILGetGUIDPointer (pidl); 838 839 if (!clsid) 840 { 841 ERR("Pidl is not reg item!\n"); 842 return E_INVALIDARG; 843 } 844 845 switch(iColumn) 846 { 847 case COL_NAME: 848 return GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); 849 case COL_TYPE: 850 return SHSetStrRet(&psd->str, IDS_SYSTEMFOLDER); 851 case COL_INFOTIP: 852 HKEY hKey; 853 if (!HCR_RegOpenClassIDKey(*clsid, &hKey)) 854 return SHSetStrRet(&psd->str, ""); 855 856 psd->str.cStr[0] = 0x00; 857 psd->str.uType = STRRET_CSTR; 858 RegLoadMUIStringA(hKey, "InfoTip", psd->str.cStr, MAX_PATH, NULL, 0, NULL); 859 RegCloseKey(hKey); 860 return S_OK; 861 default: 862 /* Return an empty string when we area asked for a column we don't support. 863 Only the regfolder is supposed to do this as it supports less columns compared to other folder 864 and its contents are supposed to be presented alongside items that support more columns. */ 865 return SHSetStrRet(&psd->str, ""); 866 } 867 return E_FAIL; 868 } 869 870 HRESULT WINAPI CRegFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 871 { 872 return E_NOTIMPL; 873 } 874 875 /* In latest windows version this is exported but it takes different arguments! */ 876 HRESULT CRegFolder_CreateInstance(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName, REFIID riid, void **ppv) 877 { 878 return ShellObjectCreatorInit<CRegFolder>(pGuid, pidlRoot, lpszPath, lpszEnumKeyName, riid, ppv); 879 } 880