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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 if (FAILED(const_cast<ShellFolder&>(_folder)->GetAttributesOf(1, (LPCITEMIDLIST*)&_pidl, &attribs))) 00176 return false; 00177 00178 if (!(attribs & SFGAO_FILESYSTEM)) 00179 return false; 00180 00181 if (FAILED(path_from_pidl(get_parent_folder(), &*_pidl, path, path_count))) 00182 return false; 00183 00184 return true; 00185 } 00186 00187 00188 BOOL ShellEntry::launch_entry(HWND hwnd, UINT nCmdShow) 00189 { 00190 CONTEXT("ShellEntry::launch_entry()"); 00191 00192 SHELLEXECUTEINFO shexinfo; 00193 00194 shexinfo.cbSize = sizeof(SHELLEXECUTEINFO); 00195 shexinfo.fMask = SEE_MASK_INVOKEIDLIST; // SEE_MASK_IDLIST is also possible. 00196 shexinfo.hwnd = hwnd; 00197 shexinfo.lpVerb = NULL; 00198 shexinfo.lpFile = NULL; 00199 shexinfo.lpParameters = NULL; 00200 shexinfo.lpDirectory = NULL; 00201 shexinfo.nShow = nCmdShow; 00202 00203 ShellPath shell_path = create_absolute_pidl(); 00204 shexinfo.lpIDList = &*shell_path; 00205 00206 // add PIDL to the recent file list 00207 SHAddToRecentDocs(SHARD_PIDL, shexinfo.lpIDList); 00208 00209 BOOL ret = TRUE; 00210 00211 if (!ShellExecuteEx(&shexinfo)) { 00212 display_error(hwnd, GetLastError()); 00213 ret = FALSE; 00214 } 00215 00216 return ret; 00217 } 00218 00219 00220 HRESULT ShellEntry::do_context_menu(HWND hwnd, LPPOINT pptScreen, CtxMenuInterfaces& cm_ifs) 00221 { 00222 ShellDirectory* dir = static_cast<ShellDirectory*>(_up); 00223 00224 ShellFolder folder = dir? dir->_folder: GetDesktopFolder(); 00225 LPCITEMIDLIST pidl = _pidl; 00226 00227 return ShellFolderContextMenu(folder, hwnd, 1, &pidl, pptScreen->x, pptScreen->y, cm_ifs); 00228 } 00229 00230 00231 HRESULT ShellEntry::GetUIObjectOf(HWND hWnd, REFIID riid, LPVOID* ppvOut) 00232 { 00233 LPCITEMIDLIST pidl = _pidl; 00234 00235 return get_parent_folder()->GetUIObjectOf(hWnd, 1, &pidl, riid, NULL, ppvOut); 00236 } 00237 00238 00239 ShellFolder Entry::get_shell_folder() const 00240 { 00241 return ShellFolder(create_absolute_pidl()); 00242 } 00243 00244 ShellFolder ShellEntry::get_shell_folder() const 00245 { 00246 return get_parent_folder(); 00247 } 00248 00249 ShellFolder ShellDirectory::get_shell_folder() const 00250 { 00251 return _folder; 00252 } 00253 00254 00255 void ShellDirectory::read_directory(int scan_flags) 00256 { 00257 CONTEXT("ShellDirectory::read_directory()"); 00258 00259 int level = _level + 1; 00260 00261 Entry* first_entry = NULL; 00262 Entry* last = NULL; 00263 00264 /*if (_folder.empty()) 00265 return;*/ 00266 00267 #ifndef _NO_WIN_FS 00268 TCHAR buffer[_MAX_PATH+_MAX_FNAME]; 00269 00270 if (!(scan_flags&SCAN_NO_FILESYSTEM) && get_path(buffer, COUNTOF(buffer)) && _tcsncmp(buffer,TEXT("::{"),3)) { 00271 Entry* entry = NULL; // eliminate useless GCC warning by initializing entry 00272 00273 LPTSTR p = buffer + _tcslen(buffer); 00274 00275 lstrcpy(p, TEXT("\\*")); 00276 00277 WIN32_FIND_DATA w32fd; 00278 HANDLE hFind = FindFirstFile(buffer, &w32fd); 00279 00280 if (hFind != INVALID_HANDLE_VALUE) { 00281 do { 00282 // ignore hidden files (usefull in the start menu) 00283 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 00284 continue; 00285 00286 // ignore directory entries "." and ".." 00287 if ((w32fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && 00288 w32fd.cFileName[0]==TEXT('.') && 00289 (w32fd.cFileName[1]==TEXT('\0') || 00290 (w32fd.cFileName[1]==TEXT('.') && w32fd.cFileName[2]==TEXT('\0')))) 00291 continue; 00292 00293 lstrcpy(p+1, w32fd.cFileName); 00294 00295 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00296 entry = new WinDirectory(this, buffer); 00297 else 00298 entry = new WinEntry(this); 00299 00300 if (!first_entry) 00301 first_entry = entry; 00302 00303 if (last) 00304 last->_next = entry; 00305 00306 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA)); 00307 00308 entry->_level = level; 00309 00310 if (!(scan_flags & SCAN_DONT_ACCESS)) { 00311 HANDLE hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 00312 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); 00313 00314 if (hFile != INVALID_HANDLE_VALUE) { 00315 if (GetFileInformationByHandle(hFile, &entry->_bhfi)) 00316 entry->_bhfi_valid = true; 00317 00318 if (ScanNTFSStreams(entry, hFile)) 00319 entry->_scanned = true; // There exist named NTFS sub-streams in this file. 00320 00321 CloseHandle(hFile); 00322 } 00323 } 00324 00325 // set file type name 00326 LPCTSTR ext = g_Globals._ftype_mgr.set_type(entry); 00327 00328 DWORD attribs = SFGAO_FILESYSTEM; 00329 00330 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00331 attribs |= SFGAO_FOLDER|SFGAO_HASSUBFOLDER; 00332 00333 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) 00334 attribs |= SFGAO_READONLY; 00335 00336 //if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 00337 // attribs |= SFGAO_HIDDEN; 00338 00339 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) 00340 attribs |= SFGAO_COMPRESSED; 00341 00342 if (ext && !_tcsicmp(ext, _T(".lnk"))) { 00343 attribs |= SFGAO_LINK; 00344 w32fd.dwFileAttributes |= ATTRIBUTE_SYMBOLIC_LINK; 00345 } 00346 00347 entry->_shell_attribs = attribs; 00348 00349 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00350 entry->_icon_id = ICID_FOLDER; 00351 else if (!(scan_flags & SCAN_DONT_EXTRACT_ICONS)) 00352 entry->_icon_id = entry->safe_extract_icon(); // Assume small icon, we can extract the large icon later on demand. 00353 00354 last = entry; 00355 } while(FindNextFile(hFind, &w32fd)); 00356 00357 FindClose(hFind); 00358 } 00359 } 00360 else // SCAN_NO_FILESYSTEM 00361 #endif 00362 { 00363 ShellItemEnumerator enumerator(_folder, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE); 00364 00365 TCHAR name[MAX_PATH]; 00366 TCHAR path[MAX_PATH]; 00367 HRESULT hr_next = S_OK; 00368 00369 if (enumerator) 00370 do { 00371 #define FETCH_ITEM_COUNT 32 00372 LPITEMIDLIST pidls[FETCH_ITEM_COUNT]; 00373 ULONG cnt = 0; 00374 00375 memset(pidls, 0, sizeof(pidls)); 00376 00377 hr_next = enumerator->Next(FETCH_ITEM_COUNT, pidls, &cnt); 00378 00379 /* don't break yet now: Registry Explorer Plugin returns E_FAIL! 00380 if (!SUCCEEDED(hr_next)) 00381 break; */ 00382 00383 if (hr_next == S_FALSE) 00384 break; 00385 00386 for(ULONG n=0; n<cnt; ++n) { 00387 WIN32_FIND_DATA w32fd; 00388 BY_HANDLE_FILE_INFORMATION bhfi; 00389 bool bhfi_valid = false; 00390 00391 memset(&w32fd, 0, sizeof(WIN32_FIND_DATA)); 00392 00393 SFGAOF attribs_before = ~SFGAO_READONLY & ~SFGAO_VALIDATE; 00394 SFGAOF attribs = attribs_before; 00395 HRESULT hr = _folder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs); 00396 bool removeable = false; 00397 00398 if (SUCCEEDED(hr) && attribs!=attribs_before) { 00399 // avoid accessing floppy drives when browsing "My Computer" 00400 if (attribs & SFGAO_REMOVABLE) { 00401 attribs |= SFGAO_HASSUBFOLDER; 00402 removeable = true; 00403 } else if (!(scan_flags & SCAN_DONT_ACCESS)) { 00404 SFGAOF attribs2 = SFGAO_READONLY; 00405 00406 HRESULT hr = _folder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs2); 00407 00408 if (SUCCEEDED(hr)) 00409 attribs |= attribs2; 00410 } 00411 } else 00412 attribs = 0; 00413 00414 bhfi_valid = fill_w32fdata_shell(pidls[n], attribs, &w32fd, &bhfi, 00415 !(scan_flags&SCAN_DONT_ACCESS) && !removeable); 00416 00417 try { 00418 Entry* entry = NULL; // eliminate useless GCC warning by initializing entry 00419 00420 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00421 entry = new ShellDirectory(this, pidls[n], _hwnd); 00422 else 00423 entry = new ShellEntry(this, pidls[n]); 00424 00425 if (!first_entry) 00426 first_entry = entry; 00427 00428 if (last) 00429 last->_next = entry; 00430 00431 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA)); 00432 00433 if (bhfi_valid) 00434 memcpy(&entry->_bhfi, &bhfi, sizeof(BY_HANDLE_FILE_INFORMATION)); 00435 00436 // store path in entry->_data.cFileName in case fill_w32fdata_shell() didn't already fill it 00437 if (!entry->_data.cFileName[0]) 00438 if (SUCCEEDED(path_from_pidl(_folder, pidls[n], path, COUNTOF(path)))) 00439 _tcscpy(entry->_data.cFileName, path); 00440 00441 if (SUCCEEDED(name_from_pidl(_folder, pidls[n], name, COUNTOF(name), SHGDN_INFOLDER|0x2000/*0x2000=SHGDN_INCLUDE_NONFILESYS*/))) { 00442 if (!entry->_data.cFileName[0]) 00443 _tcscpy(entry->_data.cFileName, name); 00444 else if (_tcscmp(entry->_display_name, name)) 00445 entry->_display_name = _tcsdup(name); // store display name separate from file name; sort display by file name 00446 } 00447 00448 if (attribs & SFGAO_LINK) 00449 w32fd.dwFileAttributes |= ATTRIBUTE_SYMBOLIC_LINK; 00450 00451 entry->_level = level; 00452 entry->_shell_attribs = attribs; 00453 entry->_bhfi_valid = bhfi_valid; 00454 00455 // set file type name 00456 g_Globals._ftype_mgr.set_type(entry); 00457 00458 // get icons for files and virtual objects 00459 if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || 00460 !(attribs & SFGAO_FILESYSTEM)) { 00461 if (!(scan_flags & SCAN_DONT_EXTRACT_ICONS)) 00462 entry->_icon_id = entry->safe_extract_icon(); // Assume small icon, we can extract the large icon later on demand. 00463 } else if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00464 entry->_icon_id = ICID_FOLDER; 00465 else 00466 entry->_icon_id = ICID_NONE; // don't try again later 00467 00468 last = entry; 00469 } catch(COMException& e) { 00470 HandleException(e, _hwnd); 00471 } 00472 } 00473 } while(SUCCEEDED(hr_next)); 00474 } 00475 00476 if (last) 00477 last->_next = NULL; 00478 00479 _down = first_entry; 00480 _scanned = true; 00481 } 00482 00483 const void* ShellDirectory::get_next_path_component(const void* p) const 00484 { 00485 LPITEMIDLIST pidl = (LPITEMIDLIST)p; 00486 00487 if (!pidl || !pidl->mkid.cb) 00488 return NULL; 00489 00490 // go to next element 00491 pidl = (LPITEMIDLIST)((LPBYTE)pidl+pidl->mkid.cb); 00492 00493 return pidl; 00494 } 00495 00496 Entry* ShellDirectory::find_entry(const void* p) 00497 { 00498 LPITEMIDLIST pidl = (LPITEMIDLIST) p; 00499 00500 // handle special case of empty trailing id list entry 00501 if (!pidl->mkid.cb) 00502 return this; 00503 00504 for(Entry*entry=_down; entry; entry=entry->_next) 00505 if (entry->_etype == ET_SHELL) { 00506 ShellEntry* se = static_cast<ShellEntry*>(entry); 00507 00508 if (se->_pidl && se->_pidl->mkid.cb==pidl->mkid.cb && !memcmp(se->_pidl, pidl, se->_pidl->mkid.cb)) 00509 return entry; 00510 } else { 00511 const ShellPath& sp = entry->create_absolute_pidl(); 00512 static DynamicFct<LPITEMIDLIST(WINAPI*)(LPCITEMIDLIST)> ILFindLastID(TEXT("SHELL32"), "ILFindLastID"); 00513 00514 if (ILFindLastID) { 00515 LPCITEMIDLIST entry_pidl = (*ILFindLastID)(sp); 00516 00517 if (entry_pidl && entry_pidl->mkid.cb==pidl->mkid.cb && !memcmp(entry_pidl, pidl, entry_pidl->mkid.cb)) 00518 return entry; 00519 } 00520 } 00521 00522 return NULL; 00523 } 00524 00525 int ShellDirectory::extract_icons(ICONCACHE_FLAGS flags) 00526 { 00527 int cnt = 0; 00528 00529 for(Entry*entry=_down; entry; entry=entry->_next) 00530 if (entry->_icon_id == ICID_UNKNOWN) { 00531 entry->_icon_id = entry->extract_icon(flags); 00532 00533 if (entry->_icon_id != ICID_NONE) 00534 ++cnt; 00535 } 00536 00537 return cnt; 00538 }
ROS Explorer Source Code Documentation
generated on 02.01.2013 by ![]() |