Это кусок моего проводника.
Всё работает, но очень медленно, если появляется желание просмотреть содержимое чего-нибудь вроде system32.
Если закомментировать ::SHGetFileInfo(...) в FillFilesList, то намного быстрее (для system32 время заполнения ListCtrl-а сокращается с 6 секунд до пары сотен милисекунд).
Но при этом иконки теряются и смотрится уже совсем не так.
Посоветуйте как это всё можно ускорить без потери наглядности.
//я пробовал вариант с FindFirstFile и FindNextFile вместо CFileFind, но время исполнения
отличается совсем мало!
struct FILE_DESCRIPTION
{
DWORD dwFileAttributes;
CString FileName;
CTime lastChangeTime;
CString FileSize;
UINT iIconIndex;
};
H>Посоветуйте как это всё можно ускорить без потери наглядности.
Как вариант: использовать virtual listview (LVS_OWNERDATA) и начинать пробегаться не по всем файлам, а только по видимым на экране, так-скзать отложенное получение информации.
Здравствуйте, Hadgi, Вы писали:
H>Всё работает, но очень медленно, если появляется желание просмотреть содержимое чего-нибудь вроде system32. H>Если закомментировать ::SHGetFileInfo(...) в FillFilesList, то намного быстрее (для system32 время заполнения ListCtrl-а сокращается с 6 секунд до пары сотен милисекунд). H>Но при этом иконки теряются и смотрится уже совсем не так. H>Посоветуйте как это всё можно ускорить без потери наглядности.
Как Вы, наверное, замечали уже, Виндовый проводник в папках с большим числом файлов показывает сначала файлы с иконкой соотвтетствующей неопределенному типу файла. А потом постепенно файлам начинают соответствовать реальные иконки. Следовательно выход в создании дополнительного потока, который будет выполнять эту работу. А основной поток будет только заполнять листвью списком файлов. Плюс, очень похоже, что проводник кэширует эту информацию (потому что при повторном вхождении в папку обновление иконок происходит достаточно быстро). Но я думаю даже без этого "всё можно ускорить без потери наглядности". Желаю удачи!
а попробуйте этот код (я использовал у себя чтобы получить иконку для exe например файлов, но можно и для других любых это сделать — AddIconByString):
// ----------------------------------------------------------------------
//
// Function: AddIconByString(CString& str,CListCtrl& refList,CImageList* pImageList)
//
// Purpose: add item with icon, if it's unique, to the list view
//
// Arguments: sz [IN] text of item to add
// refList [IN] reference to the ListView control
// pImageList [IN] pointer to image list to add icon
//
// Returns: None
//
// Notes:
//bool AddIconByString(CString& str,CListCtrl& refList,CImageList* pImageList)
{
//check for duplicates
LVFINDINFO info;
info.flags = LVFI_STRING;
info.psz = str;
if (refList.FindItem(&info) == -1)
{
refList.InsertItem(0,str,GetProcessIcon(str,pImageList));
return 1;
}
return 0;
}
// ----------------------------------------------------------------------
//
// Function: GetProcessIcon(const CString& strPath, CImageList* pImageList)
//
// Purpose: get icon from process path and add it to the image list
//
// Arguments: strPath [IN] path of process
//
// Returns: on success index of found icon in the image list,
// otherwise -1
//
// Notes:
//int GetProcessIcon(const CString& strPath, CImageList* pImageList)
{
SHFILEINFO shFinfo;
int pos=strPath.ReverseFind(_T('.'));
if (pos!=-1 && strPath.ReverseFind(_T('\\'))<pos) //don't forget about User.Domain\Folder\ case
{
CString ext;
//new way: ask default icon for extension
ext=strPath.Right(strPath.GetLength()-pos);
ext.MakeUpper();
if (ext!=_T(".EXE"))
{
if (!SHGetFileInfo(ext,FILE_ATTRIBUTE_NORMAL,&shFinfo,sizeof(shFinfo),
SHGFI_USEFILEATTRIBUTES|SHGFI_ICON|SHGFI_SMALLICON)) return 0;
}
}
//old way: try to get icon from pathif (!SHGetFileInfo(strPath,0,&shFinfo,sizeof(shFinfo),SHGFI_ICON|SHGFI_SMALLICON))
return 0;
//add to image list return pImageList->Add(shFinfo.hIcon);
}
// ----------------------------------------------------------------------
//
// Function: AddIconByString(CString& str,CListCtrl& refList,CImageList* pImageList)
//
// Purpose: add item with icon, if it's unique, to the list view
//
// Arguments: sz [IN] text of item to add
// refList [IN] reference to the ListView control
// pImageList [IN] pointer to image list to add icon
//
// Returns: None
//
// Notes:
//bool AddIconByString(CString& str,CListCtrl& refList,CImageList* pImageList)
{
//check for duplicates
LVFINDINFO info;
info.flags = LVFI_STRING;
info.psz = str;
if (refList.FindItem(&info) == -1)
{
refList.InsertItem(0,str,GetProcessIcon(str,pImageList));
return 1;
}
else
{
return 0;
}
}
давно писал но вроде бы гораздо быстрее стандартного вызова как раз за счет того что берется из кэша иконка ассоциированная с типом файла в первую очередь
... << RSDN@Home 1.1 beta 2 >>
Valery A. Boronin, RSDN Team, linkedin.com\in\boronin
R&D Mgmt & Security. AppSec & SDL. Data Protection and Systems Programming. FDE, DLP, Incident Management. Windows Filesystems and Drivers.
Здравствуйте, Hadgi, Вы писали:
H>Это кусок моего проводника. H>Всё работает, но очень медленно, если появляется желание просмотреть содержимое чего-нибудь вроде system32. H>Если закомментировать ::SHGetFileInfo(...) в FillFilesList, то намного быстрее (для system32 время заполнения ListCtrl-а сокращается с 6 секунд до пары сотен милисекунд). H>Но при этом иконки теряются и смотрится уже совсем не так. H>Посоветуйте как это всё можно ускорить без потери наглядности. H>//я пробовал вариант с FindFirstFile и FindNextFile вместо CFileFind, но время исполнения H>отличается совсем мало!
Можно вызывать SHGetFileInfo() только тогда, когда иконка выводится на экран. Для этого нужно при добавлении элемента указать iIconIndex = I_IMAGECALLBACK, и возвращать индекс иконки из обработчика LVN_GETDISPINFO. При этом можно еще поставить lvItem.mask |= LVIF_DI_SETITEM, чтобы индекс иконки запоминался и повторно не запрашивался.
Для ускорения SHGetFileInfo() можно еще указать флаг SHGFI_USEFILEATTRIBUTES в uFlags и указать атрибуты файла в dwFileAttributes. Это исключит обращение к указанному файлу и вернет зерегистрированную иконку для данного типа файлов. Поскольку система использует различные иконки для каталогов типа Мои рисунки, Моя музыка и т.д., то лучше ставить этот флаг только для файлов и не ставить для каталогов.
Здравствуйте, Hadgi, Вы писали:
H>Это кусок моего проводника. H>Всё работает, но очень медленно, если появляется желание просмотреть содержимое чего-нибудь вроде system32.
Если у вас нет желания сделать круче ms windows explorer, то идеальный вариант это использховать Shell Namespace, и для вашего случая IShellFolder в частности.