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 } 120 } 121 AddClassKeyToArray(L"Folder", hKeys, &cKeys); 122 123 return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, RegFolderContextMenuCallback, cKeys, hKeys, ppcm); 124 } 125 126 HRESULT CGuidItemExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut) 127 { 128 CComPtr<IDefaultExtractIconInit> initIcon; 129 HRESULT hr; 130 GUID const * riid; 131 int icon_idx; 132 WCHAR wTemp[MAX_PATH]; 133 134 hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon)); 135 if (FAILED(hr)) 136 return hr; 137 138 if (_ILIsDesktop(pidl)) 139 { 140 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DESKTOP); 141 return initIcon->QueryInterface(iid, ppvOut); 142 } 143 144 riid = _ILGetGUIDPointer(pidl); 145 if (!riid) 146 return E_FAIL; 147 148 /* my computer and other shell extensions */ 149 WCHAR xriid[50]; 150 151 swprintf(xriid, L"CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", 152 riid->Data1, riid->Data2, riid->Data3, 153 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3], 154 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]); 155 156 const WCHAR* iconname = NULL; 157 if (_ILIsBitBucket(pidl)) 158 { 159 CComPtr<IEnumIDList> EnumIDList; 160 CoInitialize(NULL); 161 162 CComPtr<IShellFolder2> psfRecycleBin; 163 CComPtr<IShellFolder> psfDesktop; 164 hr = SHGetDesktopFolder(&psfDesktop); 165 166 if (SUCCEEDED(hr)) 167 hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder2, &psfRecycleBin)); 168 if (SUCCEEDED(hr)) 169 hr = psfRecycleBin->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &EnumIDList); 170 171 ULONG itemcount; 172 LPITEMIDLIST pidl = NULL; 173 if (SUCCEEDED(hr) && (hr = EnumIDList->Next(1, &pidl, &itemcount)) == S_OK) 174 { 175 CoTaskMemFree(pidl); 176 iconname = L"Full"; 177 } else { 178 iconname = L"Empty"; 179 } 180 } 181 182 if (HCR_GetIconW(xriid, wTemp, iconname, MAX_PATH, &icon_idx)) 183 { 184 initIcon->SetNormalIcon(wTemp, icon_idx); 185 } 186 else 187 { 188 // FIXME: Delete these hacks and make HCR_GetIconW and registry working 189 if (IsEqualGUID(*riid, CLSID_MyComputer)) 190 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_COMPUTER); 191 else if (IsEqualGUID(*riid, CLSID_MyDocuments)) 192 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_DOCUMENTS); 193 else if (IsEqualGUID(*riid, CLSID_NetworkPlaces)) 194 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_NETWORK_PLACES); 195 else if (IsEqualGUID(*riid, CLSID_Internet)) 196 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_WEB_BROWSER); 197 else 198 initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_FOLDER); 199 } 200 201 return initIcon->QueryInterface(iid, ppvOut); 202 } 203 204 class CRegFolderEnum : 205 public CEnumIDListBase 206 { 207 public: 208 CRegFolderEnum(); 209 ~CRegFolderEnum(); 210 HRESULT Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags); 211 HRESULT AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath); 212 213 BEGIN_COM_MAP(CRegFolderEnum) 214 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 215 END_COM_MAP() 216 }; 217 218 enum registry_columns 219 { 220 REGISTRY_COL_NAME, 221 REGISTRY_COL_TYPE, 222 REGISTRY_COL_VALUE, 223 REGISTRY_COL_COUNT, 224 }; 225 226 CRegFolderEnum::CRegFolderEnum() 227 { 228 } 229 230 CRegFolderEnum::~CRegFolderEnum() 231 { 232 } 233 234 HRESULT CRegFolderEnum::Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags) 235 { 236 WCHAR KeyName[MAX_PATH]; 237 238 if (!(dwFlags & SHCONTF_FOLDERS)) 239 return S_OK; 240 241 HRESULT hr = StringCchPrintfW(KeyName, MAX_PATH, 242 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\%s\\Namespace", 243 lpszEnumKeyName); 244 if (FAILED_UNEXPECTEDLY(hr)) 245 return hr; 246 247 AddItemsFromKey(HKEY_LOCAL_MACHINE, KeyName); 248 AddItemsFromKey(HKEY_CURRENT_USER, KeyName); 249 250 return S_OK; 251 } 252 253 HRESULT CRegFolderEnum::AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath) 254 { 255 WCHAR name[MAX_PATH]; 256 HKEY hkey; 257 258 if (RegOpenKeyW(hkey_root, szRepPath, &hkey) != ERROR_SUCCESS) 259 return S_FALSE; 260 261 for (int idx = 0; ; idx++) 262 { 263 if (RegEnumKeyW(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS) 264 break; 265 266 /* If the name of the key is not a guid try to get the default value of the key */ 267 if (name[0] != L'{') 268 { 269 DWORD dwSize = sizeof(name); 270 RegGetValueW(hkey, name, NULL, RRF_RT_REG_SZ, NULL, name, &dwSize); 271 } 272 273 if (*name == '{') 274 { 275 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(name); 276 277 if (pidl) 278 AddToEnumList(pidl); 279 } 280 } 281 282 RegCloseKey(hkey); 283 284 return S_OK; 285 } 286 287 class CRegFolder : 288 public CComObjectRootEx<CComMultiThreadModelNoCS>, 289 public IShellFolder2 290 { 291 private: 292 GUID m_guid; 293 CAtlStringW m_rootPath; 294 CAtlStringW m_enumKeyName; 295 CComHeapPtr<ITEMIDLIST> m_pidlRoot; 296 297 HRESULT GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes); 298 public: 299 CRegFolder(); 300 ~CRegFolder(); 301 HRESULT WINAPI Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName); 302 303 // IShellFolder 304 virtual HRESULT WINAPI ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes); 305 virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); 306 virtual HRESULT WINAPI BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); 307 virtual HRESULT WINAPI BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); 308 virtual HRESULT WINAPI CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2); 309 virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); 310 virtual HRESULT WINAPI GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut); 311 virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); 312 virtual HRESULT WINAPI GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet); 313 virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut); 314 315 /* ShellFolder2 */ 316 virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); 317 virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); 318 virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); 319 virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); 320 virtual HRESULT WINAPI GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv); 321 virtual HRESULT WINAPI GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd); 322 virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); 323 324 DECLARE_NOT_AGGREGATABLE(CRegFolder) 325 326 DECLARE_PROTECT_FINAL_CONSTRUCT() 327 328 BEGIN_COM_MAP(CRegFolder) 329 COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) 330 COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) 331 END_COM_MAP() 332 }; 333 334 CRegFolder::CRegFolder() 335 { 336 } 337 338 CRegFolder::~CRegFolder() 339 { 340 } 341 342 HRESULT WINAPI CRegFolder::Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName) 343 { 344 memcpy(&m_guid, pGuid, sizeof(m_guid)); 345 346 m_rootPath = lpszPath; 347 if (!m_rootPath) 348 return E_OUTOFMEMORY; 349 350 m_enumKeyName = lpszEnumKeyName; 351 if (!m_enumKeyName) 352 return E_OUTOFMEMORY; 353 354 m_pidlRoot.Attach(ILClone(pidlRoot)); 355 if (!m_pidlRoot) 356 return E_OUTOFMEMORY; 357 358 return S_OK; 359 } 360 361 HRESULT CRegFolder::GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes) 362 { 363 DWORD dwAttributes = *pdwAttributes; 364 365 /* First try to get them from the registry */ 366 if (!HCR_GetFolderAttributes(pidl, pdwAttributes)) 367 { 368 /* We couldn't get anything */ 369 *pdwAttributes = 0; 370 } 371 372 /* Items have more attributes when on desktop */ 373 if (_ILIsDesktop(m_pidlRoot)) 374 { 375 *pdwAttributes |= (dwAttributes & (SFGAO_CANLINK|SFGAO_CANDELETE|SFGAO_CANRENAME|SFGAO_HASPROPSHEET)); 376 } 377 378 /* In any case, links can be created */ 379 if (*pdwAttributes == NULL) 380 { 381 *pdwAttributes |= (dwAttributes & SFGAO_CANLINK); 382 } 383 return S_OK; 384 } 385 386 HRESULT WINAPI CRegFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, 387 ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) 388 { 389 LPITEMIDLIST pidl; 390 391 if (!lpszDisplayName || !ppidl) 392 return E_INVALIDARG; 393 394 *ppidl = 0; 395 396 if (pchEaten) 397 *pchEaten = 0; 398 399 UINT cch = wcslen(lpszDisplayName); 400 if (cch < 39 || lpszDisplayName[0] != L':' || lpszDisplayName[1] != L':') 401 return E_FAIL; 402 403 pidl = _ILCreateGuidFromStrW(lpszDisplayName + 2); 404 if (pidl == NULL) 405 return E_FAIL; 406 407 if (cch < 41) 408 { 409 *ppidl = pidl; 410 if (pdwAttributes && *pdwAttributes) 411 { 412 GetGuidItemAttributes(*ppidl, pdwAttributes); 413 } 414 } 415 else 416 { 417 HRESULT hr = SHELL32_ParseNextElement(this, hwndOwner, pbc, &pidl, lpszDisplayName + 41, pchEaten, pdwAttributes); 418 if (SUCCEEDED(hr)) 419 { 420 *ppidl = pidl; 421 } 422 return hr; 423 } 424 425 return S_OK; 426 } 427 428 HRESULT WINAPI CRegFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 429 { 430 return ShellObjectCreatorInit<CRegFolderEnum>(m_enumKeyName, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 431 } 432 433 HRESULT WINAPI CRegFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 434 { 435 CComPtr<IPersistFolder> pFolder; 436 HRESULT hr; 437 438 if (!ppvOut || !pidl || !pidl->mkid.cb) 439 return E_INVALIDARG; 440 441 *ppvOut = NULL; 442 443 GUID *pGUID = _ILGetGUIDPointer(pidl); 444 if (!pGUID) 445 { 446 ERR("CRegFolder::BindToObject called for non guid item!\n"); 447 return E_INVALIDARG; 448 } 449 450 hr = SHELL32_BindToSF(m_pidlRoot, NULL, pidl, pGUID, riid, ppvOut); 451 if (FAILED_UNEXPECTEDLY(hr)) 452 return hr; 453 454 return S_OK; 455 } 456 457 HRESULT WINAPI CRegFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 458 { 459 return E_NOTIMPL; 460 } 461 462 HRESULT WINAPI CRegFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 463 { 464 if (!pidl1 || !pidl2 || pidl1->mkid.cb == 0 || pidl2->mkid.cb == 0) 465 { 466 ERR("Got an empty pidl!\n"); 467 return E_INVALIDARG; 468 } 469 470 GUID const *clsid1 = _ILGetGUIDPointer (pidl1); 471 GUID const *clsid2 = _ILGetGUIDPointer (pidl2); 472 473 if (!clsid1 && !clsid2) 474 { 475 ERR("Got no guid pidl!\n"); 476 return E_INVALIDARG; 477 } 478 else if (clsid1 && clsid2) 479 { 480 if (memcmp(clsid1, clsid2, sizeof(GUID)) == 0) 481 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2); 482 483 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2); 484 } 485 486 /* Guid folders come first compared to everything else */ 487 /* And Drives come before folders in My Computer */ 488 if (_ILIsMyComputer(m_pidlRoot)) 489 { 490 return MAKE_COMPARE_HRESULT(clsid1 ? 1 : -1); 491 } 492 else 493 { 494 return MAKE_COMPARE_HRESULT(clsid1 ? -1 : 1); 495 } 496 } 497 498 HRESULT WINAPI CRegFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) 499 { 500 return E_NOTIMPL; 501 } 502 503 HRESULT WINAPI CRegFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut) 504 { 505 if (!rgfInOut || !cidl || !apidl) 506 return E_INVALIDARG; 507 508 if (*rgfInOut == 0) 509 *rgfInOut = ~0; 510 511 while(cidl > 0 && *apidl) 512 { 513 if (_ILIsSpecialFolder(*apidl)) 514 GetGuidItemAttributes(*apidl, rgfInOut); 515 else 516 ERR("Got an unknown pidl here!\n"); 517 apidl++; 518 cidl--; 519 } 520 521 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 522 *rgfInOut &= ~SFGAO_VALIDATE; 523 524 return S_OK; 525 } 526 527 HRESULT WINAPI CRegFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 528 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) 529 { 530 LPVOID pObj = NULL; 531 HRESULT hr = E_INVALIDARG; 532 533 if (!ppvOut) 534 return hr; 535 536 *ppvOut = NULL; 537 538 if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 539 { 540 hr = CGuidItemExtractIcon_CreateInstance(apidl[0], riid, &pObj); 541 } 542 else if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1)) 543 { 544 if (!_ILGetGUIDPointer (apidl[0])) 545 { 546 ERR("Got non guid item!\n"); 547 return E_FAIL; 548 } 549 550 hr = CGuidItemContextMenu_CreateInstance(m_pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj); 551 } 552 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) 553 { 554 hr = IDataObject_Constructor (hwndOwner, m_pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 555 } 556 else 557 { 558 hr = E_NOINTERFACE; 559 } 560 561 *ppvOut = pObj; 562 return hr; 563 564 } 565 566 HRESULT WINAPI CRegFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 567 { 568 if (!strRet || (!_ILIsSpecialFolder(pidl) && pidl != NULL)) 569 return E_INVALIDARG; 570 571 if (!pidl || !pidl->mkid.cb) 572 { 573 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING)) 574 { 575 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); 576 if (!pszPath) 577 return E_OUTOFMEMORY; 578 579 /* parsing name like ::{...} */ 580 pszPath[0] = ':'; 581 pszPath[1] = ':'; 582 SHELL32_GUIDToStringW(m_guid, &pszPath[2]); 583 584 strRet->uType = STRRET_WSTR; 585 strRet->pOleStr = pszPath; 586 587 return S_OK; 588 } 589 else 590 { 591 BOOL bRet; 592 WCHAR wstrName[MAX_PATH+1]; 593 bRet = HCR_GetClassNameW(m_guid, wstrName, MAX_PATH); 594 if (!bRet) 595 return E_FAIL; 596 597 return SHSetStrRet(strRet, wstrName); 598 599 } 600 } 601 602 HRESULT hr; 603 GUID const *clsid = _ILGetGUIDPointer (pidl); 604 605 /* First of all check if we need to query the name from the child item */ 606 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING && 607 GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) 608 { 609 int bWantsForParsing = FALSE; 610 611 /* 612 * We can only get a filesystem path from a shellfolder if the 613 * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists. 614 * 615 * Exception: The MyComputer folder doesn't have this key, 616 * but any other filesystem backed folder it needs it. 617 */ 618 if (IsEqualIID (*clsid, CLSID_MyComputer)) 619 { 620 bWantsForParsing = TRUE; 621 } 622 else 623 { 624 HKEY hkeyClass; 625 if (HCR_RegOpenClassIDKey(*clsid, &hkeyClass)) 626 { 627 LONG res = SHGetValueW(hkeyClass, L"Shellfolder", L"WantsForParsing", NULL, NULL, NULL); 628 bWantsForParsing = (res == ERROR_SUCCESS); 629 RegCloseKey(hkeyClass); 630 } 631 } 632 633 if (bWantsForParsing) 634 { 635 /* 636 * we need the filesystem path to the destination folder. 637 * Only the folder itself can know it 638 */ 639 return SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags, strRet); 640 } 641 } 642 643 /* Allocate the buffer for the result */ 644 SIZE_T cchPath = MAX_PATH + 1; 645 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc(cchPath * sizeof(WCHAR)); 646 if (!pszPath) 647 return E_OUTOFMEMORY; 648 649 hr = S_OK; 650 651 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING) 652 { 653 SIZE_T pathlen = 0; 654 PWCHAR pItemName = pszPath; // GET_SHGDN_RELATION(dwFlags) == SHGDN_INFOLDER 655 if (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) 656 { 657 hr = StringCchCopyW(pszPath, cchPath, m_rootPath); 658 if (SUCCEEDED(hr)) 659 { 660 pathlen = wcslen(pszPath); 661 pItemName = &pszPath[pathlen]; 662 if (pathlen) 663 { 664 if (++pathlen < cchPath) 665 *pItemName++ = L'\\'; 666 else 667 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 668 } 669 } 670 } 671 672 if (SUCCEEDED(hr) && pathlen + 2 + 38 + 1 < cchPath) 673 { 674 /* parsing name like ::{...} */ 675 pItemName[0] = L':'; 676 pItemName[1] = L':'; 677 SHELL32_GUIDToStringW(*clsid, &pItemName[2]); 678 } 679 else 680 { 681 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 682 } 683 } 684 else 685 { 686 /* user friendly name */ 687 if (!HCR_GetClassNameW(*clsid, pszPath, cchPath)) 688 hr = E_FAIL; 689 } 690 691 if (SUCCEEDED(hr)) 692 { 693 strRet->uType = STRRET_WSTR; 694 strRet->pOleStr = pszPath; 695 } 696 else 697 { 698 CoTaskMemFree(pszPath); 699 } 700 701 return hr; 702 } 703 704 HRESULT WINAPI CRegFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */ 705 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 706 { 707 GUID const *clsid = _ILGetGUIDPointer (pidl); 708 LPOLESTR pStr; 709 HRESULT hr; 710 WCHAR szName[100]; 711 712 if (!clsid) 713 { 714 ERR("Pidl is not reg item!\n"); 715 return E_FAIL; 716 } 717 718 hr = StringFromCLSID(*clsid, &pStr); 719 if (FAILED_UNEXPECTEDLY(hr)) 720 return hr; 721 722 swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr); 723 724 DWORD cbData = (wcslen(lpName) + 1) * sizeof(WCHAR); 725 LONG res = SHSetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, lpName, cbData); 726 727 CoTaskMemFree(pStr); 728 729 if (res == ERROR_SUCCESS) 730 { 731 *pPidlOut = ILClone(pidl); 732 return S_OK; 733 } 734 735 return E_FAIL; 736 } 737 738 739 HRESULT WINAPI CRegFolder::GetDefaultSearchGUID(GUID *pguid) 740 { 741 return E_NOTIMPL; 742 } 743 744 HRESULT WINAPI CRegFolder::EnumSearches(IEnumExtraSearch ** ppenum) 745 { 746 return E_NOTIMPL; 747 } 748 749 HRESULT WINAPI CRegFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 750 { 751 if (pSort) 752 *pSort = 0; 753 if (pDisplay) 754 *pDisplay = 0; 755 756 return S_OK; 757 } 758 759 HRESULT WINAPI CRegFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 760 { 761 if (iColumn >= REGISTRY_COL_COUNT) 762 return E_INVALIDARG; 763 *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; 764 return S_OK; 765 } 766 767 HRESULT WINAPI CRegFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) 768 { 769 return E_NOTIMPL; 770 } 771 772 HRESULT WINAPI CRegFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 773 { 774 if (!psd) 775 return E_INVALIDARG; 776 777 GUID const *clsid = _ILGetGUIDPointer (pidl); 778 779 if (!clsid) 780 { 781 ERR("Pidl is not reg item!\n"); 782 return E_INVALIDARG; 783 } 784 785 switch(iColumn) 786 { 787 case REGISTRY_COL_NAME: 788 return GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); 789 case REGISTRY_COL_TYPE: 790 return SHSetStrRet(&psd->str, IDS_SYSTEMFOLDER); 791 case REGISTRY_COL_VALUE: 792 HKEY hKey; 793 if (!HCR_RegOpenClassIDKey(*clsid, &hKey)) 794 return SHSetStrRet(&psd->str, ""); 795 796 psd->str.cStr[0] = 0x00; 797 psd->str.uType = STRRET_CSTR; 798 RegLoadMUIStringA(hKey, "InfoTip", psd->str.cStr, MAX_PATH, NULL, 0, NULL); 799 RegCloseKey(hKey); 800 return S_OK; 801 default: 802 /* Return an empty string when we area asked for a column we don't support. 803 Only the regfolder is supposed to do this as it supports less columns compared to other folder 804 and its contents are supposed to be presented alongside items that support more columns. */ 805 return SHSetStrRet(&psd->str, ""); 806 } 807 return E_FAIL; 808 } 809 810 HRESULT WINAPI CRegFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 811 { 812 return E_NOTIMPL; 813 } 814 815 /* In latest windows version this is exported but it takes different arguments! */ 816 HRESULT CRegFolder_CreateInstance(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName, REFIID riid, void **ppv) 817 { 818 return ShellObjectCreatorInit<CRegFolder>(pGuid, pidlRoot, lpszPath, lpszEnumKeyName, riid, ppv); 819 } 820