explorer: add icon cache mapped by shell paths (PIDLs) to fix GDI handle leaks Modified: trunk/reactos/base/shell/explorer/explorer.cpp Modified: trunk/reactos/base/shell/explorer/globals.h Modified: trunk/reactos/base/shell/explorer/notifyhook/notifyhook.dsp Modified: trunk/reactos/base/shell/explorer/shell/entries.cpp Modified: trunk/reactos/base/shell/explorer/utility/shellclasses.h Modified: trunk/reactos/base/shell/explorer/utility/window.cpp _____
Modified: trunk/reactos/base/shell/explorer/explorer.cpp --- trunk/reactos/base/shell/explorer/explorer.cpp 2006-01-29 15:15:23 UTC (rev 34) +++ trunk/reactos/base/shell/explorer/explorer.cpp 2006-01-29 15:28:15 UTC (rev 35) @@ -95,7 +95,7 @@
if (!_cfg.read(_cfg_path)) { if (_cfg._last_error != XML_ERROR_NO_ELEMENTS) - MessageBox(g_Globals._hwndDesktop, String(_cfg._last_error_msg.c_str()), + MessageBox(_hwndDesktop, String(_cfg._last_error_msg.c_str()), TEXT("ROS Explorer - reading user settings"), MB_OK);
_cfg.read(TEXT("explorer-cfg-template.xml")); @@ -540,6 +540,73 @@ return _icons[ICID_NONE]; }
+const Icon& IconCache::extract(LPCITEMIDLIST pidl, ICONCACHE_FLAGS flags) +{ + // search for matching icon with unchanged flags in the cache + PidlCacheKey mapkey(pidl, flags); + PidlCacheMap::iterator found = _pidlcache.find(mapkey); + + if (found != _pidlcache.end()) + return _icons[found->second]; + + // search for matching icon with handle + PidlCacheKey mapkey_hicon(pidl, flags|ICF_HICON); + if (flags != mapkey_hicon.second) { + found = _pidlcache.find(mapkey_hicon); + + if (found != _pidlcache.end()) + return _icons[found->second]; + } + + // search for matching icon in the system image list cache + PidlCacheKey mapkey_syscache(pidl, flags|ICF_SYSCACHE); + if (flags != mapkey_syscache.second) { + found = _pidlcache.find(mapkey_syscache); + + if (found != _pidlcache.end()) + return _icons[found->second]; + } + + SHFILEINFO sfi; + + int shgfi_flags = SHGFI_PIDL; + + if (!(flags & (ICF_LARGE|ICF_MIDDLE))) + shgfi_flags |= SHGFI_SMALLICON; + + if (flags & ICF_OPEN) + shgfi_flags |= SHGFI_OPENICON; + + if (flags & ICF_SYSCACHE) { + assert(!(flags&ICF_OVERLAYS)); + + HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|shgfi_flags); + if (himlSys) { + const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/); + + ///@todo limit cache size + _pidlcache[mapkey_syscache] = icon; + + return icon; + } + } else { + if (flags & ICF_OVERLAYS) + shgfi_flags |= SHGFI_ADDOVERLAYS; + + if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_ICON|shgfi_flags)) { + const Icon& icon = add(sfi.hIcon, IT_CACHED); + + ///@todo limit cache size + _pidlcache[mapkey_hicon] = icon; + + return icon; + } + } + + return _icons[ICID_NONE]; +} + + const Icon& IconCache::add(HICON hIcon, ICON_TYPE type) { int id = ++s_next_id; _____
Modified: trunk/reactos/base/shell/explorer/globals.h --- trunk/reactos/base/shell/explorer/globals.h 2006-01-29 15:15:23 UTC (rev 34) +++ trunk/reactos/base/shell/explorer/globals.h 2006-01-29 15:28:15 UTC (rev 35) @@ -130,6 +130,7 @@
const Icon& extract(LPCTSTR path, ICONCACHE_FLAGS flags=ICF_NORMAL); const Icon& extract(LPCTSTR path, int icon_idx, ICONCACHE_FLAGS flags=ICF_HICON); const Icon& extract(IExtractIcon* pExtract, LPCTSTR path, int icon_idx, ICONCACHE_FLAGS flags=ICF_HICON); + const Icon& extract(LPCITEMIDLIST pidl, ICONCACHE_FLAGS flags=ICF_NORMAL);
const Icon& add(HICON hIcon, ICON_TYPE type=IT_DYNAMIC); const Icon& add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/); @@ -154,6 +155,10 @@ typedef map<IdxCacheKey, ICON_ID> IdxCacheMap; IdxCacheMap _idxCache;
+ typedef pair<ShellPath,int/*ICONCACHE_FLAGS*/> PidlCacheKey; + typedef map<PidlCacheKey, ICON_ID> PidlCacheMap; + PidlCacheMap _pidlcache; + HIMAGELIST _himlSys_small; };
@@ -165,7 +170,7 @@ #define STARTMENUROOT_ICON_SIZE ICON_SIZE_MIDDLE // ICON_SIZE_LARGE
#define ICON_SIZE_FROM_ICF(flags) (flags&ICF_LARGE? ICON_SIZE_LARGE: flags&ICF_MIDDLE? ICON_SIZE_MIDDLE: ICON_SIZE_SMALL) -#define ICF_FROM_ICON_SIZE(size) (size>=ICON_SIZE_LARGE? ICF_LARGE: size>=ICON_SIZE_MIDDLE? ICF_MIDDLE: ICF_NORMAL) +#define ICF_FROM_ICON_SIZE(size) (size>=ICON_SIZE_LARGE? ICF_LARGE: size>=ICON_SIZE_MIDDLE? ICF_MIDDLE: (ICONCACHE_FLAGS)0)
/// create a bitmap from an icon _____
Modified: trunk/reactos/base/shell/explorer/notifyhook/notifyhook.dsp --- trunk/reactos/base/shell/explorer/notifyhook/notifyhook.dsp 2006-01-29 15:15:23 UTC (rev 34) +++ trunk/reactos/base/shell/explorer/notifyhook/notifyhook.dsp 2006-01-29 15:28:15 UTC (rev 35) @@ -132,5 +132,9 @@
SOURCE=.\notifyhook.rbuild # End Source File +# Begin Source File + +SOURCE=..\utility\utility.h +# End Source File # End Target # End Project _____
Modified: trunk/reactos/base/shell/explorer/shell/entries.cpp --- trunk/reactos/base/shell/explorer/shell/entries.cpp 2006-01-29 15:15:23 UTC (rev 34) +++ trunk/reactos/base/shell/explorer/shell/entries.cpp 2006-01-29 15:28:15 UTC (rev 35) @@ -413,32 +413,10 @@
}
if (icon_id == ICID_NONE) { - SHFILEINFO sfi; - const ShellPath& pidl_abs = create_absolute_pidl(); LPCITEMIDLIST pidl = pidl_abs;
- int shgfi_flags = SHGFI_PIDL; - - if (!(flags & (ICF_LARGE|ICF_MIDDLE))) - shgfi_flags |= SHGFI_SMALLICON; - - if (flags & ICF_OPEN) - shgfi_flags |= SHGFI_OPENICON; - - if (flags & ICF_SYSCACHE) { - assert(!(flags&ICF_OVERLAYS)); - - HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|shgfi_flags); - if (himlSys) - icon_id = g_Globals._icon_cache.add(sfi.iIcon); - } else { - if (flags & ICF_OVERLAYS) - shgfi_flags |= SHGFI_ADDOVERLAYS; - - if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_ICON|shgfi_flags)) - icon_id = g_Globals._icon_cache.add(sfi.hIcon); - } + icon_id = g_Globals._icon_cache.extract(pidl, flags); } }
_____
Modified: trunk/reactos/base/shell/explorer/utility/shellclasses.h --- trunk/reactos/base/shell/explorer/utility/shellclasses.h 2006-01-29 15:15:23 UTC (rev 34) +++ trunk/reactos/base/shell/explorer/utility/shellclasses.h 2006-01-29 15:28:15 UTC (rev 35) @@ -791,6 +791,18 @@
_p = (ITEMIDLIST*)p; }
+ friend bool operator<(const ShellPath& a, const ShellPath& b) + { + int la = ILGetSize(a._p); + int lb = ILGetSize(b._p); + + int r = memcmp(a._p, b._p, min(la, lb)); + if (r) + return r < 0; + else + return la < lb; + } + void assign(LPCITEMIDLIST pidl, size_t size) { //CONTEXT("ShellPath::assign(LPCITEMIDLIST, size_t)"); _____
Modified: trunk/reactos/base/shell/explorer/utility/window.cpp --- trunk/reactos/base/shell/explorer/utility/window.cpp 2006-01-29 15:15:23 UTC (rev 34) +++ trunk/reactos/base/shell/explorer/utility/window.cpp 2006-01-29 15:28:15 UTC (rev 35) @@ -392,7 +392,7 @@
ClientRect rt(_hwnd); rt.left = _split_pos-SPLIT_WIDTH/2; rt.right = _split_pos+SPLIT_WIDTH/2+1; - HBRUSH lastBrush = SelectBrush(canvas, GetStockBrush(LTGRAY_BRUSH)); + HBRUSH lastBrush = SelectBrush(canvas, GetStockBrush(COLOR_SPLITBAR)); Rectangle(canvas, rt.left, rt.top-1, rt.right, rt.bottom+1); SetRect(&rc, rt.left, rt.top-1, rt.right, rt.bottom+1); DrawEdge(canvas, &rc, EDGE_RAISED, BF_RECT);