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