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) */