1 2 /* 3 * file system folder 4 * 5 * Copyright 1997 Marcus Meissner 6 * Copyright 1998, 1999, 2002 Juergen Schmied 7 * Copyright 2019 Katayama Hirofumi MZ 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24 #include <precomp.h> 25 26 WINE_DEFAULT_DEBUG_CHANNEL (shell); 27 28 HKEY OpenKeyFromFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName) 29 { 30 HKEY hkey; 31 32 if (!_ILIsValue(pidl)) 33 { 34 ERR("Invalid pidl!\n"); 35 return NULL; 36 } 37 38 FileStructW* pDataW = _ILGetFileStructW(pidl); 39 if (!pDataW) 40 { 41 ERR("Invalid pidl!\n"); 42 return NULL; 43 } 44 45 LPWSTR pExtension = PathFindExtensionW(pDataW->wszName); 46 if (!pExtension || *pExtension == NULL) 47 { 48 WARN("No extension for %S!\n", pDataW->wszName); 49 return NULL; 50 } 51 52 WCHAR FullName[MAX_PATH]; 53 DWORD dwSize = sizeof(FullName); 54 wsprintf(FullName, L"%s\\%s", pExtension, KeyName); 55 56 LONG res = RegOpenKeyExW(HKEY_CLASSES_ROOT, FullName, 0, KEY_READ, &hkey); 57 if (!res) 58 return hkey; 59 60 res = RegGetValueW(HKEY_CLASSES_ROOT, pExtension, NULL, RRF_RT_REG_SZ, NULL, FullName, &dwSize); 61 if (res) 62 { 63 WARN("Failed to get progid for file %S, extension %S (%x), address %x, pidl: %x, error %d\n", pDataW->wszName, pExtension, pExtension, &dwSize, pidl, res); 64 return NULL; 65 } 66 67 wcscat(FullName, L"\\"); 68 wcscat(FullName, KeyName); 69 70 hkey = NULL; 71 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, FullName, 0, KEY_READ, &hkey); 72 if (res) 73 WARN("Could not open key %S for extension %S\n", KeyName, pExtension); 74 75 return hkey; 76 } 77 78 HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pclsid) 79 { 80 HKEY hkeyProgId = OpenKeyFromFileType(pidl, KeyName); 81 if (!hkeyProgId) 82 { 83 WARN("OpenKeyFromFileType failed for key %S\n", KeyName); 84 return S_FALSE; 85 } 86 87 WCHAR wszCLSIDValue[CHARS_IN_GUID]; 88 DWORD dwSize = sizeof(wszCLSIDValue); 89 LONG res = RegGetValueW(hkeyProgId, NULL, NULL, RRF_RT_REG_SZ, NULL, wszCLSIDValue, &dwSize); 90 RegCloseKey(hkeyProgId); 91 if (res) 92 { 93 ERR("OpenKeyFromFileType succeeded but RegGetValueW failed\n"); 94 return S_FALSE; 95 } 96 97 #if 0 98 { 99 res = RegGetValueW(HKEY_LOCAL_MACHINE, 100 L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 101 wszCLSIDValue, 102 RRF_RT_REG_SZ, 103 NULL, 104 NULL, 105 NULL); 106 if (res != ERROR_SUCCESS) 107 { 108 ERR("DropHandler extension %S not approved\n", wszName); 109 return E_ACCESSDENIED; 110 } 111 } 112 #endif 113 114 if (RegGetValueW(HKEY_LOCAL_MACHINE, 115 L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Blocked", 116 wszCLSIDValue, 117 RRF_RT_REG_SZ, 118 NULL, 119 NULL, 120 NULL) == ERROR_SUCCESS) 121 { 122 ERR("Extension %S not approved\n", wszCLSIDValue); 123 return E_ACCESSDENIED; 124 } 125 126 HRESULT hres = CLSIDFromString (wszCLSIDValue, pclsid); 127 if (FAILED_UNEXPECTEDLY(hres)) 128 return hres; 129 130 return S_OK; 131 } 132 133 static HRESULT 134 getDefaultIconLocation(LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT uFlags) 135 { 136 static const WCHAR folder[] = { 'F', 'o', 'l', 'd', 'e', 'r', 0 }; 137 138 if (!HCR_GetIconW(folder, szIconFile, NULL, cchMax, piIndex)) 139 { 140 lstrcpynW(szIconFile, swShell32Name, cchMax); 141 *piIndex = -IDI_SHELL_FOLDER; 142 } 143 144 if (uFlags & GIL_OPENICON) 145 { 146 // next icon 147 if (*piIndex < 0) 148 (*piIndex)--; 149 else 150 (*piIndex)++; 151 } 152 153 return S_OK; 154 } 155 156 static const WCHAR s_shellClassInfo[] = { '.', 'S', 'h', 'e', 'l', 'l', 'C', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 }; 157 158 static BOOL 159 getShellClassInfo(LPCWSTR Entry, LPWSTR pszValue, DWORD cchValueLen, LPCWSTR IniFile) 160 { 161 return GetPrivateProfileStringW(s_shellClassInfo, Entry, NULL, pszValue, cchValueLen, IniFile); 162 } 163 164 static HRESULT 165 getIconLocationForFolder(IShellFolder * psf, PCITEMID_CHILD pidl, UINT uFlags, 166 LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags) 167 { 168 DWORD dwFileAttrs; 169 WCHAR wszPath[MAX_PATH]; 170 WCHAR wszIniFullPath[MAX_PATH]; 171 static const WCHAR iconFile[] = { 'I', 'c', 'o', 'n', 'F', 'i', 'l', 'e', 0 }; 172 static const WCHAR clsid[] = { 'C', 'L', 'S', 'I', 'D', 0 }; 173 static const WCHAR clsid2[] = { 'C', 'L', 'S', 'I', 'D', '2', 0 }; 174 static const WCHAR iconIndex[] = { 'I', 'c', 'o', 'n', 'I', 'n', 'd', 'e', 'x', 0 }; 175 static const WCHAR iconResource[] = { 'I', 'c', 'o', 'n', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 0 }; 176 static const WCHAR wszDesktopIni[] = { 'd','e','s','k','t','o','p','.','i','n','i',0 }; 177 178 if (uFlags & GIL_DEFAULTICON) 179 goto Quit; 180 181 // get path 182 if (!ILGetDisplayNameExW(psf, pidl, wszPath, 0)) 183 goto Quit; 184 if (!PathIsDirectoryW(wszPath)) 185 goto Quit; 186 187 // read-only or system folder? 188 dwFileAttrs = _ILGetFileAttributes(ILFindLastID(pidl), NULL, 0); 189 if ((dwFileAttrs & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) == 0) 190 goto Quit; 191 192 // build the full path of ini file 193 StringCchCopyW(wszIniFullPath, _countof(wszIniFullPath), wszPath); 194 PathAppendW(wszIniFullPath, wszDesktopIni); 195 196 WCHAR wszValue[MAX_PATH], wszTemp[MAX_PATH]; 197 if (getShellClassInfo(iconFile, wszValue, _countof(wszValue), wszIniFullPath)) 198 { 199 // wszValue --> wszTemp 200 ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp)); 201 202 // wszPath + wszTemp --> wszPath 203 if (PathIsRelativeW(wszTemp)) 204 PathAppendW(wszPath, wszTemp); 205 else 206 StringCchCopyW(wszPath, _countof(wszPath), wszTemp); 207 208 // wszPath --> szIconFile 209 GetFullPathNameW(wszPath, cchMax, szIconFile, NULL); 210 211 *piIndex = GetPrivateProfileIntW(s_shellClassInfo, iconIndex, 0, wszIniFullPath); 212 return S_OK; 213 } 214 else if (getShellClassInfo(clsid, wszValue, _countof(wszValue), wszIniFullPath) && 215 HCR_GetIconW(wszValue, szIconFile, NULL, cchMax, piIndex)) 216 { 217 return S_OK; 218 } 219 else if (getShellClassInfo(clsid2, wszValue, _countof(wszValue), wszIniFullPath) && 220 HCR_GetIconW(wszValue, szIconFile, NULL, cchMax, piIndex)) 221 { 222 return S_OK; 223 } 224 else if (getShellClassInfo(iconResource, wszValue, _countof(wszValue), wszIniFullPath)) 225 { 226 // wszValue --> wszTemp 227 ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp)); 228 229 // parse the icon location 230 *piIndex = PathParseIconLocationW(wszTemp); 231 232 // wszPath + wszTemp --> wszPath 233 if (PathIsRelativeW(wszTemp)) 234 PathAppendW(wszPath, wszTemp); 235 else 236 StringCchCopyW(wszPath, _countof(wszPath), wszTemp); 237 238 // wszPath --> szIconFile 239 GetFullPathNameW(wszPath, cchMax, szIconFile, NULL); 240 return S_OK; 241 } 242 243 Quit: 244 return getDefaultIconLocation(szIconFile, cchMax, piIndex, uFlags); 245 } 246 247 HRESULT CFSExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut) 248 { 249 CComPtr<IDefaultExtractIconInit> initIcon; 250 HRESULT hr; 251 int icon_idx = 0; 252 UINT flags = 0; // FIXME: Use it! 253 WCHAR wTemp[MAX_PATH] = L""; 254 255 hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon)); 256 if (FAILED(hr)) 257 return hr; 258 259 if (_ILIsFolder (pidl)) 260 { 261 if (SUCCEEDED(getIconLocationForFolder(psf, 262 pidl, 0, wTemp, _countof(wTemp), 263 &icon_idx, 264 &flags))) 265 { 266 initIcon->SetNormalIcon(wTemp, icon_idx); 267 // FIXME: if/when getIconLocationForFolder does something for 268 // GIL_FORSHORTCUT, code below should be uncommented. and 269 // the following line removed. 270 initIcon->SetShortcutIcon(wTemp, icon_idx); 271 } 272 if (SUCCEEDED(getIconLocationForFolder(psf, 273 pidl, GIL_DEFAULTICON, wTemp, _countof(wTemp), 274 &icon_idx, 275 &flags))) 276 { 277 initIcon->SetDefaultIcon(wTemp, icon_idx); 278 } 279 // if (SUCCEEDED(getIconLocationForFolder(psf, 280 // pidl, GIL_FORSHORTCUT, wTemp, _countof(wTemp), 281 // &icon_idx, 282 // &flags))) 283 // { 284 // initIcon->SetShortcutIcon(wTemp, icon_idx); 285 // } 286 if (SUCCEEDED(getIconLocationForFolder(psf, 287 pidl, GIL_OPENICON, wTemp, _countof(wTemp), 288 &icon_idx, 289 &flags))) 290 { 291 initIcon->SetOpenIcon(wTemp, icon_idx); 292 } 293 } 294 else 295 { 296 HKEY hkey = OpenKeyFromFileType(pidl, L"DefaultIcon"); 297 if (!hkey) 298 WARN("Could not open DefaultIcon key!\n"); 299 300 DWORD dwSize = sizeof(wTemp); 301 if (hkey && !SHQueryValueExW(hkey, NULL, NULL, NULL, wTemp, &dwSize)) 302 { 303 WCHAR sNum[5]; 304 if (ParseFieldW (wTemp, 2, sNum, 5)) 305 icon_idx = _wtoi(sNum); 306 else 307 icon_idx = 0; /* sometimes the icon number is missing */ 308 ParseFieldW (wTemp, 1, wTemp, MAX_PATH); 309 PathUnquoteSpacesW(wTemp); 310 311 if (!wcscmp(L"%1", wTemp)) /* icon is in the file */ 312 { 313 ILGetDisplayNameExW(psf, pidl, wTemp, ILGDN_FORPARSING); 314 icon_idx = 0; 315 316 INT ret = ExtractIconExW(wTemp, -1, NULL, NULL, 0); 317 if (ret <= 0) 318 { 319 StringCbCopyW(wTemp, sizeof(wTemp), swShell32Name); 320 icon_idx = -IDI_SHELL_EXE; 321 } 322 } 323 324 initIcon->SetNormalIcon(wTemp, icon_idx); 325 } 326 else 327 { 328 initIcon->SetNormalIcon(swShell32Name, 0); 329 } 330 331 if (hkey) 332 RegCloseKey(hkey); 333 } 334 335 return initIcon->QueryInterface(iid, ppvOut); 336 } 337 338 /* 339 CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is 340 returned by Next. When the enumerator is created, it can do numerous additional operations 341 including formatting a drive, reconnecting a network share drive, and requesting a disk 342 be inserted in a removable drive. 343 */ 344 345 /*********************************************************************** 346 * IShellFolder implementation 347 */ 348 349 class CFileSysEnum : 350 public CEnumIDListBase 351 { 352 private: 353 public: 354 CFileSysEnum(); 355 ~CFileSysEnum(); 356 HRESULT WINAPI Initialize(LPWSTR sPathTarget, DWORD dwFlags); 357 358 BEGIN_COM_MAP(CFileSysEnum) 359 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 360 END_COM_MAP() 361 }; 362 363 CFileSysEnum::CFileSysEnum() 364 { 365 } 366 367 CFileSysEnum::~CFileSysEnum() 368 { 369 } 370 371 HRESULT WINAPI CFileSysEnum::Initialize(LPWSTR lpszPath, DWORD dwFlags) 372 { 373 WIN32_FIND_DATAW stffile; 374 HANDLE hFile; 375 WCHAR szPath[MAX_PATH]; 376 BOOL succeeded = TRUE; 377 static const WCHAR stars[] = { '*','.','*',0 }; 378 static const WCHAR dot[] = { '.',0 }; 379 static const WCHAR dotdot[] = { '.','.',0 }; 380 381 TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath), dwFlags); 382 383 if(!lpszPath || !lpszPath[0]) return FALSE; 384 385 wcscpy(szPath, lpszPath); 386 PathAddBackslashW(szPath); 387 wcscat(szPath,stars); 388 389 hFile = FindFirstFileW(szPath,&stffile); 390 if ( hFile != INVALID_HANDLE_VALUE ) 391 { 392 BOOL findFinished = FALSE; 393 394 do 395 { 396 if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 397 || (dwFlags & SHCONTF_INCLUDEHIDDEN) ) 398 { 399 LPITEMIDLIST pidl = NULL; 400 401 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && 402 dwFlags & SHCONTF_FOLDERS && 403 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot)) 404 { 405 pidl = _ILCreateFromFindDataW(&stffile); 406 succeeded = succeeded && AddToEnumList(pidl); 407 } 408 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 409 && dwFlags & SHCONTF_NONFOLDERS) 410 { 411 pidl = _ILCreateFromFindDataW(&stffile); 412 succeeded = succeeded && AddToEnumList(pidl); 413 } 414 } 415 if (succeeded) 416 { 417 if (!FindNextFileW(hFile, &stffile)) 418 { 419 if (GetLastError() == ERROR_NO_MORE_FILES) 420 findFinished = TRUE; 421 else 422 succeeded = FALSE; 423 } 424 } 425 } while (succeeded && !findFinished); 426 FindClose(hFile); 427 } 428 429 return succeeded; 430 } 431 432 CFSFolder::CFSFolder() 433 { 434 pclsid = (CLSID *)&CLSID_ShellFSFolder; 435 sPathTarget = NULL; 436 pidlRoot = NULL; 437 m_bGroupPolicyActive = 0; 438 } 439 440 CFSFolder::~CFSFolder() 441 { 442 TRACE("-- destroying IShellFolder(%p)\n", this); 443 444 SHFree(pidlRoot); 445 SHFree(sPathTarget); 446 } 447 448 449 static const shvheader GenericSFHeader[] = { 450 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15}, 451 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 0}, 452 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10}, 453 {IDS_SHV_COLUMN_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, 454 {IDS_SHV_COLUMN_MODIFIED, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 12}, 455 {IDS_SHV_COLUMN_ATTRIBUTES, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10} 456 }; 457 458 #define GENERICSHELLVIEWCOLUMNS 6 459 460 /************************************************************************** 461 * SHELL32_CreatePidlFromBindCtx [internal] 462 * 463 * If the caller bound File System Bind Data, assume it is the 464 * find data for the path. 465 * This allows binding of paths that don't exist. 466 */ 467 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path) 468 { 469 IFileSystemBindData *fsbd = NULL; 470 LPITEMIDLIST pidl = NULL; 471 IUnknown *param = NULL; 472 WIN32_FIND_DATAW wfd; 473 HRESULT r; 474 475 TRACE("%p %s\n", pbc, debugstr_w(path)); 476 477 if (!pbc) 478 return NULL; 479 480 /* see if the caller bound File System Bind Data */ 481 r = pbc->GetObjectParam((LPOLESTR)STR_FILE_SYS_BIND_DATA, ¶m); 482 if (FAILED(r)) 483 return NULL; 484 485 r = param->QueryInterface(IID_PPV_ARG(IFileSystemBindData,&fsbd)); 486 if (SUCCEEDED(r)) 487 { 488 r = fsbd->GetFindData(&wfd); 489 if (SUCCEEDED(r)) 490 { 491 lstrcpynW(&wfd.cFileName[0], path, MAX_PATH); 492 pidl = _ILCreateFromFindDataW(&wfd); 493 } 494 fsbd->Release(); 495 } 496 497 return pidl; 498 } 499 500 static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID* pclsidFolder) 501 { 502 WCHAR wszCLSIDValue[CHARS_IN_GUID]; 503 WCHAR wszDesktopIni[MAX_PATH]; 504 StringCchCopyW(wszDesktopIni, MAX_PATH, pwszDir); 505 StringCchCatW(wszDesktopIni, MAX_PATH, L"\\desktop.ini"); 506 507 if (GetPrivateProfileStringW(L".ShellClassInfo", 508 KeyName, 509 L"", 510 wszCLSIDValue, 511 CHARS_IN_GUID, 512 wszDesktopIni)) 513 { 514 return CLSIDFromString(wszCLSIDValue, pclsidFolder); 515 } 516 return E_FAIL; 517 } 518 519 HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes) 520 { 521 DWORD dwFileAttributes, dwShellAttributes; 522 523 if (!_ILIsFolder(pidl) && !_ILIsValue(pidl)) 524 { 525 ERR("Got wrong type of pidl!\n"); 526 *pdwAttributes &= SFGAO_CANLINK; 527 return S_OK; 528 } 529 530 dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 531 532 /* Set common attributes */ 533 dwShellAttributes = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK | SFGAO_CANRENAME | SFGAO_CANDELETE | 534 SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSTEM; 535 536 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 537 dwShellAttributes |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STORAGE); 538 else 539 dwShellAttributes |= SFGAO_STREAM; 540 541 if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 542 dwShellAttributes |= SFGAO_HIDDEN; 543 544 if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) 545 dwShellAttributes |= SFGAO_READONLY; 546 547 if (SFGAO_LINK & *pdwAttributes) 548 { 549 char ext[MAX_PATH]; 550 551 if (_ILGetExtension(pidl, ext, MAX_PATH) && !lstrcmpiA(ext, "lnk")) 552 dwShellAttributes |= SFGAO_LINK; 553 } 554 555 if (SFGAO_HASSUBFOLDER & *pdwAttributes) 556 { 557 CComPtr<IShellFolder> psf2; 558 if (SUCCEEDED(psf->BindToObject(pidl, 0, IID_PPV_ARG(IShellFolder, &psf2)))) 559 { 560 CComPtr<IEnumIDList> pEnumIL; 561 if (SUCCEEDED(psf2->EnumObjects(0, SHCONTF_FOLDERS, &pEnumIL))) 562 { 563 if (pEnumIL->Skip(1) == S_OK) 564 dwShellAttributes |= SFGAO_HASSUBFOLDER; 565 } 566 } 567 } 568 569 *pdwAttributes = dwShellAttributes; 570 571 TRACE ("-- 0x%08x\n", *pdwAttributes); 572 return S_OK; 573 } 574 575 /************************************************************************** 576 * CFSFolder::ParseDisplayName {SHELL32} 577 * 578 * Parse a display name. 579 * 580 * PARAMS 581 * hwndOwner [in] Parent window for any message's 582 * pbc [in] optional FileSystemBindData context 583 * lpszDisplayName [in] Unicode displayname. 584 * pchEaten [out] (unicode) characters processed 585 * ppidl [out] complex pidl to item 586 * pdwAttributes [out] items attributes 587 * 588 * NOTES 589 * Every folder tries to parse only its own (the leftmost) pidl and creates a 590 * subfolder to evaluate the remaining parts. 591 * Now we can parse into namespaces implemented by shell extensions 592 * 593 * Behaviour on win98: lpszDisplayName=NULL -> crash 594 * lpszDisplayName="" -> returns mycoputer-pidl 595 * 596 * FIXME 597 * pdwAttributes is not set 598 * pchEaten is not set like in windows 599 */ 600 HRESULT WINAPI CFSFolder::ParseDisplayName(HWND hwndOwner, 601 LPBC pbc, 602 LPOLESTR lpszDisplayName, 603 DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, 604 DWORD *pdwAttributes) 605 { 606 HRESULT hr = E_INVALIDARG; 607 LPCWSTR szNext = NULL; 608 WCHAR szElement[MAX_PATH]; 609 WCHAR szPath[MAX_PATH]; 610 LPITEMIDLIST pidlTemp = NULL; 611 DWORD len; 612 613 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", 614 this, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName), 615 pchEaten, ppidl, pdwAttributes); 616 617 if (!ppidl) 618 return E_INVALIDARG; 619 620 if (!lpszDisplayName) 621 { 622 *ppidl = NULL; 623 return E_INVALIDARG; 624 } 625 626 *ppidl = NULL; 627 628 if (pchEaten) 629 *pchEaten = 0; /* strange but like the original */ 630 631 if (*lpszDisplayName) 632 { 633 /* get the next element */ 634 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH); 635 636 pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, szElement); 637 if (pidlTemp != NULL) 638 { 639 /* We are creating an id list without ensuring that the items exist. 640 If we have a remaining path, this must be a folder. 641 We have to do it now because it is set as a file by default */ 642 if (szNext) 643 { 644 pidlTemp->mkid.abID[0] = PT_FOLDER; 645 } 646 hr = S_OK; 647 } 648 else 649 { 650 /* build the full pathname to the element */ 651 lstrcpynW(szPath, sPathTarget, MAX_PATH - 1); 652 PathAddBackslashW(szPath); 653 len = wcslen(szPath); 654 lstrcpynW(szPath + len, szElement, MAX_PATH - len); 655 656 /* get the pidl */ 657 hr = _ILCreateFromPathW(szPath, &pidlTemp); 658 } 659 660 if (SUCCEEDED(hr)) 661 { 662 if (szNext && *szNext) 663 { 664 /* try to analyse the next element */ 665 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc, 666 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes); 667 } 668 else 669 { 670 /* it's the last element */ 671 if (pdwAttributes && *pdwAttributes) 672 hr = SHELL32_GetFSItemAttributes(this, pidlTemp, pdwAttributes); 673 } 674 } 675 } 676 677 if (SUCCEEDED(hr)) 678 *ppidl = pidlTemp; 679 else 680 *ppidl = NULL; 681 682 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl ? *ppidl : 0, hr); 683 684 return hr; 685 } 686 687 /************************************************************************** 688 * CFSFolder::EnumObjects 689 * PARAMETERS 690 * HWND hwndOwner, //[in ] Parent Window 691 * DWORD grfFlags, //[in ] SHCONTF enumeration mask 692 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface 693 */ 694 HRESULT WINAPI CFSFolder::EnumObjects( 695 HWND hwndOwner, 696 DWORD dwFlags, 697 LPENUMIDLIST *ppEnumIDList) 698 { 699 return ShellObjectCreatorInit<CFileSysEnum>(sPathTarget, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 700 } 701 702 /************************************************************************** 703 * CFSFolder::BindToObject 704 * PARAMETERS 705 * LPCITEMIDLIST pidl, //[in ] relative pidl to open 706 * LPBC pbc, //[in ] optional FileSystemBindData context 707 * REFIID riid, //[in ] Initial Interface 708 * LPVOID* ppvObject //[out] Interface* 709 */ 710 HRESULT WINAPI CFSFolder::BindToObject( 711 PCUIDLIST_RELATIVE pidl, 712 LPBC pbc, 713 REFIID riid, 714 LPVOID * ppvOut) 715 { 716 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbc, 717 shdebugstr_guid(&riid), ppvOut); 718 719 CComPtr<IShellFolder> pSF; 720 HRESULT hr; 721 722 if (!pidlRoot || !ppvOut || !pidl || !pidl->mkid.cb) 723 { 724 ERR("CFSFolder::BindToObject: Invalid parameters\n"); 725 return E_INVALIDARG; 726 } 727 728 /* Get the pidl data */ 729 FileStruct* pData = &_ILGetDataPointer(pidl)->u.file; 730 FileStructW* pDataW = _ILGetFileStructW(pidl); 731 732 if (!pDataW) 733 { 734 ERR("CFSFolder::BindToObject: Invalid pidl!\n"); 735 return E_INVALIDARG; 736 } 737 738 *ppvOut = NULL; 739 740 /* Create the target folder info */ 741 PERSIST_FOLDER_TARGET_INFO pfti = {0}; 742 pfti.dwAttributes = -1; 743 pfti.csidl = -1; 744 PathCombineW(pfti.szTargetParsingName, sPathTarget, pDataW->wszName); 745 746 /* Get the CLSID to bind to */ 747 CLSID clsidFolder; 748 if (_ILIsFolder(pidl)) 749 { 750 clsidFolder = CLSID_ShellFSFolder; 751 752 if ((pData->uFileAttribs & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0) 753 SHELL32_GetCLSIDForDirectory(pfti.szTargetParsingName, L"CLSID", &clsidFolder); 754 } 755 else 756 { 757 hr = GetCLSIDForFileType(pidl, L"CLSID", &clsidFolder); 758 if (hr == S_FALSE) 759 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 760 if (hr != S_OK) 761 return hr; 762 } 763 764 hr = SHELL32_BindToSF(pidlRoot, &pfti, pidl, &clsidFolder, riid, ppvOut); 765 if (FAILED_UNEXPECTEDLY(hr)) 766 return hr; 767 768 TRACE ("-- returning (%p) %08x\n", *ppvOut, hr); 769 770 return S_OK; 771 772 } 773 774 /************************************************************************** 775 * CFSFolder::BindToStorage 776 * PARAMETERS 777 * LPCITEMIDLIST pidl, //[in ] complex pidl to store 778 * LPBC pbc, //[in ] reserved 779 * REFIID riid, //[in ] Initial storage interface 780 * LPVOID* ppvObject //[out] Interface* returned 781 */ 782 HRESULT WINAPI CFSFolder::BindToStorage( 783 PCUIDLIST_RELATIVE pidl, 784 LPBC pbcReserved, 785 REFIID riid, 786 LPVOID *ppvOut) 787 { 788 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved, 789 shdebugstr_guid (&riid), ppvOut); 790 791 *ppvOut = NULL; 792 return E_NOTIMPL; 793 } 794 795 /************************************************************************** 796 * CFSFolder::CompareIDs 797 */ 798 799 HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam, 800 PCUIDLIST_RELATIVE pidl1, 801 PCUIDLIST_RELATIVE pidl2) 802 { 803 LPPIDLDATA pData1 = _ILGetDataPointer(pidl1); 804 LPPIDLDATA pData2 = _ILGetDataPointer(pidl2); 805 FileStructW* pDataW1 = _ILGetFileStructW(pidl1); 806 FileStructW* pDataW2 = _ILGetFileStructW(pidl2); 807 BOOL bIsFolder1 = _ILIsFolder(pidl1); 808 BOOL bIsFolder2 = _ILIsFolder(pidl2); 809 LPWSTR pExtension1, pExtension2; 810 811 if (!pDataW1 || !pDataW2 || LOWORD(lParam) >= GENERICSHELLVIEWCOLUMNS) 812 return E_INVALIDARG; 813 814 /* When sorting between a File and a Folder, the Folder gets sorted first */ 815 if (bIsFolder1 != bIsFolder2) 816 { 817 return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1); 818 } 819 820 int result; 821 switch (LOWORD(lParam)) 822 { 823 case 0: /* Name */ 824 result = wcsicmp(pDataW1->wszName, pDataW2->wszName); 825 break; 826 case 1: /* Comments */ 827 result = 0; 828 break; 829 case 2: /* Type */ 830 pExtension1 = PathFindExtensionW(pDataW1->wszName); 831 pExtension2 = PathFindExtensionW(pDataW2->wszName); 832 result = wcsicmp(pExtension1, pExtension2); 833 break; 834 case 3: /* Size */ 835 result = pData1->u.file.dwFileSize - pData2->u.file.dwFileSize; 836 break; 837 case 4: /* Modified */ 838 result = pData1->u.file.uFileDate - pData2->u.file.uFileDate; 839 if (result == 0) 840 result = pData1->u.file.uFileTime - pData2->u.file.uFileTime; 841 break; 842 case 5: /* Attributes */ 843 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2); 844 } 845 846 if (result == 0) 847 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2); 848 849 return MAKE_COMPARE_HRESULT(result); 850 } 851 852 /************************************************************************** 853 * CFSFolder::CreateViewObject 854 */ 855 HRESULT WINAPI CFSFolder::CreateViewObject(HWND hwndOwner, 856 REFIID riid, LPVOID * ppvOut) 857 { 858 CComPtr<IShellView> pShellView; 859 HRESULT hr = E_INVALIDARG; 860 861 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid (&riid), 862 ppvOut); 863 864 if (ppvOut) 865 { 866 *ppvOut = NULL; 867 868 BOOL bIsDropTarget = IsEqualIID (riid, IID_IDropTarget); 869 BOOL bIsShellView = !bIsDropTarget && IsEqualIID (riid, IID_IShellView); 870 871 if (bIsDropTarget || bIsShellView) 872 { 873 DWORD dwDirAttributes = _ILGetFileAttributes(ILFindLastID(pidlRoot), NULL, 0); 874 875 if ((dwDirAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0) 876 { 877 CLSID clsidFolder; 878 hr = SHELL32_GetCLSIDForDirectory(sPathTarget, L"UICLSID", &clsidFolder); 879 if (SUCCEEDED(hr)) 880 { 881 CComPtr<IPersistFolder> spFolder; 882 hr = SHCoCreateInstance(NULL, &clsidFolder, NULL, IID_PPV_ARG(IPersistFolder, &spFolder)); 883 if (!FAILED_UNEXPECTEDLY(hr)) 884 { 885 hr = spFolder->Initialize(pidlRoot); 886 887 if (!FAILED_UNEXPECTEDLY(hr)) 888 { 889 hr = spFolder->QueryInterface(riid, ppvOut); 890 } 891 } 892 } 893 else 894 { 895 // No desktop.ini, or no UICLSID present, continue as if nothing happened 896 hr = E_INVALIDARG; 897 } 898 } 899 } 900 901 if (!SUCCEEDED(hr)) 902 { 903 // No UICLSID handler found, continue to the default handlers 904 if (bIsDropTarget) 905 { 906 hr = CFSDropTarget_CreateInstance(sPathTarget, riid, ppvOut); 907 } 908 else if (IsEqualIID (riid, IID_IContextMenu)) 909 { 910 HKEY hKeys[16]; 911 UINT cKeys = 0; 912 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys); 913 914 DEFCONTEXTMENU dcm; 915 dcm.hwnd = hwndOwner; 916 dcm.pcmcb = this; 917 dcm.pidlFolder = pidlRoot; 918 dcm.psf = this; 919 dcm.cidl = 0; 920 dcm.apidl = NULL; 921 dcm.cKeys = cKeys; 922 dcm.aKeys = hKeys; 923 dcm.punkAssociationInfo = NULL; 924 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut); 925 } 926 else if (bIsShellView) 927 { 928 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this, NULL, this}; 929 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 930 } 931 else 932 { 933 hr = E_INVALIDARG; 934 } 935 } 936 } 937 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut); 938 return hr; 939 } 940 941 /************************************************************************** 942 * CFSFolder::GetAttributesOf 943 * 944 * PARAMETERS 945 * UINT cidl, //[in ] num elements in pidl array 946 * LPCITEMIDLIST* apidl, //[in ] simple pidl array 947 * ULONG* rgfInOut) //[out] result array 948 * 949 */ 950 HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl, 951 PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut) 952 { 953 HRESULT hr = S_OK; 954 955 if (!rgfInOut) 956 return E_INVALIDARG; 957 if (cidl && !apidl) 958 return E_INVALIDARG; 959 960 if (*rgfInOut == 0) 961 *rgfInOut = ~0; 962 963 if(cidl == 0) 964 { 965 LPCITEMIDLIST rpidl = ILFindLastID(pidlRoot); 966 967 if (_ILIsFolder(rpidl) || _ILIsValue(rpidl)) 968 { 969 SHELL32_GetFSItemAttributes(this, rpidl, rgfInOut); 970 } 971 else if (_ILIsDrive(rpidl)) 972 { 973 IShellFolder *psfParent = NULL; 974 hr = SHBindToParent(pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), NULL); 975 if(SUCCEEDED(hr)) 976 { 977 hr = psfParent->GetAttributesOf(1, &rpidl, (SFGAOF*)rgfInOut); 978 psfParent->Release(); 979 } 980 } 981 else 982 { 983 ERR("Got and unknown pidl!\n"); 984 } 985 } 986 else 987 { 988 while (cidl > 0 && *apidl) 989 { 990 pdump(*apidl); 991 if(_ILIsFolder(*apidl) || _ILIsValue(*apidl)) 992 SHELL32_GetFSItemAttributes(this, *apidl, rgfInOut); 993 else 994 ERR("Got an unknown type of pidl!!!\n"); 995 apidl++; 996 cidl--; 997 } 998 } 999 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 1000 *rgfInOut &= ~SFGAO_VALIDATE; 1001 1002 TRACE("-- result=0x%08x\n", *rgfInOut); 1003 1004 return hr; 1005 } 1006 1007 /************************************************************************** 1008 * CFSFolder::GetUIObjectOf 1009 * 1010 * PARAMETERS 1011 * HWND hwndOwner, //[in ] Parent window for any output 1012 * UINT cidl, //[in ] array size 1013 * LPCITEMIDLIST* apidl, //[in ] simple pidl array 1014 * REFIID riid, //[in ] Requested Interface 1015 * UINT* prgfInOut, //[ ] reserved 1016 * LPVOID* ppvObject) //[out] Resulting Interface 1017 * 1018 * NOTES 1019 * This function gets asked to return "view objects" for one or more (multiple 1020 * select) items: 1021 * The viewobject typically is an COM object with one of the following 1022 * interfaces: 1023 * IExtractIcon,IDataObject,IContextMenu 1024 * In order to support icon positions in the default Listview your DataObject 1025 * must implement the SetData method (in addition to GetData :) - the shell 1026 * passes a barely documented "Icon positions" structure to SetData when the 1027 * drag starts, and GetData's it if the drop is in another explorer window that 1028 * needs the positions. 1029 */ 1030 HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner, 1031 UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 1032 REFIID riid, UINT * prgfInOut, 1033 LPVOID * ppvOut) 1034 { 1035 LPVOID pObj = NULL; 1036 HRESULT hr = E_INVALIDARG; 1037 1038 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", 1039 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut); 1040 1041 if (ppvOut) 1042 { 1043 *ppvOut = NULL; 1044 1045 if (cidl == 1 && _ILIsValue(apidl[0])) 1046 { 1047 hr = _CreateExtensionUIObject(apidl[0], riid, ppvOut); 1048 if(hr != S_FALSE) 1049 return hr; 1050 } 1051 1052 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1)) 1053 { 1054 HKEY hKeys[16]; 1055 UINT cKeys = 0; 1056 AddFSClassKeysToArray(apidl[0], hKeys, &cKeys); 1057 1058 DEFCONTEXTMENU dcm; 1059 dcm.hwnd = hwndOwner; 1060 dcm.pcmcb = this; 1061 dcm.pidlFolder = pidlRoot; 1062 dcm.psf = this; 1063 dcm.cidl = cidl; 1064 dcm.apidl = apidl; 1065 dcm.cKeys = cKeys; 1066 dcm.aKeys = hKeys; 1067 dcm.punkAssociationInfo = NULL; 1068 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj); 1069 } 1070 else if (IsEqualIID (riid, IID_IDataObject)) 1071 { 1072 if (cidl >= 1) 1073 { 1074 hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 1075 } 1076 else 1077 { 1078 hr = E_INVALIDARG; 1079 } 1080 } 1081 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 1082 { 1083 if (_ILIsValue(apidl[0])) 1084 hr = _GetIconHandler(apidl[0], riid, (LPVOID*)&pObj); 1085 if (hr != S_OK) 1086 hr = CFSExtractIcon_CreateInstance(this, apidl[0], riid, &pObj); 1087 } 1088 else if (IsEqualIID (riid, IID_IDropTarget)) 1089 { 1090 /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */ 1091 if (cidl != 1 || FAILED(hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj))) 1092 { 1093 hr = CFSDropTarget_CreateInstance(sPathTarget, riid, (LPVOID*) &pObj); 1094 } 1095 } 1096 else 1097 hr = E_NOINTERFACE; 1098 1099 if (SUCCEEDED(hr) && !pObj) 1100 hr = E_OUTOFMEMORY; 1101 1102 *ppvOut = pObj; 1103 } 1104 TRACE("(%p)->hr=0x%08x\n", this, hr); 1105 return hr; 1106 } 1107 1108 static const WCHAR AdvancedW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"; 1109 static const WCHAR HideFileExtW[] = L"HideFileExt"; 1110 static const WCHAR NeverShowExtW[] = L"NeverShowExt"; 1111 1112 /****************************************************************************** 1113 * SHELL_FS_HideExtension [Internal] 1114 * 1115 * Query the registry if the filename extension of a given path should be 1116 * hidden. 1117 * 1118 * PARAMS 1119 * szPath [I] Relative or absolute path of a file 1120 * 1121 * RETURNS 1122 * TRUE, if the filename's extension should be hidden 1123 * FALSE, otherwise. 1124 */ 1125 BOOL SHELL_FS_HideExtension(LPWSTR szPath) 1126 { 1127 HKEY hKey; 1128 DWORD dwData; 1129 DWORD dwDataSize = sizeof (DWORD); 1130 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */ 1131 1132 if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) { 1133 if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize)) 1134 doHide = dwData; 1135 RegCloseKey (hKey); 1136 } 1137 1138 if (!doHide) { 1139 LPWSTR ext = PathFindExtensionW(szPath); 1140 1141 if (*ext != '\0') { 1142 WCHAR classname[MAX_PATH]; 1143 LONG classlen = sizeof(classname); 1144 1145 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen)) 1146 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) { 1147 if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL)) 1148 doHide = TRUE; 1149 RegCloseKey(hKey); 1150 } 1151 } 1152 } 1153 return doHide; 1154 } 1155 1156 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags) 1157 { 1158 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */ 1159 if (!(dwFlags & SHGDN_FORPARSING) && 1160 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) { 1161 if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.') 1162 PathRemoveExtensionW(szPath); 1163 } 1164 } 1165 1166 /************************************************************************** 1167 * CFSFolder::GetDisplayNameOf 1168 * Retrieves the display name for the specified file object or subfolder 1169 * 1170 * PARAMETERS 1171 * LPCITEMIDLIST pidl, //[in ] complex pidl to item 1172 * DWORD dwFlags, //[in ] SHGNO formatting flags 1173 * LPSTRRET lpName) //[out] Returned display name 1174 * 1175 * FIXME 1176 * if the name is in the pidl the ret value should be a STRRET_OFFSET 1177 */ 1178 1179 HRESULT WINAPI CFSFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, 1180 DWORD dwFlags, LPSTRRET strRet) 1181 { 1182 if (!strRet) 1183 return E_INVALIDARG; 1184 1185 /* If it is a complex pidl, let the child handle it */ 1186 if (!_ILIsPidlSimple (pidl)) /* complex pidl */ 1187 { 1188 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet); 1189 } 1190 else if (pidl && !pidl->mkid.cb) /* empty pidl */ 1191 { 1192 /* If it is an empty pidl return only the path of the folder */ 1193 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && 1194 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && 1195 sPathTarget) 1196 { 1197 return SHSetStrRet(strRet, sPathTarget); 1198 } 1199 return E_INVALIDARG; 1200 } 1201 1202 int len = 0; 1203 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); 1204 if (!pszPath) 1205 return E_OUTOFMEMORY; 1206 1207 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && 1208 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && 1209 sPathTarget) 1210 { 1211 lstrcpynW(pszPath, sPathTarget, MAX_PATH); 1212 PathAddBackslashW(pszPath); 1213 len = wcslen(pszPath); 1214 } 1215 _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len); 1216 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags); 1217 1218 strRet->uType = STRRET_WSTR; 1219 strRet->pOleStr = pszPath; 1220 1221 TRACE ("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr)); 1222 return S_OK; 1223 } 1224 1225 /************************************************************************** 1226 * CFSFolder::SetNameOf 1227 * Changes the name of a file object or subfolder, possibly changing its item 1228 * identifier in the process. 1229 * 1230 * PARAMETERS 1231 * HWND hwndOwner, //[in ] Owner window for output 1232 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change 1233 * LPCOLESTR lpszName, //[in ] the items new display name 1234 * DWORD dwFlags, //[in ] SHGNO formatting flags 1235 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned 1236 */ 1237 HRESULT WINAPI CFSFolder::SetNameOf( 1238 HWND hwndOwner, 1239 PCUITEMID_CHILD pidl, 1240 LPCOLESTR lpName, 1241 DWORD dwFlags, 1242 PITEMID_CHILD *pPidlOut) 1243 { 1244 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1]; 1245 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl)); 1246 1247 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, 1248 debugstr_w (lpName), dwFlags, pPidlOut); 1249 1250 FileStructW* pDataW = _ILGetFileStructW(pidl); 1251 if (!pDataW) 1252 { 1253 ERR("Got garbage pidl\n"); 1254 return E_INVALIDARG; 1255 } 1256 1257 /* build source path */ 1258 PathCombineW(szSrc, sPathTarget, pDataW->wszName); 1259 1260 /* build destination path */ 1261 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) 1262 PathCombineW(szDest, sPathTarget, lpName); 1263 else 1264 lstrcpynW(szDest, lpName, MAX_PATH); 1265 1266 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) { 1267 WCHAR *ext = PathFindExtensionW(szSrc); 1268 if(*ext != '\0') { 1269 INT len = wcslen(szDest); 1270 lstrcpynW(szDest + len, ext, MAX_PATH - len); 1271 } 1272 } 1273 1274 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest)); 1275 if (!wcscmp(szSrc, szDest)) 1276 { 1277 /* src and destination is the same */ 1278 HRESULT hr = S_OK; 1279 if (pPidlOut) 1280 hr = _ILCreateFromPathW(szDest, pPidlOut); 1281 1282 return hr; 1283 } 1284 1285 if (MoveFileW (szSrc, szDest)) 1286 { 1287 HRESULT hr = S_OK; 1288 1289 if (pPidlOut) 1290 hr = _ILCreateFromPathW(szDest, pPidlOut); 1291 1292 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM, 1293 SHCNF_PATHW, szSrc, szDest); 1294 1295 return hr; 1296 } 1297 1298 return E_FAIL; 1299 } 1300 1301 HRESULT WINAPI CFSFolder::GetDefaultSearchGUID(GUID * pguid) 1302 { 1303 FIXME ("(%p)\n", this); 1304 return E_NOTIMPL; 1305 } 1306 1307 HRESULT WINAPI CFSFolder::EnumSearches(IEnumExtraSearch ** ppenum) 1308 { 1309 FIXME ("(%p)\n", this); 1310 return E_NOTIMPL; 1311 } 1312 1313 HRESULT WINAPI CFSFolder::GetDefaultColumn(DWORD dwRes, 1314 ULONG * pSort, ULONG * pDisplay) 1315 { 1316 TRACE ("(%p)\n", this); 1317 1318 if (pSort) 1319 *pSort = 0; 1320 if (pDisplay) 1321 *pDisplay = 0; 1322 1323 return S_OK; 1324 } 1325 1326 HRESULT WINAPI CFSFolder::GetDefaultColumnState(UINT iColumn, 1327 DWORD * pcsFlags) 1328 { 1329 TRACE ("(%p)\n", this); 1330 1331 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS) 1332 return E_INVALIDARG; 1333 1334 *pcsFlags = GenericSFHeader[iColumn].pcsFlags; 1335 1336 return S_OK; 1337 } 1338 1339 HRESULT WINAPI CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl, 1340 const SHCOLUMNID * pscid, VARIANT * pv) 1341 { 1342 FIXME ("(%p)\n", this); 1343 1344 return E_NOTIMPL; 1345 } 1346 1347 HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl, 1348 UINT iColumn, SHELLDETAILS * psd) 1349 { 1350 HRESULT hr = E_FAIL; 1351 1352 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd); 1353 1354 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS) 1355 return E_INVALIDARG; 1356 1357 if (!pidl) 1358 { 1359 /* the header titles */ 1360 psd->fmt = GenericSFHeader[iColumn].fmt; 1361 psd->cxChar = GenericSFHeader[iColumn].cxChar; 1362 return SHSetStrRet(&psd->str, GenericSFHeader[iColumn].colnameid); 1363 } 1364 else 1365 { 1366 hr = S_OK; 1367 psd->str.uType = STRRET_CSTR; 1368 /* the data from the pidl */ 1369 switch (iColumn) 1370 { 1371 case 0: /* name */ 1372 hr = GetDisplayNameOf (pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); 1373 break; 1374 case 1: /* FIXME: comments */ 1375 psd->str.cStr[0] = 0; 1376 break; 1377 case 2: /* type */ 1378 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH); 1379 break; 1380 case 3: /* size */ 1381 _ILGetFileSize(pidl, psd->str.cStr, MAX_PATH); 1382 break; 1383 case 4: /* date */ 1384 _ILGetFileDate(pidl, psd->str.cStr, MAX_PATH); 1385 break; 1386 case 5: /* attributes */ 1387 _ILGetFileAttributes(pidl, psd->str.cStr, MAX_PATH); 1388 break; 1389 } 1390 } 1391 1392 return hr; 1393 } 1394 1395 HRESULT WINAPI CFSFolder::MapColumnToSCID (UINT column, 1396 SHCOLUMNID * pscid) 1397 { 1398 FIXME ("(%p)\n", this); 1399 return E_NOTIMPL; 1400 } 1401 1402 /************************************************************************ 1403 * CFSFolder::GetClassID 1404 */ 1405 HRESULT WINAPI CFSFolder::GetClassID(CLSID * lpClassId) 1406 { 1407 TRACE ("(%p)\n", this); 1408 1409 if (!lpClassId) 1410 return E_POINTER; 1411 1412 *lpClassId = *pclsid; 1413 1414 return S_OK; 1415 } 1416 1417 /************************************************************************ 1418 * CFSFolder::Initialize 1419 * 1420 * NOTES 1421 * sPathTarget is not set. Don't know how to handle in a non rooted environment. 1422 */ 1423 HRESULT WINAPI CFSFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 1424 { 1425 WCHAR wszTemp[MAX_PATH]; 1426 1427 TRACE ("(%p)->(%p)\n", this, pidl); 1428 1429 SHFree (pidlRoot); /* free the old pidl */ 1430 pidlRoot = ILClone (pidl); /* set my pidl */ 1431 1432 SHFree (sPathTarget); 1433 sPathTarget = NULL; 1434 1435 /* set my path */ 1436 if (SHGetPathFromIDListW (pidl, wszTemp)) 1437 { 1438 int len = wcslen(wszTemp); 1439 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); 1440 if (!sPathTarget) 1441 return E_OUTOFMEMORY; 1442 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); 1443 } 1444 1445 TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget)); 1446 return S_OK; 1447 } 1448 1449 /************************************************************************** 1450 * CFSFolder::GetCurFolder 1451 */ 1452 HRESULT WINAPI CFSFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 1453 { 1454 TRACE ("(%p)->(%p)\n", this, pidl); 1455 1456 if (!pidl) 1457 return E_POINTER; 1458 1459 *pidl = ILClone(pidlRoot); 1460 return S_OK; 1461 } 1462 1463 /************************************************************************** 1464 * CFSFolder::InitializeEx 1465 * 1466 * FIXME: error handling 1467 */ 1468 HRESULT WINAPI CFSFolder::InitializeEx(IBindCtx * pbc, LPCITEMIDLIST pidlRootx, 1469 const PERSIST_FOLDER_TARGET_INFO * ppfti) 1470 { 1471 WCHAR wszTemp[MAX_PATH]; 1472 1473 TRACE("(%p)->(%p,%p,%p)\n", this, pbc, pidlRootx, ppfti); 1474 if (ppfti) 1475 TRACE("--%p %s %s 0x%08x 0x%08x\n", 1476 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName), 1477 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes, 1478 ppfti->csidl); 1479 1480 pdump (pidlRootx); 1481 if (ppfti && ppfti->pidlTargetFolder) 1482 pdump(ppfti->pidlTargetFolder); 1483 1484 if (pidlRoot) 1485 __SHFreeAndNil(&pidlRoot); /* free the old */ 1486 if (sPathTarget) 1487 __SHFreeAndNil(&sPathTarget); 1488 1489 /* 1490 * Root path and pidl 1491 */ 1492 pidlRoot = ILClone(pidlRootx); 1493 1494 /* 1495 * the target folder is spezified in csidl OR pidlTargetFolder OR 1496 * szTargetParsingName 1497 */ 1498 if (ppfti) 1499 { 1500 if (ppfti->csidl != -1) 1501 { 1502 if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl, 1503 ppfti->csidl & CSIDL_FLAG_CREATE)) { 1504 int len = wcslen(wszTemp); 1505 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); 1506 if (!sPathTarget) 1507 return E_OUTOFMEMORY; 1508 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); 1509 } 1510 } 1511 else if (ppfti->szTargetParsingName[0]) 1512 { 1513 int len = wcslen(ppfti->szTargetParsingName); 1514 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); 1515 if (!sPathTarget) 1516 return E_OUTOFMEMORY; 1517 memcpy(sPathTarget, ppfti->szTargetParsingName, 1518 (len + 1) * sizeof(WCHAR)); 1519 } 1520 else if (ppfti->pidlTargetFolder) 1521 { 1522 if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) 1523 { 1524 int len = wcslen(wszTemp); 1525 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); 1526 if (!sPathTarget) 1527 return E_OUTOFMEMORY; 1528 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); 1529 } 1530 } 1531 } 1532 1533 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget)); 1534 pdump(pidlRoot); 1535 return (sPathTarget) ? S_OK : E_FAIL; 1536 } 1537 1538 HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti) 1539 { 1540 FIXME("(%p)->(%p)\n", this, ppfti); 1541 ZeroMemory(ppfti, sizeof (*ppfti)); 1542 return E_NOTIMPL; 1543 } 1544 1545 HRESULT CFSFolder::_CreateExtensionUIObject(PCUIDLIST_RELATIVE pidl, REFIID riid, LPVOID *ppvOut) 1546 { 1547 static const WCHAR formatW[] = {'S','h','e','l','l','E','x','\\', 1548 '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-', 1549 '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x', 1550 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0}; 1551 WCHAR buf[MAX_PATH]; 1552 1553 sprintfW(buf, formatW, riid.Data1, riid.Data2, riid.Data3, 1554 riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3], 1555 riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]); 1556 1557 CLSID clsid; 1558 HRESULT hr; 1559 1560 hr = GetCLSIDForFileType(pidl, buf, &clsid); 1561 if (hr != S_OK) 1562 return hr; 1563 1564 hr = _CreateShellExtInstance(&clsid, pidl, riid, ppvOut); 1565 if (FAILED_UNEXPECTEDLY(hr)) 1566 return hr; 1567 1568 return S_OK; 1569 } 1570 1571 HRESULT CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) 1572 { 1573 HRESULT hr; 1574 1575 TRACE("CFSFolder::_GetDropTarget entered\n"); 1576 1577 if (_ILIsFolder (pidl)) 1578 { 1579 CComPtr<IShellFolder> psfChild; 1580 hr = this->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 1581 if (FAILED_UNEXPECTEDLY(hr)) 1582 return hr; 1583 1584 return psfChild->CreateViewObject(NULL, IID_IDropTarget, ppvOut); 1585 } 1586 1587 CLSID clsid; 1588 hr = GetCLSIDForFileType(pidl, L"shellex\\DropHandler", &clsid); 1589 if (hr != S_OK) 1590 return hr; 1591 1592 hr = _CreateShellExtInstance(&clsid, pidl, IID_IDropTarget, ppvOut); 1593 if (FAILED_UNEXPECTEDLY(hr)) 1594 return S_FALSE; 1595 1596 return S_OK; 1597 } 1598 1599 HRESULT CFSFolder::_GetIconHandler(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut) 1600 { 1601 CLSID clsid; 1602 HRESULT hr; 1603 1604 hr = GetCLSIDForFileType(pidl, L"shellex\\IconHandler", &clsid); 1605 if (hr != S_OK) 1606 return hr; 1607 1608 hr = _CreateShellExtInstance(&clsid, pidl, riid, ppvOut); 1609 if (FAILED_UNEXPECTEDLY(hr)) 1610 return S_FALSE; 1611 1612 return S_OK; 1613 } 1614 1615 HRESULT CFSFolder::_CreateShellExtInstance(const CLSID *pclsid, LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut) 1616 { 1617 HRESULT hr; 1618 WCHAR wszPath[MAX_PATH]; 1619 1620 FileStructW* pDataW = _ILGetFileStructW(pidl); 1621 if (!pDataW) 1622 { 1623 ERR("Got garbage pidl\n"); 1624 return E_INVALIDARG; 1625 } 1626 1627 PathCombineW(wszPath, sPathTarget, pDataW->wszName); 1628 1629 CComPtr<IPersistFile> pp; 1630 hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IPersistFile, &pp)); 1631 if (FAILED_UNEXPECTEDLY(hr)) 1632 return hr; 1633 1634 pp->Load(wszPath, 0); 1635 1636 hr = pp->QueryInterface(riid, ppvOut); 1637 if (hr != S_OK) 1638 { 1639 ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid)); 1640 return hr; 1641 } 1642 return hr; 1643 } 1644 1645 HRESULT WINAPI CFSFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) 1646 { 1647 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND) 1648 return S_OK; 1649 1650 /* no data object means no selection */ 1651 if (!pdtobj) 1652 { 1653 if (uMsg == DFM_INVOKECOMMAND && wParam == 0) 1654 { 1655 PUITEMID_CHILD pidlChild = ILClone(ILFindLastID(pidlRoot)); 1656 LPITEMIDLIST pidlParent = ILClone(pidlRoot); 1657 ILRemoveLastID(pidlParent); 1658 HRESULT hr = SH_ShowPropertiesDialog(sPathTarget, pidlParent, &pidlChild); 1659 if (FAILED(hr)) 1660 ERR("SH_ShowPropertiesDialog failed\n"); 1661 ILFree(pidlChild); 1662 ILFree(pidlParent); 1663 } 1664 else if (uMsg == DFM_MERGECONTEXTMENU) 1665 { 1666 QCMINFO *pqcminfo = (QCMINFO *)lParam; 1667 HMENU hpopup = CreatePopupMenu(); 1668 _InsertMenuItemW(hpopup, 0, TRUE, 0, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); 1669 Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu++, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR); 1670 DestroyMenu(hpopup); 1671 } 1672 1673 return S_OK; 1674 } 1675 1676 if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES) 1677 return S_OK; 1678 1679 return Shell_DefaultContextMenuCallBack(this, pdtobj); 1680 } 1681 1682 static HBITMAP DoLoadPicture(LPCWSTR pszFileName) 1683 { 1684 // create stream from file 1685 HRESULT hr; 1686 CComPtr<IStream> pStream; 1687 hr = SHCreateStreamOnFileEx(pszFileName, STGM_READ, FILE_ATTRIBUTE_NORMAL, 1688 FALSE, NULL, &pStream); 1689 if (FAILED(hr)) 1690 return NULL; 1691 1692 // load the picture 1693 HBITMAP hbm = NULL; 1694 CComPtr<IPicture> pPicture; 1695 OleLoadPicture(pStream, 0, FALSE, IID_IPicture, (LPVOID *)&pPicture); 1696 1697 // get the bitmap handle 1698 if (pPicture) 1699 { 1700 pPicture->get_Handle((OLE_HANDLE *)&hbm); 1701 1702 // copy the bitmap handle 1703 hbm = (HBITMAP)CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); 1704 } 1705 1706 return hbm; 1707 } 1708 1709 HRESULT WINAPI CFSFolder::GetCustomViewInfo(ULONG unknown, SFVM_CUSTOMVIEWINFO_DATA *data) 1710 { 1711 if (data == NULL) 1712 { 1713 return E_POINTER; 1714 } 1715 if (data->cbSize != sizeof(*data)) 1716 { 1717 // NOTE: You have to set the cbData member before SFVM_GET_CUSTOMVIEWINFO call. 1718 return E_INVALIDARG; 1719 } 1720 1721 data->hbmBack = NULL; 1722 data->clrText = CLR_INVALID; 1723 data->clrTextBack = CLR_INVALID; 1724 1725 WCHAR szPath[MAX_PATH], szIniFile[MAX_PATH]; 1726 1727 // does the folder exists? 1728 if (!SHGetPathFromIDListW(pidlRoot, szPath) || !PathIsDirectoryW(szPath)) 1729 { 1730 return E_INVALIDARG; 1731 } 1732 1733 // don't use custom view in network path for security 1734 if (PathIsNetworkPath(szPath)) 1735 { 1736 return E_ACCESSDENIED; 1737 } 1738 1739 // build the ini file path 1740 StringCchCopyW(szIniFile, _countof(szIniFile), szPath); 1741 PathAppend(szIniFile, L"desktop.ini"); 1742 1743 static LPCWSTR TheGUID = L"{BE098140-A513-11D0-A3A4-00C04FD706EC}"; 1744 static LPCWSTR Space = L" \t\n\r\f\v"; 1745 1746 // get info from ini file 1747 WCHAR szImage[MAX_PATH], szText[64]; 1748 1749 // load the image 1750 szImage[0] = UNICODE_NULL; 1751 GetPrivateProfileStringW(TheGUID, L"IconArea_Image", L"", szImage, _countof(szImage), szIniFile); 1752 if (szImage[0]) 1753 { 1754 StrTrimW(szImage, Space); 1755 if (PathIsRelativeW(szImage)) 1756 { 1757 PathAppendW(szPath, szImage); 1758 StringCchCopyW(szImage, _countof(szImage), szPath); 1759 } 1760 data->hbmBack = DoLoadPicture(szImage); 1761 } 1762 1763 // load the text color 1764 szText[0] = UNICODE_NULL; 1765 GetPrivateProfileStringW(TheGUID, L"IconArea_Text", L"", szText, _countof(szText), szIniFile); 1766 if (szText[0]) 1767 { 1768 StrTrimW(szText, Space); 1769 1770 LPWSTR pchEnd = NULL; 1771 COLORREF cr = (wcstol(szText, &pchEnd, 0) & 0xFFFFFF); 1772 1773 if (pchEnd && !*pchEnd) 1774 data->clrText = cr; 1775 } 1776 1777 // load the text background color 1778 szText[0] = UNICODE_NULL; 1779 GetPrivateProfileStringW(TheGUID, L"IconArea_TextBackground", L"", szText, _countof(szText), szIniFile); 1780 if (szText[0]) 1781 { 1782 StrTrimW(szText, Space); 1783 1784 LPWSTR pchEnd = NULL; 1785 COLORREF cr = (wcstol(szText, &pchEnd, 0) & 0xFFFFFF); 1786 1787 if (pchEnd && !*pchEnd) 1788 data->clrTextBack = cr; 1789 } 1790 1791 if (data->hbmBack != NULL || data->clrText != CLR_INVALID || data->clrTextBack != CLR_INVALID) 1792 return S_OK; 1793 1794 return E_FAIL; 1795 } 1796 1797 HRESULT WINAPI CFSFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) 1798 { 1799 HRESULT hr = E_NOTIMPL; 1800 switch (uMsg) 1801 { 1802 case SFVM_GET_CUSTOMVIEWINFO: 1803 hr = GetCustomViewInfo((ULONG)wParam, (SFVM_CUSTOMVIEWINFO_DATA *)lParam); 1804 break; 1805 } 1806 return hr; 1807 } 1808