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