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 #define HIDDEN FILE_ATTRIBUTE_HIDDEN 395 #define SUPER_HIDDEN (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM) 396 397 do 398 { 399 if ((stffile.dwFileAttributes & HIDDEN) == 0 || 400 ((dwFlags & SHCONTF_INCLUDEHIDDEN) && 401 (stffile.dwFileAttributes & SUPER_HIDDEN) == HIDDEN) || 402 ((dwFlags & SHCONTF_INCLUDESUPERHIDDEN) && 403 (stffile.dwFileAttributes & SUPER_HIDDEN) == SUPER_HIDDEN)) 404 { 405 LPITEMIDLIST pidl = NULL; 406 407 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && 408 dwFlags & SHCONTF_FOLDERS && 409 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot)) 410 { 411 pidl = _ILCreateFromFindDataW(&stffile); 412 succeeded = succeeded && AddToEnumList(pidl); 413 } 414 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 415 && dwFlags & SHCONTF_NONFOLDERS) 416 { 417 pidl = _ILCreateFromFindDataW(&stffile); 418 succeeded = succeeded && AddToEnumList(pidl); 419 } 420 } 421 if (succeeded) 422 { 423 if (!FindNextFileW(hFile, &stffile)) 424 { 425 if (GetLastError() == ERROR_NO_MORE_FILES) 426 findFinished = TRUE; 427 else 428 succeeded = FALSE; 429 } 430 } 431 } while (succeeded && !findFinished); 432 FindClose(hFile); 433 } 434 435 return succeeded; 436 } 437 438 CFSFolder::CFSFolder() 439 { 440 m_pclsid = &CLSID_ShellFSFolder; 441 m_sPathTarget = NULL; 442 m_pidlRoot = NULL; 443 m_bGroupPolicyActive = 0; 444 } 445 446 CFSFolder::~CFSFolder() 447 { 448 TRACE("-- destroying IShellFolder(%p)\n", this); 449 450 SHFree(m_pidlRoot); 451 SHFree(m_sPathTarget); 452 } 453 454 455 static const shvheader GenericSFHeader[] = { 456 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15}, 457 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 0}, 458 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10}, 459 {IDS_SHV_COLUMN_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, 460 {IDS_SHV_COLUMN_MODIFIED, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 12}, 461 {IDS_SHV_COLUMN_ATTRIBUTES, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10} 462 }; 463 464 #define GENERICSHELLVIEWCOLUMNS 6 465 466 /************************************************************************** 467 * SHELL32_CreatePidlFromBindCtx [internal] 468 * 469 * If the caller bound File System Bind Data, assume it is the 470 * find data for the path. 471 * This allows binding of paths that don't exist. 472 */ 473 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path) 474 { 475 IFileSystemBindData *fsbd = NULL; 476 LPITEMIDLIST pidl = NULL; 477 IUnknown *param = NULL; 478 WIN32_FIND_DATAW wfd; 479 HRESULT r; 480 481 TRACE("%p %s\n", pbc, debugstr_w(path)); 482 483 if (!pbc) 484 return NULL; 485 486 /* see if the caller bound File System Bind Data */ 487 r = pbc->GetObjectParam((LPOLESTR)STR_FILE_SYS_BIND_DATA, ¶m); 488 if (FAILED(r)) 489 return NULL; 490 491 r = param->QueryInterface(IID_PPV_ARG(IFileSystemBindData,&fsbd)); 492 if (SUCCEEDED(r)) 493 { 494 r = fsbd->GetFindData(&wfd); 495 if (SUCCEEDED(r)) 496 { 497 lstrcpynW(&wfd.cFileName[0], path, MAX_PATH); 498 pidl = _ILCreateFromFindDataW(&wfd); 499 } 500 fsbd->Release(); 501 } 502 503 return pidl; 504 } 505 506 static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID* pclsidFolder) 507 { 508 WCHAR wszCLSIDValue[CHARS_IN_GUID]; 509 WCHAR wszDesktopIni[MAX_PATH]; 510 StringCchCopyW(wszDesktopIni, MAX_PATH, pwszDir); 511 StringCchCatW(wszDesktopIni, MAX_PATH, L"\\desktop.ini"); 512 513 if (GetPrivateProfileStringW(L".ShellClassInfo", 514 KeyName, 515 L"", 516 wszCLSIDValue, 517 CHARS_IN_GUID, 518 wszDesktopIni)) 519 { 520 return CLSIDFromString(wszCLSIDValue, pclsidFolder); 521 } 522 return E_FAIL; 523 } 524 525 HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes) 526 { 527 DWORD dwFileAttributes, dwShellAttributes; 528 529 if (!_ILIsFolder(pidl) && !_ILIsValue(pidl)) 530 { 531 ERR("Got wrong type of pidl!\n"); 532 *pdwAttributes &= SFGAO_CANLINK; 533 return S_OK; 534 } 535 536 dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); 537 538 /* Set common attributes */ 539 dwShellAttributes = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK | SFGAO_CANRENAME | SFGAO_CANDELETE | 540 SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSTEM; 541 542 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 543 dwShellAttributes |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STORAGE); 544 else 545 dwShellAttributes |= SFGAO_STREAM; 546 547 if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 548 dwShellAttributes |= SFGAO_HIDDEN; 549 550 if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) 551 dwShellAttributes |= SFGAO_READONLY; 552 553 if (SFGAO_LINK & *pdwAttributes) 554 { 555 char ext[MAX_PATH]; 556 557 if (_ILGetExtension(pidl, ext, MAX_PATH) && !lstrcmpiA(ext, "lnk")) 558 dwShellAttributes |= SFGAO_LINK; 559 } 560 561 if (SFGAO_HASSUBFOLDER & *pdwAttributes) 562 { 563 CComPtr<IShellFolder> psf2; 564 if (SUCCEEDED(psf->BindToObject(pidl, 0, IID_PPV_ARG(IShellFolder, &psf2)))) 565 { 566 CComPtr<IEnumIDList> pEnumIL; 567 if (SUCCEEDED(psf2->EnumObjects(0, SHCONTF_FOLDERS, &pEnumIL))) 568 { 569 if (pEnumIL->Skip(1) == S_OK) 570 dwShellAttributes |= SFGAO_HASSUBFOLDER; 571 } 572 } 573 } 574 575 *pdwAttributes = dwShellAttributes; 576 577 TRACE ("-- 0x%08x\n", *pdwAttributes); 578 return S_OK; 579 } 580 581 /************************************************************************** 582 * CFSFolder::ParseDisplayName {SHELL32} 583 * 584 * Parse a display name. 585 * 586 * PARAMS 587 * hwndOwner [in] Parent window for any message's 588 * pbc [in] optional FileSystemBindData context 589 * lpszDisplayName [in] Unicode displayname. 590 * pchEaten [out] (unicode) characters processed 591 * ppidl [out] complex pidl to item 592 * pdwAttributes [out] items attributes 593 * 594 * NOTES 595 * Every folder tries to parse only its own (the leftmost) pidl and creates a 596 * subfolder to evaluate the remaining parts. 597 * Now we can parse into namespaces implemented by shell extensions 598 * 599 * Behaviour on win98: lpszDisplayName=NULL -> crash 600 * lpszDisplayName="" -> returns mycoputer-pidl 601 * 602 * FIXME 603 * pdwAttributes is not set 604 * pchEaten is not set like in windows 605 */ 606 HRESULT WINAPI CFSFolder::ParseDisplayName(HWND hwndOwner, 607 LPBC pbc, 608 LPOLESTR lpszDisplayName, 609 DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, 610 DWORD *pdwAttributes) 611 { 612 HRESULT hr = E_INVALIDARG; 613 LPCWSTR szNext = NULL; 614 WCHAR szElement[MAX_PATH]; 615 WCHAR szPath[MAX_PATH]; 616 LPITEMIDLIST pidlTemp = NULL; 617 DWORD len; 618 619 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", 620 this, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName), 621 pchEaten, ppidl, pdwAttributes); 622 623 if (!ppidl) 624 return E_INVALIDARG; 625 626 if (!lpszDisplayName) 627 { 628 *ppidl = NULL; 629 return E_INVALIDARG; 630 } 631 632 *ppidl = NULL; 633 634 if (pchEaten) 635 *pchEaten = 0; /* strange but like the original */ 636 637 if (*lpszDisplayName) 638 { 639 /* get the next element */ 640 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH); 641 642 pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, szElement); 643 if (pidlTemp != NULL) 644 { 645 /* We are creating an id list without ensuring that the items exist. 646 If we have a remaining path, this must be a folder. 647 We have to do it now because it is set as a file by default */ 648 if (szNext) 649 { 650 pidlTemp->mkid.abID[0] = PT_FOLDER; 651 } 652 hr = S_OK; 653 } 654 else 655 { 656 /* build the full pathname to the element */ 657 lstrcpynW(szPath, m_sPathTarget, MAX_PATH - 1); 658 PathAddBackslashW(szPath); 659 len = wcslen(szPath); 660 lstrcpynW(szPath + len, szElement, MAX_PATH - len); 661 662 /* get the pidl */ 663 hr = _ILCreateFromPathW(szPath, &pidlTemp); 664 } 665 666 if (SUCCEEDED(hr)) 667 { 668 if (szNext && *szNext) 669 { 670 /* try to analyse the next element */ 671 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc, 672 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes); 673 } 674 else 675 { 676 /* it's the last element */ 677 if (pdwAttributes && *pdwAttributes) 678 hr = SHELL32_GetFSItemAttributes(this, pidlTemp, pdwAttributes); 679 } 680 } 681 } 682 683 if (SUCCEEDED(hr)) 684 *ppidl = pidlTemp; 685 else 686 *ppidl = NULL; 687 688 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl ? *ppidl : 0, hr); 689 690 return hr; 691 } 692 693 /************************************************************************** 694 * CFSFolder::EnumObjects 695 * PARAMETERS 696 * HWND hwndOwner, //[in ] Parent Window 697 * DWORD grfFlags, //[in ] SHCONTF enumeration mask 698 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface 699 */ 700 HRESULT WINAPI CFSFolder::EnumObjects( 701 HWND hwndOwner, 702 DWORD dwFlags, 703 LPENUMIDLIST *ppEnumIDList) 704 { 705 return ShellObjectCreatorInit<CFileSysEnum>(m_sPathTarget, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 706 } 707 708 /************************************************************************** 709 * CFSFolder::BindToObject 710 * PARAMETERS 711 * LPCITEMIDLIST pidl, //[in ] relative pidl to open 712 * LPBC pbc, //[in ] optional FileSystemBindData context 713 * REFIID riid, //[in ] Initial Interface 714 * LPVOID* ppvObject //[out] Interface* 715 */ 716 HRESULT WINAPI CFSFolder::BindToObject( 717 PCUIDLIST_RELATIVE pidl, 718 LPBC pbc, 719 REFIID riid, 720 LPVOID * ppvOut) 721 { 722 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbc, 723 shdebugstr_guid(&riid), ppvOut); 724 725 CComPtr<IShellFolder> pSF; 726 HRESULT hr; 727 728 if (!m_pidlRoot || !ppvOut || !pidl || !pidl->mkid.cb) 729 { 730 ERR("CFSFolder::BindToObject: Invalid parameters\n"); 731 return E_INVALIDARG; 732 } 733 734 /* Get the pidl data */ 735 FileStruct* pData = &_ILGetDataPointer(pidl)->u.file; 736 FileStructW* pDataW = _ILGetFileStructW(pidl); 737 738 if (!pDataW) 739 { 740 ERR("CFSFolder::BindToObject: Invalid pidl!\n"); 741 return E_INVALIDARG; 742 } 743 744 *ppvOut = NULL; 745 746 /* Create the target folder info */ 747 PERSIST_FOLDER_TARGET_INFO pfti = {0}; 748 pfti.dwAttributes = -1; 749 pfti.csidl = -1; 750 PathCombineW(pfti.szTargetParsingName, m_sPathTarget, pDataW->wszName); 751 752 /* Get the CLSID to bind to */ 753 CLSID clsidFolder; 754 if (_ILIsFolder(pidl)) 755 { 756 clsidFolder = CLSID_ShellFSFolder; 757 758 if ((pData->uFileAttribs & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0) 759 SHELL32_GetCLSIDForDirectory(pfti.szTargetParsingName, L"CLSID", &clsidFolder); 760 } 761 else 762 { 763 hr = GetCLSIDForFileType(pidl, L"CLSID", &clsidFolder); 764 if (hr == S_FALSE) 765 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 766 if (hr != S_OK) 767 return hr; 768 } 769 770 hr = SHELL32_BindToSF(m_pidlRoot, &pfti, pidl, &clsidFolder, riid, ppvOut); 771 if (FAILED_UNEXPECTEDLY(hr)) 772 return hr; 773 774 TRACE ("-- returning (%p) %08x\n", *ppvOut, hr); 775 776 return S_OK; 777 778 } 779 780 /************************************************************************** 781 * CFSFolder::BindToStorage 782 * PARAMETERS 783 * LPCITEMIDLIST pidl, //[in ] complex pidl to store 784 * LPBC pbc, //[in ] reserved 785 * REFIID riid, //[in ] Initial storage interface 786 * LPVOID* ppvObject //[out] Interface* returned 787 */ 788 HRESULT WINAPI CFSFolder::BindToStorage( 789 PCUIDLIST_RELATIVE pidl, 790 LPBC pbcReserved, 791 REFIID riid, 792 LPVOID *ppvOut) 793 { 794 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved, 795 shdebugstr_guid (&riid), ppvOut); 796 797 *ppvOut = NULL; 798 return E_NOTIMPL; 799 } 800 801 /************************************************************************** 802 * CFSFolder::CompareIDs 803 */ 804 805 HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam, 806 PCUIDLIST_RELATIVE pidl1, 807 PCUIDLIST_RELATIVE pidl2) 808 { 809 LPPIDLDATA pData1 = _ILGetDataPointer(pidl1); 810 LPPIDLDATA pData2 = _ILGetDataPointer(pidl2); 811 FileStructW* pDataW1 = _ILGetFileStructW(pidl1); 812 FileStructW* pDataW2 = _ILGetFileStructW(pidl2); 813 BOOL bIsFolder1 = _ILIsFolder(pidl1); 814 BOOL bIsFolder2 = _ILIsFolder(pidl2); 815 LPWSTR pExtension1, pExtension2; 816 817 if (!pDataW1 || !pDataW2 || LOWORD(lParam) >= GENERICSHELLVIEWCOLUMNS) 818 return E_INVALIDARG; 819 820 /* When sorting between a File and a Folder, the Folder gets sorted first */ 821 if (bIsFolder1 != bIsFolder2) 822 { 823 return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1); 824 } 825 826 int result; 827 switch (LOWORD(lParam)) 828 { 829 case 0: /* Name */ 830 result = wcsicmp(pDataW1->wszName, pDataW2->wszName); 831 break; 832 case 1: /* Comments */ 833 result = 0; 834 break; 835 case 2: /* Type */ 836 pExtension1 = PathFindExtensionW(pDataW1->wszName); 837 pExtension2 = PathFindExtensionW(pDataW2->wszName); 838 result = wcsicmp(pExtension1, pExtension2); 839 break; 840 case 3: /* Size */ 841 result = pData1->u.file.dwFileSize - pData2->u.file.dwFileSize; 842 break; 843 case 4: /* Modified */ 844 result = pData1->u.file.uFileDate - pData2->u.file.uFileDate; 845 if (result == 0) 846 result = pData1->u.file.uFileTime - pData2->u.file.uFileTime; 847 break; 848 case 5: /* Attributes */ 849 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2); 850 } 851 852 if (result == 0) 853 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2); 854 855 return MAKE_COMPARE_HRESULT(result); 856 } 857 858 /************************************************************************** 859 * CFSFolder::CreateViewObject 860 */ 861 HRESULT WINAPI CFSFolder::CreateViewObject(HWND hwndOwner, 862 REFIID riid, LPVOID * ppvOut) 863 { 864 CComPtr<IShellView> pShellView; 865 HRESULT hr = E_INVALIDARG; 866 867 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid (&riid), 868 ppvOut); 869 870 if (ppvOut) 871 { 872 *ppvOut = NULL; 873 874 BOOL bIsDropTarget = IsEqualIID (riid, IID_IDropTarget); 875 BOOL bIsShellView = !bIsDropTarget && IsEqualIID (riid, IID_IShellView); 876 877 if (bIsDropTarget || bIsShellView) 878 { 879 DWORD dwDirAttributes = _ILGetFileAttributes(ILFindLastID(m_pidlRoot), NULL, 0); 880 881 if ((dwDirAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0) 882 { 883 CLSID clsidFolder; 884 hr = SHELL32_GetCLSIDForDirectory(m_sPathTarget, L"UICLSID", &clsidFolder); 885 if (SUCCEEDED(hr)) 886 { 887 CComPtr<IPersistFolder> spFolder; 888 hr = SHCoCreateInstance(NULL, &clsidFolder, NULL, IID_PPV_ARG(IPersistFolder, &spFolder)); 889 if (!FAILED_UNEXPECTEDLY(hr)) 890 { 891 hr = spFolder->Initialize(m_pidlRoot); 892 893 if (!FAILED_UNEXPECTEDLY(hr)) 894 { 895 hr = spFolder->QueryInterface(riid, ppvOut); 896 } 897 } 898 } 899 else 900 { 901 // No desktop.ini, or no UICLSID present, continue as if nothing happened 902 hr = E_INVALIDARG; 903 } 904 } 905 } 906 907 if (!SUCCEEDED(hr)) 908 { 909 // No UICLSID handler found, continue to the default handlers 910 if (bIsDropTarget) 911 { 912 hr = CFSDropTarget_CreateInstance(m_sPathTarget, riid, ppvOut); 913 } 914 else if (IsEqualIID (riid, IID_IContextMenu)) 915 { 916 HKEY hKeys[16]; 917 UINT cKeys = 0; 918 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys); 919 920 DEFCONTEXTMENU dcm; 921 dcm.hwnd = hwndOwner; 922 dcm.pcmcb = this; 923 dcm.pidlFolder = m_pidlRoot; 924 dcm.psf = this; 925 dcm.cidl = 0; 926 dcm.apidl = NULL; 927 dcm.cKeys = cKeys; 928 dcm.aKeys = hKeys; 929 dcm.punkAssociationInfo = NULL; 930 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut); 931 } 932 else if (bIsShellView) 933 { 934 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this, NULL, this}; 935 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 936 } 937 else 938 { 939 hr = E_INVALIDARG; 940 } 941 } 942 } 943 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut); 944 return hr; 945 } 946 947 /************************************************************************** 948 * CFSFolder::GetAttributesOf 949 * 950 * PARAMETERS 951 * UINT cidl, //[in ] num elements in pidl array 952 * LPCITEMIDLIST* apidl, //[in ] simple pidl array 953 * ULONG* rgfInOut) //[out] result array 954 * 955 */ 956 HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl, 957 PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut) 958 { 959 HRESULT hr = S_OK; 960 961 if (!rgfInOut) 962 return E_INVALIDARG; 963 if (cidl && !apidl) 964 return E_INVALIDARG; 965 966 if (*rgfInOut == 0) 967 *rgfInOut = ~0; 968 969 if(cidl == 0) 970 { 971 LPCITEMIDLIST rpidl = ILFindLastID(m_pidlRoot); 972 973 if (_ILIsFolder(rpidl) || _ILIsValue(rpidl)) 974 { 975 SHELL32_GetFSItemAttributes(this, rpidl, rgfInOut); 976 } 977 else if (_ILIsDrive(rpidl)) 978 { 979 IShellFolder *psfParent = NULL; 980 hr = SHBindToParent(m_pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), NULL); 981 if(SUCCEEDED(hr)) 982 { 983 hr = psfParent->GetAttributesOf(1, &rpidl, (SFGAOF*)rgfInOut); 984 psfParent->Release(); 985 } 986 } 987 else 988 { 989 ERR("Got and unknown pidl!\n"); 990 } 991 } 992 else 993 { 994 while (cidl > 0 && *apidl) 995 { 996 pdump(*apidl); 997 if(_ILIsFolder(*apidl) || _ILIsValue(*apidl)) 998 SHELL32_GetFSItemAttributes(this, *apidl, rgfInOut); 999 else 1000 ERR("Got an unknown type of pidl!!!\n"); 1001 apidl++; 1002 cidl--; 1003 } 1004 } 1005 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 1006 *rgfInOut &= ~SFGAO_VALIDATE; 1007 1008 TRACE("-- result=0x%08x\n", *rgfInOut); 1009 1010 return hr; 1011 } 1012 1013 /************************************************************************** 1014 * CFSFolder::GetUIObjectOf 1015 * 1016 * PARAMETERS 1017 * HWND hwndOwner, //[in ] Parent window for any output 1018 * UINT cidl, //[in ] array size 1019 * LPCITEMIDLIST* apidl, //[in ] simple pidl array 1020 * REFIID riid, //[in ] Requested Interface 1021 * UINT* prgfInOut, //[ ] reserved 1022 * LPVOID* ppvObject) //[out] Resulting Interface 1023 * 1024 * NOTES 1025 * This function gets asked to return "view objects" for one or more (multiple 1026 * select) items: 1027 * The viewobject typically is an COM object with one of the following 1028 * interfaces: 1029 * IExtractIcon,IDataObject,IContextMenu 1030 * In order to support icon positions in the default Listview your DataObject 1031 * must implement the SetData method (in addition to GetData :) - the shell 1032 * passes a barely documented "Icon positions" structure to SetData when the 1033 * drag starts, and GetData's it if the drop is in another explorer window that 1034 * needs the positions. 1035 */ 1036 HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner, 1037 UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 1038 REFIID riid, UINT * prgfInOut, 1039 LPVOID * ppvOut) 1040 { 1041 LPVOID pObj = NULL; 1042 HRESULT hr = E_INVALIDARG; 1043 1044 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", 1045 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut); 1046 1047 if (ppvOut) 1048 { 1049 *ppvOut = NULL; 1050 1051 if (cidl == 1 && _ILIsValue(apidl[0])) 1052 { 1053 hr = _CreateExtensionUIObject(apidl[0], riid, ppvOut); 1054 if(hr != S_FALSE) 1055 return hr; 1056 } 1057 1058 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1)) 1059 { 1060 HKEY hKeys[16]; 1061 UINT cKeys = 0; 1062 AddFSClassKeysToArray(apidl[0], hKeys, &cKeys); 1063 1064 DEFCONTEXTMENU dcm; 1065 dcm.hwnd = hwndOwner; 1066 dcm.pcmcb = this; 1067 dcm.pidlFolder = m_pidlRoot; 1068 dcm.psf = this; 1069 dcm.cidl = cidl; 1070 dcm.apidl = apidl; 1071 dcm.cKeys = cKeys; 1072 dcm.aKeys = hKeys; 1073 dcm.punkAssociationInfo = NULL; 1074 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj); 1075 } 1076 else if (IsEqualIID (riid, IID_IDataObject)) 1077 { 1078 if (cidl >= 1) 1079 { 1080 hr = IDataObject_Constructor (hwndOwner, m_pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 1081 } 1082 else 1083 { 1084 hr = E_INVALIDARG; 1085 } 1086 } 1087 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 1088 { 1089 if (_ILIsValue(apidl[0])) 1090 hr = _GetIconHandler(apidl[0], riid, (LPVOID*)&pObj); 1091 if (hr != S_OK) 1092 hr = CFSExtractIcon_CreateInstance(this, apidl[0], riid, &pObj); 1093 } 1094 else if (IsEqualIID (riid, IID_IDropTarget)) 1095 { 1096 /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */ 1097 if (cidl != 1 || FAILED(hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj))) 1098 { 1099 hr = CFSDropTarget_CreateInstance(m_sPathTarget, riid, (LPVOID*) &pObj); 1100 } 1101 } 1102 else 1103 hr = E_NOINTERFACE; 1104 1105 if (SUCCEEDED(hr) && !pObj) 1106 hr = E_OUTOFMEMORY; 1107 1108 *ppvOut = pObj; 1109 } 1110 TRACE("(%p)->hr=0x%08x\n", this, hr); 1111 return hr; 1112 } 1113 1114 static const WCHAR AdvancedW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"; 1115 static const WCHAR HideFileExtW[] = L"HideFileExt"; 1116 static const WCHAR NeverShowExtW[] = L"NeverShowExt"; 1117 1118 /****************************************************************************** 1119 * SHELL_FS_HideExtension [Internal] 1120 * 1121 * Query the registry if the filename extension of a given path should be 1122 * hidden. 1123 * 1124 * PARAMS 1125 * szPath [I] Relative or absolute path of a file 1126 * 1127 * RETURNS 1128 * TRUE, if the filename's extension should be hidden 1129 * FALSE, otherwise. 1130 */ 1131 BOOL SHELL_FS_HideExtension(LPWSTR szPath) 1132 { 1133 HKEY hKey; 1134 DWORD dwData; 1135 DWORD dwDataSize = sizeof (DWORD); 1136 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */ 1137 1138 if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) { 1139 if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize)) 1140 doHide = dwData; 1141 RegCloseKey (hKey); 1142 } 1143 1144 if (!doHide) { 1145 LPWSTR ext = PathFindExtensionW(szPath); 1146 1147 if (*ext != '\0') { 1148 WCHAR classname[MAX_PATH]; 1149 LONG classlen = sizeof(classname); 1150 1151 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen)) 1152 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) { 1153 if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL)) 1154 doHide = TRUE; 1155 RegCloseKey(hKey); 1156 } 1157 } 1158 } 1159 return doHide; 1160 } 1161 1162 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags) 1163 { 1164 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */ 1165 if (!(dwFlags & SHGDN_FORPARSING) && 1166 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) { 1167 if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.') 1168 PathRemoveExtensionW(szPath); 1169 } 1170 } 1171 1172 /************************************************************************** 1173 * CFSFolder::GetDisplayNameOf 1174 * Retrieves the display name for the specified file object or subfolder 1175 * 1176 * PARAMETERS 1177 * LPCITEMIDLIST pidl, //[in ] complex pidl to item 1178 * DWORD dwFlags, //[in ] SHGNO formatting flags 1179 * LPSTRRET lpName) //[out] Returned display name 1180 * 1181 * FIXME 1182 * if the name is in the pidl the ret value should be a STRRET_OFFSET 1183 */ 1184 1185 HRESULT WINAPI CFSFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, 1186 DWORD dwFlags, LPSTRRET strRet) 1187 { 1188 if (!strRet) 1189 return E_INVALIDARG; 1190 1191 /* If it is a complex pidl, let the child handle it */ 1192 if (!_ILIsPidlSimple (pidl)) /* complex pidl */ 1193 { 1194 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet); 1195 } 1196 else if (pidl && !pidl->mkid.cb) /* empty pidl */ 1197 { 1198 /* If it is an empty pidl return only the path of the folder */ 1199 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && 1200 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && 1201 m_sPathTarget) 1202 { 1203 return SHSetStrRet(strRet, m_sPathTarget); 1204 } 1205 return E_INVALIDARG; 1206 } 1207 1208 int len = 0; 1209 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); 1210 if (!pszPath) 1211 return E_OUTOFMEMORY; 1212 1213 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && 1214 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && 1215 m_sPathTarget) 1216 { 1217 lstrcpynW(pszPath, m_sPathTarget, MAX_PATH); 1218 PathAddBackslashW(pszPath); 1219 len = wcslen(pszPath); 1220 } 1221 _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len); 1222 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags); 1223 1224 strRet->uType = STRRET_WSTR; 1225 strRet->pOleStr = pszPath; 1226 1227 TRACE ("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr)); 1228 return S_OK; 1229 } 1230 1231 /************************************************************************** 1232 * CFSFolder::SetNameOf 1233 * Changes the name of a file object or subfolder, possibly changing its item 1234 * identifier in the process. 1235 * 1236 * PARAMETERS 1237 * HWND hwndOwner, //[in ] Owner window for output 1238 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change 1239 * LPCOLESTR lpszName, //[in ] the items new display name 1240 * DWORD dwFlags, //[in ] SHGNO formatting flags 1241 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned 1242 */ 1243 HRESULT WINAPI CFSFolder::SetNameOf( 1244 HWND hwndOwner, 1245 PCUITEMID_CHILD pidl, 1246 LPCOLESTR lpName, 1247 DWORD dwFlags, 1248 PITEMID_CHILD *pPidlOut) 1249 { 1250 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1]; 1251 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl)); 1252 1253 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, 1254 debugstr_w (lpName), dwFlags, pPidlOut); 1255 1256 FileStructW* pDataW = _ILGetFileStructW(pidl); 1257 if (!pDataW) 1258 { 1259 ERR("Got garbage pidl\n"); 1260 return E_INVALIDARG; 1261 } 1262 1263 /* build source path */ 1264 PathCombineW(szSrc, m_sPathTarget, pDataW->wszName); 1265 1266 /* build destination path */ 1267 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) 1268 PathCombineW(szDest, m_sPathTarget, lpName); 1269 else 1270 lstrcpynW(szDest, lpName, MAX_PATH); 1271 1272 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) { 1273 WCHAR *ext = PathFindExtensionW(szSrc); 1274 if(*ext != '\0') { 1275 INT len = wcslen(szDest); 1276 lstrcpynW(szDest + len, ext, MAX_PATH - len); 1277 } 1278 } 1279 1280 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest)); 1281 if (!wcscmp(szSrc, szDest)) 1282 { 1283 /* src and destination is the same */ 1284 HRESULT hr = S_OK; 1285 if (pPidlOut) 1286 hr = _ILCreateFromPathW(szDest, pPidlOut); 1287 1288 return hr; 1289 } 1290 1291 if (MoveFileW (szSrc, szDest)) 1292 { 1293 HRESULT hr = S_OK; 1294 1295 if (pPidlOut) 1296 hr = _ILCreateFromPathW(szDest, pPidlOut); 1297 1298 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM, 1299 SHCNF_PATHW, szSrc, szDest); 1300 1301 return hr; 1302 } 1303 1304 return E_FAIL; 1305 } 1306 1307 HRESULT WINAPI CFSFolder::GetDefaultSearchGUID(GUID * pguid) 1308 { 1309 FIXME ("(%p)\n", this); 1310 return E_NOTIMPL; 1311 } 1312 1313 HRESULT WINAPI CFSFolder::EnumSearches(IEnumExtraSearch ** ppenum) 1314 { 1315 FIXME ("(%p)\n", this); 1316 return E_NOTIMPL; 1317 } 1318 1319 HRESULT WINAPI CFSFolder::GetDefaultColumn(DWORD dwRes, 1320 ULONG * pSort, ULONG * pDisplay) 1321 { 1322 TRACE ("(%p)\n", this); 1323 1324 if (pSort) 1325 *pSort = 0; 1326 if (pDisplay) 1327 *pDisplay = 0; 1328 1329 return S_OK; 1330 } 1331 1332 HRESULT WINAPI CFSFolder::GetDefaultColumnState(UINT iColumn, 1333 DWORD * pcsFlags) 1334 { 1335 TRACE ("(%p)\n", this); 1336 1337 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS) 1338 return E_INVALIDARG; 1339 1340 *pcsFlags = GenericSFHeader[iColumn].pcsFlags; 1341 1342 return S_OK; 1343 } 1344 1345 HRESULT WINAPI CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl, 1346 const SHCOLUMNID * pscid, VARIANT * pv) 1347 { 1348 FIXME ("(%p)\n", this); 1349 1350 return E_NOTIMPL; 1351 } 1352 1353 HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl, 1354 UINT iColumn, SHELLDETAILS * psd) 1355 { 1356 HRESULT hr = E_FAIL; 1357 1358 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd); 1359 1360 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS) 1361 return E_INVALIDARG; 1362 1363 if (!pidl) 1364 { 1365 /* the header titles */ 1366 psd->fmt = GenericSFHeader[iColumn].fmt; 1367 psd->cxChar = GenericSFHeader[iColumn].cxChar; 1368 return SHSetStrRet(&psd->str, GenericSFHeader[iColumn].colnameid); 1369 } 1370 else 1371 { 1372 hr = S_OK; 1373 psd->str.uType = STRRET_CSTR; 1374 /* the data from the pidl */ 1375 switch (iColumn) 1376 { 1377 case 0: /* name */ 1378 hr = GetDisplayNameOf (pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); 1379 break; 1380 case 1: /* FIXME: comments */ 1381 psd->str.cStr[0] = 0; 1382 break; 1383 case 2: /* type */ 1384 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH); 1385 break; 1386 case 3: /* size */ 1387 _ILGetFileSize(pidl, psd->str.cStr, MAX_PATH); 1388 break; 1389 case 4: /* date */ 1390 _ILGetFileDate(pidl, psd->str.cStr, MAX_PATH); 1391 break; 1392 case 5: /* attributes */ 1393 _ILGetFileAttributes(pidl, psd->str.cStr, MAX_PATH); 1394 break; 1395 } 1396 } 1397 1398 return hr; 1399 } 1400 1401 HRESULT WINAPI CFSFolder::MapColumnToSCID (UINT column, 1402 SHCOLUMNID * pscid) 1403 { 1404 FIXME ("(%p)\n", this); 1405 return E_NOTIMPL; 1406 } 1407 1408 /************************************************************************ 1409 * CFSFolder::GetClassID 1410 */ 1411 HRESULT WINAPI CFSFolder::GetClassID(CLSID * lpClassId) 1412 { 1413 TRACE ("(%p)\n", this); 1414 1415 if (!lpClassId) 1416 return E_POINTER; 1417 1418 *lpClassId = *m_pclsid; 1419 1420 return S_OK; 1421 } 1422 1423 /************************************************************************ 1424 * CFSFolder::Initialize 1425 * 1426 * NOTES 1427 * m_sPathTarget is not set. Don't know how to handle in a non rooted environment. 1428 */ 1429 HRESULT WINAPI CFSFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 1430 { 1431 WCHAR wszTemp[MAX_PATH]; 1432 1433 TRACE ("(%p)->(%p)\n", this, pidl); 1434 1435 SHFree(m_pidlRoot); /* free the old pidl */ 1436 m_pidlRoot = ILClone (pidl); /* set my pidl */ 1437 1438 SHFree (m_sPathTarget); 1439 m_sPathTarget = NULL; 1440 1441 /* set my path */ 1442 if (SHGetPathFromIDListW (pidl, wszTemp)) 1443 { 1444 int len = wcslen(wszTemp); 1445 m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); 1446 if (!m_sPathTarget) 1447 return E_OUTOFMEMORY; 1448 memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); 1449 } 1450 1451 TRACE ("--(%p)->(%s)\n", this, debugstr_w(m_sPathTarget)); 1452 return S_OK; 1453 } 1454 1455 /************************************************************************** 1456 * CFSFolder::GetCurFolder 1457 */ 1458 HRESULT WINAPI CFSFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 1459 { 1460 TRACE ("(%p)->(%p)\n", this, pidl); 1461 1462 if (!pidl) 1463 return E_POINTER; 1464 1465 *pidl = ILClone(m_pidlRoot); 1466 return S_OK; 1467 } 1468 1469 /************************************************************************** 1470 * CFSFolder::InitializeEx 1471 * 1472 * FIXME: error handling 1473 */ 1474 HRESULT WINAPI CFSFolder::InitializeEx(IBindCtx * pbc, LPCITEMIDLIST pidlRootx, 1475 const PERSIST_FOLDER_TARGET_INFO * ppfti) 1476 { 1477 WCHAR wszTemp[MAX_PATH]; 1478 1479 TRACE("(%p)->(%p,%p,%p)\n", this, pbc, pidlRootx, ppfti); 1480 if (ppfti) 1481 TRACE("--%p %s %s 0x%08x 0x%08x\n", 1482 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName), 1483 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes, 1484 ppfti->csidl); 1485 1486 pdump (pidlRootx); 1487 if (ppfti && ppfti->pidlTargetFolder) 1488 pdump(ppfti->pidlTargetFolder); 1489 1490 if (m_pidlRoot) 1491 __SHFreeAndNil(&m_pidlRoot); /* free the old */ 1492 if (m_sPathTarget) 1493 __SHFreeAndNil(&m_sPathTarget); 1494 1495 /* 1496 * Root path and pidl 1497 */ 1498 m_pidlRoot = ILClone(pidlRootx); 1499 1500 /* 1501 * the target folder is spezified in csidl OR pidlTargetFolder OR 1502 * szTargetParsingName 1503 */ 1504 if (ppfti) 1505 { 1506 if (ppfti->csidl != -1) 1507 { 1508 if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl, 1509 ppfti->csidl & CSIDL_FLAG_CREATE)) { 1510 int len = wcslen(wszTemp); 1511 m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); 1512 if (!m_sPathTarget) 1513 return E_OUTOFMEMORY; 1514 memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); 1515 } 1516 } 1517 else if (ppfti->szTargetParsingName[0]) 1518 { 1519 int len = wcslen(ppfti->szTargetParsingName); 1520 m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); 1521 if (!m_sPathTarget) 1522 return E_OUTOFMEMORY; 1523 memcpy(m_sPathTarget, ppfti->szTargetParsingName, 1524 (len + 1) * sizeof(WCHAR)); 1525 } 1526 else if (ppfti->pidlTargetFolder) 1527 { 1528 if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) 1529 { 1530 int len = wcslen(wszTemp); 1531 m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); 1532 if (!m_sPathTarget) 1533 return E_OUTOFMEMORY; 1534 memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); 1535 } 1536 } 1537 } 1538 1539 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(m_sPathTarget)); 1540 pdump(m_pidlRoot); 1541 return (m_sPathTarget) ? S_OK : E_FAIL; 1542 } 1543 1544 HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti) 1545 { 1546 FIXME("(%p)->(%p)\n", this, ppfti); 1547 ZeroMemory(ppfti, sizeof (*ppfti)); 1548 return E_NOTIMPL; 1549 } 1550 1551 HRESULT CFSFolder::_CreateExtensionUIObject(PCUIDLIST_RELATIVE pidl, REFIID riid, LPVOID *ppvOut) 1552 { 1553 static const WCHAR formatW[] = {'S','h','e','l','l','E','x','\\', 1554 '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-', 1555 '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x', 1556 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0}; 1557 WCHAR buf[MAX_PATH]; 1558 1559 sprintfW(buf, formatW, riid.Data1, riid.Data2, riid.Data3, 1560 riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3], 1561 riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]); 1562 1563 CLSID clsid; 1564 HRESULT hr; 1565 1566 hr = GetCLSIDForFileType(pidl, buf, &clsid); 1567 if (hr != S_OK) 1568 return hr; 1569 1570 hr = _CreateShellExtInstance(&clsid, pidl, riid, ppvOut); 1571 if (FAILED_UNEXPECTEDLY(hr)) 1572 return hr; 1573 1574 return S_OK; 1575 } 1576 1577 HRESULT CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) 1578 { 1579 HRESULT hr; 1580 1581 TRACE("CFSFolder::_GetDropTarget entered\n"); 1582 1583 if (_ILIsFolder (pidl)) 1584 { 1585 CComPtr<IShellFolder> psfChild; 1586 hr = this->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 1587 if (FAILED_UNEXPECTEDLY(hr)) 1588 return hr; 1589 1590 return psfChild->CreateViewObject(NULL, IID_IDropTarget, ppvOut); 1591 } 1592 1593 CLSID clsid; 1594 hr = GetCLSIDForFileType(pidl, L"shellex\\DropHandler", &clsid); 1595 if (hr != S_OK) 1596 return hr; 1597 1598 hr = _CreateShellExtInstance(&clsid, pidl, IID_IDropTarget, ppvOut); 1599 if (FAILED_UNEXPECTEDLY(hr)) 1600 return S_FALSE; 1601 1602 return S_OK; 1603 } 1604 1605 HRESULT CFSFolder::_GetIconHandler(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut) 1606 { 1607 CLSID clsid; 1608 HRESULT hr; 1609 1610 hr = GetCLSIDForFileType(pidl, L"shellex\\IconHandler", &clsid); 1611 if (hr != S_OK) 1612 return hr; 1613 1614 hr = _CreateShellExtInstance(&clsid, pidl, riid, ppvOut); 1615 if (FAILED_UNEXPECTEDLY(hr)) 1616 return S_FALSE; 1617 1618 return S_OK; 1619 } 1620 1621 HRESULT CFSFolder::_CreateShellExtInstance(const CLSID *pclsid, LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut) 1622 { 1623 HRESULT hr; 1624 WCHAR wszPath[MAX_PATH]; 1625 1626 FileStructW* pDataW = _ILGetFileStructW(pidl); 1627 if (!pDataW) 1628 { 1629 ERR("Got garbage pidl\n"); 1630 return E_INVALIDARG; 1631 } 1632 1633 PathCombineW(wszPath, m_sPathTarget, pDataW->wszName); 1634 1635 CComPtr<IPersistFile> pp; 1636 hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IPersistFile, &pp)); 1637 if (FAILED_UNEXPECTEDLY(hr)) 1638 return hr; 1639 1640 pp->Load(wszPath, 0); 1641 1642 hr = pp->QueryInterface(riid, ppvOut); 1643 if (hr != S_OK) 1644 { 1645 ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid)); 1646 return hr; 1647 } 1648 return hr; 1649 } 1650 1651 HRESULT WINAPI CFSFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) 1652 { 1653 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND) 1654 return S_OK; 1655 1656 /* no data object means no selection */ 1657 if (!pdtobj) 1658 { 1659 if (uMsg == DFM_INVOKECOMMAND && wParam == 0) 1660 { 1661 PUITEMID_CHILD pidlChild = ILClone(ILFindLastID(m_pidlRoot)); 1662 LPITEMIDLIST pidlParent = ILClone(m_pidlRoot); 1663 ILRemoveLastID(pidlParent); 1664 HRESULT hr = SH_ShowPropertiesDialog(m_sPathTarget, pidlParent, &pidlChild); 1665 if (FAILED(hr)) 1666 ERR("SH_ShowPropertiesDialog failed\n"); 1667 ILFree(pidlChild); 1668 ILFree(pidlParent); 1669 } 1670 else if (uMsg == DFM_MERGECONTEXTMENU) 1671 { 1672 QCMINFO *pqcminfo = (QCMINFO *)lParam; 1673 HMENU hpopup = CreatePopupMenu(); 1674 _InsertMenuItemW(hpopup, 0, TRUE, 0, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); 1675 Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu++, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR); 1676 DestroyMenu(hpopup); 1677 } 1678 1679 return S_OK; 1680 } 1681 1682 if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES) 1683 return S_OK; 1684 1685 return Shell_DefaultContextMenuCallBack(this, pdtobj); 1686 } 1687 1688 static HBITMAP DoLoadPicture(LPCWSTR pszFileName) 1689 { 1690 // create stream from file 1691 HRESULT hr; 1692 CComPtr<IStream> pStream; 1693 hr = SHCreateStreamOnFileEx(pszFileName, STGM_READ, FILE_ATTRIBUTE_NORMAL, 1694 FALSE, NULL, &pStream); 1695 if (FAILED(hr)) 1696 return NULL; 1697 1698 // load the picture 1699 HBITMAP hbm = NULL; 1700 CComPtr<IPicture> pPicture; 1701 OleLoadPicture(pStream, 0, FALSE, IID_IPicture, (LPVOID *)&pPicture); 1702 1703 // get the bitmap handle 1704 if (pPicture) 1705 { 1706 pPicture->get_Handle((OLE_HANDLE *)&hbm); 1707 1708 // copy the bitmap handle 1709 hbm = (HBITMAP)CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); 1710 } 1711 1712 return hbm; 1713 } 1714 1715 HRESULT WINAPI CFSFolder::GetCustomViewInfo(ULONG unknown, SFVM_CUSTOMVIEWINFO_DATA *data) 1716 { 1717 if (data == NULL) 1718 { 1719 return E_POINTER; 1720 } 1721 if (data->cbSize != sizeof(*data)) 1722 { 1723 // NOTE: You have to set the cbData member before SFVM_GET_CUSTOMVIEWINFO call. 1724 return E_INVALIDARG; 1725 } 1726 1727 data->hbmBack = NULL; 1728 data->clrText = CLR_INVALID; 1729 data->clrTextBack = CLR_INVALID; 1730 1731 WCHAR szPath[MAX_PATH], szIniFile[MAX_PATH]; 1732 1733 // does the folder exists? 1734 if (!SHGetPathFromIDListW(m_pidlRoot, szPath) || !PathIsDirectoryW(szPath)) 1735 { 1736 return E_INVALIDARG; 1737 } 1738 1739 // don't use custom view in network path for security 1740 if (PathIsNetworkPath(szPath)) 1741 { 1742 return E_ACCESSDENIED; 1743 } 1744 1745 // build the ini file path 1746 StringCchCopyW(szIniFile, _countof(szIniFile), szPath); 1747 PathAppend(szIniFile, L"desktop.ini"); 1748 1749 static LPCWSTR TheGUID = L"{BE098140-A513-11D0-A3A4-00C04FD706EC}"; 1750 static LPCWSTR Space = L" \t\n\r\f\v"; 1751 1752 // get info from ini file 1753 WCHAR szImage[MAX_PATH], szText[64]; 1754 1755 // load the image 1756 szImage[0] = UNICODE_NULL; 1757 GetPrivateProfileStringW(TheGUID, L"IconArea_Image", L"", szImage, _countof(szImage), szIniFile); 1758 if (szImage[0]) 1759 { 1760 StrTrimW(szImage, Space); 1761 if (PathIsRelativeW(szImage)) 1762 { 1763 PathAppendW(szPath, szImage); 1764 StringCchCopyW(szImage, _countof(szImage), szPath); 1765 } 1766 data->hbmBack = DoLoadPicture(szImage); 1767 } 1768 1769 // load the text color 1770 szText[0] = UNICODE_NULL; 1771 GetPrivateProfileStringW(TheGUID, L"IconArea_Text", L"", szText, _countof(szText), szIniFile); 1772 if (szText[0]) 1773 { 1774 StrTrimW(szText, Space); 1775 1776 LPWSTR pchEnd = NULL; 1777 COLORREF cr = (wcstol(szText, &pchEnd, 0) & 0xFFFFFF); 1778 1779 if (pchEnd && !*pchEnd) 1780 data->clrText = cr; 1781 } 1782 1783 // load the text background color 1784 szText[0] = UNICODE_NULL; 1785 GetPrivateProfileStringW(TheGUID, L"IconArea_TextBackground", L"", szText, _countof(szText), szIniFile); 1786 if (szText[0]) 1787 { 1788 StrTrimW(szText, Space); 1789 1790 LPWSTR pchEnd = NULL; 1791 COLORREF cr = (wcstol(szText, &pchEnd, 0) & 0xFFFFFF); 1792 1793 if (pchEnd && !*pchEnd) 1794 data->clrTextBack = cr; 1795 } 1796 1797 if (data->hbmBack != NULL || data->clrText != CLR_INVALID || data->clrTextBack != CLR_INVALID) 1798 return S_OK; 1799 1800 return E_FAIL; 1801 } 1802 1803 HRESULT WINAPI CFSFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) 1804 { 1805 HRESULT hr = E_NOTIMPL; 1806 switch (uMsg) 1807 { 1808 case SFVM_GET_CUSTOMVIEWINFO: 1809 hr = GetCustomViewInfo((ULONG)wParam, (SFVM_CUSTOMVIEWINFO_DATA *)lParam); 1810 break; 1811 } 1812 return hr; 1813 } 1814