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 return MAKE_COMPARE_HRESULT(clsid1 ? -1 : 1); 478 } 479 480 HRESULT WINAPI CRegFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) 481 { 482 return E_NOTIMPL; 483 } 484 485 HRESULT WINAPI CRegFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut) 486 { 487 if (!rgfInOut || !cidl || !apidl) 488 return E_INVALIDARG; 489 490 if (*rgfInOut == 0) 491 *rgfInOut = ~0; 492 493 while(cidl > 0 && *apidl) 494 { 495 if (_ILIsSpecialFolder(*apidl)) 496 GetGuidItemAttributes(*apidl, rgfInOut); 497 else 498 ERR("Got an unkown pidl here!\n"); 499 apidl++; 500 cidl--; 501 } 502 503 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 504 *rgfInOut &= ~SFGAO_VALIDATE; 505 506 return S_OK; 507 } 508 509 HRESULT WINAPI CRegFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 510 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) 511 { 512 LPVOID pObj = NULL; 513 HRESULT hr = E_INVALIDARG; 514 515 if (!ppvOut) 516 return hr; 517 518 *ppvOut = NULL; 519 520 if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 521 { 522 hr = CGuidItemExtractIcon_CreateInstance(apidl[0], riid, &pObj); 523 } 524 else if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1)) 525 { 526 if (!_ILGetGUIDPointer (apidl[0])) 527 { 528 ERR("Got non guid item!\n"); 529 return E_FAIL; 530 } 531 532 hr = CGuidItemContextMenu_CreateInstance(m_pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj); 533 } 534 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) 535 { 536 hr = IDataObject_Constructor (hwndOwner, m_pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 537 } 538 else 539 { 540 hr = E_NOINTERFACE; 541 } 542 543 *ppvOut = pObj; 544 return hr; 545 546 } 547 548 HRESULT WINAPI CRegFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 549 { 550 if (!strRet || (!_ILIsSpecialFolder(pidl) && pidl != NULL)) 551 return E_INVALIDARG; 552 553 if (!pidl || !pidl->mkid.cb) 554 { 555 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING)) 556 { 557 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); 558 if (!pszPath) 559 return E_OUTOFMEMORY; 560 561 /* parsing name like ::{...} */ 562 pszPath[0] = ':'; 563 pszPath[1] = ':'; 564 SHELL32_GUIDToStringW(m_guid, &pszPath[2]); 565 566 strRet->uType = STRRET_WSTR; 567 strRet->pOleStr = pszPath; 568 569 return S_OK; 570 } 571 else 572 { 573 BOOL bRet; 574 WCHAR wstrName[MAX_PATH+1]; 575 bRet = HCR_GetClassNameW(m_guid, wstrName, MAX_PATH); 576 if (!bRet) 577 return E_FAIL; 578 579 return SHSetStrRet(strRet, wstrName); 580 581 } 582 } 583 584 HRESULT hr; 585 GUID const *clsid = _ILGetGUIDPointer (pidl); 586 587 /* First of all check if we need to query the name from the child item */ 588 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING && 589 GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) 590 { 591 int bWantsForParsing = FALSE; 592 593 /* 594 * We can only get a filesystem path from a shellfolder if the 595 * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists. 596 * 597 * Exception: The MyComputer folder doesn't have this key, 598 * but any other filesystem backed folder it needs it. 599 */ 600 if (IsEqualIID (*clsid, CLSID_MyComputer)) 601 { 602 bWantsForParsing = TRUE; 603 } 604 else 605 { 606 HKEY hkeyClass; 607 if (HCR_RegOpenClassIDKey(*clsid, &hkeyClass)) 608 { 609 LONG res = SHGetValueW(hkeyClass, L"Shellfolder", L"WantsForParsing", NULL, NULL, NULL); 610 bWantsForParsing = (res == ERROR_SUCCESS); 611 RegCloseKey(hkeyClass); 612 } 613 } 614 615 if (bWantsForParsing) 616 { 617 /* 618 * we need the filesystem path to the destination folder. 619 * Only the folder itself can know it 620 */ 621 return SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags, strRet); 622 } 623 } 624 625 /* Allocate the buffer for the result */ 626 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); 627 if (!pszPath) 628 return E_OUTOFMEMORY; 629 630 hr = S_OK; 631 632 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING) 633 { 634 wcscpy(pszPath, m_rootPath); 635 PWCHAR pItemName = &pszPath[wcslen(pszPath)]; 636 637 /* parsing name like ::{...} */ 638 pItemName[0] = ':'; 639 pItemName[1] = ':'; 640 SHELL32_GUIDToStringW (*clsid, &pItemName[2]); 641 } 642 else 643 { 644 /* user friendly name */ 645 if (!HCR_GetClassNameW (*clsid, pszPath, MAX_PATH)) 646 hr = E_FAIL; 647 } 648 649 if (SUCCEEDED(hr)) 650 { 651 strRet->uType = STRRET_WSTR; 652 strRet->pOleStr = pszPath; 653 } 654 else 655 { 656 CoTaskMemFree(pszPath); 657 } 658 659 return hr; 660 } 661 662 HRESULT WINAPI CRegFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */ 663 LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 664 { 665 GUID const *clsid = _ILGetGUIDPointer (pidl); 666 LPOLESTR pStr; 667 HRESULT hr; 668 WCHAR szName[100]; 669 670 if (!clsid) 671 { 672 ERR("Pidl is not reg item!\n"); 673 return E_FAIL; 674 } 675 676 hr = StringFromCLSID(*clsid, &pStr); 677 if (FAILED_UNEXPECTEDLY(hr)) 678 return hr; 679 680 swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr); 681 682 DWORD cbData = (wcslen(lpName) + 1) * sizeof(WCHAR); 683 LONG res = SHSetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, lpName, cbData); 684 685 CoTaskMemFree(pStr); 686 687 if (res == ERROR_SUCCESS) 688 { 689 *pPidlOut = ILClone(pidl); 690 return S_OK; 691 } 692 693 return E_FAIL; 694 } 695 696 697 HRESULT WINAPI CRegFolder::GetDefaultSearchGUID(GUID *pguid) 698 { 699 return E_NOTIMPL; 700 } 701 702 HRESULT WINAPI CRegFolder::EnumSearches(IEnumExtraSearch ** ppenum) 703 { 704 return E_NOTIMPL; 705 } 706 707 HRESULT WINAPI CRegFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 708 { 709 if (pSort) 710 *pSort = 0; 711 if (pDisplay) 712 *pDisplay = 0; 713 714 return S_OK; 715 } 716 717 HRESULT WINAPI CRegFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 718 { 719 if (iColumn >= 2) 720 return E_INVALIDARG; 721 *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; 722 return S_OK; 723 } 724 725 HRESULT WINAPI CRegFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) 726 { 727 return E_NOTIMPL; 728 } 729 730 HRESULT WINAPI CRegFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 731 { 732 if (!psd) 733 return E_INVALIDARG; 734 735 GUID const *clsid = _ILGetGUIDPointer (pidl); 736 737 if (!clsid) 738 { 739 ERR("Pidl is not reg item!\n"); 740 return E_INVALIDARG; 741 } 742 743 if (iColumn >= 3) 744 { 745 /* Return an empty string when we area asked for a column we don't support. 746 Only the regfolder is supposed to do this as it supports less columns compared to other folder 747 and its contents are supposed to be presented alongside items that support more columns. */ 748 return SHSetStrRet(&psd->str, ""); 749 } 750 751 switch(iColumn) 752 { 753 case 0: /* name */ 754 return GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); 755 case 1: /* comments */ 756 HKEY hKey; 757 if (!HCR_RegOpenClassIDKey(*clsid, &hKey)) 758 return SHSetStrRet(&psd->str, ""); 759 760 psd->str.cStr[0] = 0x00; 761 psd->str.uType = STRRET_CSTR; 762 RegLoadMUIStringA(hKey, "InfoTip", psd->str.cStr, MAX_PATH, NULL, 0, NULL); 763 RegCloseKey(hKey); 764 return S_OK; 765 case 2: /* type */ 766 //return SHSetStrRet(&psd->str, resource_id); /* FIXME: translate */ 767 return SHSetStrRet(&psd->str, "System Folder"); 768 } 769 return E_FAIL; 770 } 771 772 HRESULT WINAPI CRegFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 773 { 774 return E_NOTIMPL; 775 } 776 777 /* In latest windows version this is exported but it takes different arguments! */ 778 HRESULT CRegFolder_CreateInstance(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName, REFIID riid, void **ppv) 779 { 780 return ShellObjectCreatorInit<CRegFolder>(pGuid, pidlRoot, lpszPath, lpszEnumKeyName, riid, ppv); 781 } 782