From d3521da667e0e48f2b621c53a90ef17daba2b384 Mon Sep 17 00:00:00 2001 From: Martin Fuchs Date: Mon, 21 Nov 2005 13:35:06 +0000 Subject: [PATCH] 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. --- dlls/shell32/iconcache.c | 100 ++++++++++++++++++++++++++++-------- dlls/shell32/shell32_main.c | 50 ++++++++++++++---- dlls/shell32/shell32_main.h | 3 ++ 3 files changed, 122 insertions(+), 31 deletions(-) diff --git a/dlls/shell32/iconcache.c b/dlls/shell32/iconcache.c index e35091729d3..696115effef 100644 --- a/dlls/shell32/iconcache.c +++ b/dlls/shell32/iconcache.c @@ -96,6 +96,9 @@ static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam) return 0; } +/* declare SIC_LoadOverlayIcon() */ +static int SIC_LoadOverlayIcon(int idx); + /***************************************************************************** * SIC_OverlayShortcutImage [internal] * @@ -103,7 +106,7 @@ static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam) * 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(HICON SourceIcon) 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 sSourceFile, INT dwSourceIndex, DWORD dwFlags) 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 SHMapPIDLToSystemImageListIndex( 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; } diff --git a/dlls/shell32/shell32_main.c b/dlls/shell32/shell32_main.c index 6dbc714a238..2b3509860c9 100644 --- a/dlls/shell32/shell32_main.c +++ b/dlls/shell32/shell32_main.c @@ -297,6 +297,32 @@ static DWORD shgfi_get_exe_type(LPCWSTR szFullPath) 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 path,DWORD dwFileAttributes, 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 path,DWORD dwFileAttributes, } /* ### 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 path,DWORD dwFileAttributes, &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 path,DWORD dwFileAttributes, else { if (!(PidlToSicIndex(psfParent, pidlLast, !(flags & SHGFI_SMALLICON), - (flags & SHGFI_OPENICON)? GIL_OPENICON : 0, &(psfi->iIcon)))) + uGilFlags, &(psfi->iIcon)))) { ret = FALSE; } diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index 3d39676d05a..4efec8a1d99 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -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