From 8fd25fe53f564ebbe2dd2a2de6ed1126c4b4ee1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sun, 3 Aug 2014 02:23:44 +0200
Subject: shell32: Add support for extra large and jumbo icon lists. (v2)

---
 dlls/shell32/iconcache.c    | 203 +++++++++++++++++++++++++++++---------------
 dlls/shell32/shell32_main.h |   3 +
 dlls/shell32/shellord.c     |  28 ++++--
 3 files changed, 156 insertions(+), 78 deletions(-)

diff --git a/dlls/shell32/iconcache.c b/dlls/shell32/iconcache.c
index 4549d5b..2aff054 100644
--- a/dlls/shell32/iconcache.c
+++ b/dlls/shell32/iconcache.c
@@ -62,7 +62,9 @@ typedef struct
 static HDPA sic_hdpa;
 static INIT_ONCE sic_init_once = INIT_ONCE_STATIC_INIT;
 static HIMAGELIST ShellSmallIconList;
-static HIMAGELIST ShellBigIconList;
+static HIMAGELIST ShellLargeIconList;
+static HIMAGELIST ShellExtraLargeIconList;
+static HIMAGELIST ShellJumboIconList;
 
 static CRITICAL_SECTION SHELL32_SicCS;
 static CRITICAL_SECTION_DEBUG critsect_debug =
@@ -109,7 +111,7 @@ static int SIC_LoadOverlayIcon(int icon_idx);
  *  Creates a new icon as a copy of the passed-in icon, overlayed with a
  *  shortcut image. 
  */
-static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
+static HICON SIC_OverlayShortcutImage(HICON SourceIcon, int type)
 {	ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
 	HICON ShortcutIcon, TargetIcon;
 	BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
@@ -139,10 +141,16 @@ static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
 
 	if (s_imgListIdx != -1)
 	{
-	    if (large)
-	        ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT);
-	    else
-	        ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT);
+        if (type == SHIL_SMALL)
+            ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT);
+        else if (type == SHIL_LARGE)
+            ShortcutIcon = ImageList_GetIcon(ShellLargeIconList, s_imgListIdx, ILD_TRANSPARENT);
+        else if (type == SHIL_EXTRALARGE)
+            ShortcutIcon = ImageList_GetIcon(ShellExtraLargeIconList, s_imgListIdx, ILD_TRANSPARENT);
+        else if (type == SHIL_JUMBO)
+            ShortcutIcon = ImageList_GetIcon(ShellJumboIconList, s_imgListIdx, ILD_TRANSPARENT);
+        else
+            ShortcutIcon = NULL;
 	} else
 	    ShortcutIcon = NULL;
 
@@ -258,11 +266,14 @@ fail:
  * NOTES
  *  appends an icon pair to the end of the cache
  */
-static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon, DWORD dwFlags)
-{	LPSIC_ENTRY lpsice;
-	INT ret, index, index1;
+static INT SIC_IconAppend(LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon,
+                          HICON hLargeIcon, HICON hExtraLargeIcon, HICON hJumboIcon, DWORD dwFlags)
+{
+    LPSIC_ENTRY lpsice;
+    INT ret, index, index1, index2, index3;
 	WCHAR path[MAX_PATH];
-	TRACE("%s %i %p %p\n", debugstr_w(sSourceFile), dwSourceIndex, hSmallIcon ,hBigIcon);
+    TRACE("%s %i %p %p %p %p %d\n", debugstr_w(sSourceFile), dwSourceIndex, hSmallIcon,
+        hLargeIcon, hExtraLargeIcon, hJumboIcon, dwFlags);
 
 	lpsice = SHAlloc(sizeof(SIC_ENTRY));
 
@@ -284,13 +295,14 @@ static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallI
 	}
 	else
 	{
-	  index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon);
-	  index1= ImageList_AddIcon (ShellBigIconList, hBigIcon);
+        index  = ImageList_AddIcon( ShellSmallIconList, hSmallIcon );
+        index1 = ImageList_AddIcon( ShellLargeIconList, hLargeIcon );
+        index2 = ImageList_AddIcon( ShellExtraLargeIconList, hExtraLargeIcon );
+        index3 = ImageList_AddIcon( ShellJumboIconList, hJumboIcon );
+
+        if (index != index1 || index != index2 || index != index3)
+            FIXME("iconlists out of sync 0x%x 0x%x 0x%x 0x%x\n", index, index1, index2, index3);
 
-	  if (index!=index1)
-	  {
-	    FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1);
-	  }
 	  lpsice->dwListIndex = index;
 	  ret = lpsice->dwListIndex;
 	}
