https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5461abeeba643d6ba1cce…
commit 5461abeeba643d6ba1cce3f0610b023f71afc1e9
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Sun Mar 9 15:41:53 2025 +0100
Commit: GitHub <noreply(a)github.com>
CommitDate: Sun Mar 9 15:41:53 2025 +0100
[SHELL32][SHELL32_APITESTS] SHDefExtractIcon zero icon size as sysmetric (#7768)
---
dll/win32/shell32/iconcache.cpp | 3 +
.../rostests/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 <stdio.h>
+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 },