shell32: handle overlay icon flags and registry settings

Martin Fuchs martin-fuchs at gmx.net
Sun Nov 20 07:28:02 CST 2005


This new patch superseded my last one. It now also looks into the registry to handle icon overrides.
I introduced a new internal function SHELL_IsShortcut() to merge common code.


Changelog:
- SHGetFileInfoW(): handle SHGFI_LINKOVERLAY and SHGFI_OVERLAYINDEX
- SHMapPIDLToSystemImageListIndex(): determine overlay flag for PidlToSicIndex() and return -1 in error cases
- Read shell overlay icon settings from registry to allow icon overrides.


Index: iconcache.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/iconcache.c,v
retrieving revision 1.95
diff -u -p -d -w -b -r1.95 iconcache.c
--- iconcache.c	27 Oct 2005 12:08:44 -0000	1.95
+++ iconcache.c	20 Nov 2005 13:26:03 -0000
@@ -96,6 +96,9 @@ static INT CALLBACK SIC_CompareEntries( 
 	return 0;
 }
 
+/* declare SIC_LoadOverlayIcon() */
+static int SIC_LoadOverlayIcon(int idx);
+
 /*****************************************************************************
  * SIC_OverlayShortcutImage			[internal]
  *
@@ -103,7 +106,7 @@ static INT CALLBACK SIC_CompareEntries( 
  *  Creates a new icon as a copy of the passed-in icon, overlayed with a
  *  shortcut image. 
  */
-static HICON SIC_OverlayShortcutImage(HICON SourceIcon)
+static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
 {	ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
 	HICON ShortcutIcon, TargetIcon;
 	BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
@@ -115,15 +118,28 @@ static HICON SIC_OverlayShortcutImage(HI
 	  OldShortcutBitmap = NULL,
 	  OldTargetBitmap = NULL;
 
+	static int s_imgListIdx = -1;
+
 	/* Get information about the source icon and shortcut overlay */
 	if (! GetIconInfo(SourceIcon, &SourceIconInfo)
 	    || 0 == GetObjectW(SourceIconInfo.hbmColor, sizeof(BITMAP), &SourceBitmapInfo))
 	{
 	  return NULL;
 	}
-	ShortcutIcon = LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_SHORTCUT),
-	                          IMAGE_ICON, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmWidth,
-	                          LR_SHARED);
+
+	/* search for the shortcut icon only once */
+	if (s_imgListIdx == -1)
+	    s_imgListIdx = SIC_LoadOverlayIcon(29); /* icon index for IDI_SHELL_SHORTCUT */
+
+	if (s_imgListIdx != -1)
+	{
+	    if (large)
+	        ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT);
+	    else
+	        ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT);
+	} else
+	    ShortcutIcon = NULL;
+
 	if (NULL == ShortcutIcon
 	    || ! GetIconInfo(ShortcutIcon, &ShortcutIconInfo)
 	    || 0 == GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo))
@@ -299,8 +315,8 @@ static INT SIC_LoadIcon (LPCWSTR sSource
 
 	if (0 != (dwFlags & GIL_FORSHORTCUT))
 	{
-	  hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge);
-	  hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall);
+	  hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE);
+	  hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE);
 	  if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut)
 	  {
 	    hiconLarge = hiconLargeShortcut;
@@ -443,6 +459,52 @@ void SIC_Destroy(void)
 	DeleteCriticalSection(&SHELL32_SicCS);
 }
 
