https://git.reactos.org/?p=reactos.git;a=commitdiff;h=705a985789ddba840e7cd9ad1af0744574ba1b48

commit 705a985789ddba840e7cd9ad1af0744574ba1b48
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Mon Feb 17 13:46:20 2025 +0100
Commit:     GitHub <nore...@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 <whinds...@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) */

Reply via email to