@@ -305,17 +317,24 @@ static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallI
  *  gets small/big icon by number from a file
  */
 static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags)
-{	HICON	hiconLarge=0;
-	HICON	hiconSmall=0;
-	HICON 	hiconLargeShortcut;
-	HICON	hiconSmallShortcut;
-
-        PrivateExtractIconsW( sSourceFile, dwSourceIndex, GetSystemMetrics(SM_CXICON),
-                              GetSystemMetrics(SM_CYICON), &hiconLarge, 0, 1, 0 );
-        PrivateExtractIconsW( sSourceFile, dwSourceIndex, GetSystemMetrics(SM_CXSMICON),
-                              GetSystemMetrics(SM_CYSMICON), &hiconSmall, 0, 1, 0 );
-
-	if ( !hiconLarge ||  !hiconSmall)
+{
+    HICON   hiconSmall=0;
+    HICON   hiconLarge=0;
+    HICON   hiconExtraLarge=0;
+    HICON   hiconJumbo=0;
+    HICON   hiconSmallShortcut;
+    HICON   hiconLargeShortcut;
+    HICON   hiconExtraLargeShortcut;
+    HICON   hiconJumboShortcut;
+
+    PrivateExtractIconsW( sSourceFile, dwSourceIndex, GetSystemMetrics(SM_CXSMICON),
+                          GetSystemMetrics(SM_CYSMICON), &hiconSmall, 0, 1, 0 );
+    PrivateExtractIconsW( sSourceFile, dwSourceIndex, GetSystemMetrics(SM_CXICON),
+                          GetSystemMetrics(SM_CYICON), &hiconLarge, 0, 1, 0 );
+    PrivateExtractIconsW( sSourceFile, dwSourceIndex, 48, 48, &hiconExtraLarge, 0, 1, 0 );
+    PrivateExtractIconsW( sSourceFile, dwSourceIndex, 256, 256, &hiconJumbo, 0, 1, 0 );
+
+	if (!hiconSmall || !hiconLarge || !hiconExtraLarge || !hiconJumbo)
 	{
 	  WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex, debugstr_w(sSourceFile), hiconLarge, hiconSmall);
 	  return -1;
@@ -323,38 +342,59 @@ static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags)
 
 	if (0 != (dwFlags & GIL_FORSHORTCUT))
 	{
-	  hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE);
-	  hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE);
-	  if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut)
-	  {
-	    hiconLarge = hiconLargeShortcut;
-	    hiconSmall = hiconSmallShortcut;
-	  }
-	  else
-	  {
-	    WARN("Failed to create shortcut overlayed icons\n");
-	    if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut);
-	    if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut);
-	    dwFlags &= ~ GIL_FORSHORTCUT;
-	  }
+        hiconSmallShortcut = SIC_OverlayShortcutImage( hiconSmall, SHIL_SMALL );
+        hiconLargeShortcut = SIC_OverlayShortcutImage( hiconLarge, SHIL_LARGE );
+        hiconExtraLargeShortcut = SIC_OverlayShortcutImage( hiconExtraLarge, SHIL_EXTRALARGE );
+        hiconJumboShortcut = SIC_OverlayShortcutImage( hiconJumbo, SHIL_JUMBO );
+
+        if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut &&
+            NULL != hiconExtraLargeShortcut && NULL != hiconJumboShortcut)
+        {
+            hiconSmall = hiconSmallShortcut;
+            hiconLarge = hiconLargeShortcut;
+            hiconExtraLarge = hiconExtraLargeShortcut;
+            hiconJumbo = hiconJumboShortcut;
+        }
+        else
+        {
+            WARN("Failed to create shortcut overlayed icons\n");
+            if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut);
+            if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut);
+            if (NULL != hiconExtraLargeShortcut) DestroyIcon(hiconExtraLargeShortcut);
+            if (NULL != hiconJumboShortcut) DestroyIcon(hiconJumboShortcut);
+            dwFlags &= ~ GIL_FORSHORTCUT;
+        }
 	}
 
