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