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