-	return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, dwFlags);
+    return SIC_IconAppend( sSourceFile, dwSourceIndex, hiconSmall, hiconLarge,
+                           hiconExtraLarge, hiconJumbo, dwFlags );
 }
 /*****************************************************************************
  * SIC_Initialize			[internal]
  */
 static BOOL WINAPI SIC_Initialize( INIT_ONCE *once, void *param, void **context )
 {
-	HICON		hSm, hLg;
-	int		cx_small, cy_small;
-	int		cx_large, cy_large;
+    HICON   hSm, hLg, hELg, hJb;
+    int     cx_small, cy_small;
+    int     cx_large, cy_large;
+    int     cx_extralarge, cy_extralarge;
+    int     cx_jumbo, cy_jumbo;
 
 	cx_small = GetSystemMetrics(SM_CXSMICON);
 	cy_small = GetSystemMetrics(SM_CYSMICON);
 	cx_large = GetSystemMetrics(SM_CXICON);
 	cy_large = GetSystemMetrics(SM_CYICON);
 
+    /*
+     * TODO: according to
+     * http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx
+     * the size can be configured, but where is the value defined?
+     */
+    cx_extralarge = 48;
+    cy_extralarge = 48;
+    cx_jumbo = 256;
+    cy_jumbo = 256;
+
 	TRACE("\n");
 
 	sic_hdpa = DPA_Create(16);
@@ -364,28 +404,36 @@ static BOOL WINAPI SIC_Initialize( INIT_ONCE *once, void *param, void **context
 	  return(FALSE);
 	}
 
-        ShellSmallIconList = ImageList_Create(cx_small,cy_small,ILC_COLOR32|ILC_MASK,0,0x20);
-        ShellBigIconList = ImageList_Create(cx_large,cy_large,ILC_COLOR32|ILC_MASK,0,0x20);
-
-        ImageList_SetBkColor(ShellSmallIconList, CLR_NONE);
-        ImageList_SetBkColor(ShellBigIconList, CLR_NONE);
+    ShellSmallIconList = ImageList_Create( cx_small,cy_small,ILC_COLOR32|ILC_MASK,0,0x20 );
+    ShellLargeIconList = ImageList_Create( cx_large,cy_large,ILC_COLOR32|ILC_MASK,0,0x20 );
+    ShellExtraLargeIconList = ImageList_Create( cx_extralarge,cy_extralarge,ILC_COLOR32|ILC_MASK,0,0x20 );
+    ShellJumboIconList = ImageList_Create( cx_jumbo,cy_jumbo,ILC_COLOR32|ILC_MASK,0,0x20 );
+
+    ImageList_SetBkColor( ShellSmallIconList, CLR_NONE );
+    ImageList_SetBkColor( ShellLargeIconList, CLR_NONE );
+    ImageList_SetBkColor( ShellExtraLargeIconList, CLR_NONE );
+    ImageList_SetBkColor( ShellJumboIconList, CLR_NONE );
+
+    /* Load the document icon, which is used as the default if an icon isn't found. */
+    hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT),
+                            IMAGE_ICON, cx_small, cy_small, LR_SHARED);
+    hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT),
+                            IMAGE_ICON, cx_large, cy_large, LR_SHARED);
+    hELg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT),
+                            IMAGE_ICON, cx_extralarge, cy_extralarge, LR_SHARED);
+    hJb = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT),
+                            IMAGE_ICON, cx_jumbo, cy_jumbo, LR_SHARED);
+    if (!hSm || !hLg || !hELg || !hJb)
+    {
+      FIXME("Failed to load IDI_SHELL_DOCUMENT icon!\n");
+      return FALSE;
+    }
 
-        /* Load the document icon, which is used as the default if an icon isn't found. */
-        hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT),
-                                IMAGE_ICON, cx_small, cy_small, LR_SHARED);
-        hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_DOCUMENT),
-                                IMAGE_ICON, cx_large, cy_large, LR_SHARED);
+    SIC_IconAppend( swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, hELg, hJb, 0 );
+    SIC_IconAppend( swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, hELg, hJb, 0 );
 
-        if (!hSm || !hLg) 
-        {
-          FIXME("Failed to load IDI_SHELL_DOCUMENT icon!\n");
-          return FALSE;
-        }
-
-        SIC_IconAppend (swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, 0);
-        SIC_IconAppend (swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, 0);
-   
-	TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
+    TRACE("hIconSmall=%p hIconLarge=%p hExtraLargeIcon=%p hJumboIcon=%p\n",
+        ShellSmallIconList, ShellLargeIconList, ShellExtraLargeIconList, ShellJumboIconList);
 
 	return TRUE;
 }
@@ -409,10 +457,14 @@ void SIC_Destroy(void)
 
 	if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
 
