From 398b10102e725923b08d1a463a37731e79fcf695 Mon Sep 17 00:00:00 2001 From: Martin Fuchs Date: Sat, 3 Jan 2004 18:27:54 +0000 Subject: [PATCH] direct file system access for start menu svn path=/trunk/; revision=7424 --- .../system/explorer/dialogs/searchprogram.cpp | 103 ++--- .../system/explorer/dialogs/searchprogram.h | 6 +- .../subsys/system/explorer/doc/changes.txt | 1 + reactos/subsys/system/explorer/explorer.dsp | 12 +- .../subsys/system/explorer/shell/entries.cpp | 19 +- .../subsys/system/explorer/shell/entries.h | 19 +- reactos/subsys/system/explorer/shell/pane.cpp | 14 +- .../system/explorer/shell/shellbrowser.cpp | 37 +- .../subsys/system/explorer/shell/shellfs.cpp | 364 +++++++++++++----- .../subsys/system/explorer/shell/shellfs.h | 29 +- .../subsys/system/explorer/shell/winfs.cpp | 95 +++-- reactos/subsys/system/explorer/shell/winfs.h | 14 +- .../system/explorer/taskbar/quicklaunch.cpp | 13 +- .../system/explorer/taskbar/quicklaunch.h | 2 +- .../system/explorer/taskbar/startmenu.cpp | 184 ++++++--- .../system/explorer/taskbar/startmenu.h | 13 +- 16 files changed, 615 insertions(+), 310 deletions(-) diff --git a/reactos/subsys/system/explorer/dialogs/searchprogram.cpp b/reactos/subsys/system/explorer/dialogs/searchprogram.cpp index 798c8838bdd..9989ea60891 100644 --- a/reactos/subsys/system/explorer/dialogs/searchprogram.cpp +++ b/reactos/subsys/system/explorer/dialogs/searchprogram.cpp @@ -60,7 +60,7 @@ void CollectProgramsThread::collect_programs(const ShellPath& path) ShellDirectory* dir = new ShellDirectory(Desktop(), path, 0); _dirs.push(dir); - dir->smart_scan(); + dir->smart_scan(SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM); for(Entry*entry=dir->_down; entry; entry=entry->_next) { if (!_alive) @@ -69,13 +69,14 @@ void CollectProgramsThread::collect_programs(const ShellPath& path) if (entry->_shell_attribs & SFGAO_HIDDEN) continue; - ShellEntry* shell_entry = static_cast(entry); + if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + ShellPath shell_path; - if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - collect_programs(shell_entry->create_absolute_pidl()); - else if (entry->_shell_attribs & SFGAO_LINK) + if (get_entry_pidl(entry, shell_path)) + collect_programs(shell_path); + } else if (entry->_shell_attribs & SFGAO_LINK) if (_alive) - _callback(dir->_folder, shell_entry, _para); + _callback(entry, _para); } } @@ -172,56 +173,70 @@ void FindProgramDlg::Refresh(bool delete_cache) } } -void FindProgramDlg::collect_programs_callback(ShellFolder& folder, ShellEntry* shell_entry, void* param) +void FindProgramDlg::collect_programs_callback(Entry* entry, void* param) { FindProgramDlg* pThis = (FindProgramDlg*) param; - LPCITEMIDLIST pidl = shell_entry->_pidl; + ShellPath shell_path; + + if (!get_entry_pidl(entry, shell_path)) + return; IShellLink* pShellLink; - HRESULT hr = folder->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (LPVOID*)&pShellLink); + LPCITEMIDLIST pidl_last = NULL; + IShellFolder* pFolder; + + HRESULT hr = SHBindToParent(shell_path, IID_IShellFolder, (LPVOID*)&pFolder, &pidl_last); + if (SUCCEEDED(hr)) { - ShellLinkPtr shell_link(pShellLink); + hr = pFolder->GetUIObjectOf(pThis->_hwnd, 1, &pidl_last, IID_IShellLink, NULL, (LPVOID*)&pShellLink); - /*hr = pShellLink->Resolve(pThis->_hwnd, SLR_NO_UI); - if (SUCCEEDED(hr))*/ { - WIN32_FIND_DATA wfd; - TCHAR path[MAX_PATH]; + if (SUCCEEDED(hr)) { + ShellLinkPtr shell_link(pShellLink); - hr = pShellLink->GetPath(path, MAX_PATH-1, &wfd, SLGP_UNCPRIORITY); + /*hr = pShellLink->Resolve(pThis->_hwnd, SLR_NO_UI); + if (SUCCEEDED(hr))*/ { + WIN32_FIND_DATA wfd; + TCHAR path[MAX_PATH]; - if (SUCCEEDED(hr)) { - FileSysShellPath entry_path(shell_entry->create_absolute_pidl()); - String menu_path; + hr = pShellLink->GetPath(path, MAX_PATH-1, &wfd, SLGP_UNCPRIORITY); - int len = pThis->_common_programs.size(); + if (SUCCEEDED(hr)) { + TCHAR entry_path[MAX_PATH]; - if (len && !_tcsnicmp(entry_path, pThis->_common_programs, len)) - menu_path = ResString(IDS_ALL_USERS) + (String(entry_path)+len); - else if ((len=pThis->_user_programs.size()) && !_tcsnicmp(entry_path, pThis->_user_programs, len)) - menu_path = String(entry_path)+len; + entry->get_path(entry_path); - // store info in cache - FPDEntry new_entry; + String menu_path; - new_entry._shell_entry = shell_entry; - new_entry._menu_path = menu_path; - new_entry._path = path; + int len = pThis->_common_programs.size(); - if (shell_entry->_hIcon != (HICON)-1) - new_entry._idxIcon = ImageList_AddIcon(pThis->_himl, shell_entry->_hIcon); - else - new_entry._idxIcon = pThis->_idxNoIcon; + if (len && !_tcsnicmp(entry_path, pThis->_common_programs, len)) + menu_path = ResString(IDS_ALL_USERS) + (String(entry_path)+len); + else if ((len=pThis->_user_programs.size()) && !_tcsnicmp(entry_path, pThis->_user_programs, len)) + menu_path = String(entry_path)+len; - pThis->_cache.push_front(new_entry); - FPDEntry& cache_entry = pThis->_cache.front(); + // store info in cache + FPDEntry new_entry; - Lock lock(pThis->_thread._crit_sect); + new_entry._entry = entry; + new_entry._menu_path = menu_path; + new_entry._path = path; - // resolve deadlocks while executing Thread::Stop() - if (!pThis->_thread.is_alive()) - return; + if (entry->_hIcon != (HICON)-1) + new_entry._idxIcon = ImageList_AddIcon(pThis->_himl, entry->_hIcon); + else + new_entry._idxIcon = pThis->_idxNoIcon; - pThis->add_entry(cache_entry); + pThis->_cache.push_front(new_entry); + FPDEntry& cache_entry = pThis->_cache.front(); + + Lock lock(pThis->_thread._crit_sect); + + // resolve deadlocks while executing Thread::Stop() + if (!pThis->_thread.is_alive()) + return; + + pThis->add_entry(cache_entry); + } } } } @@ -230,7 +245,7 @@ void FindProgramDlg::collect_programs_callback(ShellFolder& folder, ShellEntry* void FindProgramDlg::add_entry(const FPDEntry& cache_entry) { String lwr_path = cache_entry._path; - String lwr_name = cache_entry._shell_entry->_display_name; + String lwr_name = cache_entry._entry->_display_name; #ifndef __WINE__ ///@todo _tcslwr((LPTSTR)lwr_path.c_str()); @@ -246,7 +261,7 @@ void FindProgramDlg::add_entry(const FPDEntry& cache_entry) LV_ITEM item = {LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, INT_MAX}; - item.pszText = cache_entry._shell_entry->_display_name; + item.pszText = cache_entry._entry->_display_name; item.iImage = cache_entry._idxIcon; item.lParam = (LPARAM) &cache_entry; item.iItem = ListView_InsertItem(_list_ctrl, &item); // We could use the information in _sort to enable manual sorting while populating the list. @@ -297,7 +312,7 @@ void FindProgramDlg::LaunchSelected() if (lparam) { FPDEntry& cache_entry = *(FPDEntry*)lparam; - cache_entry._shell_entry->launch_entry(_hwnd); + cache_entry._entry->launch_entry(_hwnd); } } } @@ -334,7 +349,7 @@ int FindProgramDlg::Notify(int id, NMHDR* pnmh) if (lparam) { FPDEntry& cache_entry = *(FPDEntry*)lparam; - cache_entry._shell_entry->launch_entry(_hwnd); + cache_entry._entry->launch_entry(_hwnd); } }*/ break; @@ -366,7 +381,7 @@ int CALLBACK FindProgramDlg::CompareFunc(LPARAM lparam1, LPARAM lparam2, LPARAM switch(sort->_sort_crit) { case 0: - cmp = _tcsicoll(a._shell_entry->_display_name, b._shell_entry->_display_name); + cmp = _tcsicoll(a._entry->_display_name, b._entry->_display_name); break; case 1: diff --git a/reactos/subsys/system/explorer/dialogs/searchprogram.h b/reactos/subsys/system/explorer/dialogs/searchprogram.h index cabf8405c17..4ce15c8d68b 100644 --- a/reactos/subsys/system/explorer/dialogs/searchprogram.h +++ b/reactos/subsys/system/explorer/dialogs/searchprogram.h @@ -30,7 +30,7 @@ #include -typedef void (*COLLECT_CALLBACK)(ShellFolder& folder, ShellEntry* shell_entry, void* param); +typedef void (*COLLECT_CALLBACK)(Entry* entry, void* param); typedef stack ShellDirectoryStack; /// Thread for collecting start menu entries @@ -67,7 +67,7 @@ protected: /// entry for the list in "find program" dialogs struct FPDEntry { - ShellEntry* _shell_entry; + Entry* _entry; int _idxIcon; String _menu_path; String _path; @@ -106,6 +106,6 @@ protected: void add_entry(const FPDEntry& cache_entry); void LaunchSelected(); - static void collect_programs_callback(ShellFolder& folder, ShellEntry* entry, void* param); + static void collect_programs_callback(Entry* entry, void* param); static int CALLBACK CompareFunc(LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort); }; diff --git a/reactos/subsys/system/explorer/doc/changes.txt b/reactos/subsys/system/explorer/doc/changes.txt index 1a3276c263b..a47bc88eccc 100644 --- a/reactos/subsys/system/explorer/doc/changes.txt +++ b/reactos/subsys/system/explorer/doc/changes.txt @@ -52,3 +52,4 @@ If you search for more information, look into the CVS repository. 01.01.2004 m. fuchs integrated icons of Everaldo (http://www.everaldo.com) into the start menu. 02.01.2004 m. fuchs reimplemented start menu as light weight version 03.01.2004 m. fuchs lazy icon extraction for start menu + direct file system access for start menu diff --git a/reactos/subsys/system/explorer/explorer.dsp b/reactos/subsys/system/explorer/explorer.dsp index 9ffbceff7d7..2267aa54e57 100644 --- a/reactos/subsys/system/explorer/explorer.dsp +++ b/reactos/subsys/system/explorer/explorer.dsp @@ -57,7 +57,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 user32.lib gdi32.lib advapi32.lib ole32.lib shell32.lib comctl32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 shell32.lib comctl32.lib gdi32.lib user32.lib advapi32.lib ole32.lib /nologo /subsystem:windows /machine:I386 # SUBTRACT LINK32 /pdb:none /force !ELSEIF "$(CFG)" == "explorer - Win32 Debug" @@ -82,7 +82,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib ole32.lib shell32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib shell32.lib comctl32.lib gdi32.lib user32.lib advapi32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # SUBTRACT LINK32 /pdb:none /force !ELSEIF "$(CFG)" == "explorer - Win32 Debug Release" @@ -108,7 +108,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib comctl32.lib shell32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 user32.lib gdi32.lib advapi32.lib ole32.lib shell32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 +# ADD LINK32 shell32.lib comctl32.lib gdi32.lib user32.lib advapi32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 # SUBTRACT LINK32 /pdb:none /force !ELSEIF "$(CFG)" == "explorer - Win32 Unicode Release" @@ -134,7 +134,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib comctl32.lib shell32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 user32.lib gdi32.lib advapi32.lib ole32.lib shell32.lib comctl32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 shell32.lib comctl32.lib gdi32.lib user32.lib advapi32.lib ole32.lib /nologo /subsystem:windows /machine:I386 # SUBTRACT LINK32 /pdb:none /force !ELSEIF "$(CFG)" == "explorer - Win32 Unicode Debug" @@ -160,7 +160,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib comctl32.lib shell32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 user32.lib gdi32.lib advapi32.lib ole32.lib shell32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 shell32.lib comctl32.lib gdi32.lib user32.lib advapi32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # SUBTRACT LINK32 /pdb:none /force !ELSEIF "$(CFG)" == "explorer - Win32 _NO_COMUTIL" @@ -187,7 +187,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib comctl32.lib shell32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 user32.lib gdi32.lib advapi32.lib ole32.lib shell32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 shell32.lib comctl32.lib gdi32.lib user32.lib advapi32.lib ole32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # SUBTRACT LINK32 /pdb:none /force !ELSEIF "$(CFG)" == "explorer - Win32" diff --git a/reactos/subsys/system/explorer/shell/entries.cpp b/reactos/subsys/system/explorer/shell/entries.cpp index e3df78e0a53..25a113861d2 100644 --- a/reactos/subsys/system/explorer/shell/entries.cpp +++ b/reactos/subsys/system/explorer/shell/entries.cpp @@ -48,9 +48,9 @@ Entry::Entry(ENTRY_TYPE etype) _display_name = _data.cFileName; } -Entry::Entry(Entry* parent) +Entry::Entry(Entry* parent, ENTRY_TYPE etype) : _up(parent), - _etype(parent->_etype) + _etype(etype) { _next = NULL; _down = NULL; @@ -126,17 +126,17 @@ Entry* Entry::read_tree(const void* path, SORT_ORDER sortOrder) } -void Entry::read_directory(SORT_ORDER sortOrder, bool read_icons) +void Entry::read_directory(SORT_ORDER sortOrder, int scan_flags) { CONTEXT("Entry::read_directory(SORT_ORDER)"); // call into subclass - read_directory(read_icons); + read_directory(scan_flags); - if (g_Globals._prescan_nodes) { //@todo _prescan_nodes should not be used for filling the start menu. + if (g_Globals._prescan_nodes) { //@todo _prescan_nodes should not be used for reading the start menu. for(Entry*entry=_down; entry; entry=entry->_next) if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - entry->read_directory(read_icons); + entry->read_directory(scan_flags); entry->sort_directory(sortOrder); } } @@ -284,13 +284,13 @@ void Entry::sort_directory(SORT_ORDER sortOrder) } -void Entry::smart_scan(bool read_icons) +void Entry::smart_scan(int scan_flags) { CONTEXT("Entry::smart_scan()"); if (!_scanned) { free_subentries(); - read_directory(SORT_NAME, read_icons); // we could use IShellFolder2::GetDefaultColumn to determine sort order + read_directory(SORT_NAME, scan_flags); // we could use IShellFolder2::GetDefaultColumn to determine sort order } } @@ -299,7 +299,8 @@ BOOL Entry::launch_entry(HWND hwnd, UINT nCmdShow) { TCHAR cmd[MAX_PATH]; - get_path(cmd); + if (!get_path(cmd)) + return FALSE; // start program, open document... return launch_file(hwnd, cmd, nCmdShow); diff --git a/reactos/subsys/system/explorer/shell/entries.h b/reactos/subsys/system/explorer/shell/entries.h index f30a953f112..5fcd039638d 100644 --- a/reactos/subsys/system/explorer/shell/entries.h +++ b/reactos/subsys/system/explorer/shell/entries.h @@ -41,12 +41,21 @@ enum SORT_ORDER { SORT_DATE }; +enum SCAN_FLAGS { + SCAN_EXTRACT_ICONS = 1, + SCAN_DO_ACCESS = 2, + + SCAN_ALL = 3, + + SCAN_FILESYSTEM = 4 +}; + /// base of all file and directory entries struct Entry { protected: Entry(ENTRY_TYPE etype); - Entry(Entry* parent); + Entry(Entry* parent, ENTRY_TYPE etype); Entry(const Entry&); public: @@ -73,15 +82,15 @@ public: void free_subentries(); - void read_directory(SORT_ORDER sortOrder, bool read_icons=true); + void read_directory(SORT_ORDER sortOrder, int scan_flags=SCAN_ALL); Entry* read_tree(const void* path, SORT_ORDER sortOrder); void sort_directory(SORT_ORDER sortOrder); - void smart_scan(bool read_icons=true); + void smart_scan(int scan_flags=SCAN_ALL); - virtual void read_directory(bool read_icons=true) {} + virtual void read_directory(int scan_flags=SCAN_ALL) {} virtual const void* get_next_path_component(const void*) {return NULL;} virtual Entry* find_entry(const void*) {return NULL;} - virtual void get_path(PTSTR path) const = 0; + virtual bool get_path(PTSTR path) const = 0; virtual BOOL launch_entry(HWND hwnd, UINT nCmdShow=SW_SHOWNORMAL); }; diff --git a/reactos/subsys/system/explorer/shell/pane.cpp b/reactos/subsys/system/explorer/shell/pane.cpp index 69e9798af4f..4a700b1f7e9 100644 --- a/reactos/subsys/system/explorer/shell/pane.cpp +++ b/reactos/subsys/system/explorer/shell/pane.cpp @@ -501,14 +501,12 @@ void Pane::draw_item(LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol) if (cx > IMAGE_WIDTH) cx = IMAGE_WIDTH; - if (entry->_hIcon != (HICON)-1) { - if (entry->_hIcon) - DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, entry->_hIcon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL); - else - ImageList_DrawEx(_himl, img, dis->hDC, - img_pos, dis->rcItem.top, cx, - IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL); - } + if (entry->_hIcon && entry->_hIcon!=(HICON)-1) + DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, entry->_hIcon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL); + else + ImageList_DrawEx(_himl, img, dis->hDC, + img_pos, dis->rcItem.top, cx, + IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL); } } diff --git a/reactos/subsys/system/explorer/shell/shellbrowser.cpp b/reactos/subsys/system/explorer/shell/shellbrowser.cpp index 4ccae8b7431..7a5bc2469c2 100644 --- a/reactos/subsys/system/explorer/shell/shellbrowser.cpp +++ b/reactos/subsys/system/explorer/shell/shellbrowser.cpp @@ -211,11 +211,13 @@ void ShellBrowserChild::Tree_DoItemMenu(HWND hwndTreeView, HTREEITEM hItem, LPPO if (itemData) { Entry* entry = (Entry*)itemData; - ShellDirectory* dir = static_cast(entry->_up); - ShellFolder folder = dir? dir->_folder: Desktop(); - LPCITEMIDLIST pidl = static_cast(entry)->_pidl; + if (entry->_etype == ET_SHELL) { + ShellDirectory* dir = static_cast(entry->_up); + ShellFolder folder = dir? dir->_folder: Desktop(); + LPCITEMIDLIST pidl = static_cast(entry)->_pidl; - CHECKERROR(ShellFolderContextMenu(folder, ::GetParent(hwndTreeView), 1, &pidl, pptScreen->x, pptScreen->y)); + CHECKERROR(ShellFolderContextMenu(folder, ::GetParent(hwndTreeView), 1, &pidl, pptScreen->x, pptScreen->y)); + } } } @@ -341,19 +343,21 @@ void ShellBrowserChild::OnTreeItemSelected(int idCtrl, LPNMTREEVIEW pnmtv) _last_sel = pnmtv->itemNew.hItem; - IShellFolder* folder; + if (entry->_etype == ET_SHELL) { + IShellFolder* folder; - if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - folder = static_cast(entry)->_folder; - else - folder = entry->get_parent_folder(); + if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + folder = static_cast(entry)->_folder; + else + folder = entry->get_parent_folder(); - if (!folder) { - assert(folder); - return; + if (!folder) { + assert(folder); + return; + } + + UpdateFolderView(folder); } - - UpdateFolderView(folder); } void ShellBrowserChild::UpdateFolderView(IShellFolder* folder) @@ -456,8 +460,9 @@ HRESULT ShellBrowserChild::OnDefaultCommand(LPIDA pida) Entry* entry = parent->find_entry(pidl); if (entry && (entry->_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) - if (expand_folder(static_cast(entry))) - return S_OK; + if (entry->_etype == ET_SHELL) + if (expand_folder(static_cast(entry))) + return S_OK; } } } else { // no tree control diff --git a/reactos/subsys/system/explorer/shell/shellfs.cpp b/reactos/subsys/system/explorer/shell/shellfs.cpp index 00fe3f7053a..d56300f29b2 100644 --- a/reactos/subsys/system/explorer/shell/shellfs.cpp +++ b/reactos/subsys/system/explorer/shell/shellfs.cpp @@ -33,6 +33,9 @@ #include "entries.h" #include "shellfs.h" +#include "winfs.h" + +#include bool ShellDirectory::fill_w32fdata_shell(LPCITEMIDLIST pidl, SFGAOF attribs, WIN32_FIND_DATA* pw32fdata, BY_HANDLE_FILE_INFORMATION* pbhfi, bool do_access) @@ -60,7 +63,7 @@ bool ShellDirectory::fill_w32fdata_shell(LPCITEMIDLIST pidl, SFGAOF attribs, WIN LPCTSTR path = (LPCTSTR)GlobalLock(medium.UNION_MEMBER(hGlobal)); UINT sem_org = SetErrorMode(SEM_FAILCRITICALERRORS); - // fill out drive names "C:", ... + // fill with drive names "C:", ... _tcscpy(pw32fdata->cFileName, path); if (GetFileAttributesEx(path, GetFileExInfoStandard, &fad)) { @@ -111,41 +114,63 @@ ShellPath ShellEntry::create_absolute_pidl() const { CONTEXT("ShellEntry::create_absolute_pidl()"); - if (_up/* && _up->_etype==ET_SHELL*/) { - ShellDirectory* dir = static_cast(_up); + if (_up) + if (_up->_etype==ET_SHELL) { + ShellDirectory* dir = static_cast(_up); - if (dir->_pidl->mkid.cb) // Caching of absolute PIDLs could enhance performance. - return _pidl.create_absolute_pidl(dir->create_absolute_pidl()); - } + if (dir->_pidl->mkid.cb) // Caching of absolute PIDLs could enhance performance. + return _pidl.create_absolute_pidl(dir->create_absolute_pidl()); + } else { + ShellPath shell_path; + + if (get_entry_pidl(_up, shell_path)) + return _pidl.create_absolute_pidl(shell_path); + } return _pidl; } // get full path of a shell entry -void ShellEntry::get_path(PTSTR path) const +bool ShellEntry::get_path(PTSTR path) const { +/* path[0] = TEXT('\0'); - /*HRESULT hr = */path_from_pidl(get_parent_folder(), &*_pidl, path, MAX_PATH); + if (FAILED(path_from_pidl(get_parent_folder(), &*_pidl, path, MAX_PATH))) + return false; +*/ + FileSysShellPath fs_path(create_absolute_pidl()); + + if (!(LPCTSTR)fs_path) + return false; + + _tcscpy(path, fs_path); + + return true; } // get full path of a shell folder -void ShellDirectory::get_path(PTSTR path) const +bool ShellDirectory::get_path(PTSTR path) const { CONTEXT("ShellDirectory::get_path()"); path[0] = TEXT('\0'); SFGAOF attribs = 0; - HRESULT hr = S_OK; if (!_folder.empty()) - hr = const_cast(_folder)->GetAttributesOf(1, (LPCITEMIDLIST*)&_pidl, &attribs); + if (FAILED(const_cast(_folder)->GetAttributesOf(1, (LPCITEMIDLIST*)&_pidl, &attribs))) + return false; - if (SUCCEEDED(hr) && (attribs&SFGAO_FILESYSTEM)) - hr = path_from_pidl(get_parent_folder(), &*_pidl, path, MAX_PATH); + if (!(attribs & SFGAO_FILESYSTEM)) + return false; + + if (FAILED(path_from_pidl(get_parent_folder(), &*_pidl, path, MAX_PATH))) + return false; + + return true; } @@ -185,12 +210,12 @@ static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl) IExtractIcon* pExtract; if (SUCCEEDED(folder->GetUIObjectOf(0, 1, (LPCITEMIDLIST*)&pidl, IID_IExtractIcon, 0, (LPVOID*)&pExtract))) { - TCHAR path[_MAX_PATH]; + TCHAR path[MAX_PATH]; unsigned flags; HICON hIcon; int idx; - if (SUCCEEDED(pExtract->GetIconLocation(GIL_FORSHELL, path, _MAX_PATH, &idx, &flags))) { + if (SUCCEEDED(pExtract->GetIconLocation(GIL_FORSHELL, path, MAX_PATH, &idx, &flags))) { if (!(flags & GIL_NOTFILENAME)) { if (idx == -1) idx = 0; // special case for some control panel applications @@ -234,25 +259,48 @@ static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl) return 0; } -static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl, ShellEntry* entry) +static HICON extract_icon(IShellFolder* folder, const ShellEntry* entry) { - HICON hIcon = extract_icon(folder, pidl); + HICON hIcon = extract_icon(folder, entry->_pidl); if (!hIcon) { - ShellPath pidl_abs = static_cast(entry)->create_absolute_pidl(); - LPCITEMIDLIST pidl = pidl_abs; - SHFILEINFO sfi; + ShellPath pidl_abs = entry->create_absolute_pidl(); + LPCITEMIDLIST pidl = pidl_abs; + if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_ICON|SHGFI_SMALLICON)) - entry->_hIcon = sfi.hIcon; + hIcon = sfi.hIcon; } return hIcon; } +HICON extract_icon(const Entry* entry) +{ + if (entry->_etype == ET_SHELL) { + const ShellEntry* shell_entry = static_cast(entry); -void ShellDirectory::read_directory(bool read_icons) + return extract_icon(shell_entry->get_parent_folder(), shell_entry); + } else { + TCHAR path[MAX_PATH]; + + if (entry->get_path(path)) { + SHFILEINFO sfi; + + ShellPath shell_path(path); + LPCITEMIDLIST pidl = shell_path; + + if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_ICON|SHGFI_SMALLICON)) + return sfi.hIcon; + } + } + + return 0; +} + + +void ShellDirectory::read_directory(int scan_flags) { CONTEXT("ShellDirectory::read_directory()"); @@ -264,65 +312,37 @@ void ShellDirectory::read_directory(bool read_icons) /*if (_folder.empty()) return;*/ - ShellItemEnumerator enumerator(_folder, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE); + TCHAR buffer[MAX_PATH]; - TCHAR name[MAX_PATH]; - HRESULT hr_next = S_OK; + if ((scan_flags&SCAN_FILESYSTEM) && get_path(buffer)) { + Entry* entry; - do { -#define FETCH_ITEM_COUNT 32 - LPITEMIDLIST pidls[FETCH_ITEM_COUNT]; - ULONG cnt = 0; - ULONG n; + LPTSTR p = buffer + _tcslen(buffer); - memset(pidls, 0, sizeof(pidls)); + lstrcpy(p, TEXT("\\*")); - hr_next = enumerator->Next(FETCH_ITEM_COUNT, pidls, &cnt); + WIN32_FIND_DATA w32fd; + HANDLE hFind = FindFirstFile(buffer, &w32fd); - /* don't break yet now: Registry Explorer Plugin returns E_FAIL! - if (!SUCCEEDED(hr_next)) - break; */ + if (hFind != INVALID_HANDLE_VALUE) { + do { + // ignore hidden files (usefull in the start menu) + if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + continue; - if (hr_next == S_FALSE) - break; + // ignore directory entries "." and ".." + if ((w32fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && + w32fd.cFileName[0]==TEXT('.') && + (w32fd.cFileName[1]==TEXT('\0') || + (w32fd.cFileName[1]==TEXT('.') && w32fd.cFileName[2]==TEXT('\0')))) + continue; - for(n=0; nGetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs); - bool removeable = false; - - if (SUCCEEDED(hr) && attribs!=attribs_before) { - // avoid accessing floppy drives when browsing "My Computer" - if (attribs & SFGAO_REMOVABLE) { - attribs |= SFGAO_HASSUBFOLDER; - removeable = true; - } else { - DWORD attribs2 = SFGAO_READONLY; - - HRESULT hr = _folder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs2); - - if (SUCCEEDED(hr)) - attribs |= attribs2; - } - } else - attribs = 0; - - bhfi_valid = fill_w32fdata_shell(pidls[n], attribs, &w32fd, &bhfi, !removeable); - - try { - Entry* entry; + lstrcpy(p+1, w32fd.cFileName); if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - entry = new ShellDirectory(this, pidls[n], _hwnd); + entry = new WinDirectory(this, buffer); else - entry = new ShellEntry(this, pidls[n]); + entry = new WinEntry(this); if (!first_entry) first_entry = entry; @@ -332,21 +352,9 @@ void ShellDirectory::read_directory(bool read_icons) memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA)); - if (bhfi_valid) - memcpy(&entry->_bhfi, &bhfi, sizeof(BY_HANDLE_FILE_INFORMATION)); - - if (SUCCEEDED(name_from_pidl(_folder, pidls[n], name, MAX_PATH, SHGDN_INFOLDER|0x2000/*0x2000=SHGDN_INCLUDE_NONFILESYS*/))) { - if (!entry->_data.cFileName[0]) - _tcscpy(entry->_data.cFileName, name); - else if (_tcscmp(entry->_display_name, name)) - entry->_display_name = _tcsdup(name); // store display name separate from file name; sort display by file name - } - - // get display icons for files and virtual objects - if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || - !(attribs & SFGAO_FILESYSTEM)) { - if (read_icons) { - entry->_hIcon = extract_icon(_folder, pidls[n], static_cast(entry)); + if (!(w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (scan_flags & SCAN_EXTRACT_ICONS) { + entry->_hIcon = extract_icon(entry); if (!entry->_hIcon) entry->_hIcon = (HICON)-1; // don't try again later @@ -359,15 +367,166 @@ void ShellDirectory::read_directory(bool read_icons) entry->_expanded = false; entry->_scanned = false; entry->_level = level; + entry->_bhfi_valid = false; + + if (scan_flags & SCAN_DO_ACCESS) { + HANDLE hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + + if (hFile != INVALID_HANDLE_VALUE) { + if (GetFileInformationByHandle(hFile, &entry->_bhfi)) + entry->_bhfi_valid = true; + + if (ScanNTFSStreams(entry, hFile)) + entry->_scanned = true; // There exist named NTFS sub-streams in this file. + + CloseHandle(hFile); + } + } + + LPCTSTR ext = _tcsrchr(entry->_data.cFileName, TEXT('.')); + + if (ext) {//@@ + int len = ext - entry->_data.cFileName; + + entry->_display_name = (LPTSTR) malloc((len+1)*sizeof(TCHAR)); + _tcsncpy(entry->_display_name, entry->_data.cFileName, len); + entry->_display_name[len] = TEXT('\0'); + } + + DWORD attribs = SFGAO_FILESYSTEM; + + if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + attribs |= SFGAO_FOLDER; + + if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + attribs |= SFGAO_READONLY; + + //if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + // attribs |= SFGAO_HIDDEN; + + if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) + attribs |= SFGAO_COMPRESSED; + + if (ext && !_tcsicmp(ext, _T(".lnk"))) + attribs |= SFGAO_LINK; + entry->_shell_attribs = attribs; - entry->_bhfi_valid = bhfi_valid; last = entry; - } catch(COMException& e) { - HandleException(e, _hwnd); - } + } while(FindNextFile(hFind, &w32fd)); + + FindClose(hFind); } - } while(SUCCEEDED(hr_next)); + + } else { // !SCAN_FILESYSTEM + + ShellItemEnumerator enumerator(_folder, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE); + + TCHAR name[MAX_PATH]; + HRESULT hr_next = S_OK; + + do { +#define FETCH_ITEM_COUNT 32 + LPITEMIDLIST pidls[FETCH_ITEM_COUNT]; + ULONG cnt = 0; + ULONG n; + + memset(pidls, 0, sizeof(pidls)); + + hr_next = enumerator->Next(FETCH_ITEM_COUNT, pidls, &cnt); + + /* don't break yet now: Registry Explorer Plugin returns E_FAIL! + if (!SUCCEEDED(hr_next)) + break; */ + + if (hr_next == S_FALSE) + break; + + for(n=0; nGetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs); + bool removeable = false; + + if (SUCCEEDED(hr) && attribs!=attribs_before) { + // avoid accessing floppy drives when browsing "My Computer" + if (attribs & SFGAO_REMOVABLE) { + attribs |= SFGAO_HASSUBFOLDER; + removeable = true; + } else if (scan_flags & SCAN_DO_ACCESS) { + DWORD attribs2 = SFGAO_READONLY; + + HRESULT hr = _folder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs2); + + if (SUCCEEDED(hr)) + attribs |= attribs2; + } + } else + attribs = 0; + + bhfi_valid = fill_w32fdata_shell(pidls[n], attribs, &w32fd, &bhfi, + (scan_flags&SCAN_DO_ACCESS) && !removeable); + + try { + Entry* entry; + + if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + entry = new ShellDirectory(this, pidls[n], _hwnd); + else + entry = new ShellEntry(this, pidls[n]); + + if (!first_entry) + first_entry = entry; + + if (last) + last->_next = entry; + + memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA)); + + if (bhfi_valid) + memcpy(&entry->_bhfi, &bhfi, sizeof(BY_HANDLE_FILE_INFORMATION)); + + if (SUCCEEDED(name_from_pidl(_folder, pidls[n], name, MAX_PATH, SHGDN_INFOLDER|0x2000/*0x2000=SHGDN_INCLUDE_NONFILESYS*/))) { + if (!entry->_data.cFileName[0]) + _tcscpy(entry->_data.cFileName, name); + else if (_tcscmp(entry->_display_name, name)) + entry->_display_name = _tcsdup(name); // store display name separate from file name; sort display by file name + } + + // get icons for files and virtual objects + if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || + !(attribs & SFGAO_FILESYSTEM)) { + if (scan_flags & SCAN_EXTRACT_ICONS) { + entry->_hIcon = extract_icon(_folder, static_cast(entry)); + + if (!entry->_hIcon) + entry->_hIcon = (HICON)-1; // don't try again later + } else + entry->_hIcon = 0; + } else + entry->_hIcon = (HICON)-1; // don't try again later + + entry->_down = NULL; + entry->_expanded = false; + entry->_scanned = false; + entry->_level = level; + entry->_shell_attribs = attribs; + entry->_bhfi_valid = bhfi_valid; + + last = entry; + } catch(COMException& e) { + HandleException(e, _hwnd); + } + } + } while(SUCCEEDED(hr_next)); + } if (last) last->_next = NULL; @@ -393,12 +552,13 @@ Entry* ShellDirectory::find_entry(const void* p) { LPITEMIDLIST pidl = (LPITEMIDLIST) p; - for(Entry*entry=_down; entry; entry=entry->_next) { - ShellEntry* se = static_cast(entry); + for(Entry*entry=_down; entry; entry=entry->_next) + if (entry->_etype == ET_SHELL) { + ShellEntry* se = static_cast(entry); - if (se->_pidl && se->_pidl->mkid.cb==pidl->mkid.cb && !memcmp(se->_pidl, pidl, se->_pidl->mkid.cb)) - return entry; - } + if (se->_pidl && se->_pidl->mkid.cb==pidl->mkid.cb && !memcmp(se->_pidl, pidl, se->_pidl->mkid.cb)) + return entry; + } return NULL; } @@ -407,18 +567,18 @@ int ShellDirectory::extract_icons() { int cnt = 0; - for(Entry*entry=_down; entry; entry=entry->_next) { - ShellEntry* se = static_cast(entry); - - if (!se->_hIcon) { - se->_hIcon = extract_icon(_folder, se->_pidl, static_cast(se)); + for(Entry*entry=_down; entry; entry=entry->_next) + if (!entry->_hIcon) { + if (entry->_etype == ET_SHELL) + entry->_hIcon = extract_icon(_folder, static_cast(entry)); + else // !ET_SHELL + entry->_hIcon = extract_icon(entry); if (entry->_hIcon) ++cnt; else entry->_hIcon = (HICON)-1; // don't try again later } - } return cnt; } diff --git a/reactos/subsys/system/explorer/shell/shellfs.h b/reactos/subsys/system/explorer/shell/shellfs.h index a9cca6e90b0..1c86df9acb8 100644 --- a/reactos/subsys/system/explorer/shell/shellfs.h +++ b/reactos/subsys/system/explorer/shell/shellfs.h @@ -29,10 +29,10 @@ /// shell file/directory entry struct ShellEntry : public Entry { - ShellEntry(Entry* parent, LPITEMIDLIST shell_path) : Entry(parent), _pidl(shell_path) {} - ShellEntry(Entry* parent, const ShellPath& shell_path) : Entry(parent), _pidl(shell_path) {} + ShellEntry(Entry* parent, LPITEMIDLIST shell_path) : Entry(parent, ET_SHELL), _pidl(shell_path) {} + ShellEntry(Entry* parent, const ShellPath& shell_path) : Entry(parent, ET_SHELL), _pidl(shell_path) {} - virtual void get_path(PTSTR path) const; + virtual bool get_path(PTSTR path) const; virtual BOOL launch_entry(HWND hwnd, UINT nCmdShow=SW_SHOWNORMAL); IShellFolder* get_parent_folder() const; @@ -45,6 +45,23 @@ protected: ShellEntry(const ShellPath& shell_path) : Entry(ET_SHELL), _pidl(shell_path) {} }; +bool inline get_entry_pidl(Entry* entry, ShellPath& shell_path) +{ + if (entry->_etype == ET_SHELL) { + shell_path = static_cast(entry)->create_absolute_pidl(); + return true; + } else { + TCHAR path[MAX_PATH]; + + if (!entry->get_path(path)) + return false; + + shell_path = path; + + return true; + } +} + /// shell folder entry struct ShellDirectory : public ShellEntry, public Directory @@ -97,11 +114,11 @@ struct ShellDirectory : public ShellEntry, public Directory pFolder->Release(); } - virtual void read_directory(bool read_icons=true); + virtual void read_directory(int scan_flags=SCAN_ALL); virtual const void* get_next_path_component(const void*); virtual Entry* find_entry(const void* p); - virtual void get_path(PTSTR path) const; + virtual bool get_path(PTSTR path) const; int extract_icons(); @@ -120,3 +137,5 @@ inline IShellFolder* ShellEntry::get_parent_folder() const else return Desktop(); } + +extern HICON extract_icon(const Entry* entry); diff --git a/reactos/subsys/system/explorer/shell/winfs.cpp b/reactos/subsys/system/explorer/shell/winfs.cpp index 0e0a8adaad6..e0a36d888b9 100644 --- a/reactos/subsys/system/explorer/shell/winfs.cpp +++ b/reactos/subsys/system/explorer/shell/winfs.cpp @@ -119,14 +119,16 @@ int ScanNTFSStreams(Entry* entry, HANDLE hFile) } -void WinDirectory::read_directory(bool read_icons) +void WinDirectory::read_directory(int scan_flags) { + CONTEXT("WinDirectory::read_directory()"); + + int level = _level + 1; + Entry* first_entry = NULL; Entry* last = NULL; Entry* entry; - int level = _level + 1; - LPCTSTR path = (LPCTSTR)_path; TCHAR buffer[MAX_PATH], *p; for(p=buffer; *path; ) @@ -159,20 +161,22 @@ void WinDirectory::read_directory(bool read_icons) entry->_level = level; entry->_bhfi_valid = false; - HANDLE hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (scan_flags & SCAN_DO_ACCESS) { + HANDLE hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); - if (hFile != INVALID_HANDLE_VALUE) { - if (GetFileInformationByHandle(hFile, &entry->_bhfi)) - entry->_bhfi_valid = true; + if (hFile != INVALID_HANDLE_VALUE) { + if (GetFileInformationByHandle(hFile, &entry->_bhfi)) + entry->_bhfi_valid = true; - if (ScanNTFSStreams(entry, hFile)) - entry->_scanned = true; // There exist named NTFS sub-streams in this file. + if (ScanNTFSStreams(entry, hFile)) + entry->_scanned = true; // There exist named NTFS sub-streams in this file. - CloseHandle(hFile); + CloseHandle(hFile); + } } - last = entry; + last = entry; // There is always at least one entry, because FindFirstFile() succeeded and we don't filter the file entries. } while(FindNextFile(hFind, &w32fd)); last->_next = NULL; @@ -229,41 +233,68 @@ Entry* WinDirectory::find_entry(const void* p) // get full path of specified directory entry -void WinEntry::get_path(PTSTR path) const +bool WinEntry::get_path(PTSTR path) const { int level = 0; int len = 0; + int l = 0; + LPCTSTR name = NULL; + TCHAR buffer[MAX_PATH]; - for(const Entry* entry=this; entry; level++) { - LPCTSTR name = entry->_data.cFileName; - int l = 0; + const Entry* entry; + for(entry=this; entry; level++) { + l = 0; - for(LPCTSTR s=name; *s && *s!=TEXT('/') && *s!=TEXT('\\'); s++) - ++l; + if (entry->_etype == ET_WINDOWS) { + name = entry->_data.cFileName; - if (entry->_up) { - if (l > 0) { - memmove(path+l+1, path, len*sizeof(TCHAR)); - memcpy(path+1, name, l*sizeof(TCHAR)); - len += l+1; + for(LPCTSTR s=name; *s && *s!=TEXT('/') && *s!=TEXT('\\'); s++) + ++l; - if (entry->_up && !(entry->_up->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) // a NTFS stream? - path[0] = TEXT(':'); - else - path[0] = TEXT('\\'); + if (!entry->_up) + break; + } else { + if (entry->get_path(buffer)) { + l = _tcslen(buffer); + name = buffer; + + /* special handling of drive names */ + if (l>0 && buffer[l-1]=='\\' && path[0]=='\\') + --l; + + memmove(path+l, path, len*sizeof(TCHAR)); + memcpy(path, name, l*sizeof(TCHAR)); + len += l; } - entry = entry->_up; - } else { - memmove(path+l, path, len*sizeof(TCHAR)); - memcpy(path, name, l*sizeof(TCHAR)); - len += l; + entry = NULL; break; } + + if (l > 0) { + memmove(path+l+1, path, len*sizeof(TCHAR)); + memcpy(path+1, name, l*sizeof(TCHAR)); + len += l+1; + + if (entry->_up && !(entry->_up->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) // a NTFS stream? + path[0] = TEXT(':'); + else + path[0] = TEXT('\\'); + } + + entry = entry->_up; + } + + if (entry) { + memmove(path+l, path, len*sizeof(TCHAR)); + memcpy(path, name, l*sizeof(TCHAR)); + len += l; } if (!level) path[len++] = TEXT('\\'); path[len] = TEXT('\0'); + + return true; } diff --git a/reactos/subsys/system/explorer/shell/winfs.h b/reactos/subsys/system/explorer/shell/winfs.h index dd720637668..97e3326d4b2 100644 --- a/reactos/subsys/system/explorer/shell/winfs.h +++ b/reactos/subsys/system/explorer/shell/winfs.h @@ -26,19 +26,19 @@ // - /// Windows File System file-entry + /// Windows file system file-entry struct WinEntry : public Entry { - WinEntry(Entry* parent) : Entry(parent) {} + WinEntry(Entry* parent) : Entry(parent, ET_WINDOWS) {} protected: WinEntry() : Entry(ET_WINDOWS) {} - virtual void get_path(PTSTR path) const; + virtual bool get_path(PTSTR path) const; }; - /// Windows File System directory-entry + /// Windows file system directory-entry struct WinDirectory : public WinEntry, public Directory { WinDirectory(LPCTSTR root_path) @@ -47,7 +47,7 @@ struct WinDirectory : public WinEntry, public Directory _path = _tcsdup(root_path); } - WinDirectory(WinDirectory* parent, LPCTSTR path) + WinDirectory(Entry* parent, LPCTSTR path) : WinEntry(parent) { _path = _tcsdup(path); @@ -59,7 +59,9 @@ struct WinDirectory : public WinEntry, public Directory _path = NULL; } - virtual void read_directory(bool read_icons=true); + virtual void read_directory(int scan_flags=SCAN_ALL); virtual const void* get_next_path_component(const void*); virtual Entry* find_entry(const void*); }; + +extern int ScanNTFSStreams(Entry* entry, HANDLE hFile); diff --git a/reactos/subsys/system/explorer/taskbar/quicklaunch.cpp b/reactos/subsys/system/explorer/taskbar/quicklaunch.cpp index 0c30fb5fd19..2b857e093c4 100644 --- a/reactos/subsys/system/explorer/taskbar/quicklaunch.cpp +++ b/reactos/subsys/system/explorer/taskbar/quicklaunch.cpp @@ -94,7 +94,7 @@ void QuickLaunchBar::AddShortcuts() WaitCursor wait; try { - TCHAR path[_MAX_PATH]; + TCHAR path[MAX_PATH]; SpecialFolderFSPath app_data(CSIDL_APPDATA, _hwnd); // perhaps also look into CSIDL_COMMON_APPDATA ? @@ -102,7 +102,7 @@ void QuickLaunchBar::AddShortcuts() _dir = new ShellDirectory(Desktop(), path, _hwnd); - _dir->smart_scan(); + _dir->smart_scan(SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM); } catch(COMException&) { return; } @@ -120,10 +120,7 @@ void QuickLaunchBar::AddShortcuts() // hide subfolders if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - ShellEntry* shell_entry = static_cast(entry); - - const String& entry_name = desktop_folder.get_name(shell_entry->_pidl); - HBITMAP hbmp = create_bitmap_from_icon(shell_entry->_hIcon, GetSysColorBrush(COLOR_BTNFACE), canvas); + HBITMAP hbmp = create_bitmap_from_icon(entry->_hIcon, GetSysColorBrush(COLOR_BTNFACE), canvas); TBADDBITMAP ab = {0, (UINT_PTR)hbmp}; int bmp_idx = SendMessage(_hwnd, TB_ADDBITMAP, 1, (LPARAM)&ab); @@ -133,8 +130,8 @@ void QuickLaunchBar::AddShortcuts() int id = ++_next_id; qle._hbmp = hbmp; - qle._title = entry_name; - qle._entry = shell_entry; + qle._title = entry->_display_name; //entry->_etype==ET_SHELL? desktop_folder.get_name(static_cast(entry)->_pidl): entry->_display_name + qle._entry = entry; _entries[id] = qle; diff --git a/reactos/subsys/system/explorer/taskbar/quicklaunch.h b/reactos/subsys/system/explorer/taskbar/quicklaunch.h index e2983104f4c..801d412546d 100644 --- a/reactos/subsys/system/explorer/taskbar/quicklaunch.h +++ b/reactos/subsys/system/explorer/taskbar/quicklaunch.h @@ -45,7 +45,7 @@ struct QuickLaunchEntry HBITMAP _hbmp; String _title; - ShellEntry* _entry; + Entry* _entry; }; /// map for managing the task bar buttons diff --git a/reactos/subsys/system/explorer/taskbar/startmenu.cpp b/reactos/subsys/system/explorer/taskbar/startmenu.cpp index 5ea0c01af96..cdd47f3c156 100644 --- a/reactos/subsys/system/explorer/taskbar/startmenu.cpp +++ b/reactos/subsys/system/explorer/taskbar/startmenu.cpp @@ -188,9 +188,9 @@ void StartMenu::AddEntries() WaitCursor wait; #ifdef _LAZY_ICONEXTRACT - dir.smart_scan(false); // lazy icon extraction + dir.smart_scan(SCAN_FILESYSTEM); // lazy icon extraction, try to read directly from filesystem #else - dir.smart_scan(true); + dir.smart_scan(SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM); #endif } @@ -218,9 +218,10 @@ void StartMenu::AddShellEntries(const ShellDirectory& dir, int max, bool subfold if (++cnt == max) break; - const ShellEntry* shell_entry = static_cast(entry); - - AddEntry(dir._folder, shell_entry); + if (entry->_etype == ET_SHELL) + AddEntry(dir._folder, static_cast(entry)); + else + AddEntry(dir._folder, entry); } } @@ -268,7 +269,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) RECT rect; // check mouse cursor for coordinates of floating button - GetFloatingButonRect(&rect); + GetFloatingButtonRect(&rect); if (PtInRect(&rect, Point(lparam))) { // create a floating copy of the current start menu @@ -334,7 +335,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) #ifdef _LAZY_ICONEXTRACT case PM_UPDATE_ICONS: - UpdateIcons(); + UpdateIcons(wparam); break; #endif @@ -441,7 +442,7 @@ void StartMenu::SelectButton(int id) #endif -bool StartMenu::GetButtonRect(int id, PRECT prect) +bool StartMenu::GetButtonRect(int id, PRECT prect) const { #ifdef _LIGHT_STARTMENU ClientRect clnt(_hwnd); @@ -452,7 +453,7 @@ bool StartMenu::GetButtonRect(int id, PRECT prect) rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT: STARTMENU_LINE_HEIGHT); - if (info._id == _selected_id) { + if (info._id == id) { *prect = rect; return true; } @@ -484,7 +485,7 @@ void StartMenu::DrawFloatingButton(HDC hdc) DrawIconEx(hdc, clnt.right-12, 0, floatingIcon, 8, 4, 0, 0, DI_NORMAL); } -void StartMenu::GetFloatingButonRect(LPRECT prect) +void StartMenu::GetFloatingButtonRect(LPRECT prect) { GetClientRect(_hwnd, prect); @@ -509,12 +510,12 @@ void StartMenu::Paint(PaintCanvas& canvas) BkMode bk_mode(canvas, TRANSPARENT); for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it) { - const SMBtnInfo& info = *it; + const SMBtnInfo& btn = *it; if (rect.top > canvas.rcPaint.bottom) break; - if (info._id == -1) { // a separator? + if (btn._id == -1) { // a separator? rect.bottom = rect.top + STARTMENU_SEP_HEIGHT; BrushSelection brush_sel(canvas, GetSysColorBrush(COLOR_BTNSHADOW)); @@ -526,8 +527,8 @@ void StartMenu::Paint(PaintCanvas& canvas) rect.bottom = rect.top + STARTMENU_LINE_HEIGHT; if (rect.top >= canvas.rcPaint.top) - DrawStartMenuButton(canvas, rect, info._title, info._hIcon, - info._hasSubmenu, info._enabled, info._id==_selected_id, false); + DrawStartMenuButton(canvas, rect, btn._title, btn._hIcon, + btn._hasSubmenu, btn._enabled, btn._id==_selected_id, false); } rect.top = rect.bottom; @@ -536,12 +537,52 @@ void StartMenu::Paint(PaintCanvas& canvas) } #ifdef _LAZY_ICONEXTRACT -void StartMenu::UpdateIcons() +void StartMenu::UpdateIcons(int idx) { UpdateWindow(_hwnd); +#ifdef _SINGLE_ICONEXTRACT + // extract only one icon per call to allow leaving the folder while the lazy extraction is running + if (idx >= 0) { + for(; idx<(int)_buttons.size(); ++idx) { + SMBtnInfo& btn = _buttons[idx]; + + if (!btn._hIcon && btn._id>0) { + StartMenuEntry& sme = _entries[btn._id]; + + btn._hIcon = (HICON)-1; + + for(ShellEntrySet::const_iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) { + const Entry* entry = *it; + + HICON hIcon = extract_icon(entry); + + if (hIcon) { + btn._hIcon = hIcon; + break; + } + } + + if (btn._hIcon != (HICON)-1) { + RECT rect; + GetButtonRect(btn._id, &rect); + WindowCanvas canvas(_hwnd); + DrawStartMenuButton(canvas, rect, NULL, btn._hIcon, btn._hasSubmenu, btn._enabled, btn._id==_selected_id, false); + //InvalidateRect(_hwnd, &rect, FALSE); + //UpdateWindow(_hwnd); + break; + } + } + } + + if (++idx < (int)_buttons.size()) + PostMessage(_hwnd, PM_UPDATE_ICONS, idx, 0); + + return; + } +#else int icons_extracted = 0; - int icons_refreshed = 0; + int icons_updated = 0; for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) { ShellDirectory& dir = it->_dir; @@ -557,7 +598,7 @@ void StartMenu::UpdateIcons() sme._hIcon = (HICON)-1; for(ShellEntrySet::const_iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) { - const ShellEntry* sm_entry = *it2; + const Entry* sm_entry = *it2; if (sm_entry->_hIcon) { sme._hIcon = sm_entry->_hIcon; @@ -572,15 +613,16 @@ void StartMenu::UpdateIcons() if (info._id>0 && !info._hIcon) { info._hIcon = _entries[info._id]._hIcon; - ++icons_refreshed; + ++icons_updated; } } } - if (icons_refreshed) { - InvalidateRect(_hwnd, NULL, TRUE); + if (icons_updated) { + InvalidateRect(_hwnd, NULL, FALSE); UpdateWindow(_hwnd); } +#endif } #endif @@ -630,7 +672,31 @@ int StartMenu::Command(int id, int code) } -StartMenuEntry& StartMenu::AddEntry(LPCTSTR title, HICON hIcon, int id) +StartMenuEntry& StartMenu::AddEntry(const String& title, HICON hIcon, const Entry* entry) +{ + // search for an already existing subdirectory entry with the same name + if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + for(ShellEntryMap::iterator it=_entries.begin(); it!=_entries.end(); ++it) { + StartMenuEntry& sme = it->second; + + if (sme._title == title) ///@todo speed up by using a map indexed by name + for(ShellEntrySet::iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) { + if ((*it2)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + // merge the new shell entry with the existing of the same name + sme._entries.insert(entry); + return sme; + } + } + } + + StartMenuEntry& sme = AddEntry(title, hIcon); + + sme._entries.insert(entry); + + return sme; +} + +StartMenuEntry& StartMenu::AddEntry(const String& title, HICON hIcon, int id) { if (id == -1) id = ++_next_id; @@ -648,32 +714,20 @@ StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, const ShellEntry* HICON hIcon = entry->_hIcon; if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - hIcon = SmallIcon(IDI_EXPLORER); + hIcon = SmallIcon(IDI_FOLDER); - const String& entry_name = folder.get_name(entry->_pidl); - - // search for an already existing subdirectory entry with the same name - if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - for(ShellEntryMap::iterator it=_entries.begin(); it!=_entries.end(); ++it) { - StartMenuEntry& sme = it->second; - - if (sme._title == entry_name) ///@todo speed up by using a map indexed by name - for(ShellEntrySet::iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) { - if ((*it2)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - // merge the new shell entry with the existing of the same name - sme._entries.insert(entry); - return sme; - } - } - } - - StartMenuEntry& sme = AddEntry(entry_name, hIcon); - - sme._entries.insert(entry); - - return sme; + return AddEntry(folder.get_name(entry->_pidl), hIcon, entry); } +StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, const Entry* entry) +{ + HICON hIcon = entry->_hIcon; + + if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + hIcon = SmallIcon(IDI_FOLDER); + + return AddEntry(entry->_display_name, hIcon, entry); +} void StartMenu::AddButton(LPCTSTR title, HICON hIcon, bool hasSubmenu, int id, bool enabled) @@ -743,8 +797,8 @@ bool StartMenu::CloseOtherSubmenus(int id) if (_submenu_id == id) return false; else { - DestroyWindow(_submenu); _submenu_id = 0; + DestroyWindow(_submenu); // _submenu should be reset automatically by PM_STARTMENU_CLOSED, but safety first... } } @@ -825,10 +879,20 @@ void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries) String title; for(ShellEntrySet::const_iterator it=entries.begin(); it!=entries.end(); ++it) { - ShellEntry* entry = const_cast(*it); + Entry* entry = const_cast(*it); if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - new_folders.push_back(entry->create_absolute_pidl()); + + ///@todo If the user explicitely clicked on a submenu, display this folder as floating start menu. + + if (entry->_etype == ET_SHELL) + new_folders.push_back(static_cast(entry)->create_absolute_pidl()); + else { + TCHAR path[MAX_PATH]; + + if (entry->get_path(path)) + new_folders.push_back(path); + } if (title.empty()) title = entry->_display_name; @@ -903,7 +967,9 @@ void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon, HBRUSH bk_brush = GetSysColorBrush(bk_color); - FillRect(hdc, &rect, bk_brush); + if (title) + FillRect(hdc, &rect, bk_brush); + DrawIconEx(hdc, iconPos.x, iconPos.y, hIcon, 16, 16, 0, bk_brush, DI_NORMAL); // draw submenu arrow at the right @@ -916,13 +982,15 @@ void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon, 16, 16, 0, bk_brush, DI_NORMAL); } - BkMode bk_mode(hdc, TRANSPARENT); + if (title) { + BkMode bk_mode(hdc, TRANSPARENT); - if (!enabled) // dis->itemState & (ODS_DISABLED|ODS_GRAYED) - DrawGrayText(hdc, &textRect, title, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER); - else { - TextColor lcColor(hdc, GetSysColor(text_color)); - DrawText(hdc, title, -1, &textRect, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER); + if (!enabled) // dis->itemState & (ODS_DISABLED|ODS_GRAYED) + DrawGrayText(hdc, &textRect, title, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER); + else { + TextColor lcColor(hdc, GetSysColor(text_color)); + DrawText(hdc, title, -1, &textRect, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER); + } } } @@ -1505,10 +1573,6 @@ void SearchMenu::AddEntries() void RecentStartMenu::AddEntries() { - - ///@todo A cache would really speed up processing of long recent doc lists. - ///@todo Alternativelly we could also use direct file system access instead of iterating in shell namespace. - for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) { StartMenuDirectory& smd = *it; ShellDirectory& dir = smd._dir; @@ -1517,9 +1581,9 @@ void RecentStartMenu::AddEntries() WaitCursor wait; #ifdef _LAZY_ICONEXTRACT - dir.smart_scan(false); // lazy icon extraction + dir.smart_scan(SCAN_FILESYSTEM); #else - dir.smart_scan(true); + dir.smart_scan(SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM); #endif } diff --git a/reactos/subsys/system/explorer/taskbar/startmenu.h b/reactos/subsys/system/explorer/taskbar/startmenu.h index 21a6ff03505..06015468187 100644 --- a/reactos/subsys/system/explorer/taskbar/startmenu.h +++ b/reactos/subsys/system/explorer/taskbar/startmenu.h @@ -28,6 +28,7 @@ #define _LIGHT_STARTMENU #define _LAZY_ICONEXTRACT +#define _SINGLE_ICONEXTRACT #define CLASSNAME_STARTMENU TEXT("ReactosStartmenuClass") @@ -69,7 +70,7 @@ struct StartMenuDirectory }; typedef list StartMenuShellDirs; -typedef set ShellEntrySet; +typedef set ShellEntrySet; /// structure holding information about one start menu entry struct StartMenuEntry @@ -253,8 +254,10 @@ protected: virtual void AddEntries(); - StartMenuEntry& AddEntry(LPCTSTR title, HICON hIcon=0, int id=-1); + StartMenuEntry& AddEntry(const String& title, HICON hIcon, const Entry* entry); + StartMenuEntry& AddEntry(const String& title, HICON hIcon=0, int id=-1); StartMenuEntry& AddEntry(const ShellFolder folder, const ShellEntry* entry); + StartMenuEntry& AddEntry(const ShellFolder folder, const Entry* entry); void AddShellEntries(const ShellDirectory& dir, int max=-1, bool subfolders=true); @@ -270,13 +273,13 @@ protected: void ActivateEntry(int id, const ShellEntrySet& entries); void CloseStartMenu(int id=0); - bool GetButtonRect(int id, PRECT prect); + bool GetButtonRect(int id, PRECT prect) const; void DrawFloatingButton(HDC hdc); - void GetFloatingButonRect(LPRECT prect); + void GetFloatingButtonRect(LPRECT prect); void Paint(PaintCanvas& canvas); - void UpdateIcons(); + void UpdateIcons(int idx); };