+/*****************************************************************************
+ * SIC_LoadOverlayIcon			[internal]
+ *
+ * Load a shell overlay icon and return its icon cache index.
+ */
+static int SIC_LoadOverlayIcon(int idx)
+{
+	WCHAR buffer[1024], wszIdx[8];
+	HKEY hKeyShellIcons;
+	LPCWSTR iconPath;
+	int iconIdx;
+
+	static const WCHAR wszShellIcons[] = {
+	    'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+	    'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+	    'E','x','p','l','o','r','e','r','\\','S','h','e','l','l',' ','I','c','o','n','s',0
+	}; 
+	static const WCHAR wszNumFmt[] = {'%','d',0};
+
+	iconPath = swShell32Name;	/* default: load icon from shell32.dll */
+	iconIdx = idx;
+
+	if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszShellIcons, 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS)
+	{
+	    DWORD count = sizeof(buffer);
+
+	    sprintfW(wszIdx, wszNumFmt, idx);
+
+	    /* read icon path and index */
+	    if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS)
+	    {
+		LPWSTR p = strchrW(buffer, ',');
+
+		if (p)
+		    *p++ = 0;
+
+		iconPath = buffer;
+		iconIdx = atoiW(p);
+	    }
+
+	    RegCloseKey(hKeyShellIcons);
+	}
+
+	return SIC_LoadIcon(iconPath, iconIdx, 0);
+}
+
 /*************************************************************************
  * Shell_GetImageList			[SHELL32.71]
  *
@@ -481,29 +543,15 @@ BOOL PidlToSicIndex (
 {
 	IExtractIconW	*ei;
 	WCHAR		szIconFile[MAX_PATH];	/* file containing the icon */
-	char		szTemp[MAX_PATH];
 	INT		iSourceIndex;		/* index or resID(negated) in this file */
 	BOOL		ret = FALSE;
 	UINT		dwFlags = 0;
-	HKEY		keyCls;
 	int		iShortcutDefaultIndex = INVALID_INDEX;
 
 	TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
 
 	if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
 	{
-	  if (_ILGetExtension(pidl, szTemp, MAX_PATH) &&
-	      HCR_MapTypeToValueA(szTemp, szTemp, MAX_PATH, TRUE))
-	  {
-	    if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_QUERY_VALUE, &keyCls))
-	    {
-	      if (ERROR_SUCCESS == RegQueryValueExA(keyCls, "IsShortcut", NULL, NULL, NULL, NULL))
-	      {
-	        uFlags |= GIL_FORSHORTCUT;
-	      }
-	      RegCloseKey(keyCls);
-	    }
-	  }
 	  if (SUCCEEDED(IExtractIconW_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
 	  {
 	    *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
@@ -547,13 +595,21 @@ int WINAPI SHMapPIDLToSystemImageListInd
 	int *pIndex)
 {
 	int Index;
+	UINT uGilFlags = 0;
 
 	TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
 	pdump(pidl);
 
+	if (SHELL_IsShortcut(pidl))
+	    uGilFlags |= GIL_FORSHORTCUT;
+
 	if (pIndex)
-	  PidlToSicIndex ( sh, pidl, 1, 0, pIndex);
-	PidlToSicIndex ( sh, pidl, 0, 0, &Index);
+	    if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex))
+	        *pIndex = -1;
+
+	if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index))
+	    return -1;
+
 	return Index;
 }
 
Index: shell32_main.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shell32_main.c,v
retrieving revision 1.156
diff -u -p -d -w -b -r1.156 shell32_main.c
--- shell32_main.c	2 Sep 2005 11:32:18 -0000	1.156
+++ shell32_main.c	20 Nov 2005 13:26:03 -0000
@@ -297,6 +297,32 @@ static DWORD shgfi_get_exe_type(LPCWSTR 
     return 0;
 }
 