-	if (ShellSmallIconList)
-	    ImageList_Destroy(ShellSmallIconList);
-	if (ShellBigIconList)
-	    ImageList_Destroy(ShellBigIconList);
+    if (ShellSmallIconList)
+        ImageList_Destroy( ShellSmallIconList );
+    if (ShellLargeIconList)
+        ImageList_Destroy( ShellLargeIconList );
+    if (ShellExtraLargeIconList)
+        ImageList_Destroy( ShellExtraLargeIconList );
+    if (ShellJumboIconList)
+        ImageList_Destroy( ShellJumboIconList );
 
 	LeaveCriticalSection(&SHELL32_SicCS);
 	DeleteCriticalSection(&SHELL32_SicCS);
@@ -529,10 +581,21 @@ BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList
 {
     TRACE("(%p,%p)\n",lpBigList,lpSmallList);
     InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
-    if (lpBigList) *lpBigList = ShellBigIconList;
+    if (lpBigList) *lpBigList = ShellLargeIconList;
     if (lpSmallList) *lpSmallList = ShellSmallIconList;
     return TRUE;
 }
+
+void SHELL_GetInternalImageLists(HIMAGELIST *lpSmallList, HIMAGELIST *lpLargeList,
+    HIMAGELIST *lpExtraLargeList, HIMAGELIST *lpJumboList)
+{
+    InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
+    if (lpSmallList) *lpSmallList = ShellSmallIconList;
+    if (lpLargeList) *lpLargeList = ShellLargeIconList;
+    if (lpExtraLargeList) *lpExtraLargeList = ShellExtraLargeIconList;
+    if (lpJumboList) *lpJumboList = ShellJumboIconList;
+}
+
 /*************************************************************************
  * PidlToSicIndex			[INTERNAL]
  *
diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h
index 492f79f..69d2c86 100644
--- a/dlls/shell32/shell32_main.h
+++ b/dlls/shell32/shell32_main.h
@@ -244,4 +244,7 @@ HRESULT get_typeinfo(enum tid_t, ITypeInfo**) DECLSPEC_HIDDEN;
 void release_typelib(void) DECLSPEC_HIDDEN;
 void release_desktop_folder(void) DECLSPEC_HIDDEN;
 
+void SHELL_GetInternalImageLists(HIMAGELIST *lpSmallList, HIMAGELIST *lpLargeList,
+    HIMAGELIST *lpExtraLargeList, HIMAGELIST *lpJumboList) DECLSPEC_HIDDEN;
+
 #endif
diff --git a/dlls/shell32/shellord.c b/dlls/shell32/shellord.c
index 914dc5a..75e5d645a 100644
--- a/dlls/shell32/shellord.c
+++ b/dlls/shell32/shellord.c
@@ -2182,20 +2182,32 @@ void WINAPI SHFlushSFCache(void)
  */
 HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv)
 {
-    HIMAGELIST hLarge, hSmall;
+    HIMAGELIST hSmall, hLarge, hExtraLarge, hJumbo;
     HIMAGELIST hNew;
     HRESULT ret = E_FAIL;
 
-    /* Wine currently only maintains large and small image lists */
-    if ((iImageList != SHIL_LARGE) && (iImageList != SHIL_SMALL) && (iImageList != SHIL_SYSSMALL))
+    SHELL_GetInternalImageLists( &hSmall, &hLarge, &hExtraLarge, &hJumbo );
+
+    switch (iImageList)
     {
-        FIXME("Unsupported image list %i requested\n", iImageList);
-        return E_FAIL;
+        case SHIL_SMALL:
+        case SHIL_SYSSMALL:
+            hNew = ImageList_Duplicate( hSmall );
+            break;
+        case SHIL_LARGE:
+            hNew = ImageList_Duplicate( hLarge );
+            break;
+        case SHIL_EXTRALARGE:
+            hNew = ImageList_Duplicate( hExtraLarge );
+            break;
+        case SHIL_JUMBO:
+            hNew = ImageList_Duplicate( hJumbo );
+            break;
+        default:
+            FIXME("Unsupported image list %i requested\n", iImageList);
+            return E_FAIL;
     }
 
-    Shell_GetImageLists(&hLarge, &hSmall);
-    hNew = ImageList_Duplicate(iImageList == SHIL_LARGE ? hLarge : hSmall);
-
     /* Get the interface for the new image list */
     if (hNew)
     {
-- 
2.5.0

