ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

shellfs.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.