+/*************************************************************************
+ * SHELL_IsShortcut		[internal]
+ *
+ * Decide if an item id list points to a shell shortcut
+ */
+BOOL SHELL_IsShortcut(LPCITEMIDLIST pidlLast)
+{
+    char szTemp[MAX_PATH];
+    HKEY keyCls;
+    BOOL ret = FALSE;
+
+    if (_ILGetExtension(pidlLast, szTemp, MAX_PATH) &&
+          HCR_MapTypeToValueA(szTemp, szTemp, MAX_PATH, TRUE))
+    {
+        if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_QUERY_VALUE, &keyCls))
+        {
+          if (ERROR_SUCCESS == RegQueryValueExA(keyCls, "IsShortcut", NULL, NULL, NULL, NULL))
+            ret = TRUE;
+
+          RegCloseKey(keyCls);
+        }
+    }
+
+    return ret;
+}
+
 #define SHGFI_KNOWN_FLAGS \
     (SHGFI_SMALLICON | SHGFI_OPENICON | SHGFI_SHELLICONSIZE | SHGFI_PIDL | \
      SHGFI_USEFILEATTRIBUTES | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX | \
@@ -320,6 +346,7 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR 
     LPITEMIDLIST    pidlLast = NULL, pidl = NULL;
     HRESULT hr = S_OK;
     BOOL IconNotYetLoaded=TRUE;
+    UINT uGilFlags = 0;
 
     TRACE("%s fattr=0x%lx sfi=%p(attr=0x%08lx) size=0x%x flags=0x%x\n",
           (flags & SHGFI_PIDL)? "pidl" : debugstr_w(path), dwFileAttributes,
@@ -458,15 +485,21 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR 
     }
 
     /* ### icons ###*/
-    if (flags & SHGFI_ADDOVERLAYS)
-        FIXME("SHGFI_ADDOVERLAYS unhandled\n");
+    if (flags & SHGFI_OPENICON)
+        uGilFlags |= GIL_OPENICON;
+
+    if (flags & SHGFI_LINKOVERLAY)
+        uGilFlags |= GIL_FORSHORTCUT;
+    else if ((flags&SHGFI_ADDOVERLAYS) ||
+             (flags&(SHGFI_ICON|SHGFI_SMALLICON))==SHGFI_ICON)
+    {
+        if (SHELL_IsShortcut(pidlLast))
+            uGilFlags |= GIL_FORSHORTCUT;
+    }
 
     if (flags & SHGFI_OVERLAYINDEX)
         FIXME("SHGFI_OVERLAYINDEX unhandled\n");
 
-    if (flags & SHGFI_LINKOVERLAY)
-        FIXME("set icon to link, stub\n");
-
     if (flags & SHGFI_SELECTED)
         FIXME("set icon to selected, stub\n");
 
@@ -483,12 +516,11 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR 
                &uDummy, (LPVOID*)&pei);
         if (SUCCEEDED(hr))
         {
-            hr = IExtractIconW_GetIconLocation(pei, 
-                    (flags & SHGFI_OPENICON)? GIL_OPENICON : 0,
+            hr = IExtractIconW_GetIconLocation(pei, uGilFlags,
                     szLocation, MAX_PATH, &iIndex, &uFlags);
             psfi->iIcon = iIndex;
 
-            if (uFlags != GIL_NOTFILENAME)
+            if (!(uFlags & GIL_NOTFILENAME))
                 lstrcpyW (psfi->szDisplayName, szLocation);
             else
                 ret = FALSE;
@@ -550,7 +582,7 @@ DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR 
         else
         {
             if (!(PidlToSicIndex(psfParent, pidlLast, !(flags & SHGFI_SMALLICON),
-                (flags & SHGFI_OPENICON)? GIL_OPENICON : 0, &(psfi->iIcon))))
+                uGilFlags, &(psfi->iIcon))))
             {
                 ret = FALSE;
             }
Index: shell32_main.h
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shell32_main.h,v
retrieving revision 1.108
diff -u -p -d -w -b -r1.108 shell32_main.h
--- shell32_main.h	11 Nov 2005 10:54:07 -0000	1.108
+++ shell32_main.h	20 Nov 2005 13:26:04 -0000
@@ -231,4 +231,7 @@ extern const GUID CLSID_UnixDosFolder;
 /* Default shell folder value registration */
 HRESULT SHELL_RegisterShellFolders(void);
 
+/* Detect Shell Links */
+BOOL SHELL_IsShortcut(LPCITEMIDLIST);
+
 #endif




More information about the wine-patches mailing list