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