direct file system access for start menu

svn path=/trunk/; revision=7424
This commit is contained in:
Martin Fuchs 2004-01-03 18:27:54 +00:00
parent 33f1db80ee
commit 398b10102e
16 changed files with 615 additions and 310 deletions

View file

@ -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<ShellEntry*>(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:

View file

@ -30,7 +30,7 @@
#include <stack>
typedef void (*COLLECT_CALLBACK)(ShellFolder& folder, ShellEntry* shell_entry, void* param);
typedef void (*COLLECT_CALLBACK)(Entry* entry, void* param);
typedef stack<ShellDirectory*> 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);
};

View file

@ -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

View file

@ -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"

View file

@ -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);

View file

@ -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);
};

View file

@ -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);
}
}

View file

@ -211,11 +211,13 @@ void ShellBrowserChild::Tree_DoItemMenu(HWND hwndTreeView, HTREEITEM hItem, LPPO
if (itemData) {
Entry* entry = (Entry*)itemData;
ShellDirectory* dir = static_cast<ShellDirectory*>(entry->_up);
ShellFolder folder = dir? dir->_folder: Desktop();
LPCITEMIDLIST pidl = static_cast<ShellEntry*>(entry)->_pidl;
if (entry->_etype == ET_SHELL) {
ShellDirectory* dir = static_cast<ShellDirectory*>(entry->_up);
ShellFolder folder = dir? dir->_folder: Desktop();
LPCITEMIDLIST pidl = static_cast<ShellEntry*>(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<ShellDirectory*>(entry)->_folder;
else
folder = entry->get_parent_folder();
if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
folder = static_cast<ShellDirectory*>(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<ShellDirectory*>(entry)))
return S_OK;
if (entry->_etype == ET_SHELL)
if (expand_folder(static_cast<ShellDirectory*>(entry)))
return S_OK;
}
}
} else { // no tree control

View file

@ -33,6 +33,9 @@
#include "entries.h"
#include "shellfs.h"
#include "winfs.h"
#include <shlwapi.h>
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<ShellDirectory*>(_up);
if (_up)
if (_up->_etype==ET_SHELL) {
ShellDirectory* dir = static_cast<ShellDirectory*>(_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<ShellFolder&>(_folder)->GetAttributesOf(1, (LPCITEMIDLIST*)&_pidl, &attribs);
if (FAILED(const_cast<ShellFolder&>(_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<ShellEntry*>(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<const ShellEntry*>(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; n<cnt; ++n) {
WIN32_FIND_DATA w32fd;
BY_HANDLE_FILE_INFORMATION bhfi;
bool bhfi_valid = false;
memset(&w32fd, 0, sizeof(WIN32_FIND_DATA));
SFGAOF attribs_before = ~SFGAO_READONLY & ~SFGAO_VALIDATE;
SFGAOF attribs = attribs_before;
HRESULT hr = _folder->GetAttributesOf(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<ShellEntry*>(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; n<cnt; ++n) {
WIN32_FIND_DATA w32fd;
BY_HANDLE_FILE_INFORMATION bhfi;
bool bhfi_valid = false;
memset(&w32fd, 0, sizeof(WIN32_FIND_DATA));
SFGAOF attribs_before = ~SFGAO_READONLY & ~SFGAO_VALIDATE;
SFGAOF attribs = attribs_before;
HRESULT hr = _folder->GetAttributesOf(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<ShellEntry*>(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<ShellEntry*>(entry);
for(Entry*entry=_down; entry; entry=entry->_next)
if (entry->_etype == ET_SHELL) {
ShellEntry* se = static_cast<ShellEntry*>(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<ShellEntry*>(entry);
if (!se->_hIcon) {
se->_hIcon = extract_icon(_folder, se->_pidl, static_cast<ShellEntry*>(se));
for(Entry*entry=_down; entry; entry=entry->_next)
if (!entry->_hIcon) {
if (entry->_etype == ET_SHELL)
entry->_hIcon = extract_icon(_folder, static_cast<ShellEntry*>(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;
}

View file

@ -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<ShellEntry*>(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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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<ShellEntry*>(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<ShellEntry*>(entry)->_pidl): entry->_display_name
qle._entry = entry;
_entries[id] = qle;

View file

@ -45,7 +45,7 @@ struct QuickLaunchEntry
HBITMAP _hbmp;
String _title;
ShellEntry* _entry;
Entry* _entry;
};
/// map for managing the task bar buttons

View file

@ -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<const ShellEntry*>(entry);
AddEntry(dir._folder, shell_entry);
if (entry->_etype == ET_SHELL)
AddEntry(dir._folder, static_cast<const ShellEntry*>(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<ShellEntry*>(*it);
Entry* entry = const_cast<Entry*>(*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<const ShellEntry*>(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
}

View file

@ -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<StartMenuDirectory> StartMenuShellDirs;
typedef set<const ShellEntry*> ShellEntrySet;
typedef set<const Entry*> 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);
};