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