Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenshellfs.cpp
Go to the documentation of this file.
00001 /* 00002 * Copyright 2003, 2004, 2005, 2006 Martin Fuchs 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00017 */ 00018 00019 00020 // 00021 // Explorer clone 00022 // 00023 // shellfs.cpp 00024 // 00025 // Martin Fuchs, 23.07.2003 00026 // 00027 00028 00029 #include <precomp.h> 00030 00031 //#include "shellfs.h" 00032 //#include "winfs.h" 00033 00034 #include <shlwapi.h> 00035 00036 00037 bool ShellDirectory::fill_w32fdata_shell(LPCITEMIDLIST pidl, SFGAOF attribs, WIN32_FIND_DATA* pw32fdata, BY_HANDLE_FILE_INFORMATION* pbhfi, bool do_access) 00038 { 00039 CONTEXT("ShellDirectory::fill_w32fdata_shell()"); 00040 00041 bool bhfi_valid = false; 00042 00043 if (do_access && !( (attribs&SFGAO_FILESYSTEM) && SUCCEEDED( 00044 SHGetDataFromIDList(_folder, pidl, SHGDFIL_FINDDATA, pw32fdata, sizeof(WIN32_FIND_DATA))) )) { 00045 WIN32_FILE_ATTRIBUTE_DATA fad; 00046 IDataObject* pDataObj; 00047 00048 STGMEDIUM medium = {0, {0}, 0}; 00049 FORMATETC fmt = {g_Globals._cfStrFName, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; 00050 00051 HRESULT hr = _folder->GetUIObjectOf(0, 1, &pidl, IID_IDataObject, 0, (LPVOID*)&pDataObj); 00052 00053 if (SUCCEEDED(hr)) { 00054 hr = pDataObj->GetData(&fmt, &medium); 00055 00056 pDataObj->Release(); 00057 00058 if (SUCCEEDED(hr)) { 00059 LPCTSTR path = (LPCTSTR)GlobalLock(medium.UNION_MEMBER(hGlobal)); 00060 00061 if (path) { 00062 // fill with drive names "C:", ... 00063 assert(_tcslen(path) < GlobalSize(medium.UNION_MEMBER(hGlobal))); 00064 _tcscpy(pw32fdata->cFileName, path); 00065 00066 UINT sem_org = SetErrorMode(SEM_FAILCRITICALERRORS); 00067 00068 if (GetFileAttributesEx(path, GetFileExInfoStandard, &fad)) { 00069 pw32fdata->dwFileAttributes = fad.dwFileAttributes; 00070 pw32fdata->ftCreationTime = fad.ftCreationTime; 00071 pw32fdata->ftLastAccessTime = fad.ftLastAccessTime; 00072 pw32fdata->ftLastWriteTime = fad.ftLastWriteTime; 00073 00074 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { 00075 // copy file size 00076 pw32fdata->nFileSizeLow = fad.nFileSizeLow; 00077 pw32fdata->nFileSizeHigh = fad.nFileSizeHigh; 00078 } else { 00079 // ignore FILE_ATTRIBUTE_HIDDEN attribute of NTFS drives - this would hide those drives in ShellBrowser 00080 if (pw32fdata->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) { 00081 if (path[1]==':' && path[2]=='\\' && !path[3]) // Is it a drive path? 00082 pw32fdata->dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN; 00083 } 00084 } 00085 } 00086 00087 HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 00088 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); 00089 00090 if (hFile != INVALID_HANDLE_VALUE) { 00091 if (GetFileInformationByHandle(hFile, pbhfi)) 00092 bhfi_valid = true; 00093 00094 CloseHandle(hFile); 00095 } 00096 00097 SetErrorMode(sem_org); 00098 00099 GlobalUnlock(medium.UNION_MEMBER(hGlobal)); 00100 GlobalFree(medium.UNION_MEMBER(hGlobal)); 00101 } 00102 } 00103 } 00104 } 00105 00106 if (!do_access || !(attribs&SFGAO_FILESYSTEM)) // Archiv files should not be displayed as folders in explorer view. 00107 if (attribs & (SFGAO_FOLDER|SFGAO_HASSUBFOLDER)) 00108 pw32fdata->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; 00109 00110 if (attribs & SFGAO_READONLY) 00111 pw32fdata->dwFileAttributes |= FILE_ATTRIBUTE_READONLY; 00112 00113 if (attribs & SFGAO_COMPRESSED) 00114 pw32fdata->dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED; 00115 00116 return bhfi_valid; 00117 } 00118 00119 00120 ShellPath ShellEntry::create_absolute_pidl() const 00121 { 00122 CONTEXT("ShellEntry::create_absolute_pidl()"); 00123 00124 if (_up) 00125 { 00126 if (_up->_etype == ET_SHELL) { 00127 ShellDirectory* dir = static_cast<ShellDirectory*>(_up); 00128 00129 if (dir->_pidl->mkid.cb) // Caching of absolute PIDLs could enhance performance. 00130 return _pidl.create_absolute_pidl(dir->create_absolute_pidl()); 00131 } else 00132 return _pidl.create_absolute_pidl(_up->create_absolute_pidl()); 00133 } 00134 return _pidl; 00135 } 00136 00137 00138 // get full path of a shell entry 00139 bool ShellEntry::get_path(PTSTR path, size_t path_count) const 00140 { 00141 if (!path || path_count==0) 00142 return false; 00143 /* 00144 path[0] = TEXT('\0'); 00145 00146 if (FAILED(path_from_pidl(get_parent_folder(), &*_pidl, path, path_count))) 00147 return false; 00148 */ 00149 FileSysShellPath fs_path(create_absolute_pidl()); 00150 LPCTSTR ret = fs_path; 00151 00152 if (ret) { 00153 lstrcpyn(path, ret, path_count); 00154 return true; 00155 } else 00156 return false; 00157 } 00158 00159 00160 // get full path of a shell folder 00161 bool ShellDirectory::get_path(PTSTR path, size_t path_count) const 00162 { 00163 CONTEXT("ShellDirectory::get_path()"); 00164 00165 if (!path || path_count==0) 00166 return false; 00167 00168 path[0] = TEXT('\0'); 00169 00170 if (_folder.empty()) 00171 return false; 00172 00173 SFGAOF attribs = SFGAO_FILESYSTEM; 00174 00175 // Split pidl into current and parent folder PIDLs 00176 ShellPath pidlParent, pidlFolder; 00177 _pidl.split(pidlParent, pidlFolder); 00178 00179 if (FAILED(const_cast<ShellFolder&>(_folder)->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlFolder, &attribs))) 00180 return false; 00181 00182 if (!(attribs & SFGAO_FILESYSTEM)) 00183 return false; 00184 00185 if (FAILED(path_from_pidl(get_parent_folder(), &*_pidl, path, path_count))) 00186 return false; 00187 00188 return true; 00189 } 00190 00191 00192 BOOL ShellEntry::launch_entry(HWND hwnd, UINT nCmdShow) 00193 { 00194 CONTEXT("ShellEntry::launch_entry()"); 00195 00196 SHELLEXECUTEINFO shexinfo; 00197 00198 shexinfo.cbSize = sizeof(SHELLEXECUTEINFO); 00199 shexinfo.fMask = SEE_MASK_INVOKEIDLIST; // SEE_MASK_IDLIST is also possible. 00200 shexinfo.hwnd = hwnd; 00201 shexinfo.lpVerb = NULL; 00202 shexinfo.lpFile = NULL; 00203 shexinfo.lpParameters = NULL; 00204 shexinfo.lpDirectory = NULL; 00205 shexinfo.nShow = nCmdShow; 00206 00207 ShellPath shell_path = create_absolute_pidl(); 00208 shexinfo.lpIDList = &*shell_path; 00209 00210 // add PIDL to the recent file list 00211 SHAddToRecentDocs(SHARD_PIDL, shexinfo.lpIDList); 00212 00213 BOOL ret = TRUE; 00214 00215 if (!ShellExecuteEx(&shexinfo)) { 00216 display_error(hwnd, GetLastError()); 00217 ret = FALSE; 00218 } 00219 00220 return ret; 00221 } 00222 00223 00224 HRESULT ShellEntry::do_context_menu(HWND hwnd, const POINT& pptScreen, CtxMenuInterfaces& cm_ifs) 00225 { 00226 ShellDirectory* dir = static_cast<ShellDirectory*>(_up); 00227 00228 ShellFolder folder = dir? dir->_folder: GetDesktopFolder(); 00229 LPCITEMIDLIST pidl = _pidl; 00230 00231 return ShellFolderContextMenu(folder, hwnd, 1, &pidl, pptScreen.x, pptScreen.y, cm_ifs); 00232 } 00233 00234 00235 HRESULT ShellEntry::GetUIObjectOf(HWND hWnd, REFIID riid, LPVOID* ppvOut) 00236 { 00237 LPCITEMIDLIST pidl = _pidl; 00238 00239 return get_parent_folder()->GetUIObjectOf(hWnd, 1, &pidl, riid, NULL, ppvOut); 00240 } 00241 00242 00243 ShellFolder Entry::get_shell_folder() const 00244 { 00245 return ShellFolder(create_absolute_pidl()); 00246 } 00247 00248 ShellFolder ShellEntry::get_shell_folder() const 00249 { 00250 return get_parent_folder(); 00251 } 00252 00253 ShellFolder ShellDirectory::get_shell_folder() const 00254 { 00255 return _folder; 00256 } 00257 00258 00259 void ShellDirectory::read_directory(int scan_flags) 00260 { 00261 CONTEXT("ShellDirectory::read_directory()"); 00262 00263 int level = _level + 1; 00264 00265 Entry* first_entry = NULL; 00266 Entry* last = NULL; 00267 00268 /*if (_folder.empty()) 00269 return;*/ 00270 00271 #ifndef _NO_WIN_FS 00272 TCHAR buffer[_MAX_PATH+_MAX_FNAME]; 00273 00274 if (!(scan_flags&SCAN_NO_FILESYSTEM) && get_path(buffer, COUNTOF(buffer)) && _tcsncmp(buffer,TEXT("::{"),3)) { 00275 Entry* entry = NULL; // eliminate useless GCC warning by initializing entry 00276 00277 LPTSTR p = buffer + _tcslen(buffer); 00278 00279 lstrcpy(p, TEXT("\\*")); 00280 00281 WIN32_FIND_DATA w32fd; 00282 HANDLE hFind = FindFirstFile(buffer, &w32fd); 00283 00284 if (hFind != INVALID_HANDLE_VALUE) { 00285 do { 00286 // ignore hidden files (usefull in the start menu) 00287 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 00288 continue; 00289 00290 // ignore directory entries "." and ".." 00291 if ((w32fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && 00292 w32fd.cFileName[0]==TEXT('.') && 00293 (w32fd.cFileName[1]==TEXT('\0') || 00294 (w32fd.cFileName[1]==TEXT('.') && w32fd.cFileName[2]==TEXT('\0')))) 00295 continue; 00296 00297 lstrcpy(p+1, w32fd.cFileName); 00298 00299 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00300 entry = new WinDirectory(this, buffer); 00301 else 00302 entry = new WinEntry(this); 00303 00304 if (!first_entry) 00305 first_entry = entry; 00306 00307 if (last) 00308 last->_next = entry; 00309 00310 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA)); 00311 00312 entry->_level = level; 00313 00314 if (!(scan_flags & SCAN_DONT_ACCESS)) { 00315 HANDLE hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 00316 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); 00317 00318 if (hFile != INVALID_HANDLE_VALUE) { 00319 if (GetFileInformationByHandle(hFile, &entry->_bhfi)) 00320 entry->_bhfi_valid = true; 00321 00322 if (ScanNTFSStreams(entry, hFile)) 00323 entry->_scanned = true; // There exist named NTFS sub-streams in this file. 00324 00325 CloseHandle(hFile); 00326 } 00327 } 00328 00329 // set file type name 00330 LPCTSTR ext = g_Globals._ftype_mgr.set_type(entry); 00331 00332 DWORD attribs = SFGAO_FILESYSTEM; 00333 00334 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00335 attribs |= SFGAO_FOLDER|SFGAO_HASSUBFOLDER; 00336 00337 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) 00338 attribs |= SFGAO_READONLY; 00339 00340 //if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 00341 // attribs |= SFGAO_HIDDEN; 00342 00343 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) 00344 attribs |= SFGAO_COMPRESSED; 00345 00346 if (ext && !_tcsicmp(ext, _T(".lnk"))) { 00347 attribs |= SFGAO_LINK; 00348 w32fd.dwFileAttributes |= ATTRIBUTE_SYMBOLIC_LINK; 00349 } 00350 00351 entry->_shell_attribs = attribs; 00352 00353 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00354 entry->_icon_id = ICID_FOLDER; 00355 else if (!(scan_flags & SCAN_DONT_EXTRACT_ICONS)) 00356 entry->_icon_id = entry->safe_extract_icon(); // Assume small icon, we can extract the large icon later on demand. 00357 00358 last = entry; 00359 } while(FindNextFile(hFind, &w32fd)); 00360 00361 FindClose(hFind); 00362 } 00363 } 00364 else // SCAN_NO_FILESYSTEM 00365 #endif 00366 { 00367 ShellItemEnumerator enumerator(_folder, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE); 00368 00369 TCHAR name[MAX_PATH]; 00370 TCHAR path[MAX_PATH]; 00371 HRESULT hr_next = S_OK; 00372 00373 do { 00374 #define FETCH_ITEM_COUNT 32 00375 LPITEMIDLIST pidls[FETCH_ITEM_COUNT]; 00376 ULONG cnt = 0; 00377 00378 memset(pidls, 0, sizeof(pidls)); 00379 00380 hr_next = enumerator->Next(FETCH_ITEM_COUNT, pidls, &cnt); 00381 00382 /* don't break yet now: Registry Explorer Plugin returns E_FAIL! 00383 if (!SUCCEEDED(hr_next)) 00384 break; */ 00385 00386 if (hr_next == S_FALSE) 00387 break; 00388 00389 for(ULONG n=0; n<cnt; ++n) { 00390 WIN32_FIND_DATA w32fd; 00391 BY_HANDLE_FILE_INFORMATION bhfi; 00392 bool bhfi_valid = false; 00393 00394 memset(&w32fd, 0, sizeof(WIN32_FIND_DATA)); 00395 00396 SFGAOF attribs_before = ~SFGAO_READONLY & ~SFGAO_VALIDATE; 00397 SFGAOF attribs = attribs_before; 00398 HRESULT hr = _folder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs); 00399 bool removeable = false; 00400 00401 if (SUCCEEDED(hr) && attribs!=attribs_before) { 00402 // avoid accessing floppy drives when browsing "My Computer" 00403 if (attribs & SFGAO_REMOVABLE) { 00404 attribs |= SFGAO_HASSUBFOLDER; 00405 removeable = true; 00406 } else if (!(scan_flags & SCAN_DONT_ACCESS)) { 00407 SFGAOF attribs2 = SFGAO_READONLY; 00408 00409 HRESULT hr = _folder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs2); 00410 00411 if (SUCCEEDED(hr)) 00412 attribs |= attribs2; 00413 } 00414 } else 00415 attribs = 0; 00416 00417 bhfi_valid = fill_w32fdata_shell(pidls[n], attribs, &w32fd, &bhfi, 00418 !(scan_flags&SCAN_DONT_ACCESS) && !removeable); 00419 00420 try { 00421 Entry* entry = NULL; // eliminate useless GCC warning by initializing entry 00422 00423 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00424 entry = new ShellDirectory(this, pidls[n], _hwnd); 00425 else 00426 entry = new ShellEntry(this, pidls[n]); 00427 00428 if (!first_entry) 00429 first_entry = entry; 00430 00431 if (last) 00432 last->_next = entry; 00433 00434 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA)); 00435 00436 if (bhfi_valid) 00437 memcpy(&entry->_bhfi, &bhfi, sizeof(BY_HANDLE_FILE_INFORMATION)); 00438 00439 // store path in entry->_data.cFileName in case fill_w32fdata_shell() didn't already fill it 00440 if (!entry->_data.cFileName[0]) 00441 if (SUCCEEDED(path_from_pidl(_folder, pidls[n], path, COUNTOF(path)))) 00442 _tcscpy(entry->_data.cFileName, path); 00443 00444 if (SUCCEEDED(name_from_pidl(_folder, pidls[n], name, COUNTOF(name), SHGDN_INFOLDER|0x2000/*0x2000=SHGDN_INCLUDE_NONFILESYS*/))) { 00445 if (!entry->_data.cFileName[0]) 00446 _tcscpy(entry->_data.cFileName, name); 00447 else if (_tcscmp(entry->_display_name, name)) 00448 entry->_display_name = _tcsdup(name); // store display name separate from file name; sort display by file name 00449 } 00450 00451 if (attribs & SFGAO_LINK) 00452 w32fd.dwFileAttributes |= ATTRIBUTE_SYMBOLIC_LINK; 00453 00454 entry->_level = level; 00455 entry->_shell_attribs = attribs; 00456 entry->_bhfi_valid = bhfi_valid; 00457 00458 // set file type name 00459 g_Globals._ftype_mgr.set_type(entry); 00460 00461 // get icons for files and virtual objects 00462 if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || 00463 !(attribs & SFGAO_FILESYSTEM)) { 00464 if (!(scan_flags & SCAN_DONT_EXTRACT_ICONS)) 00465 entry->_icon_id = entry->safe_extract_icon(); // Assume small icon, we can extract the large icon later on demand. 00466 } else if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00467 entry->_icon_id = ICID_FOLDER; 00468 else 00469 entry->_icon_id = ICID_NONE; // don't try again later 00470 00471 last = entry; 00472 } catch(COMException& e) { 00473 HandleException(e, _hwnd); 00474 } 00475 } 00476 } while(SUCCEEDED(hr_next)); 00477 } 00478 00479 if (last) 00480 last->_next = NULL; 00481 00482 _down = first_entry; 00483 _scanned = true; 00484 } 00485 00486 const void* ShellDirectory::get_next_path_component(const void* p) const 00487 { 00488 LPITEMIDLIST pidl = (LPITEMIDLIST)p; 00489 00490 if (!pidl || !pidl->mkid.cb) 00491 return NULL; 00492 00493 // go to next element 00494 pidl = (LPITEMIDLIST)((LPBYTE)pidl+pidl->mkid.cb); 00495 00496 return pidl; 00497 } 00498 00499 Entry* ShellDirectory::find_entry(const void* p) 00500 { 00501 LPITEMIDLIST pidl = (LPITEMIDLIST) p; 00502 00503 // handle special case of empty trailing id list entry 00504 if (!pidl->mkid.cb) 00505 return this; 00506 00507 for(Entry*entry=_down; entry; entry=entry->_next) 00508 if (entry->_etype == ET_SHELL) { 00509 ShellEntry* se = static_cast<ShellEntry*>(entry); 00510 00511 if (se->_pidl && se->_pidl->mkid.cb==pidl->mkid.cb && !memcmp(se->_pidl, pidl, se->_pidl->mkid.cb)) 00512 return entry; 00513 } else { 00514 const ShellPath& sp = entry->create_absolute_pidl(); 00515 static DynamicFct<LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST)> ILFindLastID(TEXT("SHELL32"), "ILFindLastID"); 00516 00517 if (ILFindLastID) { 00518 LPCITEMIDLIST entry_pidl = (*ILFindLastID)(sp); 00519 00520 if (entry_pidl && entry_pidl->mkid.cb==pidl->mkid.cb && !memcmp(entry_pidl, pidl, entry_pidl->mkid.cb)) 00521 return entry; 00522 } 00523 } 00524 00525 return NULL; 00526 } 00527 00528 int ShellDirectory::extract_icons(ICONCACHE_FLAGS flags) 00529 { 00530 int cnt = 0; 00531 00532 for(Entry*entry=_down; entry; entry=entry->_next) 00533 if (entry->_icon_id == ICID_UNKNOWN) { 00534 entry->_icon_id = entry->extract_icon(flags); 00535 00536 if (entry->_icon_id != ICID_NONE) 00537 ++cnt; 00538 } 00539 00540 return cnt; 00541 } Generated on Mon May 28 2012 04:18:20 for ReactOS by
1.7.6.1
|