From 5461abeeba643d6ba1cce3f0610b023f71afc1e9 Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Sun, 9 Mar 2025 15:41:53 +0100 Subject: [PATCH] [SHELL32][SHELL32_APITESTS] SHDefExtractIcon zero icon size as sysmetric (#7768) --- dll/win32/shell32/iconcache.cpp | 3 + .../apitests/shell32/ExtractIconEx.cpp | 85 +++++++++++++++++++ modules/rostests/apitests/shell32/testlist.c | 2 + 3 files changed, 90 insertions(+) diff --git a/dll/win32/shell32/iconcache.cpp b/dll/win32/shell32/iconcache.cpp index 392d5fa75ea..e0d8b179ecb 100644 --- a/dll/win32/shell32/iconcache.cpp +++ b/dll/win32/shell32/iconcache.cpp @@ -1019,6 +1019,9 @@ HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON hIcons[2]; WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); + if (!nIconSize) + nIconSize = MAKELONG(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CXSMICON)); + ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR); /* FIXME: deal with uFlags parameter which contains GIL_ flags */ if (ret == 0xFFFFFFFF) diff --git a/modules/rostests/apitests/shell32/ExtractIconEx.cpp b/modules/rostests/apitests/shell32/ExtractIconEx.cpp index 244081199f3..d8e9fd4b564 100644 --- a/modules/rostests/apitests/shell32/ExtractIconEx.cpp +++ b/modules/rostests/apitests/shell32/ExtractIconEx.cpp @@ -9,6 +9,28 @@ #include "shelltest.h" #include +EXTERN_C BOOL WINAPI SHAreIconsEqual(HICON hIcon1, HICON hIcon2); + +static void SafeDestroyIcon(HICON hIco) +{ + if (hIco) + DestroyIcon(hIco); +} + +static UINT GetIcoSize(HICON hIco) +{ + ICONINFO info; + if (!GetIconInfo(hIco, &info)) + return 0; + + BITMAP bm; + if (!GetObject(info.hbmColor ? info.hbmColor : info.hbmMask, sizeof(bm), &bm)) + bm.bmWidth = 0; + DeleteObject(info.hbmMask); + DeleteObject(info.hbmColor); + return bm.bmWidth; +} + typedef struct { PCWSTR pszFilePath; @@ -122,3 +144,66 @@ START_TEST(ExtractIconEx) DeleteFileA(FileName[0]); DeleteFileA(FileName[1]); } + +static HRESULT SHDEI(LPCWSTR pszIconFile, int Index = 0, UINT GIL = 0, UINT Size = 0) +{ + HICON hIco = NULL; + HRESULT hr = SHDefExtractIcon(pszIconFile, Index, GIL, &hIco, NULL, Size); + if (hr == S_OK) + { + hr = GetIcoSize(hIco); + SafeDestroyIcon(hIco); + } + return hr; +} + +START_TEST(SHDefExtractIcon) +{ + HRESULT hr; + int SysBigIconSize = GetSystemMetrics(SM_CXICON); + + // Modern Windows requires the system image list to be initialized for GIL_SIMULATEDOC to work! + SHFILEINFOW shfi; + SHGetFileInfoW(L"x", 0, &shfi, sizeof(shfi), SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES); + + WCHAR path[MAX_PATH]; + GetSystemDirectoryW(path, _countof(path)); + PathAppendW(path, L"user32.dll"); + int index = 1; + + ok(SHDEI(path, index, 0, 0) == SysBigIconSize, "0 size must match GetSystemMetrics\n"); + ok(SHDEI(path, index, 0, SysBigIconSize * 2) == SysBigIconSize * 2, "Resize failed\n"); + + HICON hIcoLarge, hIcoSmall; + if (SHDefExtractIcon(path, index, 0, &hIcoLarge, &hIcoSmall, 0) != S_OK) + hIcoLarge = hIcoSmall = NULL; + ok(hIcoLarge && hIcoSmall && !SHAreIconsEqual(hIcoLarge, hIcoSmall), "Large+Small failed\n"); + SafeDestroyIcon(hIcoLarge); + SafeDestroyIcon(hIcoSmall); + + static const int sizes[] = { 0, SysBigIconSize * 2 }; + for (UINT i = 0; i < _countof(sizes); ++i) + { + HICON hIcoNormal, hIcoSimDoc; + if (FAILED(hr = SHDefExtractIcon(path, index, 0, &hIcoNormal, NULL, sizes[i]))) + hIcoNormal = NULL; + if (FAILED(hr = SHDefExtractIcon(path, index, GIL_SIMULATEDOC, &hIcoSimDoc, NULL, sizes[i]))) + hIcoSimDoc = NULL; + ok(hIcoNormal && hIcoSimDoc && !SHAreIconsEqual(hIcoNormal, hIcoSimDoc), "GIL_SIMULATEDOC failed\n"); + SafeDestroyIcon(hIcoNormal); + SafeDestroyIcon(hIcoSimDoc); + } + + GetTempPathW(_countof(path), path); + GetTempFileNameW(path, L"TEST", 0, path); + ok(SHDEI(path) == S_FALSE, "Empty file should return S_FALSE\n"); + HANDLE hFile = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD io; + WriteFile(hFile, "!", 1, &io, NULL); + CloseHandle(hFile); + ok(SHDEI(path) == S_FALSE, "File without icons should return S_FALSE\n"); + } + DeleteFile(path); +} diff --git a/modules/rostests/apitests/shell32/testlist.c b/modules/rostests/apitests/shell32/testlist.c index 1c964c36be4..cc5398ddb68 100644 --- a/modules/rostests/apitests/shell32/testlist.c +++ b/modules/rostests/apitests/shell32/testlist.c @@ -34,6 +34,7 @@ extern void func_SHChangeNotify(void); extern void func_SHCreateDataObject(void); extern void func_SHCreateFileDataObject(void); extern void func_SHCreateFileExtractIconW(void); +extern void func_SHDefExtractIcon(void); extern void func_SHEnumerateUnreadMailAccountsW(void); extern void func_She(void); extern void func_ShellExec_RunDLL(void); @@ -89,6 +90,7 @@ const struct test winetest_testlist[] = { "SHCreateDataObject", func_SHCreateDataObject }, { "SHCreateFileDataObject", func_SHCreateFileDataObject }, { "SHCreateFileExtractIconW", func_SHCreateFileExtractIconW }, + { "SHDefExtractIcon", func_SHDefExtractIcon }, { "SHEnumerateUnreadMailAccountsW", func_SHEnumerateUnreadMailAccountsW }, { "She", func_She }, { "ShellExec_RunDLL", func_ShellExec_RunDLL },