Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/user32/cursoricon.c | 102 ++++++++++++++++++--------------- dlls/user32/tests/cursoricon.c | 53 ++++++++++++----- 2 files changed, 96 insertions(+), 59 deletions(-)
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c index e772d541235..ee6d27acf2e 100644 --- a/dlls/user32/cursoricon.c +++ b/dlls/user32/cursoricon.c @@ -1570,29 +1570,47 @@ static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name, }
+static HBITMAP create_masked_bitmap( int width, int height, const void *and, const void *xor ) +{ + HDC dc = CreateCompatibleDC( 0 ); + HBITMAP bitmap; + + const BITMAPINFO bitmap_info = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biWidth = width, + .bmiHeader.biHeight = height * 2, + .bmiHeader.biPlanes = 1, + .bmiHeader.biBitCount = 1, + }; + + bitmap = CreateBitmap( width, height * 2, 1, 1, NULL ); + SetDIBits( dc, bitmap, 0, height, and, &bitmap_info, FALSE ); + SetDIBits( dc, bitmap, height, height, xor, &bitmap_info, FALSE ); + DeleteDC( dc ); + return bitmap; +} + + /*********************************************************************** * CreateCursor (USER32.@) */ -HCURSOR WINAPI CreateCursor( HINSTANCE hInstance, - INT xHotSpot, INT yHotSpot, - INT nWidth, INT nHeight, - LPCVOID lpANDbits, LPCVOID lpXORbits ) +HCURSOR WINAPI CreateCursor( HINSTANCE instance, int hotspot_x, int hotspot_y, + int width, int height, const void *and, const void *xor ) { ICONINFO info; - HCURSOR hCursor; + HCURSOR cursor;
- TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n", - nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits); + TRACE( "hotspot (%d,%d), size %dx%d\n", hotspot_x, hotspot_y, width, height );
info.fIcon = FALSE; - info.xHotspot = xHotSpot; - info.yHotspot = yHotSpot; - info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits ); - info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, lpXORbits ); - hCursor = CreateIconIndirect( &info ); + info.xHotspot = hotspot_x; + info.yHotspot = hotspot_y; + info.hbmColor = NULL; + info.hbmMask = create_masked_bitmap( width, height, and, xor ); + cursor = CreateIconIndirect( &info ); DeleteObject( info.hbmMask ); - DeleteObject( info.hbmColor ); - return hCursor; + return cursor; }
@@ -1615,33 +1633,34 @@ HCURSOR WINAPI CreateCursor( HINSTANCE hInstance, * * FIXME: Do we need to resize the bitmaps? */ -HICON WINAPI CreateIcon( - HINSTANCE hInstance, /* [in] the application's hInstance */ - INT nWidth, /* [in] the width of the provided bitmaps */ - INT nHeight, /* [in] the height of the provided bitmaps */ - BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */ - BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */ - LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */ - LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */ +HICON WINAPI CreateIcon( HINSTANCE instance, int width, int height, BYTE planes, + BYTE depth, const void *and, const void *xor ) { - ICONINFO iinfo; - HICON hIcon; + ICONINFO info; + HICON icon;
- TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n", - nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits); + TRACE_(icon)( "%dx%d, planes %d, depth %d\n", width, height, planes, depth );
- iinfo.fIcon = TRUE; - iinfo.xHotspot = nWidth / 2; - iinfo.yHotspot = nHeight / 2; - iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits ); - iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits ); + info.fIcon = TRUE; + info.xHotspot = width / 2; + info.yHotspot = height / 2; + if (depth == 1) + { + info.hbmColor = NULL; + info.hbmMask = create_masked_bitmap( width, height, and, xor ); + } + else + { + info.hbmColor = CreateBitmap( width, height, planes, depth, xor ); + info.hbmMask = CreateBitmap( width, height, 1, 1, and ); + }
- hIcon = CreateIconIndirect( &iinfo ); + icon = CreateIconIndirect( &info );
- DeleteObject( iinfo.hbmMask ); - DeleteObject( iinfo.hbmColor ); + DeleteObject( info.hbmMask ); + DeleteObject( info.hbmColor );
- return hIcon; + return icon; }
@@ -2248,19 +2267,14 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
width = bmpXor.bmWidth; height = bmpXor.bmHeight; - if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1 || bmpAnd.bmPlanes * bmpAnd.bmBitsPixel != 1) - { - color = create_color_bitmap( width, height ); - mask = CreateBitmap( width, height, 1, 1, NULL ); - } - else mask = CreateBitmap( width, height * 2, 1, 1, NULL ); + color = create_color_bitmap( width, height ); } else { width = bmpAnd.bmWidth; height = bmpAnd.bmHeight; - mask = CreateBitmap( width, height, 1, 1, NULL ); } + mask = CreateBitmap( width, height, 1, 1, NULL );
hdc = CreateCompatibleDC( 0 ); SelectObject( hdc, mask ); @@ -2271,10 +2285,6 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo) SelectObject( hdc, color ); stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmColor, width, height ); } - else if (iconinfo->hbmColor) - { - stretch_blt_icon( hdc, 0, height, width, height, iconinfo->hbmColor, width, height ); - } else height /= 2;
DeleteDC( hdc ); diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c index d2265be9b19..f60c845f8bc 100644 --- a/dlls/user32/tests/cursoricon.c +++ b/dlls/user32/tests/cursoricon.c @@ -709,7 +709,8 @@ static void test_initial_cursor(void) ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error); }
-static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_mask_cy, UINT exp_bpp, int line) +static void test_icon_info_(HICON hIcon, UINT exp_cx, UINT exp_cy, + UINT exp_mask_cy, UINT exp_bpp, UINT has_color, int line) { ICONINFO info; DWORD ret; @@ -726,8 +727,7 @@ static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_m ret = GetObjectA(info.hbmMask, sizeof(bmMask), &bmMask); ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %u\n", ret);
- if (exp_bpp == 1) - ok_(__FILE__, line)(info.hbmColor == 0, "info.hbmColor should be NULL\n"); + ok_(__FILE__, line)(!!info.hbmColor == has_color, "got hbmColor %p\n", info.hbmColor);
if (info.hbmColor) { @@ -790,7 +790,7 @@ static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_m } }
-#define test_icon_info(a,b,c,d,e) test_icon_info_dbg((a),(b),(c),(d),(e),__LINE__) +#define test_icon_info(a,b,c,d,e,f) test_icon_info_(a,b,c,d,e,f,__LINE__)
static void test_CreateIcon(void) { @@ -814,12 +814,17 @@ static void test_CreateIcon(void)
hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, bmp_bits); ok(hIcon != 0, "CreateIcon failed\n"); - test_icon_info(hIcon, 16, 16, 32, 1); + test_icon_info(hIcon, 16, 16, 32, 1, FALSE); DestroyIcon(hIcon);
+ hIcon = CreateCursor(0, 8, 8, 16, 16, bmp_bits, bmp_bits); + ok(hIcon != 0, "CreateCursor failed\n"); + test_icon_info(hIcon, 16, 16, 32, 1, FALSE); + DestroyCursor(hIcon); + hIcon = CreateIcon(0, 16, 16, 1, display_bpp, bmp_bits, bmp_bits); ok(hIcon != 0, "CreateIcon failed\n"); - test_icon_info(hIcon, 16, 16, 16, display_bpp); + test_icon_info(hIcon, 16, 16, 16, display_bpp, TRUE); DestroyIcon(hIcon);
hbmMask = CreateBitmap(16, 16, 1, 1, bmp_bits); @@ -854,7 +859,7 @@ static void test_CreateIcon(void) info.hbmColor = hbmColor; hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 16, 16, 16, display_bpp); + test_icon_info(hIcon, 16, 16, 16, display_bpp, TRUE); DestroyIcon(hIcon);
DeleteObject(hbmMask); @@ -871,8 +876,17 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 16, 16, 32, 1); + test_icon_info(hIcon, 16, 16, 32, 1, FALSE); DestroyIcon(hIcon); + + info.hbmMask = hbmMask; + info.hbmColor = hbmMask; + SetLastError(0xdeadbeaf); + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + test_icon_info(hIcon, 16, 32, 32, 1, TRUE); + DestroyIcon(hIcon); + DeleteObject(hbmMask);
for (i = 0; i <= 4; i++) @@ -888,11 +902,24 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 1, i / 2, max(i,1), 1); + test_icon_info(hIcon, 1, i / 2, max(i,1), 1, FALSE); DestroyIcon(hIcon); DeleteObject(hbmMask); }
+ hbmMask = CreateBitmap(16, 32, 1, 16, bmp_bits); + ok(hbmMask != 0, "CreateBitmap failed\n"); + + info.hbmMask = hbmMask; + info.hbmColor = 0; + SetLastError(0xdeadbeaf); + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + test_icon_info(hIcon, 16, 16, 32, 1, FALSE); + DestroyIcon(hIcon); + + DeleteObject(hbmMask); + /* test creating an icon from a DIB section */
bmpinfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO,bmiColors[256])); @@ -920,7 +947,7 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 32, 32, 32, 8); + test_icon_info(hIcon, 32, 32, 32, 8, TRUE); DestroyIcon(hIcon); DeleteObject(hbmColor);
@@ -938,7 +965,7 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 32, 32, 32, 8); + test_icon_info(hIcon, 32, 32, 32, 8, TRUE); DestroyIcon(hIcon); DeleteObject(hbmColor);
@@ -956,7 +983,7 @@ static void test_CreateIcon(void) SetLastError(0xdeadbeaf); hIcon = CreateIconIndirect(&info); ok(hIcon != 0, "CreateIconIndirect failed\n"); - test_icon_info(hIcon, 32, 32, 32, 8); + test_icon_info(hIcon, 32, 32, 32, 8, TRUE); DestroyIcon(hIcon);
DeleteObject(hbmMask); @@ -2662,7 +2689,7 @@ static void test_PrivateExtractIcons(void) ok(ret == 1, "PrivateExtractIconsA returned %u\n", ret); ok(icon != NULL, "icon == NULL\n");
- test_icon_info(icon, 32, 32, 32, 32); + test_icon_info(icon, 32, 32, 32, 32, TRUE); DestroyIcon(icon);
DeleteFileA("extract.ico");
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/user32/cursoricon.c | 92 +++++++++++++-- dlls/user32/tests/cursoricon.c | 203 ++++++++++++++++++++++----------- 2 files changed, 219 insertions(+), 76 deletions(-)
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c index ee6d27acf2e..fc95fa1c56f 100644 --- a/dlls/user32/cursoricon.c +++ b/dlls/user32/cursoricon.c @@ -2776,6 +2776,21 @@ HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type, return 0; }
+ +/* StretchBlt from src to dest; helper for CopyImage(). */ +static void stretch_bitmap( HBITMAP dst, HBITMAP src, int dst_width, int dst_height, int src_width, int src_height ) +{ + HDC src_dc = CreateCompatibleDC( 0 ), dst_dc = CreateCompatibleDC( 0 ); + + SelectObject( src_dc, src ); + SelectObject( dst_dc, dst ); + StretchBlt( dst_dc, 0, 0, dst_width, dst_height, src_dc, 0, 0, src_width, src_height, SRCCOPY ); + + DeleteDC( src_dc ); + DeleteDC( dst_dc ); +} + + /****************************************************************************** * CopyImage (USER32.@) Creates new image and copies attributes to it * @@ -2974,23 +2989,84 @@ HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx, case IMAGE_ICON: case IMAGE_CURSOR: { + struct cursoricon_frame *frame; struct cursoricon_object *icon; - HICON res = 0; int depth = (flags & LR_MONOCHROME) ? 1 : get_display_bpp(); + ICONINFO info; + HICON res; + + if (!(icon = get_icon_ptr( hnd ))) return 0; + + if (icon->rsrc && (flags & LR_COPYFROMRESOURCE)) + { + hnd = CURSORICON_Load( icon->module, icon->resname, desiredx, desiredy, depth, + !icon->is_icon, flags ); + release_user_handle_ptr( icon ); + if (!(icon = get_icon_ptr( hnd ))) return 0; + } + frame = get_icon_frame( icon, 0 );
if (flags & LR_DEFAULTSIZE) { if (!desiredx) desiredx = GetSystemMetrics( type == IMAGE_ICON ? SM_CXICON : SM_CXCURSOR ); if (!desiredy) desiredy = GetSystemMetrics( type == IMAGE_ICON ? SM_CYICON : SM_CYCURSOR ); } - - if (!(icon = get_icon_ptr( hnd ))) return 0; - - if (icon->rsrc && (flags & LR_COPYFROMRESOURCE)) - res = CURSORICON_Load( icon->module, icon->resname, desiredx, desiredy, depth, - !icon->is_icon, flags ); else - res = CopyIcon( hnd ); /* FIXME: change size if necessary */ + { + if (!desiredx) desiredx = frame->width; + if (!desiredy) desiredy = frame->height; + } + + info.fIcon = icon->is_icon; + info.xHotspot = icon->hotspot.x; + info.yHotspot = icon->hotspot.y; + + if (desiredx == frame->width && desiredy == frame->height) + { + info.hbmColor = frame->color; + info.hbmMask = frame->mask; + res = CreateIconIndirect( &info ); + } + else + { + if (frame->color) + { + if (!(info.hbmColor = create_color_bitmap( desiredx, desiredy ))) + { + release_user_handle_ptr( icon ); + return 0; + } + stretch_bitmap( info.hbmColor, frame->color, desiredx, desiredy, + frame->width, frame->height ); + + if (!(info.hbmMask = CreateBitmap( desiredx, desiredy, 1, 1, NULL ))) + { + DeleteObject( info.hbmColor ); + release_user_handle_ptr( icon ); + return 0; + } + stretch_bitmap( info.hbmMask, frame->mask, desiredx, desiredy, + frame->width, frame->height ); + } + else + { + info.hbmColor = NULL; + + if (!(info.hbmMask = CreateBitmap( desiredx, desiredy * 2, 1, 1, NULL ))) + { + release_user_handle_ptr( icon ); + return 0; + } + stretch_bitmap( info.hbmColor, frame->color, desiredx, desiredy * 2, + frame->width, frame->height * 2 ); + } + + res = CreateIconIndirect( &info ); + + DeleteObject( info.hbmColor ); + DeleteObject( info.hbmMask ); + } + release_user_handle_ptr( icon );
if (res && (flags & LR_COPYDELETEORG)) DeleteObject( hnd ); diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c index f60c845f8bc..39ffe9d88e6 100644 --- a/dlls/user32/tests/cursoricon.c +++ b/dlls/user32/tests/cursoricon.c @@ -486,22 +486,53 @@ static BOOL color_match(COLORREF a, COLORREF b) return (a & 0x00F8F8F8) == (b & 0x00F8F8F8); }
-static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight, - INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected) +static void check_copy_image(HBITMAP bitmap, UINT type, UINT flags, INT copyWidth, INT copyHeight, + INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected) { HBITMAP copy; BITMAP origBitmap; BITMAP copyBitmap; - BOOL orig_is_dib; BOOL copy_is_dib; + BOOL ret;
- copy = CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags); + GetObjectA(bitmap, sizeof(origBitmap), &origBitmap); + + winetest_push_context("%s, type %#x, flags %#x, size %ux%u", + origBitmap.bmBits ? "DIB" : "DDB", type, flags, copyWidth, copyHeight); + + if (type == IMAGE_BITMAP) + { + copy = CopyImage(bitmap, type, copyWidth, copyHeight, flags); + } + else + { + ICONINFO info = + { + .fIcon = (type == IMAGE_ICON), + .hbmColor = bitmap, + .hbmMask = bitmap, + }; + HICON icon = CreateIconIndirect(&info); + ok(!!icon, "Failed to create icon, error %u\n", GetLastError()); + copy = CopyImage(icon, type, copyWidth, copyHeight, flags); + ret = DestroyIcon(icon); + ok(ret, "Failed to destroy icon, error %u\n", GetLastError()); + } ok(copy != NULL, "CopyImage() failed\n"); if (copy != NULL) { - GetObjectA(bitmap, sizeof(origBitmap), &origBitmap); - GetObjectA(copy, sizeof(copyBitmap), ©Bitmap); - orig_is_dib = (origBitmap.bmBits != NULL); + if (type == IMAGE_BITMAP) + { + GetObjectA(copy, sizeof(copyBitmap), ©Bitmap); + } + else + { + ICONINFO info; + + ret = GetIconInfo((HICON)copy, &info); + ok(ret, "Failed to get icon info, error %u\n", GetLastError()); + GetObjectA(info.hbmColor, sizeof(copyBitmap), ©Bitmap); + } copy_is_dib = (copyBitmap.bmBits != NULL);
if (copy_is_dib && dibExpected @@ -525,21 +556,49 @@ static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT expectedDepth = origBitmap.bmBitsPixel; }
- ok((!(dibExpected ^ copy_is_dib) - && (copyBitmap.bmWidth == expectedWidth) - && (copyBitmap.bmHeight == expectedHeight) - && (copyBitmap.bmBitsPixel == expectedDepth)), - "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n", - orig_is_dib ? "DIB" : "DDB", origBitmap.bmWidth, origBitmap.bmHeight, origBitmap.bmBitsPixel, - copyWidth, copyHeight, flags, - dibExpected ? "DIB" : "DDB", expectedWidth, expectedHeight, expectedDepth, - copy_is_dib ? "DIB" : "DDB", copyBitmap.bmWidth, copyBitmap.bmHeight, copyBitmap.bmBitsPixel); + if (type != IMAGE_BITMAP) + { + dibExpected = FALSE; + expectedDepth = 32; + }
- DeleteObject(copy); + ok(copy_is_dib == dibExpected, "Expected %s, got %s\n", + dibExpected ? "DIB" : "DDB", copy_is_dib ? "DIB" : "DDB"); + ok(copyBitmap.bmWidth == expectedWidth, "Expected width %u, got %u\n", + expectedWidth, copyBitmap.bmWidth); + ok(copyBitmap.bmHeight == expectedHeight, "Expected height %u, got %u\n", + expectedHeight, copyBitmap.bmHeight); + ok(copyBitmap.bmBitsPixel == expectedDepth, "Expected depth %u, got %u\n", + expectedDepth, copyBitmap.bmBitsPixel); + + if (type != IMAGE_BITMAP) + { + ICONINFO info; + + ret = GetIconInfo((HICON)copy, &info); + ok(ret, "Failed to get icon info, error %u\n", GetLastError()); + GetObjectA(info.hbmMask, sizeof(copyBitmap), ©Bitmap); + + ok(!copyBitmap.bmBits, "Expected DDB\n"); + ok(copyBitmap.bmWidth == expectedWidth, "Expected mask width %u, got %u\n", + expectedWidth, copyBitmap.bmWidth); + ok(copyBitmap.bmHeight == expectedHeight, "Expected mask height %u, got %u\n", + expectedHeight, copyBitmap.bmHeight); + ok(copyBitmap.bmBitsPixel == 1, "Got mask depth %u\n", copyBitmap.bmBitsPixel); + } + + if (type == IMAGE_BITMAP) + DeleteObject(copy); + else if (type == IMAGE_ICON) + DestroyIcon((HICON)copy); + else + DestroyCursor((HCURSOR)copy); } + + winetest_pop_context(); }
-static void test_CopyImage_Bitmap(int depth) +static void do_test_copy_image(UINT type, UINT depth) { HBITMAP ddb, dib; HDC screenDC; @@ -582,53 +641,53 @@ static void test_CopyImage_Bitmap(int depth)
if (ddb != NULL) { - test_CopyImage_Check(ddb, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE); - test_CopyImage_Check(ddb, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE); - test_CopyImage_Check(ddb, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE); - test_CopyImage_Check(ddb, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE); + check_copy_image(ddb, type, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE); + check_copy_image(ddb, type, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE); + check_copy_image(ddb, type, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE); + check_copy_image(ddb, type, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE);
- test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE); - test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE); - test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE); - test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE); + check_copy_image(ddb, type, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE); + check_copy_image(ddb, type, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE); + check_copy_image(ddb, type, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE); + check_copy_image(ddb, type, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
- test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); - test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); - test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); - test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); + check_copy_image(ddb, type, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); + check_copy_image(ddb, type, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); + check_copy_image(ddb, type, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); + check_copy_image(ddb, type, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
/* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */ - test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); - test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); - test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); - test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); + check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); + check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); + check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); + check_copy_image(ddb, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
DeleteObject(ddb); }
if (depth != 1) { - test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE); + check_copy_image(dib, type, 0, 0, 0, 2, 2, screen_depth, FALSE); + check_copy_image(dib, type, 0, 5, 0, 5, 2, screen_depth, FALSE); + check_copy_image(dib, type, 0, 0, 5, 2, 5, screen_depth, FALSE); + check_copy_image(dib, type, 0, 5, 5, 5, 5, screen_depth, FALSE); }
- test_CopyImage_Check(dib, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE); - test_CopyImage_Check(dib, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE); - test_CopyImage_Check(dib, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE); - test_CopyImage_Check(dib, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE); + check_copy_image(dib, type, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE); + check_copy_image(dib, type, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE); + check_copy_image(dib, type, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE); + check_copy_image(dib, type, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
- test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); - test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); - test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); - test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); + check_copy_image(dib, type, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); + check_copy_image(dib, type, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); + check_copy_image(dib, type, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); + check_copy_image(dib, type, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
/* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */ - test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); - test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); - test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); - test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE); + check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE); + check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE); + check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE); + check_copy_image(dib, type, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
DeleteObject(dib);
@@ -651,10 +710,10 @@ static void test_CopyImage_Bitmap(int depth) info->bmiColors[1].rgbBlue = 0;
dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0); - test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE); - test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE); + check_copy_image(dib, type, 0, 0, 0, 2, 2, screen_depth, FALSE); + check_copy_image(dib, type, 0, 5, 0, 5, 2, screen_depth, FALSE); + check_copy_image(dib, type, 0, 0, 5, 2, 5, screen_depth, FALSE); + check_copy_image(dib, type, 0, 5, 5, 5, 5, screen_depth, FALSE); DeleteObject(dib);
info->bmiHeader.biBitCount = 1; @@ -666,10 +725,10 @@ static void test_CopyImage_Bitmap(int depth) info->bmiColors[1].rgbBlue = 0xFF;
dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0); - test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE); - test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE); - test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE); - test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE); + check_copy_image(dib, type, 0, 0, 0, 2, 2, 1, FALSE); + check_copy_image(dib, type, 0, 5, 0, 5, 2, 1, FALSE); + check_copy_image(dib, type, 0, 0, 5, 2, 5, 1, FALSE); + check_copy_image(dib, type, 0, 5, 5, 5, 5, 1, FALSE); DeleteObject(dib);
info->bmiHeader.biBitCount = 1; @@ -681,10 +740,10 @@ static void test_CopyImage_Bitmap(int depth) info->bmiColors[1].rgbBlue = 0;
dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0); - test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE); - test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE); - test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE); - test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE); + check_copy_image(dib, type, 0, 0, 0, 2, 2, 1, FALSE); + check_copy_image(dib, type, 0, 5, 0, 5, 2, 1, FALSE); + check_copy_image(dib, type, 0, 0, 5, 2, 5, 1, FALSE); + check_copy_image(dib, type, 0, 5, 5, 5, 5, 1, FALSE); DeleteObject(dib); } } @@ -3018,6 +3077,19 @@ static void test_Image_StretchMode(void) HeapFree(GetProcessHeap(), 0, bmi); }
+static void test_copy_image(void) +{ + static const UINT types[] = {IMAGE_BITMAP, IMAGE_ICON, IMAGE_CURSOR}; + static const UINT depths[] = {1, 4, 8, 16, 24, 32}; + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(types); ++i) + { + for (j = 0; j < ARRAY_SIZE(depths); ++j) + do_test_copy_image(types[i], depths[j]); + } +} + START_TEST(cursoricon) { pGetCursorInfo = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetCursorInfo" ); @@ -3039,12 +3111,7 @@ START_TEST(cursoricon) return; }
- test_CopyImage_Bitmap(1); - test_CopyImage_Bitmap(4); - test_CopyImage_Bitmap(8); - test_CopyImage_Bitmap(16); - test_CopyImage_Bitmap(24); - test_CopyImage_Bitmap(32); + test_copy_image(); test_Image_StretchMode(); test_initial_cursor(); test_CreateIcon();
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91065
Your paranoid android.
=== w1064v1507 (32 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w1064v1809 (32 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w1064 (32 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w1064v1507 (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w1064v1809 (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w1064 (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w1064_2qxl (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w10pro64 (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w10pro64_ar (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w10pro64_he (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w10pro64_ja (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== w10pro64_zh_CN (64 bit report) ===
user32: cursoricon.c:2506: Test failed: cursor not shown in info cursoricon.c:2530: Test failed: cursor not shown in info cursoricon.c:2583: Test failed: cursor not shown in info cursoricon.c:2595: Test failed: cursor not shown in info
=== debiant2 (32 bit Chinese:China report) ===
user32: msg.c:14834: Test failed: bad time 3d1377c
=== debiant2 (64 bit WoW report) ===
user32: menu.c:2337: Test failed: test 25
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/user32/cursoricon.c | 45 ++++++---------------------------------- 1 file changed, 6 insertions(+), 39 deletions(-)
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c index fc95fa1c56f..a923f2f8315 100644 --- a/dlls/user32/cursoricon.c +++ b/dlls/user32/cursoricon.c @@ -1667,48 +1667,15 @@ HICON WINAPI CreateIcon( HINSTANCE instance, int width, int height, BYTE planes, /*********************************************************************** * CopyIcon (USER32.@) */ -HICON WINAPI CopyIcon( HICON hIcon ) +HICON WINAPI CopyIcon( HICON icon ) { - struct cursoricon_object *ptrOld, *ptrNew; - HICON hNew; + ICONINFOEXW info;
- if (!(ptrOld = get_icon_ptr( hIcon ))) - { - SetLastError( ERROR_INVALID_CURSOR_HANDLE ); - return 0; - } - if ((hNew = alloc_icon_handle( FALSE, 0 ))) - { - struct cursoricon_frame *frameOld, *frameNew; + info.cbSize = sizeof(info); + if (!GetIconInfoExW( icon, &info )) + return NULL;
- ptrNew = get_icon_ptr( hNew ); - ptrNew->is_icon = ptrOld->is_icon; - ptrNew->hotspot = ptrOld->hotspot; - if (!(frameOld = get_icon_frame( ptrOld, 0 ))) - { - release_user_handle_ptr( ptrOld ); - SetLastError( ERROR_INVALID_CURSOR_HANDLE ); - return 0; - } - if (!(frameNew = get_icon_frame( ptrNew, 0 ))) - { - release_icon_frame( ptrOld, frameOld ); - release_user_handle_ptr( ptrOld ); - SetLastError( ERROR_INVALID_CURSOR_HANDLE ); - return 0; - } - frameNew->delay = 0; - frameNew->width = frameOld->width; - frameNew->height = frameOld->height; - frameNew->mask = copy_bitmap( frameOld->mask ); - frameNew->color = copy_bitmap( frameOld->color ); - frameNew->alpha = copy_bitmap( frameOld->alpha ); - release_icon_frame( ptrOld, frameOld ); - release_icon_frame( ptrNew, frameNew ); - release_user_handle_ptr( ptrNew ); - } - release_user_handle_ptr( ptrOld ); - return hNew; + return CopyImage( icon, info.fIcon ? IMAGE_ICON : IMAGE_CURSOR, 0, 0, 0 ); }
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47915 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- v2: Now with more tests. It turns out that InternalGetWindowIcon() doesn't resize images at all, including the IDI_APPLICATION fallback.
dlls/user32/tests/win.c | 250 ++++++++++++++++++++++++++++++++++++---- dlls/user32/user32.spec | 1 + dlls/user32/win.c | 47 ++++++++ 3 files changed, 275 insertions(+), 23 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index a37afd2dc5e..c1a9ba50df1 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -64,6 +64,7 @@ static BOOL (WINAPI *pGetWindowDisplayAffinity)(HWND hwnd, DWORD *affinity); static BOOL (WINAPI *pSetWindowDisplayAffinity)(HWND hwnd, DWORD affinity); static BOOL (WINAPI *pAdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); static BOOL (WINAPI *pSystemParametersInfoForDpi)(UINT,UINT,void*,UINT,UINT); +static HICON (WINAPI *pInternalGetWindowIcon)(HWND window, UINT type);
static BOOL test_lbuttondown_flag; static DWORD num_gettext_msgs; @@ -2369,68 +2370,270 @@ todo_wine DestroyWindow(mdi_hwndMain); }
+#define check_icon_size(a, b, c) check_icon_size_(__LINE__, a, b, c) +static void check_icon_size_( int line, HICON icon, LONG width, LONG height ) +{ + ICONINFO info = {sizeof(info)}; + BITMAP bitmap; + BOOL ret; + + ret = GetIconInfo( icon, &info ); + ok_(__FILE__, line)(ret, "failed to get icon info, error %u\n", GetLastError()); + ret = GetObjectW(info.hbmColor, sizeof(bitmap), &bitmap); + ok_(__FILE__, line)(ret, "failed to get bitmap, error %u\n", GetLastError()); + ok_(__FILE__, line)(bitmap.bmWidth == width, "expected width %d, got %d\n", width, bitmap.bmWidth); + ok_(__FILE__, line)(bitmap.bmHeight == height, "expected height %d, got %d\n", height, bitmap.bmHeight); +} + +#define check_internal_icon_size(a, b, c, d) check_internal_icon_size_(__LINE__, a, b, c, d) +static void check_internal_icon_size_( int line, HANDLE window, UINT type, LONG width, LONG height ) +{ + HICON icon; + BOOL ret; + + icon = pInternalGetWindowIcon( window, type ); + ok_(__FILE__, line)(icon != 0, "expected nonzero icon\n"); + check_icon_size_( line, icon, width, height ); + ret = DestroyIcon( icon ); + ok_(__FILE__, line)(ret, "failed to destroy icon, error %u\n", GetLastError()); +} + +static DWORD WINAPI internal_get_icon_thread(void *arg) +{ + HICON icon; + BOOL ret; + + icon = pInternalGetWindowIcon( arg, ICON_BIG ); + ok( icon != 0, "expected nonzero icon\n" ); + ret = DestroyIcon( icon ); + ok( ret, "got error %u\n", GetLastError() ); + + return 0; +} + static void test_icons(void) { - WNDCLASSEXA cls; + static const BYTE bitmap_bits[50 * 50 * 4]; + HICON icon = CreateIcon( 0, 10, 10, 1, 32, bitmap_bits, bitmap_bits ); + HICON icon2 = CreateIcon( 0, 20, 20, 1, 32, bitmap_bits, bitmap_bits ); + HICON icon3 = CreateIcon( 0, 30, 30, 1, 32, bitmap_bits, bitmap_bits ); + HICON icon4 = CreateIcon( 0, 40, 40, 1, 32, bitmap_bits, bitmap_bits ); + HICON icon5 = CreateIcon( 0, 50, 50, 1, 32, bitmap_bits, bitmap_bits ); + LONG big_width = GetSystemMetrics( SM_CXICON ), big_height = GetSystemMetrics( SM_CYICON ); + LONG small_width = GetSystemMetrics( SM_CXSMICON ), small_height = GetSystemMetrics( SM_CYSMICON ); + WNDCLASSEXA cls = {sizeof(cls)}; + HICON res, res2; + HANDLE thread; HWND hwnd; - HICON icon = LoadIconA(0, (LPCSTR)IDI_APPLICATION); - HICON icon2 = LoadIconA(0, (LPCSTR)IDI_QUESTION); - HICON small_icon = LoadImageA(0, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED ); - HICON res; + BOOL ret;
- cls.cbSize = sizeof(cls); - cls.style = 0; cls.lpfnWndProc = DefWindowProcA; - cls.cbClsExtra = 0; - cls.cbWndExtra = 0; - cls.hInstance = 0; - cls.hIcon = LoadIconA(0, (LPCSTR)IDI_HAND); - cls.hIconSm = small_icon; - cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); - cls.hbrBackground = GetStockObject(WHITE_BRUSH); - cls.lpszMenuName = NULL; + cls.hIcon = icon4; + cls.hIconSm = icon5; cls.lpszClassName = "IconWindowClass"; - RegisterClassExA(&cls);
hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); - assert( hwnd ); + ok( hwnd != NULL, "failed to create window\n" );
res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == 0, "wrong big icon %p/0\n", res ); + SetLastError( 0xdeadbeef ); + res = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res != 0, "expected nonzero icon\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError() ); + check_icon_size( res, 40, 40 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 40, 40 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res ); + ok( ret, "got error %u\n", GetLastError() ); + + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); + ok( !res, "wrong small icon %p\n", res ); + res = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res != 0, "expected nonzero icon\n" ); + check_icon_size( res, 50, 50 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 50, 50 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res ); + ok( ret, "got error %u\n", GetLastError() ); + + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( !res, "wrong small2 icon %p\n", res ); + res = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res != 0, "expected nonzero icon\n" ); + check_icon_size( res, 50, 50 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 50, 50 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon ); ok( res == 0, "wrong previous big icon %p/0\n", res ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon, "wrong big icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon, "got %p\n", res2 ); + check_icon_size( res2, 10, 10 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon2 ); ok( res == icon, "wrong previous big icon %p/%p\n", res, icon ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon2, "got %p\n", res2 ); + check_icon_size( res2, 20, 20 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() );
res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == 0, "wrong small icon %p/0\n", res ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 != 0, "expected nonzero icon\n" ); + check_icon_size( res2, small_width, small_height ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( (res && res != small_icon && res != icon2) || broken(!res), "wrong small2 icon %p\n", res ); + ok( res && res != icon3 && res != icon2, "wrong small2 icon %p\n", res ); + res2 = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res2 == res, "expected icon to match\n" ); + check_icon_size( res, small_width, small_height ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != icon3 && res2 != icon2 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, small_width, small_height ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon ); ok( res == 0, "wrong previous small icon %p/0\n", res ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == icon, "wrong small icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 && res2 != icon, "got %p\n", res2 ); + check_icon_size( res2, 10, 10 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( res == icon || broken(!res), "wrong small2 icon after set %p/%p\n", res, icon ); - res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon ); + ok( res == icon, "wrong small2 icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != icon && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 10, 10 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon3 ); ok( res == icon, "wrong previous small icon %p/%p\n", res, icon ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); - ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon ); + ok( res == icon3, "wrong small icon after set %p/%p\n", res, icon3 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 && res2 != icon3, "got %p\n", res2 ); + check_icon_size( res2, 30, 30 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( res == small_icon || broken(!res), "wrong small2 icon after set %p/%p\n", res, small_icon ); + ok( res == icon3, "wrong small2 icon after set %p/%p\n", res, icon3 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != icon3 && res2 != res, "got %p\n", res2 ); + check_icon_size( res2, 30, 30 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() );
/* make sure the big icon hasn't changed */ res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon2, "got %p\n", res2 ); + check_icon_size( res2, 20, 20 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + res = pInternalGetWindowIcon( NULL, ICON_BIG ); + ok( !res, "got %p\n", res ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + res = pInternalGetWindowIcon( hwnd, 0xdeadbeef ); + ok( !res, "got %p\n", res ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError() ); + + thread = CreateThread( NULL, 0, internal_get_icon_thread, hwnd, 0, NULL ); + ret = WaitForSingleObject( thread, 1000 ); + ok( !ret, "wait timed out\n" ); + CloseHandle( thread );
DestroyWindow( hwnd ); + UnregisterClassA( "IconWindowClass", GetModuleHandleA( NULL ) ); + + /* check when the big class icon is missing */ + + cls.hIcon = 0; + cls.hIconSm = icon5; + RegisterClassExA(&cls); + + hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, + 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); + ok( hwnd != NULL, "failed to create window\n" ); + + check_internal_icon_size( hwnd, ICON_BIG, big_width, big_height ); + check_internal_icon_size( hwnd, ICON_SMALL, 50, 50 ); + check_internal_icon_size( hwnd, ICON_SMALL2, 50, 50 ); + + DestroyWindow( hwnd ); + UnregisterClassA( "IconWindowClass", GetModuleHandleA( NULL ) ); + + /* and when the small class icon is missing */ + + cls.hIcon = icon4; + cls.hIconSm = 0; + RegisterClassExA(&cls); + hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, + 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); + ok( hwnd != NULL, "failed to create window\n" ); + + check_internal_icon_size( hwnd, ICON_BIG, 40, 40 ); + check_internal_icon_size( hwnd, ICON_SMALL, small_width, small_width ); + check_internal_icon_size( hwnd, ICON_SMALL2, small_width, small_width ); + + DestroyWindow( hwnd ); + UnregisterClassA( "IconWindowClass", GetModuleHandleA( NULL ) ); + + /* and when both are missing */ + + cls.hIcon = 0; + cls.hIconSm = 0; + RegisterClassExA(&cls); + hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, + 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); + ok( hwnd != NULL, "failed to create window\n" ); + + check_internal_icon_size( hwnd, ICON_BIG, big_width, big_height ); + check_internal_icon_size( hwnd, ICON_SMALL, big_width, big_height ); + check_internal_icon_size( hwnd, ICON_SMALL2, big_width, big_height ); + + DestroyWindow( hwnd ); + UnregisterClassA( "IconWindowClass", GetModuleHandleA( NULL ) ); + + DestroyIcon( icon ); + DestroyIcon( icon2 ); + DestroyIcon( icon3 ); + DestroyIcon( icon4 ); + DestroyIcon( icon5 ); }
static LRESULT WINAPI nccalcsize_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -12027,6 +12230,7 @@ START_TEST(win) pSetWindowDisplayAffinity = (void *)GetProcAddress( user32, "SetWindowDisplayAffinity" ); pAdjustWindowRectExForDpi = (void *)GetProcAddress( user32, "AdjustWindowRectExForDpi" ); pSystemParametersInfoForDpi = (void *)GetProcAddress( user32, "SystemParametersInfoForDpi" ); + pInternalGetWindowIcon = (void *)GetProcAddress( user32, "InternalGetWindowIcon" );
if (argc == 4) { diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 190ee74fd6c..391e304a063 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -445,6 +445,7 @@ @ stdcall InsertMenuItemA(long long long ptr) @ stdcall InsertMenuItemW(long long long ptr) @ stdcall InsertMenuW(long long long long ptr) +@ stdcall InternalGetWindowIcon(ptr long) @ stdcall InternalGetWindowText(long ptr long) @ stdcall IntersectRect(ptr ptr ptr) @ stdcall InvalidateRect(long ptr long) diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 2f6b2fdf066..7c2471d2746 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -4369,3 +4369,50 @@ BOOL WINAPI SetWindowCompositionAttribute(HWND hwnd, void *data) SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } + +/*********************************************************************** + * InternalGetWindowIcon (USER32.@) + */ +HICON WINAPI InternalGetWindowIcon( HWND hwnd, UINT type ) +{ + WND *win = WIN_GetPtr( hwnd ); + HICON ret; + + TRACE( "hwnd %p, type %#x\n", hwnd, type ); + + if (!win) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } + if (win == WND_OTHER_PROCESS || win == WND_DESKTOP) + { + if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd ); + return 0; + } + + switch (type) + { + case ICON_BIG: + ret = win->hIcon; + if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON ); + break; + + case ICON_SMALL: + case ICON_SMALL2: + ret = win->hIconSmall ? win->hIconSmall : win->hIconSmall2; + if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICONSM ); + if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON ); + break; + + default: + SetLastError( ERROR_INVALID_PARAMETER ); + WIN_ReleasePtr( win ); + return 0; + } + + if (!ret) ret = LoadIconW( 0, (const WCHAR *)IDI_APPLICATION ); + + WIN_ReleasePtr( win ); + return CopyIcon( ret ); +}
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91104
Your paranoid android.
=== w1064 (32 bit report) ===
user32: win.c:9693: Test failed: Timed out waiting for the child process
=== w1064_tsign (32 bit report) ===
user32: win.c:4071: Test failed: hwnd 000701D0/000701D0 message 0200 win.c:4075: Test failed: hwnd 000701D0/000701D0 message 0201 win.c:4084: Test failed: hwnd 007E023A/007E023A message 0202 win.c:4087: Test failed: hwnd 007E023A/007E023A message 0201
=== debiant2 (32 bit report) ===
user32: win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
=== debiant2 (32 bit Arabic:Morocco report) ===
user32: win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
=== debiant2 (32 bit French report) ===
user32: win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
=== debiant2 (32 bit Hebrew:Israel report) ===
user32: win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
=== debiant2 (32 bit Hindi:India report) ===
user32: win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
=== debiant2 (32 bit Japanese:Japan report) ===
user32: win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
=== debiant2 (32 bit Chinese:China report) ===
user32: win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
=== debiant2 (32 bit WoW report) ===
user32: win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
=== debiant2 (64 bit WoW report) ===
user32: input.c:2222: Test failed: GetRawInputData succeeded input.c:2223: Test failed: GetRawInputData returned deadbeef input.c:2341: Test failed: Spurious WM_INPUT messages win.c:2505: Test failed: expected width 16, got 20 win.c:2505: Test failed: expected height 16, got 20 win.c:2513: Test failed: expected width 16, got 20 win.c:2513: Test failed: expected height 16, got 20 win.c:2516: Test failed: expected width 16, got 20 win.c:2516: Test failed: expected height 16, got 20 win.c:2610: Test failed: expected width 16, got 40 win.c:2610: Test failed: expected height 16, got 40 win.c:2611: Test failed: expected width 16, got 40 win.c:2611: Test failed: expected height 16, got 40
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91064
Your paranoid android.
=== w1064v1507 (32 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w1064v1809 (32 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w1064 (32 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w1064v1507 (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w1064v1809 (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w1064 (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w1064_2qxl (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w10pro64 (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w10pro64_ar (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w10pro64_he (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w10pro64_ja (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== w10pro64_zh_CN (64 bit report) ===
user32: cursoricon.c:2447: Test failed: cursor not shown in info cursoricon.c:2471: Test failed: cursor not shown in info cursoricon.c:2524: Test failed: cursor not shown in info cursoricon.c:2536: Test failed: cursor not shown in info
=== debiant2 (32 bit Chinese:China report) ===
user32: win.c:10161: Test failed: Expected foreground window 000E0120, got 00EB00D4