From b73fce3206de216ebb9423caae4bcc02d64de261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= 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 | 223 ++++++++++++++++++++++++++--------------- dlls/shell32/shell32_main.h | 3 + dlls/shell32/shellord.c | 28 ++++-- dlls/shell32/tests/shelllink.c | 7 +- 4 files changed, 169 insertions(+), 92 deletions(-) diff --git a/dlls/shell32/iconcache.c b/dlls/shell32/iconcache.c index 0ea2eb9e0e8..767c90e8e71 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 = @@ -158,7 +160,7 @@ static int SIC_LoadOverlayIcon(int icon_idx); * Creates a new icon as a copy of the passed-in icon, overlaid 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; @@ -188,10 +190,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; @@ -307,11 +315,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)); @@ -333,13 +344,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; } @@ -353,7 +365,7 @@ static BOOL get_imagelist_icon_size(int list, SIZE *size) HIMAGELIST image_list; if (list < SHIL_LARGE || list > SHIL_SMALL) return FALSE; - image_list = (list == SHIL_LARGE) ? ShellBigIconList : ShellSmallIconList; + image_list = (list == SHIL_LARGE) ? ShellLargeIconList : ShellSmallIconList; return ImageList_GetIconSize( image_list, &size->cx, &size->cy ); } @@ -366,19 +378,25 @@ static BOOL get_imagelist_icon_size(int list, SIZE *size) */ static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags) { - HICON hiconLarge=0; - HICON hiconSmall=0; - HICON hiconLargeShortcut; - HICON hiconSmallShortcut; - int ret; - SIZE size; - - get_imagelist_icon_size( SHIL_LARGE, &size ); - PrivateExtractIconsW( sSourceFile, dwSourceIndex, size.cx, size.cy, &hiconLarge, 0, 1, 0 ); - get_imagelist_icon_size( SHIL_SMALL, &size ); - PrivateExtractIconsW( sSourceFile, dwSourceIndex, size.cx, size.cy, &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; + int ret; + SIZE size; + + get_imagelist_icon_size( SHIL_SMALL, &size ); + PrivateExtractIconsW( sSourceFile, dwSourceIndex, size.cx, size.cy, &hiconSmall, 0, 1, 0 ); + get_imagelist_icon_size( SHIL_LARGE, &size ); + PrivateExtractIconsW( sSourceFile, dwSourceIndex, size.cx, size.cy, &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; @@ -386,28 +404,42 @@ 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) - { - DestroyIcon( hiconLarge ); + 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) + { DestroyIcon( hiconSmall ); - hiconLarge = hiconLargeShortcut; - hiconSmall = hiconSmallShortcut; - } - else - { - WARN("Failed to create shortcut overlaid icons\n"); - if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut); - if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut); - dwFlags &= ~ GIL_FORSHORTCUT; - } + DestroyIcon( hiconLarge ); + DestroyIcon( hiconExtraLarge ); + DestroyIcon( hiconJumbo ); + + hiconSmall = hiconSmallShortcut; + hiconLarge = hiconLargeShortcut; + hiconExtraLarge = hiconExtraLargeShortcut; + hiconJumbo = hiconJumboShortcut; + } + else + { + WARN("Failed to create shortcut overlaid 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; + } } - ret = SIC_IconAppend( sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, dwFlags ); - DestroyIcon( hiconLarge ); - DestroyIcon( hiconSmall ); - return ret; + ret = SIC_IconAppend( sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, + hiconExtraLarge, hiconJumbo, dwFlags ); + DestroyIcon( hiconSmall ); + DestroyIcon( hiconLarge ); + DestroyIcon( hiconExtraLarge ); + DestroyIcon( hiconJumbo ); + return ret; } static int get_shell_icon_size(void) @@ -433,9 +465,11 @@ static int get_shell_icon_size(void) */ 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; if (!IsProcessDPIAware()) { @@ -451,7 +485,13 @@ static BOOL WINAPI SIC_Initialize( INIT_ONCE *once, void *param, void **context cy_small = cy_large / 2; } + cx_extralarge = (GetSystemMetrics( SM_CXICON ) * 3) / 2; + cy_extralarge = (GetSystemMetrics( SM_CYICON ) * 3) / 2; + cx_jumbo = 256; + cy_jumbo = 256; + TRACE("large %dx%d small %dx%d\n", cx_large, cy_large, cx_small, cx_small); + TRACE("extra %dx%d jumbo %dx%d\n", cx_extralarge, cy_extralarge, cx_jumbo, cy_jumbo); sic_hdpa = DPA_Create(16); @@ -460,28 +500,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); - - /* 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); + 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; + } - if (!hSm || !hLg) - { - FIXME("Failed to load IDI_SHELL_DOCUMENT icon!\n"); - return FALSE; - } + SIC_IconAppend( swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, hELg, hJb, 0 ); + SIC_IconAppend( swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, hELg, hJb, 0 ); - 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; } @@ -505,13 +553,17 @@ void SIC_Destroy(void) if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL ); - if (ShellSmallIconList) - ImageList_Destroy(ShellSmallIconList); - if (ShellBigIconList) - ImageList_Destroy(ShellBigIconList); - - LeaveCriticalSection(&SHELL32_SicCS); - DeleteCriticalSection(&SHELL32_SicCS); + 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); } /***************************************************************************** @@ -625,10 +677,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 fc2a5ba8a86..b91bb5528ad 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -251,4 +251,7 @@ static inline WCHAR *strdupAtoW(const char *str) return ret; } +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 f9814997dae..5102bf0e475 100644 --- a/dlls/shell32/shellord.c +++ b/dlls/shell32/shellord.c @@ -2146,18 +2146,30 @@ void WINAPI SHFlushSFCache(void) */ HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv) { - HIMAGELIST hLarge, hSmall; + HIMAGELIST hSmall, hLarge, hExtraLarge, hJumbo; HIMAGELIST hNew; - /* 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 = hSmall; + break; + case SHIL_LARGE: + hNew = hLarge; + break; + case SHIL_EXTRALARGE: + hNew = hExtraLarge; + break; + case SHIL_JUMBO: + hNew = hJumbo; + break; + default: + FIXME("Unsupported image list %i requested\n", iImageList); + return E_FAIL; } - Shell_GetImageLists(&hLarge, &hSmall); - hNew = (iImageList == SHIL_LARGE) ? hLarge : hSmall; - return HIMAGELIST_QueryInterface(hNew, riid, ppv); } diff --git a/dlls/shell32/tests/shelllink.c b/dlls/shell32/tests/shelllink.c index ad254c83498..03878af46dd 100644 --- a/dlls/shell32/tests/shelllink.c +++ b/dlls/shell32/tests/shelllink.c @@ -1363,10 +1363,9 @@ static void test_SHGetImageList(void) for (i = 0; i <= SHIL_LAST; i++) { hr = SHGetImageList( i, &IID_IImageList, (void **)&list ); - todo_wine_if(i == SHIL_EXTRALARGE || i == SHIL_JUMBO) - ok( hr == S_OK || - broken( i == SHIL_JUMBO && hr == E_INVALIDARG ), /* XP and 2003 */ - "%d: got %08x\n", i, hr ); + ok( hr == S_OK || + broken( i == SHIL_JUMBO && hr == E_INVALIDARG ), /* XP and 2003 */ + "%d: got %08x\n", i, hr ); if (FAILED(hr)) continue; IImageList_GetIconSize( list, &width, &height ); switch (i) -- 2.13.0