From 1c55924045facde76d9f7c855f0760e16365b778 Mon Sep 17 00:00:00 2001 From: Doug Lyons Date: Tue, 24 Dec 2024 17:51:31 -0600 Subject: [PATCH] [USER32_APTEST][USER32] CopyImage improve regression test and function. (#7524) CORE-19806 and CORE-17902. * Follow-up of PR #6886 and commit d3ec7cd to remove hack. --- modules/rostests/apitests/user32/CopyImage.c | 53 ++++++++++++++++++++ win32ss/user/user32/windows/cursoricon.c | 46 ++++++++++++++--- 2 files changed, 93 insertions(+), 6 deletions(-) diff --git a/modules/rostests/apitests/user32/CopyImage.c b/modules/rostests/apitests/user32/CopyImage.c index bad7c472f4f..2280b20a6ba 100644 --- a/modules/rostests/apitests/user32/CopyImage.c +++ b/modules/rostests/apitests/user32/CopyImage.c @@ -3,6 +3,7 @@ * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) * PURPOSE: Test for SetFocus/GetFocus/GetGUIThreadInfo * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ +* Copyright 2024 Doug Lyons */ #include "precomp.h" @@ -76,9 +77,61 @@ Test_CopyImage_Flags(UINT uType) DeleteObject(hImage); } +static VOID +Test_CopyImage_hImage_NULL(void) +{ + HANDLE hImg; + DWORD LastError; + + /* Test NULL HANDLE return and GetLastError return. */ + SetLastError(0xdeadbeef); + hImg = CopyImage(NULL, IMAGE_ICON, 16, 16, LR_COPYFROMRESOURCE); + LastError = GetLastError(); + ok(LastError == ERROR_INVALID_CURSOR_HANDLE, "Wrong error 0x%08lx returned\n", LastError); + ok(!hImg, "Image returned should have been NULL, hImg was %p\n", hImg); + + SetLastError(0xdeadbeef); + hImg = CopyImage(NULL, IMAGE_BITMAP, 16, 16, LR_COPYFROMRESOURCE); + LastError = GetLastError(); + ok(LastError == ERROR_INVALID_HANDLE, "Wrong error 0x%08lx returned\n", LastError); + ok(!hImg, "Image returned should have been NULL, hImg was %p\n", hImg); + + + SetLastError(0xdeadbeef); + hImg = CopyImage(NULL, IMAGE_CURSOR, 16, 16, LR_COPYFROMRESOURCE); + LastError = GetLastError(); + ok(LastError == ERROR_INVALID_CURSOR_HANDLE, "Wrong error 0x%08lx returned\n", LastError); + ok(!hImg, "Image returned should have been NULL, hImg was %p\n", hImg); + + /* Test bad Flags for Invalid Parameter return */ + SetLastError(0xdeadbeef); + /* 0x80000000 is an invalid flag value */ + hImg = CopyImage(NULL, IMAGE_BITMAP, 16, 16, 0x80000000); + LastError = GetLastError(); + ok(LastError == ERROR_INVALID_PARAMETER, "Wrong error 0x%08lx returned\n", LastError); + ok(!hImg, "Image returned should have been NULL, hImg was %p\n", hImg); + + /* Test bad Type (5) GetLastError return value. Not Icon, Cursor, or Bitmap. */ + SetLastError(0xdeadbeef); + hImg = CopyImage(NULL, 5, 16, 16, LR_COPYFROMRESOURCE); + LastError = GetLastError(); + ok(LastError == ERROR_INVALID_PARAMETER, "Wrong error 0x%08lx returned\n", LastError); + ok(!hImg, "Image returned should have been NULL, hImg was %p\n", hImg); + + /* Test bad type (5) GetLastError return value with good HANDLE */ + hImg = CreateTestImage(IMAGE_ICON); + SetLastError(0xdeadbeef); + hImg = CopyImage(hImg, 5, 16, 16, LR_COPYFROMRESOURCE); + LastError = GetLastError(); + ok(LastError == ERROR_INVALID_PARAMETER, "Wrong error 0x%08lx returned\n", LastError); + ok(!hImg, "Image returned should have been NULL, hImg was %p\n", hImg); + DeleteObject(hImg); +} + START_TEST(CopyImage) { Test_CopyImage_Flags(IMAGE_BITMAP); Test_CopyImage_Flags(IMAGE_CURSOR); Test_CopyImage_Flags(IMAGE_ICON); + Test_CopyImage_hImage_NULL(); } diff --git a/win32ss/user/user32/windows/cursoricon.c b/win32ss/user/user32/windows/cursoricon.c index 53c98456e81..b1d8bc7e69a 100644 --- a/win32ss/user/user32/windows/cursoricon.c +++ b/win32ss/user/user32/windows/cursoricon.c @@ -2041,16 +2041,50 @@ HANDLE WINAPI CopyImage( switch(uType) { case IMAGE_BITMAP: + if (!hImage) + { + SetLastError(ERROR_INVALID_HANDLE); + break; + } return BITMAP_CopyImage(hImage, cxDesired, cyDesired, fuFlags); case IMAGE_CURSOR: case IMAGE_ICON: - /* HACK: Copying bitmaps with LR_COPYFROMRESOURCE flag fails. CORE-17902. - * This is a way to return the original bit map if we need - * the icons to show up. We need a simpler test. */ { - HANDLE handle = CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags); - if (!handle && (fuFlags & (LR_COPYFROMRESOURCE|LR_COPYRETURNORG))) - handle = CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, (fuFlags & ~LR_COPYFROMRESOURCE)); + HANDLE handle; + if (!hImage) + { + SetLastError(ERROR_INVALID_CURSOR_HANDLE); + break; + } + handle = CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags); + if (!handle && (fuFlags & LR_COPYFROMRESOURCE)) + { + /* Test if the hImage is the same size as what we want by getting + * its BITMAP and comparing its dimensions to the desired size. */ + BITMAP bm; + + ICONINFO iconinfo = { 0 }; + if (!GetIconInfo(hImage, &iconinfo)) + { + ERR("GetIconInfo Failed. hImage %p\n", hImage); + return NULL; + } + if (!GetObject(iconinfo.hbmColor, sizeof(bm), &bm)) + { + ERR("GetObject Failed. iconinfo %p\n", iconinfo); + return NULL; + } + + DeleteObject(iconinfo.hbmMask); + DeleteObject(iconinfo.hbmColor); + + /* If the images are the same size remove LF_COPYFROMRESOURCE and try again */ + if (cxDesired == bm.bmWidth && cyDesired == bm.bmHeight) + { + handle = CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, + cyDesired, (fuFlags & ~LR_COPYFROMRESOURCE)); + } + } return handle; } default: