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 BOOL (WINAPI
*pGetCursorInfo
)(CURSORINFO
*);
69 static LRESULT CALLBACK
callback_child(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
76 /* Destroy the cursor. */
78 SetLastError(0xdeadbeef);
79 ret
= DestroyCursor((HCURSOR
) lParam
);
80 error
= GetLastError();
81 todo_wine
ok(!ret
|| broken(ret
) /* win9x */, "DestroyCursor on the active cursor succeeded.\n");
82 ok(error
== ERROR_DESTROY_OBJECT_OF_OTHER_THREAD
||
83 error
== 0xdeadbeef, /* vista */
84 "Last error: %u\n", error
);
91 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
94 static LRESULT CALLBACK
callback_parent(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
98 child
= (HWND
) wParam
;
102 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
105 static void do_child(void)
111 /* Register a new class. */
112 class.style
= CS_GLOBALCLASS
;
113 class.lpfnWndProc
= callback_child
;
114 class.cbClsExtra
= 0;
115 class.cbWndExtra
= 0;
116 class.hInstance
= GetModuleHandle(NULL
);
118 class.hCursor
= NULL
;
119 class.hbrBackground
= NULL
;
120 class.lpszMenuName
= NULL
;
121 class.lpszClassName
= "cursor_child";
123 SetLastError(0xdeadbeef);
124 ret
= RegisterClass(&class);
125 ok(ret
, "Failed to register window class. Error: %u\n", GetLastError());
127 /* Create a window. */
128 child
= CreateWindowA("cursor_child", "cursor_child", WS_POPUP
| WS_VISIBLE
,
129 0, 0, 200, 200, 0, 0, 0, NULL
);
130 ok(child
!= 0, "CreateWindowA failed. Error: %u\n", GetLastError());
132 /* Let the parent know our HWND. */
133 PostMessage(parent
, PROC_INIT
, (WPARAM
) child
, 0);
135 /* Receive messages. */
136 while ((ret
= GetMessage(&msg
, 0, 0, 0)))
138 ok(ret
!= -1, "GetMessage failed. Error: %u\n", GetLastError());
139 TranslateMessage(&msg
);
140 DispatchMessage(&msg
);
144 static void do_parent(void)
146 char path_name
[MAX_PATH
];
147 PROCESS_INFORMATION info
;
148 STARTUPINFOA startup
;
153 /* Register a new class. */
154 class.style
= CS_GLOBALCLASS
;
155 class.lpfnWndProc
= callback_parent
;
156 class.cbClsExtra
= 0;
157 class.cbWndExtra
= 0;
158 class.hInstance
= GetModuleHandle(NULL
);
160 class.hCursor
= NULL
;
161 class.hbrBackground
= NULL
;
162 class.lpszMenuName
= NULL
;
163 class.lpszClassName
= "cursor_parent";
165 SetLastError(0xdeadbeef);
166 ret
= RegisterClass(&class);
167 ok(ret
, "Failed to register window class. Error: %u\n", GetLastError());
169 /* Create a window. */
170 parent
= CreateWindowA("cursor_parent", "cursor_parent", WS_POPUP
| WS_VISIBLE
,
171 0, 0, 200, 200, 0, 0, 0, NULL
);
172 ok(parent
!= 0, "CreateWindowA failed. Error: %u\n", GetLastError());
174 /* Start child process. */
175 memset(&startup
, 0, sizeof(startup
));
176 startup
.cb
= sizeof(startup
);
177 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
178 startup
.wShowWindow
= SW_SHOWNORMAL
;
180 sprintf(path_name
, "%s cursoricon %lx", test_argv
[0], (INT_PTR
)parent
);
181 ok(CreateProcessA(NULL
, path_name
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed.\n");
182 child_process
= info
.hProcess
;
184 /* Wait for child window handle. */
185 while ((child
== 0) && (ret
= GetMessage(&msg
, parent
, 0, 0)))
187 ok(ret
!= -1, "GetMessage failed. Error: %u\n", GetLastError());
188 TranslateMessage(&msg
);
189 DispatchMessage(&msg
);
193 static void finish_child_process(void)
195 SendMessage(child
, WM_CLOSE
, 0, 0);
196 winetest_wait_child_process( child_process
);
197 CloseHandle(child_process
);
200 static void test_child_process(void)
202 static const BYTE bmp_bits
[4096];
208 /* Create and set a dummy cursor. */
210 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
213 cursorInfo
.fIcon
= FALSE
;
214 cursorInfo
.xHotspot
= 0;
215 cursorInfo
.yHotspot
= 0;
216 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
217 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
219 cursor
= CreateIconIndirect(&cursorInfo
);
220 ok(cursor
!= NULL
, "CreateIconIndirect returned %p.\n", cursor
);
224 /* Destroy the cursor. */
225 SendMessage(child
, WM_USER
+1, 0, (LPARAM
) cursor
);
228 static void test_CopyImage_Check(HBITMAP bitmap
, UINT flags
, INT copyWidth
, INT copyHeight
,
229 INT expectedWidth
, INT expectedHeight
, WORD expectedDepth
, BOOL dibExpected
)
237 copy
= CopyImage(bitmap
, IMAGE_BITMAP
, copyWidth
, copyHeight
, flags
);
238 ok(copy
!= NULL
, "CopyImage() failed\n");
241 GetObject(bitmap
, sizeof(origBitmap
), &origBitmap
);
242 GetObject(copy
, sizeof(copyBitmap
), ©Bitmap
);
243 orig_is_dib
= (origBitmap
.bmBits
!= NULL
);
244 copy_is_dib
= (copyBitmap
.bmBits
!= NULL
);
246 if (copy_is_dib
&& dibExpected
247 && copyBitmap
.bmBitsPixel
== 24
248 && (expectedDepth
== 16 || expectedDepth
== 32))
250 /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
251 if (GetVersion() & 0x80000000)
257 if (copy_is_dib
&& !dibExpected
&& !(flags
& LR_CREATEDIBSECTION
))
259 /* It's not forbidden to create a DIB section if the flag
260 LR_CREATEDIBSECTION is absent.
261 Windows 9x does this if the bitmap has a depth that doesn't
262 match the screen depth, Windows NT doesn't */
264 expectedDepth
= origBitmap
.bmBitsPixel
;
267 ok((!(dibExpected
^ copy_is_dib
)
268 && (copyBitmap
.bmWidth
== expectedWidth
)
269 && (copyBitmap
.bmHeight
== expectedHeight
)
270 && (copyBitmap
.bmBitsPixel
== expectedDepth
)),
271 "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
272 orig_is_dib
? "DIB" : "DDB", origBitmap
.bmWidth
, origBitmap
.bmHeight
, origBitmap
.bmBitsPixel
,
273 copyWidth
, copyHeight
, flags
,
274 dibExpected
? "DIB" : "DDB", expectedWidth
, expectedHeight
, expectedDepth
,
275 copy_is_dib
? "DIB" : "DDB", copyBitmap
.bmWidth
, copyBitmap
.bmHeight
, copyBitmap
.bmBitsPixel
);
281 static void test_CopyImage_Bitmap(int depth
)
290 /* Create a device-independent bitmap (DIB) */
291 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
292 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
293 info
->bmiHeader
.biWidth
= 2;
294 info
->bmiHeader
.biHeight
= 2;
295 info
->bmiHeader
.biPlanes
= 1;
296 info
->bmiHeader
.biBitCount
= depth
;
297 info
->bmiHeader
.biCompression
= BI_RGB
;
299 for (i
=0; i
< 256; i
++)
301 info
->bmiColors
[i
].rgbRed
= i
;
302 info
->bmiColors
[i
].rgbGreen
= i
;
303 info
->bmiColors
[i
].rgbBlue
= 255 - i
;
304 info
->bmiColors
[i
].rgbReserved
= 0;
307 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
309 /* Create a device-dependent bitmap (DDB) */
310 screenDC
= GetDC(NULL
);
311 screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
312 if (depth
== 1 || depth
== screen_depth
)
314 ddb
= CreateBitmap(2, 2, 1, depth
, NULL
);
320 ReleaseDC(NULL
, screenDC
);
324 test_CopyImage_Check(ddb
, 0, 0, 0, 2, 2, depth
== 1 ? 1 : screen_depth
, FALSE
);
325 test_CopyImage_Check(ddb
, 0, 0, 5, 2, 5, depth
== 1 ? 1 : screen_depth
, FALSE
);
326 test_CopyImage_Check(ddb
, 0, 5, 0, 5, 2, depth
== 1 ? 1 : screen_depth
, FALSE
);
327 test_CopyImage_Check(ddb
, 0, 5, 5, 5, 5, depth
== 1 ? 1 : screen_depth
, FALSE
);
329 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 0, 0, 2, 2, 1, FALSE
);
330 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 5, 0, 5, 2, 1, FALSE
);
331 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 0, 5, 2, 5, 1, FALSE
);
332 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 5, 5, 5, 5, 1, FALSE
);
334 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
335 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
336 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
337 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
339 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
340 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
341 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
342 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
343 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
350 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, screen_depth
, FALSE
);
351 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, screen_depth
, FALSE
);
352 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, screen_depth
, FALSE
);
353 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, screen_depth
, FALSE
);
356 test_CopyImage_Check(dib
, LR_MONOCHROME
, 0, 0, 2, 2, 1, FALSE
);
357 test_CopyImage_Check(dib
, LR_MONOCHROME
, 5, 0, 5, 2, 1, FALSE
);
358 test_CopyImage_Check(dib
, LR_MONOCHROME
, 0, 5, 2, 5, 1, FALSE
);
359 test_CopyImage_Check(dib
, LR_MONOCHROME
, 5, 5, 5, 5, 1, FALSE
);
361 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
362 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
363 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
364 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
366 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
367 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
368 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
369 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
370 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
376 /* Special case: A monochrome DIB is converted to a monochrome DDB if
377 the colors in the color table are black and white.
379 Skip this test on Windows 95, it always creates a monochrome DDB
382 if (!(GetVersion() & 0x80000000))
384 info
->bmiHeader
.biBitCount
= 1;
385 info
->bmiColors
[0].rgbRed
= 0xFF;
386 info
->bmiColors
[0].rgbGreen
= 0;
387 info
->bmiColors
[0].rgbBlue
= 0;
388 info
->bmiColors
[1].rgbRed
= 0;
389 info
->bmiColors
[1].rgbGreen
= 0xFF;
390 info
->bmiColors
[1].rgbBlue
= 0;
392 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
393 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, screen_depth
, FALSE
);
394 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, screen_depth
, FALSE
);
395 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, screen_depth
, FALSE
);
396 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, screen_depth
, FALSE
);
399 info
->bmiHeader
.biBitCount
= 1;
400 info
->bmiColors
[0].rgbRed
= 0;
401 info
->bmiColors
[0].rgbGreen
= 0;
402 info
->bmiColors
[0].rgbBlue
= 0;
403 info
->bmiColors
[1].rgbRed
= 0xFF;
404 info
->bmiColors
[1].rgbGreen
= 0xFF;
405 info
->bmiColors
[1].rgbBlue
= 0xFF;
407 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
408 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, 1, FALSE
);
409 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, 1, FALSE
);
410 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, 1, FALSE
);
411 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, 1, FALSE
);
414 info
->bmiHeader
.biBitCount
= 1;
415 info
->bmiColors
[0].rgbRed
= 0xFF;
416 info
->bmiColors
[0].rgbGreen
= 0xFF;
417 info
->bmiColors
[0].rgbBlue
= 0xFF;
418 info
->bmiColors
[1].rgbRed
= 0;
419 info
->bmiColors
[1].rgbGreen
= 0;
420 info
->bmiColors
[1].rgbBlue
= 0;
422 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
423 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, 1, FALSE
);
424 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, 1, FALSE
);
425 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, 1, FALSE
);
426 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, 1, FALSE
);
431 HeapFree(GetProcessHeap(), 0, info
);
434 static void test_initial_cursor(void)
436 HCURSOR cursor
, cursor2
;
439 cursor
= GetCursor();
441 /* Check what handle GetCursor() returns if a cursor is not set yet. */
442 SetLastError(0xdeadbeef);
443 cursor2
= LoadCursor(NULL
, IDC_WAIT
);
445 ok(cursor
== cursor2
, "cursor (%p) is not IDC_WAIT (%p).\n", cursor
, cursor2
);
447 error
= GetLastError();
448 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
451 static void test_icon_info_dbg(HICON hIcon
, UINT exp_cx
, UINT exp_cy
, UINT exp_bpp
, int line
)
455 BITMAP bmMask
, bmColor
;
457 ret
= GetIconInfo(hIcon
, &info
);
458 ok_(__FILE__
, line
)(ret
, "GetIconInfo failed\n");
460 /* CreateIcon under XP causes info.fIcon to be 0 */
461 ok_(__FILE__
, line
)(info
.xHotspot
== exp_cx
/2, "info.xHotspot = %u\n", info
.xHotspot
);
462 ok_(__FILE__
, line
)(info
.yHotspot
== exp_cy
/2, "info.yHotspot = %u\n", info
.yHotspot
);
463 ok_(__FILE__
, line
)(info
.hbmMask
!= 0, "info.hbmMask is NULL\n");
465 ret
= GetObject(info
.hbmMask
, sizeof(bmMask
), &bmMask
);
466 ok_(__FILE__
, line
)(ret
== sizeof(bmMask
), "GetObject(info.hbmMask) failed, ret %u\n", ret
);
469 ok_(__FILE__
, line
)(info
.hbmColor
== 0, "info.hbmColor should be NULL\n");
477 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
480 ret
= GetObject(info
.hbmColor
, sizeof(bmColor
), &bmColor
);
481 ok_(__FILE__
, line
)(ret
== sizeof(bmColor
), "GetObject(info.hbmColor) failed, ret %u\n", ret
);
483 ok_(__FILE__
, line
)(bmColor
.bmBitsPixel
== display_bpp
/* XP */ ||
484 bmColor
.bmBitsPixel
== exp_bpp
/* Win98 */,
485 "bmColor.bmBitsPixel = %d\n", bmColor
.bmBitsPixel
);
486 ok_(__FILE__
, line
)(bmColor
.bmWidth
== exp_cx
, "bmColor.bmWidth = %d\n", bmColor
.bmWidth
);
487 ok_(__FILE__
, line
)(bmColor
.bmHeight
== exp_cy
, "bmColor.bmHeight = %d\n", bmColor
.bmHeight
);
489 ok_(__FILE__
, line
)(bmMask
.bmBitsPixel
== 1, "bmMask.bmBitsPixel = %d\n", bmMask
.bmBitsPixel
);
490 ok_(__FILE__
, line
)(bmMask
.bmWidth
== exp_cx
, "bmMask.bmWidth = %d\n", bmMask
.bmWidth
);
491 ok_(__FILE__
, line
)(bmMask
.bmHeight
== exp_cy
, "bmMask.bmHeight = %d\n", bmMask
.bmHeight
);
495 ok_(__FILE__
, line
)(bmMask
.bmBitsPixel
== 1, "bmMask.bmBitsPixel = %d\n", bmMask
.bmBitsPixel
);
496 ok_(__FILE__
, line
)(bmMask
.bmWidth
== exp_cx
, "bmMask.bmWidth = %d\n", bmMask
.bmWidth
);
497 ok_(__FILE__
, line
)(bmMask
.bmHeight
== exp_cy
* 2, "bmMask.bmHeight = %d\n", bmMask
.bmHeight
);
501 #define test_icon_info(a,b,c,d) test_icon_info_dbg((a),(b),(c),(d),__LINE__)
503 static void test_CreateIcon(void)
505 static const BYTE bmp_bits
[1024];
507 HBITMAP hbmMask
, hbmColor
;
515 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
517 /* these crash under XP
518 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
519 hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits);
522 hIcon
= CreateIcon(0, 16, 16, 1, 1, bmp_bits
, bmp_bits
);
523 ok(hIcon
!= 0, "CreateIcon failed\n");
524 test_icon_info(hIcon
, 16, 16, 1);
527 hIcon
= CreateIcon(0, 16, 16, 1, display_bpp
, bmp_bits
, bmp_bits
);
528 ok(hIcon
!= 0, "CreateIcon failed\n");
529 test_icon_info(hIcon
, 16, 16, display_bpp
);
532 hbmMask
= CreateBitmap(16, 16, 1, 1, bmp_bits
);
533 ok(hbmMask
!= 0, "CreateBitmap failed\n");
534 hbmColor
= CreateBitmap(16, 16, 1, display_bpp
, bmp_bits
);
535 ok(hbmColor
!= 0, "CreateBitmap failed\n");
542 SetLastError(0xdeadbeaf);
543 hIcon
= CreateIconIndirect(&info
);
544 ok(!hIcon
, "CreateIconIndirect should fail\n");
545 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
551 info
.hbmColor
= hbmColor
;
552 SetLastError(0xdeadbeaf);
553 hIcon
= CreateIconIndirect(&info
);
554 ok(!hIcon
, "CreateIconIndirect should fail\n");
555 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
560 info
.hbmMask
= hbmMask
;
561 info
.hbmColor
= hbmColor
;
562 hIcon
= CreateIconIndirect(&info
);
563 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
564 test_icon_info(hIcon
, 16, 16, display_bpp
);
567 DeleteObject(hbmMask
);
568 DeleteObject(hbmColor
);
570 hbmMask
= CreateBitmap(16, 32, 1, 1, bmp_bits
);
571 ok(hbmMask
!= 0, "CreateBitmap failed\n");
576 info
.hbmMask
= hbmMask
;
578 SetLastError(0xdeadbeaf);
579 hIcon
= CreateIconIndirect(&info
);
580 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
581 test_icon_info(hIcon
, 16, 16, 1);
584 DeleteObject(hbmMask
);
585 DeleteObject(hbmColor
);
587 /* test creating an icon from a DIB section */
589 bmpinfo
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, FIELD_OFFSET(BITMAPINFO
,bmiColors
[256]));
590 bmpinfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
591 bmpinfo
->bmiHeader
.biWidth
= 32;
592 bmpinfo
->bmiHeader
.biHeight
= 32;
593 bmpinfo
->bmiHeader
.biPlanes
= 1;
594 bmpinfo
->bmiHeader
.biBitCount
= 8;
595 bmpinfo
->bmiHeader
.biCompression
= BI_RGB
;
596 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
597 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
599 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
600 bmpinfo
->bmiHeader
.biBitCount
= 1;
601 hbmMask
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
602 ok(hbmMask
!= NULL
, "Expected a handle to the DIB\n");
604 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
609 info
.hbmMask
= hbmColor
;
610 info
.hbmColor
= hbmMask
;
611 SetLastError(0xdeadbeaf);
612 hIcon
= CreateIconIndirect(&info
);
613 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
614 test_icon_info(hIcon
, 32, 32, 8);
616 DeleteObject(hbmColor
);
618 bmpinfo
->bmiHeader
.biBitCount
= 16;
619 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
620 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
622 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
627 info
.hbmMask
= hbmColor
;
628 info
.hbmColor
= hbmMask
;
629 SetLastError(0xdeadbeaf);
630 hIcon
= CreateIconIndirect(&info
);
631 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
632 test_icon_info(hIcon
, 32, 32, 8);
634 DeleteObject(hbmColor
);
636 bmpinfo
->bmiHeader
.biBitCount
= 32;
637 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
638 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
640 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
645 info
.hbmMask
= hbmColor
;
646 info
.hbmColor
= hbmMask
;
647 SetLastError(0xdeadbeaf);
648 hIcon
= CreateIconIndirect(&info
);
649 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
650 test_icon_info(hIcon
, 32, 32, 8);
653 DeleteObject(hbmMask
);
654 DeleteObject(hbmColor
);
655 HeapFree( GetProcessHeap(), 0, bmpinfo
);
660 /* Shamelessly ripped from dlls/oleaut32/tests/olepicture.c */
662 static const unsigned char gifimage
[35] = {
663 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
664 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
669 static const unsigned char jpgimage
[285] = {
670 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
671 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
672 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
673 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
674 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
675 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
676 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
677 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
678 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
679 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
680 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
681 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
682 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
683 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
684 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
685 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
686 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
687 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
691 static const unsigned char pngimage
[285] = {
692 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
693 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
694 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
695 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
696 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
697 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
698 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
702 static const unsigned char bmpimage
[66] = {
703 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
704 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
705 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
706 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
711 static const unsigned char gif4pixel
[42] = {
712 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
713 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
714 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
717 static void test_LoadImageFile(const unsigned char * image_data
,
718 unsigned int image_size
, const char * ext
, BOOL expect_success
)
722 DWORD error
, bytes_written
;
725 strcpy(filename
, "test.");
726 strcat(filename
, ext
);
728 /* Create the test image. */
729 handle
= CreateFileA(filename
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
730 FILE_ATTRIBUTE_NORMAL
, NULL
);
731 ok(handle
!= INVALID_HANDLE_VALUE
, "CreateFileA failed. %u\n", GetLastError());
732 ret
= WriteFile(handle
, image_data
, image_size
, &bytes_written
, NULL
);
733 ok(bytes_written
== image_size
, "test file created improperly.\n");
736 /* Load as cursor. For all tested formats, this should fail */
737 SetLastError(0xdeadbeef);
738 handle
= LoadImageA(NULL
, filename
, IMAGE_CURSOR
, 0, 0, LR_LOADFROMFILE
);
739 ok(handle
== NULL
, "LoadImage(%s) as IMAGE_CURSOR succeeded incorrectly.\n", ext
);
740 error
= GetLastError();
742 broken(error
== 0xdeadbeef) || /* Win9x */
743 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
744 "Last error: %u\n", error
);
745 if (handle
!= NULL
) DestroyCursor(handle
);
747 /* Load as icon. For all tested formats, this should fail */
748 SetLastError(0xdeadbeef);
749 handle
= LoadImageA(NULL
, filename
, IMAGE_ICON
, 0, 0, LR_LOADFROMFILE
);
750 ok(handle
== NULL
, "LoadImage(%s) as IMAGE_ICON succeeded incorrectly.\n", ext
);
751 error
= GetLastError();
753 broken(error
== 0xdeadbeef) || /* Win9x */
754 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
755 "Last error: %u\n", error
);
756 if (handle
!= NULL
) DestroyIcon(handle
);
758 /* Load as bitmap. Should succeed if bmp, fail for everything else */
759 SetLastError(0xdeadbeef);
760 handle
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
);
762 ok(handle
!= NULL
, "LoadImage(%s) as IMAGE_BITMAP failed.\n", ext
);
763 else ok(handle
== NULL
, "LoadImage(%s) as IMAGE_BITMAP succeeded incorrectly.\n", ext
);
764 error
= GetLastError();
766 error
== 0xdeadbeef, /* Win9x, WinMe */
767 "Last error: %u\n", error
);
768 if (handle
!= NULL
) DeleteObject(handle
);
770 DeleteFileA(filename
);
773 static void test_LoadImage(void)
777 DWORD error
, bytes_written
;
778 CURSORICONFILEDIR
*icon_data
;
779 CURSORICONFILEDIRENTRY
*icon_entry
;
780 BITMAPINFOHEADER
*icon_header
;
783 #define ICON_WIDTH 32
784 #define ICON_HEIGHT 32
785 #define ICON_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
788 (sizeof(CURSORICONFILEDIR) + sizeof(BITMAPINFOHEADER) \
789 + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
792 icon_data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ICON_SIZE
);
793 icon_data
->idReserved
= 0;
794 icon_data
->idType
= 1;
795 icon_data
->idCount
= 1;
797 icon_entry
= icon_data
->idEntries
;
798 icon_entry
->bWidth
= ICON_WIDTH
;
799 icon_entry
->bHeight
= ICON_HEIGHT
;
800 icon_entry
->bColorCount
= 0;
801 icon_entry
->bReserved
= 0;
802 icon_entry
->xHotspot
= 1;
803 icon_entry
->yHotspot
= 1;
804 icon_entry
->dwDIBSize
= ICON_SIZE
- sizeof(CURSORICONFILEDIR
);
805 icon_entry
->dwDIBOffset
= sizeof(CURSORICONFILEDIR
);
807 icon_header
= (BITMAPINFOHEADER
*) ((BYTE
*) icon_data
+ icon_entry
->dwDIBOffset
);
808 icon_header
->biSize
= sizeof(BITMAPINFOHEADER
);
809 icon_header
->biWidth
= ICON_WIDTH
;
810 icon_header
->biHeight
= ICON_HEIGHT
*2;
811 icon_header
->biPlanes
= 1;
812 icon_header
->biBitCount
= ICON_BPP
;
813 icon_header
->biSizeImage
= 0; /* Uncompressed bitmap. */
815 /* Create the icon. */
816 handle
= CreateFileA("icon.ico", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
817 FILE_ATTRIBUTE_NORMAL
, NULL
);
818 ok(handle
!= INVALID_HANDLE_VALUE
, "CreateFileA failed. %u\n", GetLastError());
819 ret
= WriteFile(handle
, icon_data
, ICON_SIZE
, &bytes_written
, NULL
);
820 ok(bytes_written
== ICON_SIZE
, "icon.ico created improperly.\n");
823 /* Test loading an icon as a cursor. */
824 SetLastError(0xdeadbeef);
825 handle
= LoadImageA(NULL
, "icon.ico", IMAGE_CURSOR
, 0, 0, LR_LOADFROMFILE
);
826 ok(handle
!= NULL
, "LoadImage() failed.\n");
827 error
= GetLastError();
829 broken(error
== 0xdeadbeef) || /* Win9x */
830 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
831 "Last error: %u\n", error
);
833 /* Test the icon information. */
834 SetLastError(0xdeadbeef);
835 ret
= GetIconInfo(handle
, &icon_info
);
836 ok(ret
, "GetIconInfo() failed.\n");
837 error
= GetLastError();
838 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
842 ok(icon_info
.fIcon
== FALSE
, "fIcon != FALSE.\n");
843 ok(icon_info
.xHotspot
== 1, "xHotspot is %u.\n", icon_info
.xHotspot
);
844 ok(icon_info
.yHotspot
== 1, "yHotspot is %u.\n", icon_info
.yHotspot
);
845 ok(icon_info
.hbmColor
!= NULL
|| broken(!icon_info
.hbmColor
) /* no color cursor support */,
847 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
851 SetLastError(0xdeadbeef);
852 ret
= DestroyCursor(handle
);
853 ok(ret
, "DestroyCursor() failed.\n");
854 error
= GetLastError();
855 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
857 HeapFree(GetProcessHeap(), 0, icon_data
);
858 DeleteFileA("icon.ico");
860 test_LoadImageFile(bmpimage
, sizeof(bmpimage
), "bmp", 1);
861 test_LoadImageFile(gifimage
, sizeof(gifimage
), "gif", 0);
862 test_LoadImageFile(gif4pixel
, sizeof(gif4pixel
), "gif", 0);
863 test_LoadImageFile(jpgimage
, sizeof(jpgimage
), "jpg", 0);
864 test_LoadImageFile(pngimage
, sizeof(pngimage
), "png", 0);
867 static void test_CreateIconFromResource(void)
872 BITMAPINFOHEADER
*icon_header
;
876 #define ICON_RES_WIDTH 32
877 #define ICON_RES_HEIGHT 32
878 #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
879 #define ICON_RES_BPP 32
880 #define ICON_RES_SIZE \
881 (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
882 #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE)
885 hotspot
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, CRSR_RES_SIZE
);
887 /* Cursor resources have an extra hotspot, icon resources not. */
891 icon_header
= (BITMAPINFOHEADER
*) (hotspot
+ 2);
892 icon_header
->biSize
= sizeof(BITMAPINFOHEADER
);
893 icon_header
->biWidth
= ICON_WIDTH
;
894 icon_header
->biHeight
= ICON_HEIGHT
*2;
895 icon_header
->biPlanes
= 1;
896 icon_header
->biBitCount
= ICON_BPP
;
897 icon_header
->biSizeImage
= 0; /* Uncompressed bitmap. */
899 /* Test creating a cursor. */
900 SetLastError(0xdeadbeef);
901 handle
= CreateIconFromResource((PBYTE
) hotspot
, CRSR_RES_SIZE
, FALSE
, 0x00030000);
902 ok(handle
!= NULL
, "Create cursor failed.\n");
904 /* Test the icon information. */
905 SetLastError(0xdeadbeef);
906 ret
= GetIconInfo(handle
, &icon_info
);
907 ok(ret
, "GetIconInfo() failed.\n");
908 error
= GetLastError();
909 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
913 ok(icon_info
.fIcon
== FALSE
, "fIcon != FALSE.\n");
914 ok(icon_info
.xHotspot
== 3, "xHotspot is %u.\n", icon_info
.xHotspot
);
915 ok(icon_info
.yHotspot
== 3, "yHotspot is %u.\n", icon_info
.yHotspot
);
916 ok(icon_info
.hbmColor
!= NULL
|| broken(!icon_info
.hbmColor
) /* no color cursor support */,
918 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
922 SetLastError(0xdeadbeef);
923 ret
= DestroyCursor(handle
);
924 ok(ret
, "DestroyCursor() failed.\n");
925 error
= GetLastError();
926 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
928 /* Test creating an icon. */
929 SetLastError(0xdeadbeef);
930 handle
= CreateIconFromResource((PBYTE
) icon_header
, ICON_RES_SIZE
, TRUE
,
932 ok(handle
!= NULL
, "Create icon failed.\n");
934 /* Test the icon information. */
935 SetLastError(0xdeadbeef);
936 ret
= GetIconInfo(handle
, &icon_info
);
937 ok(ret
, "GetIconInfo() failed.\n");
938 error
= GetLastError();
939 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
943 ok(icon_info
.fIcon
== TRUE
, "fIcon != TRUE.\n");
944 /* Icons always have hotspot in the middle */
945 ok(icon_info
.xHotspot
== ICON_WIDTH
/2, "xHotspot is %u.\n", icon_info
.xHotspot
);
946 ok(icon_info
.yHotspot
== ICON_HEIGHT
/2, "yHotspot is %u.\n", icon_info
.yHotspot
);
947 ok(icon_info
.hbmColor
!= NULL
, "No hbmColor!\n");
948 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
952 SetLastError(0xdeadbeef);
953 ret
= DestroyCursor(handle
);
954 ok(ret
, "DestroyCursor() failed.\n");
955 error
= GetLastError();
956 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
958 HeapFree(GetProcessHeap(), 0, hotspot
);
961 static HICON
create_test_icon(HDC hdc
, int width
, int height
, int bpp
,
962 BOOL maskvalue
, UINT32
*color
, int colorSize
)
965 BITMAPINFO bitmapInfo
;
966 UINT32
*buffer
= NULL
;
967 UINT32 mask
= maskvalue
? 0xFFFFFFFF : 0x00000000;
969 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
970 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
971 bitmapInfo
.bmiHeader
.biWidth
= width
;
972 bitmapInfo
.bmiHeader
.biHeight
= height
;
973 bitmapInfo
.bmiHeader
.biPlanes
= 1;
974 bitmapInfo
.bmiHeader
.biBitCount
= bpp
;
975 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
976 bitmapInfo
.bmiHeader
.biSizeImage
= colorSize
;
978 iconInfo
.fIcon
= TRUE
;
979 iconInfo
.xHotspot
= 0;
980 iconInfo
.yHotspot
= 0;
982 iconInfo
.hbmMask
= CreateBitmap( width
, height
, 1, 1, &mask
);
983 if(!iconInfo
.hbmMask
) return NULL
;
985 iconInfo
.hbmColor
= CreateDIBSection(hdc
, &bitmapInfo
, DIB_RGB_COLORS
, (void**)&buffer
, NULL
, 0);
986 if(!iconInfo
.hbmColor
|| !buffer
)
988 DeleteObject(iconInfo
.hbmMask
);
992 memcpy(buffer
, color
, colorSize
);
994 return CreateIconIndirect(&iconInfo
);
997 static BOOL
color_match(COLORREF a
, COLORREF b
)
999 /* 5-bit accuracy is a sufficient test. This will match, so long as
1000 * colors are never truncated to less that 3x5-bit accuracy i.e.
1002 return (a
& 0x00F8F8F8) == (b
& 0x00F8F8F8);
1005 static void check_alpha_draw(HDC hdc
, BOOL drawiconex
, BOOL alpha
, int bpp
, int line
)
1010 COLORREF modern_expected
, legacy_expected
, result
;
1013 color
[0] = 0x00A0B0C0;
1014 color
[1] = alpha
? 0xFF000000 : 0x00000000;
1015 modern_expected
= alpha
? 0x00FFFFFF : 0x00C0B0A0;
1016 legacy_expected
= 0x00C0B0A0;
1018 hicon
= create_test_icon(hdc
, 2, 1, bpp
, 0, color
, sizeof(color
));
1021 SetPixelV(hdc
, 0, 0, 0x00FFFFFF);
1024 DrawIconEx(hdc
, 0, 0, hicon
, 2, 1, 0, NULL
, DI_NORMAL
);
1026 DrawIcon(hdc
, 0, 0, hicon
);
1028 result
= GetPixel(hdc
, 0, 0);
1029 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1030 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1031 "%s. Expected a close match to %06X (modern) or %06X (legacy) with %s. "
1032 "Got %06X from line %d\n",
1033 alpha
? "Alpha blending" : "Not alpha blending", modern_expected
, legacy_expected
,
1034 drawiconex
? "DrawIconEx" : "DrawIcon", result
, line
);
1037 static void check_DrawIcon(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, COLORREF background
,
1038 COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1041 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1043 SetPixelV(hdc
, 0, 0, background
);
1044 SetPixelV(hdc
, GetSystemMetrics(SM_CXICON
)-1, GetSystemMetrics(SM_CYICON
)-1, background
);
1045 SetPixelV(hdc
, GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
), background
);
1046 DrawIcon(hdc
, 0, 0, hicon
);
1047 result
= GetPixel(hdc
, 0, 0);
1049 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1050 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1051 "Overlaying Mask %d on Color %06X with DrawIcon. "
1052 "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1053 maskvalue
, color
, modern_expected
, legacy_expected
, result
, line
);
1055 result
= GetPixel(hdc
, GetSystemMetrics(SM_CXICON
)-1, GetSystemMetrics(SM_CYICON
)-1);
1057 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1058 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1059 "Overlaying Mask %d on Color %06X with DrawIcon. "
1060 "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1061 maskvalue
, color
, modern_expected
, legacy_expected
, result
, line
);
1063 result
= GetPixel(hdc
, GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
));
1065 ok (color_match(result
, background
),
1066 "Overlaying Mask %d on Color %06X with DrawIcon. "
1067 "Expected unchanged background color %06X. Got %06X from line %d\n",
1068 maskvalue
, color
, background
, result
, line
);
1071 static void test_DrawIcon(void)
1073 BITMAPINFO bitmapInfo
;
1075 HBITMAP bmpDst
= NULL
;
1076 HBITMAP bmpOld
= NULL
;
1079 hdcDst
= CreateCompatibleDC(0);
1080 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1084 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1086 skip("Windows will distort DrawIcon colors at 8-bpp and less due to palletizing.\n");
1090 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1091 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1092 bitmapInfo
.bmiHeader
.biWidth
= GetSystemMetrics(SM_CXICON
)+1;
1093 bitmapInfo
.bmiHeader
.biHeight
= GetSystemMetrics(SM_CYICON
)+1;
1094 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1095 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1096 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1097 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1099 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, (void**)&bits
, NULL
, 0);
1100 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1101 if (!bmpDst
|| !bits
)
1103 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1105 /* Mask is only heeded if alpha channel is always zero */
1106 check_DrawIcon(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1107 check_DrawIcon(hdcDst
, TRUE
, 0x00A0B0C0, 32, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__
);
1109 /* Test alpha blending */
1110 /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
1111 check_DrawIcon(hdcDst
, FALSE
, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1112 check_DrawIcon(hdcDst
, TRUE
, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__
);
1114 check_DrawIcon(hdcDst
, FALSE
, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1115 check_DrawIcon(hdcDst
, TRUE
, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1116 check_DrawIcon(hdcDst
, FALSE
, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__
);
1117 check_DrawIcon(hdcDst
, TRUE
, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__
);
1119 check_DrawIcon(hdcDst
, FALSE
, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1120 check_DrawIcon(hdcDst
, TRUE
, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1122 /* Test detecting of alpha channel */
1123 /* If a single pixel's alpha channel is non-zero, the icon
1124 will be alpha blended, otherwise it will be draw with
1126 check_alpha_draw(hdcDst
, FALSE
, FALSE
, 32, __LINE__
);
1127 check_alpha_draw(hdcDst
, FALSE
, TRUE
, 32, __LINE__
);
1131 SelectObject(hdcDst
, bmpOld
);
1133 DeleteObject(bmpDst
);
1138 static void check_DrawIconEx(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, UINT flags
, COLORREF background
,
1139 COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1142 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1144 SetPixelV(hdc
, 0, 0, background
);
1145 DrawIconEx(hdc
, 0, 0, hicon
, 1, 1, 0, NULL
, flags
);
1146 result
= GetPixel(hdc
, 0, 0);
1148 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1149 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1150 "Overlaying Mask %d on Color %06X with DrawIconEx flags %08X. "
1151 "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
1152 maskvalue
, color
, flags
, modern_expected
, legacy_expected
, result
, line
);
1155 static void test_DrawIconEx(void)
1157 BITMAPINFO bitmapInfo
;
1159 HBITMAP bmpDst
= NULL
;
1160 HBITMAP bmpOld
= NULL
;
1163 hdcDst
= CreateCompatibleDC(0);
1164 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1168 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1170 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n");
1174 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1175 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1176 bitmapInfo
.bmiHeader
.biWidth
= 1;
1177 bitmapInfo
.bmiHeader
.biHeight
= 1;
1178 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1179 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1180 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1181 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1182 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, (void**)&bits
, NULL
, 0);
1183 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1184 if (!bmpDst
|| !bits
)
1186 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1188 /* Test null, image only, and mask only drawing */
1189 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__
);
1190 check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__
);
1192 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_MASK
, 0x00FFFFFF, 0x00000000, 0x00000000, __LINE__
);
1193 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_MASK
, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, __LINE__
);
1197 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, DI_IMAGE
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1198 check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, DI_IMAGE
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1201 /* Test normal drawing */
1202 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1203 todo_wine
check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__
);
1204 check_DrawIconEx(hdcDst
, FALSE
, 0xFFA0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1206 /* Test alpha blending */
1207 /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
1208 check_DrawIconEx(hdcDst
, TRUE
, 0xFFA0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__
);
1210 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1211 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1212 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__
);
1213 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__
);
1215 check_DrawIconEx(hdcDst
, FALSE
, 0x01FFFFFF, 32, DI_NORMAL
, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1216 check_DrawIconEx(hdcDst
, TRUE
, 0x01FFFFFF, 32, DI_NORMAL
, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1218 /* Test detecting of alpha channel */
1219 /* If a single pixel's alpha channel is non-zero, the icon
1220 will be alpha blended, otherwise it will be draw with
1222 check_alpha_draw(hdcDst
, TRUE
, FALSE
, 32, __LINE__
);
1223 check_alpha_draw(hdcDst
, TRUE
, TRUE
, 32, __LINE__
);
1227 SelectObject(hdcDst
, bmpOld
);
1229 DeleteObject(bmpDst
);
1234 static void check_DrawState_Size(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, HBRUSH hbr
, UINT flags
, int line
)
1236 COLORREF result
, background
;
1238 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1239 background
= 0x00FFFFFF;
1240 /* Set color of the 2 pixels that will be checked afterwards */
1241 SetPixelV(hdc
, 0, 0, background
);
1242 SetPixelV(hdc
, 2, 2, background
);
1244 /* Let DrawState calculate the size of the icon (it's 1x1) */
1245 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 0, 0, (DST_ICON
| flags
));
1247 result
= GetPixel(hdc
, 0, 0);
1248 passed
[0] = color_match(result
, background
);
1249 result
= GetPixel(hdc
, 2, 2);
1250 passed
[0] = passed
[0] & color_match(result
, background
);
1252 /* Check if manually specifying the icon size DOESN'T work */
1254 /* IMPORTANT: For Icons, DrawState wants the size of the source image, not the
1255 * size in which it should be ultimately drawn. Therefore giving
1256 * width/height 2x2 if the icon is only 1x1 pixels in size should
1257 * result in drawing it with size 1x1. The size parameters must be
1258 * ignored if a Icon has to be drawn! */
1259 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 2, 2, (DST_ICON
| flags
));
1261 result
= GetPixel(hdc
, 0, 0);
1262 passed
[1] = color_match(result
, background
);
1263 result
= GetPixel(hdc
, 2, 2);
1264 passed
[1] = passed
[0] & color_match(result
, background
);
1266 if(!passed
[0]&&!passed
[1])
1268 "DrawState failed to draw a 1x1 Icon in the correct size, independent of the "
1269 "width and height settings passed to it, for Icon with: Overlaying Mask %d on "
1270 "Color %06X with flags %08X. Line %d\n",
1271 maskvalue
, color
, (DST_ICON
| flags
), line
);
1274 "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
1275 "parameters passed to it are bigger than the real Icon size, for Icon with: Overlaying "
1276 "Mask %d on Color %06X with flags %08X. Line %d\n",
1277 maskvalue
, color
, (DST_ICON
| flags
), line
);
1280 "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
1281 "parameters passed to it are 0, for Icon with: Overlaying Mask %d on "
1282 "Color %06X with flags %08X. Line %d\n",
1283 maskvalue
, color
, (DST_ICON
| flags
), line
);
1286 static void check_DrawState_Color(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, HBRUSH hbr
, UINT flags
,
1287 COLORREF background
, COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1290 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1292 /* Set color of the pixel that will be checked afterwards */
1293 SetPixelV(hdc
, 1, 1, background
);
1295 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 0, 0, ( DST_ICON
| flags
));
1297 /* Check the color of the pixel is correct */
1298 result
= GetPixel(hdc
, 1, 1);
1300 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1301 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1302 "DrawState drawing Icon with Overlaying Mask %d on Color %06X with flags %08X. "
1303 "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
1304 maskvalue
, color
, (DST_ICON
| flags
), modern_expected
, legacy_expected
, result
, line
);
1307 static void test_DrawState(void)
1309 BITMAPINFO bitmapInfo
;
1311 HBITMAP bmpDst
= NULL
;
1312 HBITMAP bmpOld
= NULL
;
1315 hdcDst
= CreateCompatibleDC(0);
1316 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1320 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1322 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n");
1326 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1327 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1328 bitmapInfo
.bmiHeader
.biWidth
= 3;
1329 bitmapInfo
.bmiHeader
.biHeight
= 3;
1330 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1331 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1332 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1333 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1334 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, (void**)&bits
, NULL
, 0);
1335 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1336 if (!bmpDst
|| !bits
)
1338 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1340 /* potential flags to test with DrawState are: */
1341 /* DSS_DISABLED embosses the icon */
1342 /* DSS_MONO draw Icon using a brush as parameter 5 */
1343 /* DSS_NORMAL draw Icon without any modifications */
1344 /* DSS_UNION draw the Icon dithered */
1346 check_DrawState_Size(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, DSS_NORMAL
, __LINE__
);
1347 check_DrawState_Color(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, DSS_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1351 SelectObject(hdcDst
, bmpOld
);
1353 DeleteObject(bmpDst
);
1358 static DWORD parent_id
;
1360 static DWORD CALLBACK
set_cursor_thread( void *arg
)
1364 PeekMessage( 0, 0, 0, 0, PM_NOREMOVE
); /* create a msg queue */
1367 BOOL ret
= AttachThreadInput( GetCurrentThreadId(), parent_id
, TRUE
);
1368 ok( ret
, "AttachThreadInput failed\n" );
1370 if (arg
) ret
= SetCursor( (HCURSOR
)arg
);
1371 else ret
= GetCursor();
1372 return (DWORD_PTR
)ret
;
1375 static void test_SetCursor(void)
1377 static const BYTE bmp_bits
[4096];
1378 ICONINFO cursorInfo
;
1379 HCURSOR cursor
, old_cursor
, global_cursor
= 0;
1380 DWORD error
, id
, result
;
1388 memset( &info
, 0, sizeof(info
) );
1389 info
.cbSize
= sizeof(info
);
1390 if (!pGetCursorInfo( &info
))
1392 win_skip( "GetCursorInfo not working\n" );
1393 pGetCursorInfo
= NULL
;
1395 else global_cursor
= info
.hCursor
;
1397 cursor
= GetCursor();
1398 thread
= CreateThread( NULL
, 0, set_cursor_thread
, 0, 0, &id
);
1399 WaitForSingleObject( thread
, 1000 );
1400 GetExitCodeThread( thread
, &result
);
1401 ok( result
== (DWORD_PTR
)cursor
, "wrong thread cursor %x/%p\n", result
, cursor
);
1404 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1407 cursorInfo
.fIcon
= FALSE
;
1408 cursorInfo
.xHotspot
= 0;
1409 cursorInfo
.yHotspot
= 0;
1410 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
1411 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
1413 cursor
= CreateIconIndirect(&cursorInfo
);
1414 ok(cursor
!= NULL
, "CreateIconIndirect returned %p\n", cursor
);
1415 old_cursor
= SetCursor( cursor
);
1419 info
.cbSize
= sizeof(info
);
1420 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1421 /* global cursor doesn't change since we don't have a window */
1422 ok( info
.hCursor
== global_cursor
|| broken(info
.hCursor
!= cursor
), /* win9x */
1423 "wrong info cursor %p/%p\n", info
.hCursor
, global_cursor
);
1425 thread
= CreateThread( NULL
, 0, set_cursor_thread
, 0, 0, &id
);
1426 WaitForSingleObject( thread
, 1000 );
1427 GetExitCodeThread( thread
, &result
);
1428 ok( result
== (DWORD_PTR
)old_cursor
, "wrong thread cursor %x/%p\n", result
, old_cursor
);
1431 ok( GetCursor() == 0, "wrong cursor %p\n", GetCursor() );
1432 thread
= CreateThread( NULL
, 0, set_cursor_thread
, 0, 0, &id
);
1433 WaitForSingleObject( thread
, 1000 );
1434 GetExitCodeThread( thread
, &result
);
1435 ok( result
== (DWORD_PTR
)old_cursor
, "wrong thread cursor %x/%p\n", result
, old_cursor
);
1437 thread
= CreateThread( NULL
, 0, set_cursor_thread
, cursor
, 0, &id
);
1438 WaitForSingleObject( thread
, 1000 );
1439 GetExitCodeThread( thread
, &result
);
1440 ok( result
== (DWORD_PTR
)old_cursor
, "wrong thread cursor %x/%p\n", result
, old_cursor
);
1441 ok( GetCursor() == 0, "wrong cursor %p/0\n", GetCursor() );
1443 parent_id
= GetCurrentThreadId();
1444 thread
= CreateThread( NULL
, 0, set_cursor_thread
, cursor
, 0, &id
);
1445 WaitForSingleObject( thread
, 1000 );
1446 GetExitCodeThread( thread
, &result
);
1447 ok( result
== (DWORD_PTR
)old_cursor
, "wrong thread cursor %x/%p\n", result
, old_cursor
);
1448 ok( GetCursor() == cursor
, "wrong cursor %p/0\n", cursor
);
1452 info
.cbSize
= sizeof(info
);
1453 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1454 ok( info
.hCursor
== global_cursor
|| broken(info
.hCursor
!= cursor
), /* win9x */
1455 "wrong info cursor %p/%p\n", info
.hCursor
, global_cursor
);
1457 SetCursor( old_cursor
);
1458 DestroyCursor( cursor
);
1460 SetLastError( 0xdeadbeef );
1461 cursor
= SetCursor( (HCURSOR
)0xbadbad );
1462 error
= GetLastError();
1463 ok( cursor
== 0, "wrong cursor %p/0\n", cursor
);
1464 ok( error
== ERROR_INVALID_CURSOR_HANDLE
|| broken( error
== 0xdeadbeef ), /* win9x */
1465 "wrong error %u\n", error
);
1469 info
.cbSize
= sizeof(info
);
1470 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1471 ok( info
.hCursor
== global_cursor
|| broken(info
.hCursor
!= cursor
), /* win9x */
1472 "wrong info cursor %p/%p\n", info
.hCursor
, global_cursor
);
1476 static HANDLE event_start
, event_next
;
1478 static DWORD CALLBACK
show_cursor_thread( void *arg
)
1480 DWORD count
= (DWORD_PTR
)arg
;
1483 PeekMessage( 0, 0, 0, 0, PM_NOREMOVE
); /* create a msg queue */
1486 BOOL ret
= AttachThreadInput( GetCurrentThreadId(), parent_id
, TRUE
);
1487 ok( ret
, "AttachThreadInput failed\n" );
1489 if (!count
) ret
= ShowCursor( FALSE
);
1490 else while (count
--) ret
= ShowCursor( TRUE
);
1491 SetEvent( event_start
);
1492 WaitForSingleObject( event_next
, 2000 );
1496 static void test_ShowCursor(void)
1505 memset( &info
, 0, sizeof(info
) );
1506 info
.cbSize
= sizeof(info
);
1507 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1508 ok( info
.flags
& CURSOR_SHOWING
, "cursor not shown in info\n" );
1511 event_start
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1512 event_next
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1514 count
= ShowCursor( TRUE
);
1515 ok( count
== 1, "wrong count %d\n", count
);
1516 count
= ShowCursor( TRUE
);
1517 ok( count
== 2, "wrong count %d\n", count
);
1518 count
= ShowCursor( FALSE
);
1519 ok( count
== 1, "wrong count %d\n", count
);
1520 count
= ShowCursor( FALSE
);
1521 ok( count
== 0, "wrong count %d\n", count
);
1522 count
= ShowCursor( FALSE
);
1523 ok( count
== -1, "wrong count %d\n", count
);
1524 count
= ShowCursor( FALSE
);
1525 ok( count
== -2, "wrong count %d\n", count
);
1529 info
.cbSize
= sizeof(info
);
1530 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1531 /* global show count is not affected since we don't have a window */
1532 ok( info
.flags
& CURSOR_SHOWING
, "cursor not shown in info\n" );
1536 thread
= CreateThread( NULL
, 0, show_cursor_thread
, NULL
, 0, &id
);
1537 WaitForSingleObject( event_start
, 1000 );
1538 count
= ShowCursor( FALSE
);
1539 ok( count
== -3, "wrong count %d\n", count
);
1540 SetEvent( event_next
);
1541 WaitForSingleObject( thread
, 1000 );
1542 GetExitCodeThread( thread
, &result
);
1543 ok( result
== -1, "wrong thread count %d\n", result
);
1544 count
= ShowCursor( FALSE
);
1545 ok( count
== -4, "wrong count %d\n", count
);
1547 thread
= CreateThread( NULL
, 0, show_cursor_thread
, (void *)1, 0, &id
);
1548 WaitForSingleObject( event_start
, 1000 );
1549 count
= ShowCursor( TRUE
);
1550 ok( count
== -3, "wrong count %d\n", count
);
1551 SetEvent( event_next
);
1552 WaitForSingleObject( thread
, 1000 );
1553 GetExitCodeThread( thread
, &result
);
1554 ok( result
== 1, "wrong thread count %d\n", result
);
1555 count
= ShowCursor( TRUE
);
1556 ok( count
== -2, "wrong count %d\n", count
);
1558 parent_id
= GetCurrentThreadId();
1559 thread
= CreateThread( NULL
, 0, show_cursor_thread
, NULL
, 0, &id
);
1560 WaitForSingleObject( event_start
, 1000 );
1561 count
= ShowCursor( TRUE
);
1562 ok( count
== -2, "wrong count %d\n", count
);
1563 SetEvent( event_next
);
1564 WaitForSingleObject( thread
, 1000 );
1565 GetExitCodeThread( thread
, &result
);
1566 ok( result
== -3, "wrong thread count %d\n", result
);
1567 count
= ShowCursor( FALSE
);
1568 ok( count
== -2, "wrong count %d\n", count
);
1570 thread
= CreateThread( NULL
, 0, show_cursor_thread
, (void *)3, 0, &id
);
1571 WaitForSingleObject( event_start
, 1000 );
1572 count
= ShowCursor( TRUE
);
1573 ok( count
== 2, "wrong count %d\n", count
);
1574 SetEvent( event_next
);
1575 WaitForSingleObject( thread
, 1000 );
1576 GetExitCodeThread( thread
, &result
);
1577 ok( result
== 1, "wrong thread count %d\n", result
);
1578 count
= ShowCursor( FALSE
);
1579 ok( count
== -2, "wrong count %d\n", count
);
1583 info
.cbSize
= sizeof(info
);
1584 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1585 ok( info
.flags
& CURSOR_SHOWING
, "cursor not shown in info\n" );
1588 count
= ShowCursor( TRUE
);
1589 ok( count
== -1, "wrong count %d\n", count
);
1590 count
= ShowCursor( TRUE
);
1591 ok( count
== 0, "wrong count %d\n", count
);
1595 info
.cbSize
= sizeof(info
);
1596 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1597 ok( info
.flags
& CURSOR_SHOWING
, "cursor not shown in info\n" );
1602 static void test_DestroyCursor(void)
1604 static const BYTE bmp_bits
[4096];
1605 ICONINFO cursorInfo
;
1606 HCURSOR cursor
, cursor2
;
1613 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1616 cursorInfo
.fIcon
= FALSE
;
1617 cursorInfo
.xHotspot
= 0;
1618 cursorInfo
.yHotspot
= 0;
1619 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
1620 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
1622 cursor
= CreateIconIndirect(&cursorInfo
);
1623 ok(cursor
!= NULL
, "CreateIconIndirect returned %p\n", cursor
);
1629 SetLastError(0xdeadbeef);
1630 ret
= DestroyCursor(cursor
);
1631 ok(!ret
|| broken(ret
) /* succeeds on win9x */, "DestroyCursor on the active cursor succeeded\n");
1632 error
= GetLastError();
1633 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
1636 cursor2
= GetCursor();
1637 ok(cursor2
== cursor
, "Active was set to %p when trying to destroy it\n", cursor2
);
1640 /* Trying to destroy the cursor properly fails now with
1641 * ERROR_INVALID_CURSOR_HANDLE. This happens because we called
1642 * DestroyCursor() 2+ times after calling SetCursor(). The calls to
1643 * GetCursor() and SetCursor(NULL) in between make no difference. */
1644 ret
= DestroyCursor(cursor
);
1646 ok(!ret
, "DestroyCursor succeeded.\n");
1647 error
= GetLastError();
1648 ok(error
== ERROR_INVALID_CURSOR_HANDLE
|| error
== 0xdeadbeef, /* vista */
1649 "Last error: 0x%08x\n", error
);
1653 DeleteObject(cursorInfo
.hbmMask
);
1654 DeleteObject(cursorInfo
.hbmColor
);
1656 /* Try testing DestroyCursor() now using LoadCursor() cursors. */
1657 cursor
= LoadCursor(NULL
, IDC_ARROW
);
1659 SetLastError(0xdeadbeef);
1660 ret
= DestroyCursor(cursor
);
1661 ok(ret
|| broken(!ret
) /* fails on win9x */, "DestroyCursor on the active cursor failed.\n");
1662 error
= GetLastError();
1663 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
1665 /* Try setting the cursor to a destroyed OEM cursor. */
1666 SetLastError(0xdeadbeef);
1668 error
= GetLastError();
1670 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
1673 /* Check if LoadCursor() returns the same handle with the same icon. */
1674 cursor2
= LoadCursor(NULL
, IDC_ARROW
);
1675 ok(cursor2
== cursor
, "cursor == %p, cursor2 == %p\n", cursor
, cursor2
);
1677 /* Check if LoadCursor() returns the same handle with a different icon. */
1678 cursor2
= LoadCursor(NULL
, IDC_WAIT
);
1679 ok(cursor2
!= cursor
, "cursor == %p, cursor2 == %p\n", cursor
, cursor2
);
1682 START_TEST(cursoricon
)
1684 pGetCursorInfo
= (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetCursorInfo" );
1685 test_argc
= winetest_get_mainargs(&test_argv
);
1689 /* Child process. */
1690 sscanf (test_argv
[2], "%x", (unsigned int *) &parent
);
1692 ok(parent
!= NULL
, "Parent not found.\n");
1700 test_CopyImage_Bitmap(1);
1701 test_CopyImage_Bitmap(4);
1702 test_CopyImage_Bitmap(8);
1703 test_CopyImage_Bitmap(16);
1704 test_CopyImage_Bitmap(24);
1705 test_CopyImage_Bitmap(32);
1706 test_initial_cursor();
1709 test_CreateIconFromResource();
1715 test_DestroyCursor();
1717 test_child_process();
1718 finish_child_process();