From eb96d377d11775585ca2702b15b1181af401a4ac Mon Sep 17 00:00:00 2001 From: Oleg Dubinskiy Date: Mon, 4 Mar 2024 14:30:43 +0100 Subject: [PATCH] [SHELL32] Allow custom shortcut overlay icon (#6419) Use correct icon index in SIC_OverlayShortcutImage() to properly load shortcut overlay icon from registry instead of always using default icon. This allows to use custom shortcut icon set by user, in case it was specified there. As FIXME comment stated, the icon indexes were not implemented in the far past, so this workaround was badly required. But now they are implemented, so no need to always use default resource from shell32, enable the correct code instead. Also adapt this to CShellLink::CreateShortcutIcon() when the shortcut icon is being changed in its properties dialog, as well as in CNewMenu class when displaying menu items for creating a new folder or a shortcut. Addendum to f9a5344254. CORE-14758 --- dll/win32/shell32/CNewMenu.cpp | 32 ++++++++++++++++++++++-- dll/win32/shell32/CNewMenu.h | 1 + dll/win32/shell32/CShellLink.cpp | 16 +++++++++--- dll/win32/shell32/dialogs/filedefext.cpp | 1 + dll/win32/shell32/iconcache.cpp | 5 +--- dll/win32/shell32/wine/classes.c | 2 +- 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/dll/win32/shell32/CNewMenu.cpp b/dll/win32/shell32/CNewMenu.cpp index 6c8e9354fc3..b86f6ecc0c8 100644 --- a/dll/win32/shell32/CNewMenu.cpp +++ b/dll/win32/shell32/CNewMenu.cpp @@ -33,6 +33,8 @@ CNewMenu::CNewMenu() : m_idCmdFirst(0), m_idCmdFolder(-1), m_idCmdLink(-1), + m_bCustomIconFolder(FALSE), + m_bCustomIconLink(FALSE), m_hIconFolder(NULL), m_hIconLink(NULL) { @@ -42,6 +44,10 @@ CNewMenu::~CNewMenu() { UnloadAllItems(); + if (m_bCustomIconFolder && m_hIconFolder) + DestroyIcon(m_hIconFolder); + if (m_bCustomIconLink && m_hIconLink) + DestroyIcon(m_hIconLink); if (m_pidlFolder) ILFree(m_pidlFolder); } @@ -768,10 +774,32 @@ HRESULT WINAPI CNewMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) { + const INT cx = GetSystemMetrics(SM_CXSMICON), cy = GetSystemMetrics(SM_CYSMICON); + WCHAR wszIconPath[MAX_PATH]; + int icon_idx; + m_pidlFolder = ILClone(pidlFolder); /* Load folder and shortcut icons */ - m_hIconFolder = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, 16, 16, LR_SHARED); - m_hIconLink = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), IMAGE_ICON, 16, 16, LR_SHARED); + if (HLM_GetIconW(IDI_SHELL_FOLDER - 1, wszIconPath, _countof(wszIconPath), &icon_idx)) + { + ::ExtractIconExW(wszIconPath, icon_idx, &m_hIconFolder, NULL, 1); + m_bCustomIconFolder = TRUE; + } + else + { + m_hIconFolder = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, cx, cy, LR_SHARED); + } + + if (HLM_GetIconW(IDI_SHELL_SHORTCUT - 1, wszIconPath, _countof(wszIconPath), &icon_idx)) + { + ::ExtractIconExW(wszIconPath, icon_idx, &m_hIconLink, NULL, 1); + m_bCustomIconLink = TRUE; + } + else + { + m_hIconLink = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), IMAGE_ICON, cx, cy, LR_SHARED); + } + return S_OK; } diff --git a/dll/win32/shell32/CNewMenu.h b/dll/win32/shell32/CNewMenu.h index 6d0bbe6b927..92f65af1426 100644 --- a/dll/win32/shell32/CNewMenu.h +++ b/dll/win32/shell32/CNewMenu.h @@ -59,6 +59,7 @@ private: CComPtr m_pSite; HMENU m_hSubMenu; UINT m_idCmdFirst, m_idCmdFolder, m_idCmdLink; + BOOL m_bCustomIconFolder, m_bCustomIconLink; HICON m_hIconFolder, m_hIconLink; SHELLNEW_ITEM *LoadItem(LPCWSTR pwszExt); diff --git a/dll/win32/shell32/CShellLink.cpp b/dll/win32/shell32/CShellLink.cpp index 1944fb2f936..f83c6a9654e 100644 --- a/dll/win32/shell32/CShellLink.cpp +++ b/dll/win32/shell32/CShellLink.cpp @@ -3155,11 +3155,21 @@ HICON CShellLink::CreateShortcutIcon(LPCWSTR wszIconPath, INT IconIndex) { const INT cx = GetSystemMetrics(SM_CXICON), cy = GetSystemMetrics(SM_CYICON); const COLORREF crMask = GetSysColor(COLOR_3DFACE); + WCHAR wszLnkIcon[MAX_PATH]; + int lnk_idx; HDC hDC; HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, 1, 1); - HICON hIcon = NULL, hNewIcon = NULL; - HICON hShortcut = (HICON)LoadImageW(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), - IMAGE_ICON, cx, cy, 0); + HICON hIcon = NULL, hNewIcon = NULL, hShortcut; + + if (HLM_GetIconW(IDI_SHELL_SHORTCUT - 1, wszLnkIcon, _countof(wszLnkIcon), &lnk_idx)) + { + ::ExtractIconExW(wszLnkIcon, lnk_idx, &hShortcut, NULL, 1); + } + else + { + hShortcut = (HICON)LoadImageW(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), + IMAGE_ICON, cx, cy, 0); + } ::ExtractIconExW(wszIconPath, IconIndex, &hIcon, NULL, 1); if (!hIcon || !hShortcut || !himl) diff --git a/dll/win32/shell32/dialogs/filedefext.cpp b/dll/win32/shell32/dialogs/filedefext.cpp index 03890b20a83..959b708ad1d 100644 --- a/dll/win32/shell32/dialogs/filedefext.cpp +++ b/dll/win32/shell32/dialogs/filedefext.cpp @@ -1085,6 +1085,7 @@ void CFileDefExt::UpdateFolderIcon(HWND hwndDlg) // create the icon if (m_szFolderIconPath[0] == 0 && m_nFolderIconIndex == 0) { + // Windows ignores shell customization here and uses the default icon m_hFolderIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER)); } else diff --git a/dll/win32/shell32/iconcache.cpp b/dll/win32/shell32/iconcache.cpp index 4af8d2a5c0d..99af8f91eab 100644 --- a/dll/win32/shell32/iconcache.cpp +++ b/dll/win32/shell32/iconcache.cpp @@ -122,10 +122,7 @@ static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large) /* search for the shortcut icon only once */ if (s_imgListIdx == -1) - s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT); - /* FIXME should use icon index 29 instead of the - resource id, but not all icons are present yet - so we can't use icon indices */ + s_imgListIdx = SIC_LoadOverlayIcon(IDI_SHELL_SHORTCUT - 1); if (s_imgListIdx != -1) { diff --git a/dll/win32/shell32/wine/classes.c b/dll/win32/shell32/wine/classes.c index 0247add2710..c7919ca7478 100644 --- a/dll/win32/shell32/wine/classes.c +++ b/dll/win32/shell32/wine/classes.c @@ -352,7 +352,7 @@ BOOL HCU_GetIconW(LPCWSTR szClass, LPWSTR szDest, LPCWSTR szName, DWORD len, int { ret = HCR_RegGetIconW(hkey, szDest, szName, len, picon_idx); RegCloseKey(hkey); - } + } if (ret) TRACE("-- %s %i\n", debugstr_w(szDest), *picon_idx);