2 * Unit test suite for cursors and icons.
4 * Copyright 2006 Michael Kaufmann
5 * Copyright 2007 Dmitry Timoshkov
6 * Copyright 2007-2008 Andrew Riedi
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/test.h"
47 } CURSORICONFILEDIRENTRY
;
54 CURSORICONFILEDIRENTRY idEntries
[1];
59 static char **test_argv
;
61 static HWND child
= 0;
62 static HWND parent
= 0;
63 static HANDLE child_process
;
65 #define PROC_INIT (WM_USER+1)
67 static LRESULT CALLBACK
callback_child(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
74 /* Destroy the cursor. */
76 SetLastError(0xdeadbeef);
77 ret
= DestroyCursor((HCURSOR
) lParam
);
78 error
= GetLastError();
79 todo_wine
ok(!ret
|| broken(ret
) /* win9x */, "DestroyCursor on the active cursor succeeded.\n");
80 ok(error
== ERROR_DESTROY_OBJECT_OF_OTHER_THREAD
||
81 error
== 0xdeadbeef, /* vista */
82 "Last error: %u\n", error
);
89 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
92 static LRESULT CALLBACK
callback_parent(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
96 child
= (HWND
) wParam
;
100 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
103 static void do_child(void)
109 /* Register a new class. */
110 class.style
= CS_GLOBALCLASS
;
111 class.lpfnWndProc
= callback_child
;
112 class.cbClsExtra
= 0;
113 class.cbWndExtra
= 0;
114 class.hInstance
= GetModuleHandle(NULL
);
116 class.hCursor
= NULL
;
117 class.hbrBackground
= NULL
;
118 class.lpszMenuName
= NULL
;
119 class.lpszClassName
= "cursor_child";
121 SetLastError(0xdeadbeef);
122 ret
= RegisterClass(&class);
123 ok(ret
, "Failed to register window class. Error: %u\n", GetLastError());
125 /* Create a window. */
126 child
= CreateWindowA("cursor_child", "cursor_child", WS_POPUP
| WS_VISIBLE
,
127 0, 0, 200, 200, 0, 0, 0, NULL
);
128 ok(child
!= 0, "CreateWindowA failed. Error: %u\n", GetLastError());
130 /* Let the parent know our HWND. */
131 PostMessage(parent
, PROC_INIT
, (WPARAM
) child
, 0);
133 /* Receive messages. */
134 while ((ret
= GetMessage(&msg
, 0, 0, 0)))
136 ok(ret
!= -1, "GetMessage failed. Error: %u\n", GetLastError());
137 TranslateMessage(&msg
);
138 DispatchMessage(&msg
);
142 static void do_parent(void)
144 char path_name
[MAX_PATH
];
145 PROCESS_INFORMATION info
;
146 STARTUPINFOA startup
;
151 /* Register a new class. */
152 class.style
= CS_GLOBALCLASS
;
153 class.lpfnWndProc
= callback_parent
;
154 class.cbClsExtra
= 0;
155 class.cbWndExtra
= 0;
156 class.hInstance
= GetModuleHandle(NULL
);
158 class.hCursor
= NULL
;
159 class.hbrBackground
= NULL
;
160 class.lpszMenuName
= NULL
;
161 class.lpszClassName
= "cursor_parent";
163 SetLastError(0xdeadbeef);
164 ret
= RegisterClass(&class);
165 ok(ret
, "Failed to register window class. Error: %u\n", GetLastError());
167 /* Create a window. */
168 parent
= CreateWindowA("cursor_parent", "cursor_parent", WS_POPUP
| WS_VISIBLE
,
169 0, 0, 200, 200, 0, 0, 0, NULL
);
170 ok(parent
!= 0, "CreateWindowA failed. Error: %u\n", GetLastError());
172 /* Start child process. */
173 memset(&startup
, 0, sizeof(startup
));
174 startup
.cb
= sizeof(startup
);
175 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
176 startup
.wShowWindow
= SW_SHOWNORMAL
;
178 sprintf(path_name
, "%s cursoricon %lx", test_argv
[0], (INT_PTR
)parent
);
179 ok(CreateProcessA(NULL
, path_name
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed.\n");
180 child_process
= info
.hProcess
;
182 /* Wait for child window handle. */
183 while ((child
== 0) && (ret
= GetMessage(&msg
, parent
, 0, 0)))
185 ok(ret
!= -1, "GetMessage failed. Error: %u\n", GetLastError());
186 TranslateMessage(&msg
);
187 DispatchMessage(&msg
);
191 static void finish_child_process(void)
193 SendMessage(child
, WM_CLOSE
, 0, 0);
194 winetest_wait_child_process( child_process
);
195 CloseHandle(child_process
);
198 static void test_child_process(void)
200 static const BYTE bmp_bits
[4096];
206 /* Create and set a dummy cursor. */
208 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
211 cursorInfo
.fIcon
= FALSE
;
212 cursorInfo
.xHotspot
= 0;
213 cursorInfo
.yHotspot
= 0;
214 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
215 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
217 cursor
= CreateIconIndirect(&cursorInfo
);
218 ok(cursor
!= NULL
, "CreateIconIndirect returned %p.\n", cursor
);
222 /* Destroy the cursor. */
223 SendMessage(child
, WM_USER
+1, 0, (LPARAM
) cursor
);
226 static void test_CopyImage_Check(HBITMAP bitmap
, UINT flags
, INT copyWidth
, INT copyHeight
,
227 INT expectedWidth
, INT expectedHeight
, WORD expectedDepth
, BOOL dibExpected
)
235 copy
= CopyImage(bitmap
, IMAGE_BITMAP
, copyWidth
, copyHeight
, flags
);
236 ok(copy
!= NULL
, "CopyImage() failed\n");
239 GetObject(bitmap
, sizeof(origBitmap
), &origBitmap
);
240 GetObject(copy
, sizeof(copyBitmap
), ©Bitmap
);
241 orig_is_dib
= (origBitmap
.bmBits
!= NULL
);
242 copy_is_dib
= (copyBitmap
.bmBits
!= NULL
);
244 if (copy_is_dib
&& dibExpected
245 && copyBitmap
.bmBitsPixel
== 24
246 && (expectedDepth
== 16 || expectedDepth
== 32))
248 /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
249 if (GetVersion() & 0x80000000)
255 if (copy_is_dib
&& !dibExpected
&& !(flags
& LR_CREATEDIBSECTION
))
257 /* It's not forbidden to create a DIB section if the flag
258 LR_CREATEDIBSECTION is absent.
259 Windows 9x does this if the bitmap has a depth that doesn't
260 match the screen depth, Windows NT doesn't */
262 expectedDepth
= origBitmap
.bmBitsPixel
;
265 ok((!(dibExpected
^ copy_is_dib
)
266 && (copyBitmap
.bmWidth
== expectedWidth
)
267 && (copyBitmap
.bmHeight
== expectedHeight
)
268 && (copyBitmap
.bmBitsPixel
== expectedDepth
)),
269 "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
270 orig_is_dib
? "DIB" : "DDB", origBitmap
.bmWidth
, origBitmap
.bmHeight
, origBitmap
.bmBitsPixel
,
271 copyWidth
, copyHeight
, flags
,
272 dibExpected
? "DIB" : "DDB", expectedWidth
, expectedHeight
, expectedDepth
,
273 copy_is_dib
? "DIB" : "DDB", copyBitmap
.bmWidth
, copyBitmap
.bmHeight
, copyBitmap
.bmBitsPixel
);
279 static void test_CopyImage_Bitmap(int depth
)
288 /* Create a device-independent bitmap (DIB) */
289 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
290 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
291 info
->bmiHeader
.biWidth
= 2;
292 info
->bmiHeader
.biHeight
= 2;
293 info
->bmiHeader
.biPlanes
= 1;
294 info
->bmiHeader
.biBitCount
= depth
;
295 info
->bmiHeader
.biCompression
= BI_RGB
;
297 for (i
=0; i
< 256; i
++)
299 info
->bmiColors
[i
].rgbRed
= i
;
300 info
->bmiColors
[i
].rgbGreen
= i
;
301 info
->bmiColors
[i
].rgbBlue
= 255 - i
;
302 info
->bmiColors
[i
].rgbReserved
= 0;
305 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
307 /* Create a device-dependent bitmap (DDB) */
308 screenDC
= GetDC(NULL
);
309 screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
310 if (depth
== 1 || depth
== screen_depth
)
312 ddb
= CreateBitmap(2, 2, 1, depth
, NULL
);
318 ReleaseDC(NULL
, screenDC
);
322 test_CopyImage_Check(ddb
, 0, 0, 0, 2, 2, depth
== 1 ? 1 : screen_depth
, FALSE
);
323 test_CopyImage_Check(ddb
, 0, 0, 5, 2, 5, depth
== 1 ? 1 : screen_depth
, FALSE
);
324 test_CopyImage_Check(ddb
, 0, 5, 0, 5, 2, depth
== 1 ? 1 : screen_depth
, FALSE
);
325 test_CopyImage_Check(ddb
, 0, 5, 5, 5, 5, depth
== 1 ? 1 : screen_depth
, FALSE
);
327 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 0, 0, 2, 2, 1, FALSE
);
328 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 5, 0, 5, 2, 1, FALSE
);
329 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 0, 5, 2, 5, 1, FALSE
);
330 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 5, 5, 5, 5, 1, FALSE
);
332 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
333 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
334 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
335 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
337 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
338 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
339 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
340 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
341 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
348 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, screen_depth
, FALSE
);
349 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, screen_depth
, FALSE
);
350 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, screen_depth
, FALSE
);
351 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, screen_depth
, FALSE
);
354 test_CopyImage_Check(dib
, LR_MONOCHROME
, 0, 0, 2, 2, 1, FALSE
);
355 test_CopyImage_Check(dib
, LR_MONOCHROME
, 5, 0, 5, 2, 1, FALSE
);
356 test_CopyImage_Check(dib
, LR_MONOCHROME
, 0, 5, 2, 5, 1, FALSE
);
357 test_CopyImage_Check(dib
, LR_MONOCHROME
, 5, 5, 5, 5, 1, FALSE
);
359 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
360 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
361 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
362 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
364 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
365 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
366 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
367 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
368 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
374 /* Special case: A monochrome DIB is converted to a monochrome DDB if
375 the colors in the color table are black and white.
377 Skip this test on Windows 95, it always creates a monochrome DDB
380 if (!(GetVersion() & 0x80000000))
382 info
->bmiHeader
.biBitCount
= 1;
383 info
->bmiColors
[0].rgbRed
= 0xFF;
384 info
->bmiColors
[0].rgbGreen
= 0;
385 info
->bmiColors
[0].rgbBlue
= 0;
386 info
->bmiColors
[1].rgbRed
= 0;
387 info
->bmiColors
[1].rgbGreen
= 0xFF;
388 info
->bmiColors
[1].rgbBlue
= 0;
390 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
391 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, screen_depth
, FALSE
);
392 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, screen_depth
, FALSE
);
393 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, screen_depth
, FALSE
);
394 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, screen_depth
, FALSE
);
397 info
->bmiHeader
.biBitCount
= 1;
398 info
->bmiColors
[0].rgbRed
= 0;
399 info
->bmiColors
[0].rgbGreen
= 0;
400 info
->bmiColors
[0].rgbBlue
= 0;
401 info
->bmiColors
[1].rgbRed
= 0xFF;
402 info
->bmiColors
[1].rgbGreen
= 0xFF;
403 info
->bmiColors
[1].rgbBlue
= 0xFF;
405 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
406 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, 1, FALSE
);
407 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, 1, FALSE
);
408 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, 1, FALSE
);
409 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, 1, FALSE
);
412 info
->bmiHeader
.biBitCount
= 1;
413 info
->bmiColors
[0].rgbRed
= 0xFF;
414 info
->bmiColors
[0].rgbGreen
= 0xFF;
415 info
->bmiColors
[0].rgbBlue
= 0xFF;
416 info
->bmiColors
[1].rgbRed
= 0;
417 info
->bmiColors
[1].rgbGreen
= 0;
418 info
->bmiColors
[1].rgbBlue
= 0;
420 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
421 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, 1, FALSE
);
422 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, 1, FALSE
);
423 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, 1, FALSE
);
424 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, 1, FALSE
);
429 HeapFree(GetProcessHeap(), 0, info
);
432 static void test_initial_cursor(void)
434 HCURSOR cursor
, cursor2
;
437 cursor
= GetCursor();
439 /* Check what handle GetCursor() returns if a cursor is not set yet. */
440 SetLastError(0xdeadbeef);
441 cursor2
= LoadCursor(NULL
, IDC_WAIT
);
443 ok(cursor
== cursor2
, "cursor (%p) is not IDC_WAIT (%p).\n", cursor
, cursor2
);
445 error
= GetLastError();
446 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
449 static void test_icon_info_dbg(HICON hIcon
, UINT exp_cx
, UINT exp_cy
, UINT exp_bpp
, int line
)
453 BITMAP bmMask
, bmColor
;
455 ret
= GetIconInfo(hIcon
, &info
);
456 ok_(__FILE__
, line
)(ret
, "GetIconInfo failed\n");
458 /* CreateIcon under XP causes info.fIcon to be 0 */
459 ok_(__FILE__
, line
)(info
.xHotspot
== exp_cx
/2, "info.xHotspot = %u\n", info
.xHotspot
);
460 ok_(__FILE__
, line
)(info
.yHotspot
== exp_cy
/2, "info.yHotspot = %u\n", info
.yHotspot
);
461 ok_(__FILE__
, line
)(info
.hbmMask
!= 0, "info.hbmMask is NULL\n");
463 ret
= GetObject(info
.hbmMask
, sizeof(bmMask
), &bmMask
);
464 ok_(__FILE__
, line
)(ret
== sizeof(bmMask
), "GetObject(info.hbmMask) failed, ret %u\n", ret
);
467 ok_(__FILE__
, line
)(info
.hbmColor
== 0, "info.hbmColor should be NULL\n");
475 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
478 ret
= GetObject(info
.hbmColor
, sizeof(bmColor
), &bmColor
);
479 ok_(__FILE__
, line
)(ret
== sizeof(bmColor
), "GetObject(info.hbmColor) failed, ret %u\n", ret
);
481 ok_(__FILE__
, line
)(bmColor
.bmBitsPixel
== display_bpp
/* XP */ ||
482 bmColor
.bmBitsPixel
== exp_bpp
/* Win98 */,
483 "bmColor.bmBitsPixel = %d\n", bmColor
.bmBitsPixel
);
484 ok_(__FILE__
, line
)(bmColor
.bmWidth
== exp_cx
, "bmColor.bmWidth = %d\n", bmColor
.bmWidth
);
485 ok_(__FILE__
, line
)(bmColor
.bmHeight
== exp_cy
, "bmColor.bmHeight = %d\n", bmColor
.bmHeight
);
487 ok_(__FILE__
, line
)(bmMask
.bmBitsPixel
== 1, "bmMask.bmBitsPixel = %d\n", bmMask
.bmBitsPixel
);
488 ok_(__FILE__
, line
)(bmMask
.bmWidth
== exp_cx
, "bmMask.bmWidth = %d\n", bmMask
.bmWidth
);
489 ok_(__FILE__
, line
)(bmMask
.bmHeight
== exp_cy
, "bmMask.bmHeight = %d\n", bmMask
.bmHeight
);
493 ok_(__FILE__
, line
)(bmMask
.bmBitsPixel
== 1, "bmMask.bmBitsPixel = %d\n", bmMask
.bmBitsPixel
);
494 ok_(__FILE__
, line
)(bmMask
.bmWidth
== exp_cx
, "bmMask.bmWidth = %d\n", bmMask
.bmWidth
);
495 ok_(__FILE__
, line
)(bmMask
.bmHeight
== exp_cy
* 2, "bmMask.bmHeight = %d\n", bmMask
.bmHeight
);
499 #define test_icon_info(a,b,c,d) test_icon_info_dbg((a),(b),(c),(d),__LINE__)
501 static void test_CreateIcon(void)
503 static const BYTE bmp_bits
[1024];
505 HBITMAP hbmMask
, hbmColor
;
513 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
515 /* these crash under XP
516 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
517 hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits);
520 hIcon
= CreateIcon(0, 16, 16, 1, 1, bmp_bits
, bmp_bits
);
521 ok(hIcon
!= 0, "CreateIcon failed\n");
522 test_icon_info(hIcon
, 16, 16, 1);
525 hIcon
= CreateIcon(0, 16, 16, 1, display_bpp
, bmp_bits
, bmp_bits
);
526 ok(hIcon
!= 0, "CreateIcon failed\n");
527 test_icon_info(hIcon
, 16, 16, display_bpp
);
530 hbmMask
= CreateBitmap(16, 16, 1, 1, bmp_bits
);
531 ok(hbmMask
!= 0, "CreateBitmap failed\n");
532 hbmColor
= CreateBitmap(16, 16, 1, display_bpp
, bmp_bits
);
533 ok(hbmColor
!= 0, "CreateBitmap failed\n");
540 SetLastError(0xdeadbeaf);
541 hIcon
= CreateIconIndirect(&info
);
542 ok(!hIcon
, "CreateIconIndirect should fail\n");
543 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
549 info
.hbmColor
= hbmColor
;
550 SetLastError(0xdeadbeaf);
551 hIcon
= CreateIconIndirect(&info
);
552 ok(!hIcon
, "CreateIconIndirect should fail\n");
553 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
558 info
.hbmMask
= hbmMask
;
559 info
.hbmColor
= hbmColor
;
560 hIcon
= CreateIconIndirect(&info
);
561 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
562 test_icon_info(hIcon
, 16, 16, display_bpp
);
565 DeleteObject(hbmMask
);
566 DeleteObject(hbmColor
);
568 hbmMask
= CreateBitmap(16, 32, 1, 1, bmp_bits
);
569 ok(hbmMask
!= 0, "CreateBitmap failed\n");
574 info
.hbmMask
= hbmMask
;
576 SetLastError(0xdeadbeaf);
577 hIcon
= CreateIconIndirect(&info
);
578 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
579 test_icon_info(hIcon
, 16, 16, 1);
582 DeleteObject(hbmMask
);
583 DeleteObject(hbmColor
);
585 /* test creating an icon from a DIB section */
587 bmpinfo
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, FIELD_OFFSET(BITMAPINFO
,bmiColors
[256]));
588 bmpinfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
589 bmpinfo
->bmiHeader
.biWidth
= 32;
590 bmpinfo
->bmiHeader
.biHeight
= 32;
591 bmpinfo
->bmiHeader
.biPlanes
= 1;
592 bmpinfo
->bmiHeader
.biBitCount
= 8;
593 bmpinfo
->bmiHeader
.biCompression
= BI_RGB
;
594 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
595 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
597 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
598 bmpinfo
->bmiHeader
.biBitCount
= 1;
599 hbmMask
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
600 ok(hbmMask
!= NULL
, "Expected a handle to the DIB\n");
602 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
607 info
.hbmMask
= hbmColor
;
608 info
.hbmColor
= hbmMask
;
609 SetLastError(0xdeadbeaf);
610 hIcon
= CreateIconIndirect(&info
);
611 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
612 test_icon_info(hIcon
, 32, 32, 8);
614 DeleteObject(hbmColor
);
616 bmpinfo
->bmiHeader
.biBitCount
= 16;
617 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
618 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
620 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
625 info
.hbmMask
= hbmColor
;
626 info
.hbmColor
= hbmMask
;
627 SetLastError(0xdeadbeaf);
628 hIcon
= CreateIconIndirect(&info
);
629 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
630 test_icon_info(hIcon
, 32, 32, 8);
632 DeleteObject(hbmColor
);
634 bmpinfo
->bmiHeader
.biBitCount
= 32;
635 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
636 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
638 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
643 info
.hbmMask
= hbmColor
;
644 info
.hbmColor
= hbmMask
;
645 SetLastError(0xdeadbeaf);
646 hIcon
= CreateIconIndirect(&info
);
647 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
648 test_icon_info(hIcon
, 32, 32, 8);
651 DeleteObject(hbmMask
);
652 DeleteObject(hbmColor
);
653 HeapFree( GetProcessHeap(), 0, bmpinfo
);
658 /* Shamelessly ripped from dlls/oleaut32/tests/olepicture.c */
660 static const unsigned char gifimage
[35] = {
661 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
662 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
667 static const unsigned char jpgimage
[285] = {
668 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
669 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
670 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
671 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
672 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
673 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
674 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
675 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
676 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
677 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
678 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
679 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
680 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
681 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
682 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
683 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
684 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
685 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
689 static const unsigned char pngimage
[285] = {
690 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
691 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
692 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
693 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
694 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
695 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
696 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
700 static const unsigned char bmpimage
[66] = {
701 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
702 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
703 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
704 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
709 static const unsigned char gif4pixel
[42] = {
710 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
711 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
712 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
715 static void test_LoadImageFile(const unsigned char * image_data
,
716 unsigned int image_size
, const char * ext
, BOOL expect_success
)
720 DWORD error
, bytes_written
;
723 strcpy(filename
, "test.");
724 strcat(filename
, ext
);
726 /* Create the test image. */
727 handle
= CreateFileA(filename
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
728 FILE_ATTRIBUTE_NORMAL
, NULL
);
729 ok(handle
!= INVALID_HANDLE_VALUE
, "CreateFileA failed. %u\n", GetLastError());
730 ret
= WriteFile(handle
, image_data
, image_size
, &bytes_written
, NULL
);
731 ok(bytes_written
== image_size
, "test file created improperly.\n");
734 /* Load as cursor. For all tested formats, this should fail */
735 SetLastError(0xdeadbeef);
736 handle
= LoadImageA(NULL
, filename
, IMAGE_CURSOR
, 0, 0, LR_LOADFROMFILE
);
737 ok(handle
== NULL
, "LoadImage(%s) as IMAGE_CURSOR succeeded incorrectly.\n", ext
);
738 error
= GetLastError();
740 broken(error
== 0xdeadbeef) || /* Win9x */
741 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
742 "Last error: %u\n", error
);
743 if (handle
!= NULL
) DestroyCursor(handle
);
745 /* Load as icon. For all tested formats, this should fail */
746 SetLastError(0xdeadbeef);
747 handle
= LoadImageA(NULL
, filename
, IMAGE_ICON
, 0, 0, LR_LOADFROMFILE
);
748 ok(handle
== NULL
, "LoadImage(%s) as IMAGE_ICON succeeded incorrectly.\n", ext
);
749 error
= GetLastError();
751 broken(error
== 0xdeadbeef) || /* Win9x */
752 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
753 "Last error: %u\n", error
);
754 if (handle
!= NULL
) DestroyIcon(handle
);
756 /* Load as bitmap. Should succeed if bmp, fail for everything else */
757 SetLastError(0xdeadbeef);
758 handle
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
);
760 ok(handle
!= NULL
, "LoadImage(%s) as IMAGE_BITMAP failed.\n", ext
);
761 else ok(handle
== NULL
, "LoadImage(%s) as IMAGE_BITMAP succeeded incorrectly.\n", ext
);
762 error
= GetLastError();
764 error
== 0xdeadbeef, /* Win9x, WinMe */
765 "Last error: %u\n", error
);
766 if (handle
!= NULL
) DeleteObject(handle
);
768 DeleteFileA(filename
);
771 static void test_LoadImage(void)
775 DWORD error
, bytes_written
;
776 CURSORICONFILEDIR
*icon_data
;
777 CURSORICONFILEDIRENTRY
*icon_entry
;
778 BITMAPINFOHEADER
*icon_header
;
781 #define ICON_WIDTH 32
782 #define ICON_HEIGHT 32
783 #define ICON_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
786 (sizeof(CURSORICONFILEDIR) + sizeof(BITMAPINFOHEADER) \
787 + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
790 icon_data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ICON_SIZE
);
791 icon_data
->idReserved
= 0;
792 icon_data
->idType
= 1;
793 icon_data
->idCount
= 1;
795 icon_entry
= icon_data
->idEntries
;
796 icon_entry
->bWidth
= ICON_WIDTH
;
797 icon_entry
->bHeight
= ICON_HEIGHT
;
798 icon_entry
->bColorCount
= 0;
799 icon_entry
->bReserved
= 0;
800 icon_entry
->xHotspot
= 1;
801 icon_entry
->yHotspot
= 1;
802 icon_entry
->dwDIBSize
= ICON_SIZE
- sizeof(CURSORICONFILEDIR
);
803 icon_entry
->dwDIBOffset
= sizeof(CURSORICONFILEDIR
);
805 icon_header
= (BITMAPINFOHEADER
*) ((BYTE
*) icon_data
+ icon_entry
->dwDIBOffset
);
806 icon_header
->biSize
= sizeof(BITMAPINFOHEADER
);
807 icon_header
->biWidth
= ICON_WIDTH
;
808 icon_header
->biHeight
= ICON_HEIGHT
*2;
809 icon_header
->biPlanes
= 1;
810 icon_header
->biBitCount
= ICON_BPP
;
811 icon_header
->biSizeImage
= 0; /* Uncompressed bitmap. */
813 /* Create the icon. */
814 handle
= CreateFileA("icon.ico", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
815 FILE_ATTRIBUTE_NORMAL
, NULL
);
816 ok(handle
!= INVALID_HANDLE_VALUE
, "CreateFileA failed. %u\n", GetLastError());
817 ret
= WriteFile(handle
, icon_data
, ICON_SIZE
, &bytes_written
, NULL
);
818 ok(bytes_written
== ICON_SIZE
, "icon.ico created improperly.\n");
821 /* Test loading an icon as a cursor. */
822 SetLastError(0xdeadbeef);
823 handle
= LoadImageA(NULL
, "icon.ico", IMAGE_CURSOR
, 0, 0, LR_LOADFROMFILE
);
824 ok(handle
!= NULL
, "LoadImage() failed.\n");
825 error
= GetLastError();
827 broken(error
== 0xdeadbeef) || /* Win9x */
828 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
829 "Last error: %u\n", error
);
831 /* Test the icon information. */
832 SetLastError(0xdeadbeef);
833 ret
= GetIconInfo(handle
, &icon_info
);
834 ok(ret
, "GetIconInfo() failed.\n");
835 error
= GetLastError();
836 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
840 ok(icon_info
.fIcon
== FALSE
, "fIcon != FALSE.\n");
841 ok(icon_info
.xHotspot
== 1, "xHotspot is %u.\n", icon_info
.xHotspot
);
842 ok(icon_info
.yHotspot
== 1, "yHotspot is %u.\n", icon_info
.yHotspot
);
843 ok(icon_info
.hbmColor
!= NULL
|| broken(!icon_info
.hbmColor
) /* no color cursor support */,
845 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
849 SetLastError(0xdeadbeef);
850 ret
= DestroyCursor(handle
);
851 ok(ret
, "DestroyCursor() failed.\n");
852 error
= GetLastError();
853 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
855 HeapFree(GetProcessHeap(), 0, icon_data
);
856 DeleteFileA("icon.ico");
858 test_LoadImageFile(bmpimage
, sizeof(bmpimage
), "bmp", 1);
859 test_LoadImageFile(gifimage
, sizeof(gifimage
), "gif", 0);
860 test_LoadImageFile(gif4pixel
, sizeof(gif4pixel
), "gif", 0);
861 test_LoadImageFile(jpgimage
, sizeof(jpgimage
), "jpg", 0);
862 test_LoadImageFile(pngimage
, sizeof(pngimage
), "png", 0);
865 static void test_CreateIconFromResource(void)
870 BITMAPINFOHEADER
*icon_header
;
874 #define ICON_RES_WIDTH 32
875 #define ICON_RES_HEIGHT 32
876 #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
877 #define ICON_RES_BPP 32
878 #define ICON_RES_SIZE \
879 (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
880 #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE)
883 hotspot
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, CRSR_RES_SIZE
);
885 /* Cursor resources have an extra hotspot, icon resources not. */
889 icon_header
= (BITMAPINFOHEADER
*) (hotspot
+ 2);
890 icon_header
->biSize
= sizeof(BITMAPINFOHEADER
);
891 icon_header
->biWidth
= ICON_WIDTH
;
892 icon_header
->biHeight
= ICON_HEIGHT
*2;
893 icon_header
->biPlanes
= 1;
894 icon_header
->biBitCount
= ICON_BPP
;
895 icon_header
->biSizeImage
= 0; /* Uncompressed bitmap. */
897 /* Test creating a cursor. */
898 SetLastError(0xdeadbeef);
899 handle
= CreateIconFromResource((PBYTE
) hotspot
, CRSR_RES_SIZE
, FALSE
, 0x00030000);
900 ok(handle
!= NULL
, "Create cursor failed.\n");
902 /* Test the icon information. */
903 SetLastError(0xdeadbeef);
904 ret
= GetIconInfo(handle
, &icon_info
);
905 ok(ret
, "GetIconInfo() failed.\n");
906 error
= GetLastError();
907 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
911 ok(icon_info
.fIcon
== FALSE
, "fIcon != FALSE.\n");
912 ok(icon_info
.xHotspot
== 3, "xHotspot is %u.\n", icon_info
.xHotspot
);
913 ok(icon_info
.yHotspot
== 3, "yHotspot is %u.\n", icon_info
.yHotspot
);
914 ok(icon_info
.hbmColor
!= NULL
|| broken(!icon_info
.hbmColor
) /* no color cursor support */,
916 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
920 SetLastError(0xdeadbeef);
921 ret
= DestroyCursor(handle
);
922 ok(ret
, "DestroyCursor() failed.\n");
923 error
= GetLastError();
924 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
926 /* Test creating an icon. */
927 SetLastError(0xdeadbeef);
928 handle
= CreateIconFromResource((PBYTE
) icon_header
, ICON_RES_SIZE
, TRUE
,
930 ok(handle
!= NULL
, "Create icon failed.\n");
932 /* Test the icon information. */
933 SetLastError(0xdeadbeef);
934 ret
= GetIconInfo(handle
, &icon_info
);
935 ok(ret
, "GetIconInfo() failed.\n");
936 error
= GetLastError();
937 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
941 ok(icon_info
.fIcon
== TRUE
, "fIcon != TRUE.\n");
942 /* Icons always have hotspot in the middle */
943 ok(icon_info
.xHotspot
== ICON_WIDTH
/2, "xHotspot is %u.\n", icon_info
.xHotspot
);
944 ok(icon_info
.yHotspot
== ICON_HEIGHT
/2, "yHotspot is %u.\n", icon_info
.yHotspot
);
945 ok(icon_info
.hbmColor
!= NULL
, "No hbmColor!\n");
946 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
950 SetLastError(0xdeadbeef);
951 ret
= DestroyCursor(handle
);
952 ok(ret
, "DestroyCursor() failed.\n");
953 error
= GetLastError();
954 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
956 HeapFree(GetProcessHeap(), 0, hotspot
);
959 static HICON
create_test_icon(HDC hdc
, int width
, int height
, int bpp
,
960 BOOL maskvalue
, UINT32
*color
, int colorSize
)
963 BITMAPINFO bitmapInfo
;
964 UINT32
*buffer
= NULL
;
965 UINT32 mask
= maskvalue
? 0xFFFFFFFF : 0x00000000;
967 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
968 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
969 bitmapInfo
.bmiHeader
.biWidth
= width
;
970 bitmapInfo
.bmiHeader
.biHeight
= height
;
971 bitmapInfo
.bmiHeader
.biPlanes
= 1;
972 bitmapInfo
.bmiHeader
.biBitCount
= bpp
;
973 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
974 bitmapInfo
.bmiHeader
.biSizeImage
= colorSize
;
976 iconInfo
.fIcon
= TRUE
;
977 iconInfo
.xHotspot
= 0;
978 iconInfo
.yHotspot
= 0;
980 iconInfo
.hbmMask
= CreateBitmap( width
, height
, 1, 1, &mask
);
981 if(!iconInfo
.hbmMask
) return NULL
;
983 iconInfo
.hbmColor
= CreateDIBSection(hdc
, &bitmapInfo
, DIB_RGB_COLORS
, (void**)&buffer
, NULL
, 0);
984 if(!iconInfo
.hbmColor
|| !buffer
)
986 DeleteObject(iconInfo
.hbmMask
);
990 memcpy(buffer
, color
, colorSize
);
992 return CreateIconIndirect(&iconInfo
);
995 static BOOL
color_match(COLORREF a
, COLORREF b
)
997 /* 5-bit accuracy is a sufficient test. This will match, so long as
998 * colors are never truncated to less that 3x5-bit accuracy i.e.
1000 return (a
& 0x00F8F8F8) == (b
& 0x00F8F8F8);
1003 static void check_alpha_draw(HDC hdc
, BOOL drawiconex
, BOOL alpha
, int bpp
, int line
)
1008 COLORREF modern_expected
, legacy_expected
, result
;
1011 color
[0] = 0x00A0B0C0;
1012 color
[1] = alpha
? 0xFF000000 : 0x00000000;
1013 modern_expected
= alpha
? 0x00FFFFFF : 0x00C0B0A0;
1014 legacy_expected
= 0x00C0B0A0;
1016 hicon
= create_test_icon(hdc
, 2, 1, bpp
, 0, color
, sizeof(color
));
1019 SetPixelV(hdc
, 0, 0, 0x00FFFFFF);
1022 DrawIconEx(hdc
, 0, 0, hicon
, 2, 1, 0, NULL
, DI_NORMAL
);
1024 DrawIcon(hdc
, 0, 0, hicon
);
1026 result
= GetPixel(hdc
, 0, 0);
1027 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1028 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1029 "%s. Expected a close match to %06X (modern) or %06X (legacy) with %s. "
1030 "Got %06X from line %d\n",
1031 alpha
? "Alpha blending" : "Not alpha blending", modern_expected
, legacy_expected
,
1032 drawiconex
? "DrawIconEx" : "DrawIcon", result
, line
);
1035 static void check_DrawIcon(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, COLORREF background
,
1036 COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1039 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1041 SetPixelV(hdc
, 0, 0, background
);
1042 SetPixelV(hdc
, GetSystemMetrics(SM_CXICON
)-1, GetSystemMetrics(SM_CYICON
)-1, background
);
1043 SetPixelV(hdc
, GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
), background
);
1044 DrawIcon(hdc
, 0, 0, hicon
);
1045 result
= GetPixel(hdc
, 0, 0);
1047 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1048 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1049 "Overlaying Mask %d on Color %06X with DrawIcon. "
1050 "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1051 maskvalue
, color
, modern_expected
, legacy_expected
, result
, line
);
1053 result
= GetPixel(hdc
, GetSystemMetrics(SM_CXICON
)-1, GetSystemMetrics(SM_CYICON
)-1);
1055 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1056 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1057 "Overlaying Mask %d on Color %06X with DrawIcon. "
1058 "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1059 maskvalue
, color
, modern_expected
, legacy_expected
, result
, line
);
1061 result
= GetPixel(hdc
, GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
));
1063 ok (color_match(result
, background
),
1064 "Overlaying Mask %d on Color %06X with DrawIcon. "
1065 "Expected unchanged background color %06X. Got %06X from line %d\n",
1066 maskvalue
, color
, background
, result
, line
);
1069 static void test_DrawIcon(void)
1071 BITMAPINFO bitmapInfo
;
1073 HBITMAP bmpDst
= NULL
;
1074 HBITMAP bmpOld
= NULL
;
1077 hdcDst
= CreateCompatibleDC(0);
1078 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1082 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1084 skip("Windows will distort DrawIcon colors at 8-bpp and less due to palletizing.\n");
1088 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1089 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1090 bitmapInfo
.bmiHeader
.biWidth
= GetSystemMetrics(SM_CXICON
)+1;
1091 bitmapInfo
.bmiHeader
.biHeight
= GetSystemMetrics(SM_CYICON
)+1;
1092 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1093 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1094 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1095 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1097 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, (void**)&bits
, NULL
, 0);
1098 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1099 if (!bmpDst
|| !bits
)
1101 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1103 /* Mask is only heeded if alpha channel is always zero */
1104 check_DrawIcon(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1105 check_DrawIcon(hdcDst
, TRUE
, 0x00A0B0C0, 32, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__
);
1107 /* Test alpha blending */
1108 /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
1109 check_DrawIcon(hdcDst
, FALSE
, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1110 check_DrawIcon(hdcDst
, TRUE
, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__
);
1112 check_DrawIcon(hdcDst
, FALSE
, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1113 check_DrawIcon(hdcDst
, TRUE
, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1114 check_DrawIcon(hdcDst
, FALSE
, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__
);
1115 check_DrawIcon(hdcDst
, TRUE
, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__
);
1117 check_DrawIcon(hdcDst
, FALSE
, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1118 check_DrawIcon(hdcDst
, TRUE
, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1120 /* Test detecting of alpha channel */
1121 /* If a single pixel's alpha channel is non-zero, the icon
1122 will be alpha blended, otherwise it will be draw with
1124 check_alpha_draw(hdcDst
, FALSE
, FALSE
, 32, __LINE__
);
1125 check_alpha_draw(hdcDst
, FALSE
, TRUE
, 32, __LINE__
);
1129 SelectObject(hdcDst
, bmpOld
);
1131 DeleteObject(bmpDst
);
1136 static void check_DrawIconEx(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, UINT flags
, COLORREF background
,
1137 COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1140 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1142 SetPixelV(hdc
, 0, 0, background
);
1143 DrawIconEx(hdc
, 0, 0, hicon
, 1, 1, 0, NULL
, flags
);
1144 result
= GetPixel(hdc
, 0, 0);
1146 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1147 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1148 "Overlaying Mask %d on Color %06X with DrawIconEx flags %08X. "
1149 "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
1150 maskvalue
, color
, flags
, modern_expected
, legacy_expected
, result
, line
);
1153 static void test_DrawIconEx(void)
1155 BITMAPINFO bitmapInfo
;
1157 HBITMAP bmpDst
= NULL
;
1158 HBITMAP bmpOld
= NULL
;
1161 hdcDst
= CreateCompatibleDC(0);
1162 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1166 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1168 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n");
1172 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1173 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1174 bitmapInfo
.bmiHeader
.biWidth
= 1;
1175 bitmapInfo
.bmiHeader
.biHeight
= 1;
1176 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1177 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1178 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1179 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1180 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, (void**)&bits
, NULL
, 0);
1181 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1182 if (!bmpDst
|| !bits
)
1184 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1186 /* Test null, image only, and mask only drawing */
1187 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__
);
1188 check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__
);
1190 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_MASK
, 0x00FFFFFF, 0x00000000, 0x00000000, __LINE__
);
1191 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_MASK
, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, __LINE__
);
1195 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, DI_IMAGE
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1196 check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, DI_IMAGE
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1199 /* Test normal drawing */
1200 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1201 todo_wine
check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__
);
1202 check_DrawIconEx(hdcDst
, FALSE
, 0xFFA0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1204 /* Test alpha blending */
1205 /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
1206 check_DrawIconEx(hdcDst
, TRUE
, 0xFFA0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__
);
1208 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1209 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1210 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__
);
1211 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__
);
1213 check_DrawIconEx(hdcDst
, FALSE
, 0x01FFFFFF, 32, DI_NORMAL
, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1214 check_DrawIconEx(hdcDst
, TRUE
, 0x01FFFFFF, 32, DI_NORMAL
, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1216 /* Test detecting of alpha channel */
1217 /* If a single pixel's alpha channel is non-zero, the icon
1218 will be alpha blended, otherwise it will be draw with
1220 check_alpha_draw(hdcDst
, TRUE
, FALSE
, 32, __LINE__
);
1221 check_alpha_draw(hdcDst
, TRUE
, TRUE
, 32, __LINE__
);
1225 SelectObject(hdcDst
, bmpOld
);
1227 DeleteObject(bmpDst
);
1232 static void check_DrawState_Size(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, HBRUSH hbr
, UINT flags
, int line
)
1234 COLORREF result
, background
;
1236 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1237 background
= 0x00FFFFFF;
1238 /* Set color of the 2 pixels that will be checked afterwards */
1239 SetPixelV(hdc
, 0, 0, background
);
1240 SetPixelV(hdc
, 2, 2, background
);
1242 /* Let DrawState calculate the size of the icon (it's 1x1) */
1243 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 0, 0, (DST_ICON
| flags
));
1245 result
= GetPixel(hdc
, 0, 0);
1246 passed
[0] = color_match(result
, background
);
1247 result
= GetPixel(hdc
, 2, 2);
1248 passed
[0] = passed
[0] & color_match(result
, background
);
1250 /* Check if manually specifying the icon size DOESN'T work */
1252 /* IMPORTANT: For Icons, DrawState wants the size of the source image, not the
1253 * size in which it should be ultimately drawn. Therefore giving
1254 * width/height 2x2 if the icon is only 1x1 pixels in size should
1255 * result in drawing it with size 1x1. The size parameters must be
1256 * ignored if a Icon has to be drawn! */
1257 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 2, 2, (DST_ICON
| flags
));
1259 result
= GetPixel(hdc
, 0, 0);
1260 passed
[1] = color_match(result
, background
);
1261 result
= GetPixel(hdc
, 2, 2);
1262 passed
[1] = passed
[0] & color_match(result
, background
);
1264 if(!passed
[0]&&!passed
[1])
1266 "DrawState failed to draw a 1x1 Icon in the correct size, independent of the "
1267 "width and height settings passed to it, for Icon with: Overlaying Mask %d on "
1268 "Color %06X with flags %08X. Line %d\n",
1269 maskvalue
, color
, (DST_ICON
| flags
), line
);
1272 "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
1273 "parameters passed to it are bigger than the real Icon size, for Icon with: Overlaying "
1274 "Mask %d on Color %06X with flags %08X. Line %d\n",
1275 maskvalue
, color
, (DST_ICON
| flags
), line
);
1278 "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
1279 "parameters passed to it are 0, for Icon with: Overlaying Mask %d on "
1280 "Color %06X with flags %08X. Line %d\n",
1281 maskvalue
, color
, (DST_ICON
| flags
), line
);
1284 static void check_DrawState_Color(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, HBRUSH hbr
, UINT flags
,
1285 COLORREF background
, COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1288 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1290 /* Set color of the pixel that will be checked afterwards */
1291 SetPixelV(hdc
, 1, 1, background
);
1293 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 0, 0, ( DST_ICON
| flags
));
1295 /* Check the color of the pixel is correct */
1296 result
= GetPixel(hdc
, 1, 1);
1298 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1299 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1300 "DrawState drawing Icon with Overlaying Mask %d on Color %06X with flags %08X. "
1301 "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
1302 maskvalue
, color
, (DST_ICON
| flags
), modern_expected
, legacy_expected
, result
, line
);
1305 static void test_DrawState(void)
1307 BITMAPINFO bitmapInfo
;
1309 HBITMAP bmpDst
= NULL
;
1310 HBITMAP bmpOld
= NULL
;
1313 hdcDst
= CreateCompatibleDC(0);
1314 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1318 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1320 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n");
1324 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1325 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1326 bitmapInfo
.bmiHeader
.biWidth
= 3;
1327 bitmapInfo
.bmiHeader
.biHeight
= 3;
1328 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1329 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1330 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1331 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1332 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, (void**)&bits
, NULL
, 0);
1333 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1334 if (!bmpDst
|| !bits
)
1336 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1338 /* potential flags to test with DrawState are: */
1339 /* DSS_DISABLED embosses the icon */
1340 /* DSS_MONO draw Icon using a brush as parameter 5 */
1341 /* DSS_NORMAL draw Icon without any modifications */
1342 /* DSS_UNION draw the Icon dithered */
1344 check_DrawState_Size(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, DSS_NORMAL
, __LINE__
);
1345 check_DrawState_Color(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, DSS_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1349 SelectObject(hdcDst
, bmpOld
);
1351 DeleteObject(bmpDst
);
1356 static void test_DestroyCursor(void)
1358 static const BYTE bmp_bits
[4096];
1359 ICONINFO cursorInfo
;
1360 HCURSOR cursor
, cursor2
;
1367 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1370 cursorInfo
.fIcon
= FALSE
;
1371 cursorInfo
.xHotspot
= 0;
1372 cursorInfo
.yHotspot
= 0;
1373 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
1374 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
1376 cursor
= CreateIconIndirect(&cursorInfo
);
1377 ok(cursor
!= NULL
, "CreateIconIndirect returned %p\n", cursor
);
1383 SetLastError(0xdeadbeef);
1384 ret
= DestroyCursor(cursor
);
1385 ok(!ret
|| broken(ret
) /* succeeds on win9x */, "DestroyCursor on the active cursor succeeded\n");
1386 error
= GetLastError();
1387 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
1390 cursor2
= GetCursor();
1391 ok(cursor2
== cursor
, "Active was set to %p when trying to destroy it\n", cursor2
);
1394 /* Trying to destroy the cursor properly fails now with
1395 * ERROR_INVALID_CURSOR_HANDLE. This happens because we called
1396 * DestroyCursor() 2+ times after calling SetCursor(). The calls to
1397 * GetCursor() and SetCursor(NULL) in between make no difference. */
1398 ret
= DestroyCursor(cursor
);
1400 ok(!ret
, "DestroyCursor succeeded.\n");
1401 error
= GetLastError();
1402 ok(error
== ERROR_INVALID_CURSOR_HANDLE
|| error
== 0xdeadbeef, /* vista */
1403 "Last error: 0x%08x\n", error
);
1407 DeleteObject(cursorInfo
.hbmMask
);
1408 DeleteObject(cursorInfo
.hbmColor
);
1410 /* Try testing DestroyCursor() now using LoadCursor() cursors. */
1411 cursor
= LoadCursor(NULL
, IDC_ARROW
);
1413 SetLastError(0xdeadbeef);
1414 ret
= DestroyCursor(cursor
);
1415 ok(ret
|| broken(!ret
) /* fails on win9x */, "DestroyCursor on the active cursor failed.\n");
1416 error
= GetLastError();
1417 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
1419 /* Try setting the cursor to a destroyed OEM cursor. */
1420 SetLastError(0xdeadbeef);
1422 error
= GetLastError();
1424 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
1427 /* Check if LoadCursor() returns the same handle with the same icon. */
1428 cursor2
= LoadCursor(NULL
, IDC_ARROW
);
1429 ok(cursor2
== cursor
, "cursor == %p, cursor2 == %p\n", cursor
, cursor2
);
1431 /* Check if LoadCursor() returns the same handle with a different icon. */
1432 cursor2
= LoadCursor(NULL
, IDC_WAIT
);
1433 ok(cursor2
!= cursor
, "cursor == %p, cursor2 == %p\n", cursor
, cursor2
);
1436 START_TEST(cursoricon
)
1438 test_argc
= winetest_get_mainargs(&test_argv
);
1442 /* Child process. */
1443 sscanf (test_argv
[2], "%x", (unsigned int *) &parent
);
1445 ok(parent
!= NULL
, "Parent not found.\n");
1453 test_CopyImage_Bitmap(1);
1454 test_CopyImage_Bitmap(4);
1455 test_CopyImage_Bitmap(8);
1456 test_CopyImage_Bitmap(16);
1457 test_CopyImage_Bitmap(24);
1458 test_CopyImage_Bitmap(32);
1459 test_initial_cursor();
1462 test_CreateIconFromResource();
1466 test_DestroyCursor();
1468 test_child_process();
1469 finish_child_process();