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
@@ -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:
@@ -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);
};
@@ -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
+6 -6
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"
@@ -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);
+14 -5
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);
};
@@ -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);
}
}
@@ -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
+262 -102
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;
}
+24 -5
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);
+63 -32
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;
}
+8 -6
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);
@@ -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;
@@ -45,7 +45,7 @@ struct QuickLaunchEntry
HBITMAP _hbmp;
String _title;
ShellEntry* _entry;
Entry* _entry;
};
/// map for managing the task bar buttons
@@ -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
}
@@ -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);
};