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