https://git.reactos.org/?p=reactos.git;a=commitdiff;h=705a985789ddba840e7cd…
commit 705a985789ddba840e7cd9ad1af0744574ba1b48
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Mon Feb 17 13:46:20 2025 +0100
Commit: GitHub <noreply(a)github.com>
CommitDate: Mon Feb 17 13:46:20 2025 +0100
[COMCTL32][COMCTL32_APITEST] Implement ImageList Get/SetFlags and the system flag
(#7701)
The shell needs to be able to change the color depth of the system image lists on the
fly and it does that by changing the ILC_COLOR* flags.
---
dll/win32/comctl32/imagelist.c | 51 +++++++-
modules/rostests/apitests/comctl32/CMakeLists.txt | 2 +-
modules/rostests/apitests/comctl32/imagelist.c | 152 ++++++++++++++++++++++
modules/rostests/apitests/comctl32/testlist.c | 2 +
sdk/include/reactos/comctl32_undoc.h | 8 ++
5 files changed, 211 insertions(+), 4 deletions(-)
diff --git a/dll/win32/comctl32/imagelist.c b/dll/win32/comctl32/imagelist.c
index 5692af16ae8..e56431edc6f 100644
--- a/dll/win32/comctl32/imagelist.c
+++ b/dll/win32/comctl32/imagelist.c
@@ -121,7 +121,13 @@ struct _IMAGELIST
#ifdef __REACTOS__
#define IMAGELIST_MAGIC_DESTROYED 0x44454144
#define IMAGELIST_VERSION 0x101
-#endif
+
+#define WinVerMajor() LOBYTE(GetVersion())
+
+#include <comctl32_undoc.h>
+#define ILC_PUBLICFLAGS ( 0xFFFFFFFF ) /* Allow all flags for now */
+#define ILC_COLORMASK 0xFE
+#endif /* __REACTOS__ */
/* Header used by ImageList_Read() and ImageList_Write() */
#include "pshpack2.h"
@@ -935,7 +941,12 @@ BOOL WINAPI
ImageList_Destroy (HIMAGELIST himl)
{
if (!is_valid(himl))
- return FALSE;
+ return FALSE;
+
+#ifdef __REACTOS__
+ if ((himl->flags & ILC_SYSTEM) && WinVerMajor() >= 6)
+ return FALSE;
+#endif
IImageList_Release((IImageList *) himl);
return TRUE;
@@ -1944,7 +1955,7 @@ ImageList_GetFlags(HIMAGELIST himl)
#ifdef __REACTOS__
if(!is_valid2(himl))
return 0;
- return himl->flags;
+ return himl->flags & ILC_PUBLICFLAGS;
#else
return is_valid(himl) ? himl->flags : 0;
#endif
@@ -3047,12 +3058,46 @@ ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
* Stub.
*/
+#ifdef __REACTOS__
+static BOOL
+ChangeColorDepth(HIMAGELIST himl)
+{
+ UINT ilc = himl->flags & ILC_COLORMASK;
+ if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
+ himl->uBitsPixel = ilc;
+ else
+ himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
+
+ /* Create new himl->hbmImage for BPP changes (for SHELL32) */
+ return ((IImageList*)himl)->lpVtbl->SetImageCount((IImageList*)himl, 0) ==
S_OK;
+}
+
+BOOL WINAPI
+ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
+{
+ if (!is_valid(himl))
+ return FALSE;
+
+ if (flags & ~ILC_PUBLICFLAGS)
+ return FALSE;
+
+ if (((himl->flags ^ flags) & ILC_SYSTEM) && WinVerMajor() < 6)
+ return FALSE; /* Can't change this flag */
+
+ if (himl->flags == flags && WinVerMajor() >= 6)
+ return TRUE;
+
+ himl->flags = flags;
+ return ChangeColorDepth(himl);
+}
+#else
DWORD WINAPI
ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
{
FIXME("(%p %08x):empty stub\n", himl, flags);
return 0;
}
+#endif /* __REACTOS__ */
/*************************************************************************
diff --git a/modules/rostests/apitests/comctl32/CMakeLists.txt
b/modules/rostests/apitests/comctl32/CMakeLists.txt
index d3d11b9be77..2198b4d9fe7 100644
--- a/modules/rostests/apitests/comctl32/CMakeLists.txt
+++ b/modules/rostests/apitests/comctl32/CMakeLists.txt
@@ -1,5 +1,5 @@
-add_executable(comctl32_apitest button.c propsheet.c toolbar.c testlist.c
../include/msgtrace.c comctl32_apitest.rc)
+add_executable(comctl32_apitest button.c imagelist.c propsheet.c toolbar.c testlist.c
../include/msgtrace.c comctl32_apitest.rc)
target_link_libraries(comctl32_apitest wine)
set_module_type(comctl32_apitest win32cui)
add_importlibs(comctl32_apitest uxtheme comctl32 user32 gdi32 msvcrt kernel32 ntdll)
diff --git a/modules/rostests/apitests/comctl32/imagelist.c
b/modules/rostests/apitests/comctl32/imagelist.c
new file mode 100644
index 00000000000..8ef72f0520d
--- /dev/null
+++ b/modules/rostests/apitests/comctl32/imagelist.c
@@ -0,0 +1,152 @@
+/*
+ * PROJECT: ReactOS API Tests
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Test for imagelist
+ * COPYRIGHT: Copyright 2024 Whindmar Saksit <whindsaks(a)proton.me>
+ */
+
+#include "wine/test.h"
+#include <stdio.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <comctl32_undoc.h>
+
+#define WinVerMajor() LOBYTE(GetVersion())
+
+#define ILC_COLORMASK 0xfe
+#define IL_IMGSIZE 16
+
+static BOOL IL_IsValid(HIMAGELIST himl)
+{
+ int w = -42, h;
+ if (!himl || IsBadReadPtr(himl, sizeof(void*)))
+ return FALSE;
+ return ImageList_GetIconSize(himl, &w, &h) && w != -42;
+}
+
+static HRESULT IL_Destroy(HIMAGELIST himl)
+{
+ if (himl && !IL_IsValid(himl))
+ return E_INVALIDARG;
+ return ImageList_Destroy(himl) ? S_OK : S_FALSE;
+}
+
+static inline HIMAGELIST IL_Create(UINT flags)
+{
+ return ImageList_Create(IL_IMGSIZE, IL_IMGSIZE, flags, 1, 0);
+}
+
+static UINT IL_CalculateOtherBpp(UINT ilc)
+{
+ UINT bpp = (ilc & ILC_COLORMASK) == ILC_COLOR32 ? ILC_COLOR16 : ILC_COLOR32;
+ return (ilc & ~ILC_COLORMASK) | bpp;
+}
+
+static BOOL IL_AddImagesForTest(HIMAGELIST himl)
+{
+ int idx = -1;
+ HINSTANCE hInst = LoadLibraryW(L"USER32");
+ if (!hInst)
+ return FALSE;
+ HICON hIco = (HICON)LoadImage(hInst, MAKEINTRESOURCE(100), /* Windows */
+ IMAGE_ICON, IL_IMGSIZE, IL_IMGSIZE, 0);
+ if (!hIco)
+ hIco = (HICON)LoadImage(hInst, MAKEINTRESOURCE(32512), /* ReactOS */
+ IMAGE_ICON, IL_IMGSIZE, IL_IMGSIZE, 0);
+
+ if (hIco)
+ {
+ idx = ImageList_AddIcon(himl, hIco);
+ DestroyIcon(hIco);
+ }
+ FreeLibrary(hInst);
+ return idx != -1;
+}
+
+static void Test_SystemIL(void)
+{
+ const UINT flags = ILC_COLOR16 | ILC_MASK;
+ HIMAGELIST himl;
+
+ himl = IL_Create(flags);
+ ok(IL_Destroy(himl) == S_OK && !IL_IsValid(himl), "Can destroy
normal\n");
+
+ /* You can (sometimes) destroy a system imagelist!
+ * On Win9x it destroys it for all processes according to
+ *
https://sporks.space/2021/09/18/notes-on-the-system-image-list/ and
+ *
https://www.catch22.net/tuts/win32/system-image-list/
+ */
+ himl = IL_Create(flags | ILC_SYSTEM);
+ if (WinVerMajor() >= 6)
+ ok(IL_Destroy(himl) == S_FALSE && IL_IsValid(himl), "Can't
destroy system\n");
+ else
+ ok(IL_Destroy(himl) == S_OK && !IL_IsValid(himl), "Can destroy
system\n");
+}
+
+static void Test_Flags(void)
+{
+ const UINT flags = ILC_COLOR16 | ILC_MASK;
+ UINT flagsIn, flagsOut;
+ HIMAGELIST himl;
+
+ himl = IL_Create(flagsIn = flags);
+ flagsOut = ImageList_GetFlags(himl);
+ if (himl ? TRUE : (skip("Could not initialize\n"), FALSE))
+ {
+ ok((flagsOut & ILC_COLORMASK) == (flagsIn & ILC_COLORMASK),
"ILC_COLOR\n");
+ ok(!(flagsOut & ILC_SYSTEM), "!ILC_SYSTEM\n");
+
+ ok(IL_AddImagesForTest(himl), "Initialize\n");
+ flagsIn = IL_CalculateOtherBpp(flagsIn);
+ ok(ImageList_SetFlags(himl, flagsIn), "Can change BPP\n");
+ ok(ImageList_GetImageCount(himl) == 0, "SetFlags deletes all
images\n");
+
+ ok(IL_AddImagesForTest(himl), "Initialize\n");
+ ok(ImageList_SetFlags(himl, ImageList_GetFlags(himl)), "Can set same
flags\n");
+ if (WinVerMajor() >= 6)
+ {
+ ok(ImageList_GetImageCount(himl) != 0, "SetFlags does not delete with
same flags\n");
+ ok(ImageList_SetFlags(himl, flagsIn ^ ILC_SYSTEM), "Can change
ILC_SYSTEM\n");
+ }
+ else
+ {
+ ok(ImageList_GetImageCount(himl) == 0, "SetFlags deletes all images even
with same flags\n");
+ ok(!ImageList_SetFlags(himl, flagsIn ^ ILC_SYSTEM), "Can't change
ILC_SYSTEM\n");
+ }
+
+ IL_Destroy(himl);
+ }
+
+ himl = IL_Create(flagsIn = flags | ILC_SYSTEM);
+ flagsOut = ImageList_GetFlags(himl);
+ if (himl ? TRUE : (skip("Could not initialize\n"), FALSE))
+ {
+ ok((flagsOut & ILC_SYSTEM), "ILC_SYSTEM\n"); /* Flag is not hidden
*/
+
+ ok(IL_AddImagesForTest(himl), "Initialize\n");
+
+ flagsIn = IL_CalculateOtherBpp(flagsIn);
+ ok(ImageList_SetFlags(himl, flagsIn), "Can change BPP\n");
+ ok(ImageList_GetImageCount(himl) == 0, "SetFlags deletes all
images\n");
+
+ ok(IL_AddImagesForTest(himl), "Initialize\n");
+ ok(ImageList_SetFlags(himl, ImageList_GetFlags(himl)), "Can set same
flags\n");
+ if (WinVerMajor() >= 6)
+ {
+ ok(ImageList_SetFlags(himl, flagsIn ^ ILC_SYSTEM), "Can change
ILC_SYSTEM\n");
+ }
+ else
+ {
+ ok(!ImageList_SetFlags(himl, flagsIn ^ ILC_SYSTEM), "Can't change
ILC_SYSTEM\n");
+ }
+
+ IL_Destroy(himl);
+ }
+}
+
+START_TEST(imagelist)
+{
+ InitCommonControls();
+ Test_SystemIL();
+ Test_Flags();
+}
diff --git a/modules/rostests/apitests/comctl32/testlist.c
b/modules/rostests/apitests/comctl32/testlist.c
index da44fe7e3fb..eeb9146bf79 100644
--- a/modules/rostests/apitests/comctl32/testlist.c
+++ b/modules/rostests/apitests/comctl32/testlist.c
@@ -2,12 +2,14 @@
#include <apitest.h>
extern void func_button(void);
+extern void func_imagelist(void);
extern void func_propsheet(void);
extern void func_toolbar(void);
const struct test winetest_testlist[] =
{
{ "buttonv6", func_button },
+ { "imagelist", func_imagelist },
{ "propsheetv6", func_propsheet },
{ "toolbarv6", func_toolbar },
{ 0, 0 }
diff --git a/sdk/include/reactos/comctl32_undoc.h b/sdk/include/reactos/comctl32_undoc.h
index 1a36f4267f8..4b48e4ad5c4 100644
--- a/sdk/include/reactos/comctl32_undoc.h
+++ b/sdk/include/reactos/comctl32_undoc.h
@@ -140,6 +140,14 @@ typedef INT (WINAPI *FN_FreeMRUList)(HANDLE);
// #define GET_PROC(hComCtl32, fn) fn = (FN_##fn)GetProcAddress((hComCtl32),
(LPSTR)I_##fn)
+#ifndef NOIMAGEAPIS
+
+#define ILC_SYSTEM 0x0100 /* Used by the shell system image lists */
+DWORD WINAPI ImageList_GetFlags(HIMAGELIST himl);
+BOOL WINAPI ImageList_SetFlags(HIMAGELIST himl, DWORD flags);
+
+#endif /* NOIMAGEAPIS */
+
#ifdef __cplusplus
} /* extern "C" */
#endif /* defined(__cplusplus) */