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 BOOL
color_match(COLORREF a
, COLORREF b
)
230 /* 5-bit accuracy is a sufficient test. This will match as long as
231 * colors are never truncated to less that 3x5-bit accuracy i.e.
233 return (a
& 0x00F8F8F8) == (b
& 0x00F8F8F8);
236 static void test_CopyImage_Check(HBITMAP bitmap
, UINT flags
, INT copyWidth
, INT copyHeight
,
237 INT expectedWidth
, INT expectedHeight
, WORD expectedDepth
, BOOL dibExpected
)
245 copy
= CopyImage(bitmap
, IMAGE_BITMAP
, copyWidth
, copyHeight
, flags
);
246 ok(copy
!= NULL
, "CopyImage() failed\n");
249 GetObject(bitmap
, sizeof(origBitmap
), &origBitmap
);
250 GetObject(copy
, sizeof(copyBitmap
), ©Bitmap
);
251 orig_is_dib
= (origBitmap
.bmBits
!= NULL
);
252 copy_is_dib
= (copyBitmap
.bmBits
!= NULL
);
254 if (copy_is_dib
&& dibExpected
255 && copyBitmap
.bmBitsPixel
== 24
256 && (expectedDepth
== 16 || expectedDepth
== 32))
258 /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
259 if (GetVersion() & 0x80000000)
265 if (copy_is_dib
&& !dibExpected
&& !(flags
& LR_CREATEDIBSECTION
))
267 /* It's not forbidden to create a DIB section if the flag
268 LR_CREATEDIBSECTION is absent.
269 Windows 9x does this if the bitmap has a depth that doesn't
270 match the screen depth, Windows NT doesn't */
272 expectedDepth
= origBitmap
.bmBitsPixel
;
275 ok((!(dibExpected
^ copy_is_dib
)
276 && (copyBitmap
.bmWidth
== expectedWidth
)
277 && (copyBitmap
.bmHeight
== expectedHeight
)
278 && (copyBitmap
.bmBitsPixel
== expectedDepth
)),
279 "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
280 orig_is_dib
? "DIB" : "DDB", origBitmap
.bmWidth
, origBitmap
.bmHeight
, origBitmap
.bmBitsPixel
,
281 copyWidth
, copyHeight
, flags
,
282 dibExpected
? "DIB" : "DDB", expectedWidth
, expectedHeight
, expectedDepth
,
283 copy_is_dib
? "DIB" : "DDB", copyBitmap
.bmWidth
, copyBitmap
.bmHeight
, copyBitmap
.bmBitsPixel
);
289 static void test_CopyImage_Bitmap(int depth
)
298 /* Create a device-independent bitmap (DIB) */
299 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
300 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
301 info
->bmiHeader
.biWidth
= 2;
302 info
->bmiHeader
.biHeight
= 2;
303 info
->bmiHeader
.biPlanes
= 1;
304 info
->bmiHeader
.biBitCount
= depth
;
305 info
->bmiHeader
.biCompression
= BI_RGB
;
307 for (i
=0; i
< 256; i
++)
309 info
->bmiColors
[i
].rgbRed
= i
;
310 info
->bmiColors
[i
].rgbGreen
= i
;
311 info
->bmiColors
[i
].rgbBlue
= 255 - i
;
312 info
->bmiColors
[i
].rgbReserved
= 0;
315 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
317 /* Create a device-dependent bitmap (DDB) */
318 screenDC
= GetDC(NULL
);
319 screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
320 if (depth
== 1 || depth
== screen_depth
)
322 ddb
= CreateBitmap(2, 2, 1, depth
, NULL
);
328 ReleaseDC(NULL
, screenDC
);
332 test_CopyImage_Check(ddb
, 0, 0, 0, 2, 2, depth
== 1 ? 1 : screen_depth
, FALSE
);
333 test_CopyImage_Check(ddb
, 0, 0, 5, 2, 5, depth
== 1 ? 1 : screen_depth
, FALSE
);
334 test_CopyImage_Check(ddb
, 0, 5, 0, 5, 2, depth
== 1 ? 1 : screen_depth
, FALSE
);
335 test_CopyImage_Check(ddb
, 0, 5, 5, 5, 5, depth
== 1 ? 1 : screen_depth
, FALSE
);
337 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 0, 0, 2, 2, 1, FALSE
);
338 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 5, 0, 5, 2, 1, FALSE
);
339 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 0, 5, 2, 5, 1, FALSE
);
340 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 5, 5, 5, 5, 1, FALSE
);
342 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
343 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
344 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
345 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
347 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
348 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
349 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
350 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
351 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
358 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, screen_depth
, FALSE
);
359 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, screen_depth
, FALSE
);
360 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, screen_depth
, FALSE
);
361 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, screen_depth
, FALSE
);
364 test_CopyImage_Check(dib
, LR_MONOCHROME
, 0, 0, 2, 2, 1, FALSE
);
365 test_CopyImage_Check(dib
, LR_MONOCHROME
, 5, 0, 5, 2, 1, FALSE
);
366 test_CopyImage_Check(dib
, LR_MONOCHROME
, 0, 5, 2, 5, 1, FALSE
);
367 test_CopyImage_Check(dib
, LR_MONOCHROME
, 5, 5, 5, 5, 1, FALSE
);
369 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
370 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
371 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
372 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
374 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
375 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
376 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
377 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
378 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
384 /* Special case: A monochrome DIB is converted to a monochrome DDB if
385 the colors in the color table are black and white.
387 Skip this test on Windows 95, it always creates a monochrome DDB
390 if (!(GetVersion() & 0x80000000))
392 info
->bmiHeader
.biBitCount
= 1;
393 info
->bmiColors
[0].rgbRed
= 0xFF;
394 info
->bmiColors
[0].rgbGreen
= 0;
395 info
->bmiColors
[0].rgbBlue
= 0;
396 info
->bmiColors
[1].rgbRed
= 0;
397 info
->bmiColors
[1].rgbGreen
= 0xFF;
398 info
->bmiColors
[1].rgbBlue
= 0;
400 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
401 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, screen_depth
, FALSE
);
402 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, screen_depth
, FALSE
);
403 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, screen_depth
, FALSE
);
404 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, screen_depth
, FALSE
);
407 info
->bmiHeader
.biBitCount
= 1;
408 info
->bmiColors
[0].rgbRed
= 0;
409 info
->bmiColors
[0].rgbGreen
= 0;
410 info
->bmiColors
[0].rgbBlue
= 0;
411 info
->bmiColors
[1].rgbRed
= 0xFF;
412 info
->bmiColors
[1].rgbGreen
= 0xFF;
413 info
->bmiColors
[1].rgbBlue
= 0xFF;
415 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
416 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, 1, FALSE
);
417 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, 1, FALSE
);
418 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, 1, FALSE
);
419 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, 1, FALSE
);
422 info
->bmiHeader
.biBitCount
= 1;
423 info
->bmiColors
[0].rgbRed
= 0xFF;
424 info
->bmiColors
[0].rgbGreen
= 0xFF;
425 info
->bmiColors
[0].rgbBlue
= 0xFF;
426 info
->bmiColors
[1].rgbRed
= 0;
427 info
->bmiColors
[1].rgbGreen
= 0;
428 info
->bmiColors
[1].rgbBlue
= 0;
430 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
431 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, 1, FALSE
);
432 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, 1, FALSE
);
433 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, 1, FALSE
);
434 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, 1, FALSE
);
439 HeapFree(GetProcessHeap(), 0, info
);
442 static void test_initial_cursor(void)
444 HCURSOR cursor
, cursor2
;
447 cursor
= GetCursor();
449 /* Check what handle GetCursor() returns if a cursor is not set yet. */
450 SetLastError(0xdeadbeef);
451 cursor2
= LoadCursor(NULL
, IDC_WAIT
);
453 ok(cursor
== cursor2
, "cursor (%p) is not IDC_WAIT (%p).\n", cursor
, cursor2
);
455 error
= GetLastError();
456 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
459 static void test_icon_info_dbg(HICON hIcon
, UINT exp_cx
, UINT exp_cy
, UINT exp_bpp
, int line
)
463 BITMAP bmMask
, bmColor
;
465 ret
= GetIconInfo(hIcon
, &info
);
466 ok_(__FILE__
, line
)(ret
, "GetIconInfo failed\n");
468 /* CreateIcon under XP causes info.fIcon to be 0 */
469 ok_(__FILE__
, line
)(info
.xHotspot
== exp_cx
/2, "info.xHotspot = %u\n", info
.xHotspot
);
470 ok_(__FILE__
, line
)(info
.yHotspot
== exp_cy
/2, "info.yHotspot = %u\n", info
.yHotspot
);
471 ok_(__FILE__
, line
)(info
.hbmMask
!= 0, "info.hbmMask is NULL\n");
473 ret
= GetObject(info
.hbmMask
, sizeof(bmMask
), &bmMask
);
474 ok_(__FILE__
, line
)(ret
== sizeof(bmMask
), "GetObject(info.hbmMask) failed, ret %u\n", ret
);
477 ok_(__FILE__
, line
)(info
.hbmColor
== 0, "info.hbmColor should be NULL\n");
485 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
488 ret
= GetObject(info
.hbmColor
, sizeof(bmColor
), &bmColor
);
489 ok_(__FILE__
, line
)(ret
== sizeof(bmColor
), "GetObject(info.hbmColor) failed, ret %u\n", ret
);
491 ok_(__FILE__
, line
)(bmColor
.bmBitsPixel
== display_bpp
/* XP */ ||
492 bmColor
.bmBitsPixel
== exp_bpp
/* Win98 */,
493 "bmColor.bmBitsPixel = %d\n", bmColor
.bmBitsPixel
);
494 ok_(__FILE__
, line
)(bmColor
.bmWidth
== exp_cx
, "bmColor.bmWidth = %d\n", bmColor
.bmWidth
);
495 ok_(__FILE__
, line
)(bmColor
.bmHeight
== exp_cy
, "bmColor.bmHeight = %d\n", bmColor
.bmHeight
);
497 ok_(__FILE__
, line
)(bmMask
.bmBitsPixel
== 1, "bmMask.bmBitsPixel = %d\n", bmMask
.bmBitsPixel
);
498 ok_(__FILE__
, line
)(bmMask
.bmWidth
== exp_cx
, "bmMask.bmWidth = %d\n", bmMask
.bmWidth
);
499 ok_(__FILE__
, line
)(bmMask
.bmHeight
== exp_cy
, "bmMask.bmHeight = %d\n", bmMask
.bmHeight
);
503 ok_(__FILE__
, line
)(bmMask
.bmBitsPixel
== 1, "bmMask.bmBitsPixel = %d\n", bmMask
.bmBitsPixel
);
504 ok_(__FILE__
, line
)(bmMask
.bmWidth
== exp_cx
, "bmMask.bmWidth = %d\n", bmMask
.bmWidth
);
505 ok_(__FILE__
, line
)(bmMask
.bmHeight
== exp_cy
* 2, "bmMask.bmHeight = %d\n", bmMask
.bmHeight
);
509 #define test_icon_info(a,b,c,d) test_icon_info_dbg((a),(b),(c),(d),__LINE__)
511 static void test_CreateIcon(void)
513 static const BYTE bmp_bits
[1024];
515 HBITMAP hbmMask
, hbmColor
;
523 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
525 /* these crash under XP
526 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
527 hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits);
530 hIcon
= CreateIcon(0, 16, 16, 1, 1, bmp_bits
, bmp_bits
);
531 ok(hIcon
!= 0, "CreateIcon failed\n");
532 test_icon_info(hIcon
, 16, 16, 1);
535 hIcon
= CreateIcon(0, 16, 16, 1, display_bpp
, bmp_bits
, bmp_bits
);
536 ok(hIcon
!= 0, "CreateIcon failed\n");
537 test_icon_info(hIcon
, 16, 16, display_bpp
);
540 hbmMask
= CreateBitmap(16, 16, 1, 1, bmp_bits
);
541 ok(hbmMask
!= 0, "CreateBitmap failed\n");
542 hbmColor
= CreateBitmap(16, 16, 1, display_bpp
, bmp_bits
);
543 ok(hbmColor
!= 0, "CreateBitmap failed\n");
550 SetLastError(0xdeadbeaf);
551 hIcon
= CreateIconIndirect(&info
);
552 ok(!hIcon
, "CreateIconIndirect should fail\n");
553 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
559 info
.hbmColor
= hbmColor
;
560 SetLastError(0xdeadbeaf);
561 hIcon
= CreateIconIndirect(&info
);
562 ok(!hIcon
, "CreateIconIndirect should fail\n");
563 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
568 info
.hbmMask
= hbmMask
;
569 info
.hbmColor
= hbmColor
;
570 hIcon
= CreateIconIndirect(&info
);
571 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
572 test_icon_info(hIcon
, 16, 16, display_bpp
);
575 DeleteObject(hbmMask
);
576 DeleteObject(hbmColor
);
578 hbmMask
= CreateBitmap(16, 32, 1, 1, bmp_bits
);
579 ok(hbmMask
!= 0, "CreateBitmap failed\n");
584 info
.hbmMask
= hbmMask
;
586 SetLastError(0xdeadbeaf);
587 hIcon
= CreateIconIndirect(&info
);
588 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
589 test_icon_info(hIcon
, 16, 16, 1);
592 DeleteObject(hbmMask
);
593 DeleteObject(hbmColor
);
595 /* test creating an icon from a DIB section */
597 bmpinfo
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, FIELD_OFFSET(BITMAPINFO
,bmiColors
[256]));
598 bmpinfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
599 bmpinfo
->bmiHeader
.biWidth
= 32;
600 bmpinfo
->bmiHeader
.biHeight
= 32;
601 bmpinfo
->bmiHeader
.biPlanes
= 1;
602 bmpinfo
->bmiHeader
.biBitCount
= 8;
603 bmpinfo
->bmiHeader
.biCompression
= BI_RGB
;
604 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
605 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
607 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
608 bmpinfo
->bmiHeader
.biBitCount
= 1;
609 hbmMask
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
610 ok(hbmMask
!= NULL
, "Expected a handle to the DIB\n");
612 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
617 info
.hbmMask
= hbmColor
;
618 info
.hbmColor
= hbmMask
;
619 SetLastError(0xdeadbeaf);
620 hIcon
= CreateIconIndirect(&info
);
621 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
622 test_icon_info(hIcon
, 32, 32, 8);
624 DeleteObject(hbmColor
);
626 bmpinfo
->bmiHeader
.biBitCount
= 16;
627 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
628 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
630 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
635 info
.hbmMask
= hbmColor
;
636 info
.hbmColor
= hbmMask
;
637 SetLastError(0xdeadbeaf);
638 hIcon
= CreateIconIndirect(&info
);
639 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
640 test_icon_info(hIcon
, 32, 32, 8);
642 DeleteObject(hbmColor
);
644 bmpinfo
->bmiHeader
.biBitCount
= 32;
645 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
646 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
648 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
653 info
.hbmMask
= hbmColor
;
654 info
.hbmColor
= hbmMask
;
655 SetLastError(0xdeadbeaf);
656 hIcon
= CreateIconIndirect(&info
);
657 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
658 test_icon_info(hIcon
, 32, 32, 8);
661 DeleteObject(hbmMask
);
662 DeleteObject(hbmColor
);
663 HeapFree( GetProcessHeap(), 0, bmpinfo
);
668 /* Shamelessly ripped from dlls/oleaut32/tests/olepicture.c */
670 static unsigned char gifimage
[35] = {
671 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
672 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
677 static unsigned char jpgimage
[285] = {
678 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
679 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
680 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
681 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
682 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
683 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
684 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
685 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
686 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
687 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
688 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
689 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
690 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
691 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
692 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
693 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
694 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
695 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
699 static unsigned char pngimage
[285] = {
700 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
701 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
702 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
703 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
704 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
705 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
706 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
709 /* 1x1 pixel bmp with gap between palette and bitmap. Correct bitmap contains only
710 zeroes, gap is 0xFF. */
711 static unsigned char bmpimage
[70] = {
712 0x42,0x4d,0x46,0x00,0x00,0x00,0xDE,0xAD,0xBE,0xEF,0x42,0x00,0x00,0x00,0x28,0x00,
713 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
714 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
715 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0x55,0x55,0x55,0x00,0xFF,0xFF,
716 0xFF,0xFF,0x00,0x00,0x00,0x00
719 /* 1x1 pixel bmp using BITMAPCOREHEADER */
720 static unsigned char bmpcoreimage
[38] = {
721 0x42,0x4d,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x0c,0x00,
722 0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xff,0xff,0xff,0x00,0x55,0x55,
723 0x55,0x00,0x00,0x00,0x00,0x00
727 static unsigned char gif4pixel
[42] = {
728 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
729 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
730 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
733 static void test_LoadImageBitmap(const char * test_desc
, HBITMAP hbm
)
737 DWORD ret
, pixel
= 0;
738 HDC hdc
= GetDC(NULL
);
740 ret
= GetObject(hbm
, sizeof(bm
), &bm
);
741 ok(ret
== sizeof(bm
), "GetObject returned %d\n", ret
);
743 memset(&bmi
, 0, sizeof(bmi
));
744 bmi
.bmiHeader
.biSize
= sizeof(bmi
.bmiHeader
);
745 bmi
.bmiHeader
.biWidth
= bm
.bmWidth
;
746 bmi
.bmiHeader
.biHeight
= bm
.bmHeight
;
747 bmi
.bmiHeader
.biPlanes
= 1;
748 bmi
.bmiHeader
.biBitCount
= 24;
749 bmi
.bmiHeader
.biCompression
= BI_RGB
;
750 ret
= GetDIBits(hdc
, hbm
, 0, bm
.bmHeight
, &pixel
, &bmi
, DIB_RGB_COLORS
);
751 ok(ret
== bm
.bmHeight
, "%s: %d lines were converted, not %d\n", test_desc
, ret
, bm
.bmHeight
);
753 ok(color_match(pixel
, 0x00ffffff), "%s: Pixel is 0x%08x\n", test_desc
, pixel
);
756 static void test_LoadImageFile(const char * test_desc
, unsigned char * image_data
,
757 unsigned int image_size
, const char * ext
, BOOL expect_success
)
761 DWORD error
, bytes_written
;
764 strcpy(filename
, "test.");
765 strcat(filename
, ext
);
767 /* Create the test image. */
768 handle
= CreateFileA(filename
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
769 FILE_ATTRIBUTE_NORMAL
, NULL
);
770 ok(handle
!= INVALID_HANDLE_VALUE
, "CreateFileA failed. %u\n", GetLastError());
771 ret
= WriteFile(handle
, image_data
, image_size
, &bytes_written
, NULL
);
772 ok(ret
&& bytes_written
== image_size
, "test file created improperly.\n");
775 /* Load as cursor. For all tested formats, this should fail */
776 SetLastError(0xdeadbeef);
777 handle
= LoadImageA(NULL
, filename
, IMAGE_CURSOR
, 0, 0, LR_LOADFROMFILE
);
778 ok(handle
== NULL
, "%s: IMAGE_CURSOR succeeded incorrectly.\n", test_desc
);
779 error
= GetLastError();
781 broken(error
== 0xdeadbeef) || /* Win9x */
782 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
783 "Last error: %u\n", error
);
784 if (handle
!= NULL
) DestroyCursor(handle
);
786 /* Load as icon. For all tested formats, this should fail */
787 SetLastError(0xdeadbeef);
788 handle
= LoadImageA(NULL
, filename
, IMAGE_ICON
, 0, 0, LR_LOADFROMFILE
);
789 ok(handle
== NULL
, "%s: IMAGE_ICON succeeded incorrectly.\n", test_desc
);
790 error
= GetLastError();
792 broken(error
== 0xdeadbeef) || /* Win9x */
793 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
794 "Last error: %u\n", error
);
795 if (handle
!= NULL
) DestroyIcon(handle
);
797 /* Load as bitmap. Should succeed for correct bmp, fail for everything else */
798 SetLastError(0xdeadbeef);
799 handle
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
);
800 error
= GetLastError();
802 error
== 0xdeadbeef, /* Win9x, WinMe */
803 "Last error: %u\n", error
);
805 if (expect_success
) {
806 ok(handle
!= NULL
, "%s: IMAGE_BITMAP failed.\n", test_desc
);
807 if (handle
!= NULL
) test_LoadImageBitmap(test_desc
, handle
);
809 else ok(handle
== NULL
, "%s: IMAGE_BITMAP succeeded incorrectly.\n", test_desc
);
811 if (handle
!= NULL
) DeleteObject(handle
);
812 DeleteFileA(filename
);
815 static void test_LoadImage(void)
819 DWORD error
, bytes_written
;
820 CURSORICONFILEDIR
*icon_data
;
821 CURSORICONFILEDIRENTRY
*icon_entry
;
822 BITMAPINFOHEADER
*icon_header
;
825 #define ICON_WIDTH 32
826 #define ICON_HEIGHT 32
827 #define ICON_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
830 (sizeof(CURSORICONFILEDIR) + sizeof(BITMAPINFOHEADER) \
831 + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
834 icon_data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ICON_SIZE
);
835 icon_data
->idReserved
= 0;
836 icon_data
->idType
= 1;
837 icon_data
->idCount
= 1;
839 icon_entry
= icon_data
->idEntries
;
840 icon_entry
->bWidth
= ICON_WIDTH
;
841 icon_entry
->bHeight
= ICON_HEIGHT
;
842 icon_entry
->bColorCount
= 0;
843 icon_entry
->bReserved
= 0;
844 icon_entry
->xHotspot
= 1;
845 icon_entry
->yHotspot
= 1;
846 icon_entry
->dwDIBSize
= ICON_SIZE
- sizeof(CURSORICONFILEDIR
);
847 icon_entry
->dwDIBOffset
= sizeof(CURSORICONFILEDIR
);
849 icon_header
= (BITMAPINFOHEADER
*) ((BYTE
*) icon_data
+ icon_entry
->dwDIBOffset
);
850 icon_header
->biSize
= sizeof(BITMAPINFOHEADER
);
851 icon_header
->biWidth
= ICON_WIDTH
;
852 icon_header
->biHeight
= ICON_HEIGHT
*2;
853 icon_header
->biPlanes
= 1;
854 icon_header
->biBitCount
= ICON_BPP
;
855 icon_header
->biSizeImage
= 0; /* Uncompressed bitmap. */
857 /* Create the icon. */
858 handle
= CreateFileA("icon.ico", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
859 FILE_ATTRIBUTE_NORMAL
, NULL
);
860 ok(handle
!= INVALID_HANDLE_VALUE
, "CreateFileA failed. %u\n", GetLastError());
861 ret
= WriteFile(handle
, icon_data
, ICON_SIZE
, &bytes_written
, NULL
);
862 ok(ret
&& bytes_written
== ICON_SIZE
, "icon.ico created improperly.\n");
865 /* Test loading an icon as a cursor. */
866 SetLastError(0xdeadbeef);
867 handle
= LoadImageA(NULL
, "icon.ico", IMAGE_CURSOR
, 0, 0, LR_LOADFROMFILE
);
868 ok(handle
!= NULL
, "LoadImage() failed.\n");
869 error
= GetLastError();
871 broken(error
== 0xdeadbeef) || /* Win9x */
872 broken(error
== ERROR_BAD_PATHNAME
), /* Win98, WinMe */
873 "Last error: %u\n", error
);
875 /* Test the icon information. */
876 SetLastError(0xdeadbeef);
877 ret
= GetIconInfo(handle
, &icon_info
);
878 ok(ret
, "GetIconInfo() failed.\n");
879 error
= GetLastError();
880 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
884 ok(icon_info
.fIcon
== FALSE
, "fIcon != FALSE.\n");
885 ok(icon_info
.xHotspot
== 1, "xHotspot is %u.\n", icon_info
.xHotspot
);
886 ok(icon_info
.yHotspot
== 1, "yHotspot is %u.\n", icon_info
.yHotspot
);
887 ok(icon_info
.hbmColor
!= NULL
|| broken(!icon_info
.hbmColor
) /* no color cursor support */,
889 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
893 SetLastError(0xdeadbeef);
894 ret
= DestroyCursor(handle
);
895 ok(ret
, "DestroyCursor() failed.\n");
896 error
= GetLastError();
897 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
899 HeapFree(GetProcessHeap(), 0, icon_data
);
900 DeleteFileA("icon.ico");
902 test_LoadImageFile("BMP", bmpimage
, sizeof(bmpimage
), "bmp", 1);
903 test_LoadImageFile("BMP (coreinfo)", bmpcoreimage
, sizeof(bmpcoreimage
), "bmp", 1);
904 test_LoadImageFile("GIF", gifimage
, sizeof(gifimage
), "gif", 0);
905 test_LoadImageFile("GIF (2x2 pixel)", gif4pixel
, sizeof(gif4pixel
), "gif", 0);
906 test_LoadImageFile("JPG", jpgimage
, sizeof(jpgimage
), "jpg", 0);
907 test_LoadImageFile("PNG", pngimage
, sizeof(pngimage
), "png", 0);
908 /* Check failure for broken BMP images */
909 bmpimage
[0x14]++; /* biHeight > 65535 */
910 test_LoadImageFile("BMP (too high)", bmpimage
, sizeof(bmpimage
), "bmp", 0);
912 bmpimage
[0x18]++; /* biWidth > 65535 */
913 test_LoadImageFile("BMP (too wide)", bmpimage
, sizeof(bmpimage
), "bmp", 0);
917 static void test_CreateIconFromResource(void)
922 BITMAPINFOHEADER
*icon_header
;
926 #define ICON_RES_WIDTH 32
927 #define ICON_RES_HEIGHT 32
928 #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
929 #define ICON_RES_BPP 32
930 #define ICON_RES_SIZE \
931 (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
932 #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE)
935 hotspot
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, CRSR_RES_SIZE
);
937 /* Cursor resources have an extra hotspot, icon resources not. */
941 icon_header
= (BITMAPINFOHEADER
*) (hotspot
+ 2);
942 icon_header
->biSize
= sizeof(BITMAPINFOHEADER
);
943 icon_header
->biWidth
= ICON_WIDTH
;
944 icon_header
->biHeight
= ICON_HEIGHT
*2;
945 icon_header
->biPlanes
= 1;
946 icon_header
->biBitCount
= ICON_BPP
;
947 icon_header
->biSizeImage
= 0; /* Uncompressed bitmap. */
949 /* Test creating a cursor. */
950 SetLastError(0xdeadbeef);
951 handle
= CreateIconFromResource((PBYTE
) hotspot
, CRSR_RES_SIZE
, FALSE
, 0x00030000);
952 ok(handle
!= NULL
, "Create cursor failed.\n");
954 /* Test the icon information. */
955 SetLastError(0xdeadbeef);
956 ret
= GetIconInfo(handle
, &icon_info
);
957 ok(ret
, "GetIconInfo() failed.\n");
958 error
= GetLastError();
959 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
963 ok(icon_info
.fIcon
== FALSE
, "fIcon != FALSE.\n");
964 ok(icon_info
.xHotspot
== 3, "xHotspot is %u.\n", icon_info
.xHotspot
);
965 ok(icon_info
.yHotspot
== 3, "yHotspot is %u.\n", icon_info
.yHotspot
);
966 ok(icon_info
.hbmColor
!= NULL
|| broken(!icon_info
.hbmColor
) /* no color cursor support */,
968 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
972 SetLastError(0xdeadbeef);
973 ret
= DestroyCursor(handle
);
974 ok(ret
, "DestroyCursor() failed.\n");
975 error
= GetLastError();
976 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
978 /* Test creating an icon. */
979 SetLastError(0xdeadbeef);
980 handle
= CreateIconFromResource((PBYTE
) icon_header
, ICON_RES_SIZE
, TRUE
,
982 ok(handle
!= NULL
, "Create icon failed.\n");
984 /* Test the icon information. */
985 SetLastError(0xdeadbeef);
986 ret
= GetIconInfo(handle
, &icon_info
);
987 ok(ret
, "GetIconInfo() failed.\n");
988 error
= GetLastError();
989 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
993 ok(icon_info
.fIcon
== TRUE
, "fIcon != TRUE.\n");
994 /* Icons always have hotspot in the middle */
995 ok(icon_info
.xHotspot
== ICON_WIDTH
/2, "xHotspot is %u.\n", icon_info
.xHotspot
);
996 ok(icon_info
.yHotspot
== ICON_HEIGHT
/2, "yHotspot is %u.\n", icon_info
.yHotspot
);
997 ok(icon_info
.hbmColor
!= NULL
, "No hbmColor!\n");
998 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
1002 SetLastError(0xdeadbeef);
1003 ret
= DestroyCursor(handle
);
1004 ok(ret
, "DestroyCursor() failed.\n");
1005 error
= GetLastError();
1006 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
1008 HeapFree(GetProcessHeap(), 0, hotspot
);
1011 static HICON
create_test_icon(HDC hdc
, int width
, int height
, int bpp
,
1012 BOOL maskvalue
, UINT32
*color
, int colorSize
)
1015 BITMAPINFO bitmapInfo
;
1016 void *buffer
= NULL
;
1017 UINT32 mask
= maskvalue
? 0xFFFFFFFF : 0x00000000;
1019 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1020 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1021 bitmapInfo
.bmiHeader
.biWidth
= width
;
1022 bitmapInfo
.bmiHeader
.biHeight
= height
;
1023 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1024 bitmapInfo
.bmiHeader
.biBitCount
= bpp
;
1025 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1026 bitmapInfo
.bmiHeader
.biSizeImage
= colorSize
;
1028 iconInfo
.fIcon
= TRUE
;
1029 iconInfo
.xHotspot
= 0;
1030 iconInfo
.yHotspot
= 0;
1032 iconInfo
.hbmMask
= CreateBitmap( width
, height
, 1, 1, &mask
);
1033 if(!iconInfo
.hbmMask
) return NULL
;
1035 iconInfo
.hbmColor
= CreateDIBSection(hdc
, &bitmapInfo
, DIB_RGB_COLORS
, &buffer
, NULL
, 0);
1036 if(!iconInfo
.hbmColor
|| !buffer
)
1038 DeleteObject(iconInfo
.hbmMask
);
1042 memcpy(buffer
, color
, colorSize
);
1044 return CreateIconIndirect(&iconInfo
);
1047 static void check_alpha_draw(HDC hdc
, BOOL drawiconex
, BOOL alpha
, int bpp
, int line
)
1051 COLORREF modern_expected
, legacy_expected
, result
;
1053 color
[0] = 0x00A0B0C0;
1054 color
[1] = alpha
? 0xFF000000 : 0x00000000;
1055 modern_expected
= alpha
? 0x00FFFFFF : 0x00C0B0A0;
1056 legacy_expected
= 0x00C0B0A0;
1058 hicon
= create_test_icon(hdc
, 2, 1, bpp
, 0, color
, sizeof(color
));
1061 SetPixelV(hdc
, 0, 0, 0x00FFFFFF);
1064 DrawIconEx(hdc
, 0, 0, hicon
, 2, 1, 0, NULL
, DI_NORMAL
);
1066 DrawIcon(hdc
, 0, 0, hicon
);
1068 result
= GetPixel(hdc
, 0, 0);
1069 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1070 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1071 "%s. Expected a close match to %06X (modern) or %06X (legacy) with %s. "
1072 "Got %06X from line %d\n",
1073 alpha
? "Alpha blending" : "Not alpha blending", modern_expected
, legacy_expected
,
1074 drawiconex
? "DrawIconEx" : "DrawIcon", result
, line
);
1077 static void check_DrawIcon(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, COLORREF background
,
1078 COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1081 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1083 SetPixelV(hdc
, 0, 0, background
);
1084 SetPixelV(hdc
, GetSystemMetrics(SM_CXICON
)-1, GetSystemMetrics(SM_CYICON
)-1, background
);
1085 SetPixelV(hdc
, GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
), background
);
1086 DrawIcon(hdc
, 0, 0, hicon
);
1087 result
= GetPixel(hdc
, 0, 0);
1089 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1090 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1091 "Overlaying Mask %d on Color %06X with DrawIcon. "
1092 "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1093 maskvalue
, color
, modern_expected
, legacy_expected
, result
, line
);
1095 result
= GetPixel(hdc
, GetSystemMetrics(SM_CXICON
)-1, GetSystemMetrics(SM_CYICON
)-1);
1097 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1098 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1099 "Overlaying Mask %d on Color %06X with DrawIcon. "
1100 "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1101 maskvalue
, color
, modern_expected
, legacy_expected
, result
, line
);
1103 result
= GetPixel(hdc
, GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
));
1105 ok (color_match(result
, background
),
1106 "Overlaying Mask %d on Color %06X with DrawIcon. "
1107 "Expected unchanged background color %06X. Got %06X from line %d\n",
1108 maskvalue
, color
, background
, result
, line
);
1111 static void test_DrawIcon(void)
1113 BITMAPINFO bitmapInfo
;
1115 HBITMAP bmpDst
= NULL
;
1116 HBITMAP bmpOld
= NULL
;
1119 hdcDst
= CreateCompatibleDC(0);
1120 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1124 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1126 skip("Windows will distort DrawIcon colors at 8-bpp and less due to palletizing.\n");
1130 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1131 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1132 bitmapInfo
.bmiHeader
.biWidth
= GetSystemMetrics(SM_CXICON
)+1;
1133 bitmapInfo
.bmiHeader
.biHeight
= GetSystemMetrics(SM_CYICON
)+1;
1134 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1135 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1136 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1137 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1139 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1140 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1141 if (!bmpDst
|| !bits
)
1143 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1145 /* Mask is only heeded if alpha channel is always zero */
1146 check_DrawIcon(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1147 check_DrawIcon(hdcDst
, TRUE
, 0x00A0B0C0, 32, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__
);
1149 /* Test alpha blending */
1150 /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
1151 check_DrawIcon(hdcDst
, FALSE
, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1152 check_DrawIcon(hdcDst
, TRUE
, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__
);
1154 check_DrawIcon(hdcDst
, FALSE
, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1155 check_DrawIcon(hdcDst
, TRUE
, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1156 check_DrawIcon(hdcDst
, FALSE
, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__
);
1157 check_DrawIcon(hdcDst
, TRUE
, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__
);
1159 check_DrawIcon(hdcDst
, FALSE
, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1160 check_DrawIcon(hdcDst
, TRUE
, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1162 /* Test detecting of alpha channel */
1163 /* If a single pixel's alpha channel is non-zero, the icon
1164 will be alpha blended, otherwise it will be draw with
1166 check_alpha_draw(hdcDst
, FALSE
, FALSE
, 32, __LINE__
);
1167 check_alpha_draw(hdcDst
, FALSE
, TRUE
, 32, __LINE__
);
1171 SelectObject(hdcDst
, bmpOld
);
1173 DeleteObject(bmpDst
);
1178 static void check_DrawIconEx(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, UINT flags
, COLORREF background
,
1179 COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1182 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1184 SetPixelV(hdc
, 0, 0, background
);
1185 DrawIconEx(hdc
, 0, 0, hicon
, 1, 1, 0, NULL
, flags
);
1186 result
= GetPixel(hdc
, 0, 0);
1188 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1189 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1190 "Overlaying Mask %d on Color %06X with DrawIconEx flags %08X. "
1191 "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
1192 maskvalue
, color
, flags
, modern_expected
, legacy_expected
, result
, line
);
1195 static void test_DrawIconEx(void)
1197 BITMAPINFO bitmapInfo
;
1199 HBITMAP bmpDst
= NULL
;
1200 HBITMAP bmpOld
= NULL
;
1203 hdcDst
= CreateCompatibleDC(0);
1204 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1208 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1210 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n");
1214 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1215 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1216 bitmapInfo
.bmiHeader
.biWidth
= 1;
1217 bitmapInfo
.bmiHeader
.biHeight
= 1;
1218 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1219 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1220 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1221 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1222 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1223 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1224 if (!bmpDst
|| !bits
)
1226 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1228 /* Test null, image only, and mask only drawing */
1229 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__
);
1230 check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__
);
1232 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_MASK
, 0x00FFFFFF, 0x00000000, 0x00000000, __LINE__
);
1233 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_MASK
, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, __LINE__
);
1235 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, DI_IMAGE
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1236 check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, DI_IMAGE
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1238 /* Test normal drawing */
1239 check_DrawIconEx(hdcDst
, FALSE
, 0x00A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1240 check_DrawIconEx(hdcDst
, TRUE
, 0x00A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__
);
1241 check_DrawIconEx(hdcDst
, FALSE
, 0xFFA0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1243 /* Test alpha blending */
1244 /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
1245 check_DrawIconEx(hdcDst
, TRUE
, 0xFFA0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__
);
1247 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1248 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__
);
1249 check_DrawIconEx(hdcDst
, FALSE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__
);
1250 check_DrawIconEx(hdcDst
, TRUE
, 0x80A0B0C0, 32, DI_NORMAL
, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__
);
1252 check_DrawIconEx(hdcDst
, FALSE
, 0x01FFFFFF, 32, DI_NORMAL
, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1253 check_DrawIconEx(hdcDst
, TRUE
, 0x01FFFFFF, 32, DI_NORMAL
, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__
);
1255 /* Test detecting of alpha channel */
1256 /* If a single pixel's alpha channel is non-zero, the icon
1257 will be alpha blended, otherwise it will be draw with
1259 check_alpha_draw(hdcDst
, TRUE
, FALSE
, 32, __LINE__
);
1260 check_alpha_draw(hdcDst
, TRUE
, TRUE
, 32, __LINE__
);
1264 SelectObject(hdcDst
, bmpOld
);
1266 DeleteObject(bmpDst
);
1271 static void check_DrawState_Size(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, HBRUSH hbr
, UINT flags
, int line
)
1273 COLORREF result
, background
;
1275 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1276 background
= 0x00FFFFFF;
1277 /* Set color of the 2 pixels that will be checked afterwards */
1278 SetPixelV(hdc
, 0, 0, background
);
1279 SetPixelV(hdc
, 2, 2, background
);
1281 /* Let DrawState calculate the size of the icon (it's 1x1) */
1282 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 0, 0, (DST_ICON
| flags
));
1284 result
= GetPixel(hdc
, 0, 0);
1285 passed
[0] = color_match(result
, background
);
1286 result
= GetPixel(hdc
, 2, 2);
1287 passed
[0] = passed
[0] & color_match(result
, background
);
1289 /* Check if manually specifying the icon size DOESN'T work */
1291 /* IMPORTANT: For Icons, DrawState wants the size of the source image, not the
1292 * size in which it should be ultimately drawn. Therefore giving
1293 * width/height 2x2 if the icon is only 1x1 pixels in size should
1294 * result in drawing it with size 1x1. The size parameters must be
1295 * ignored if a Icon has to be drawn! */
1296 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 2, 2, (DST_ICON
| flags
));
1298 result
= GetPixel(hdc
, 0, 0);
1299 passed
[1] = color_match(result
, background
);
1300 result
= GetPixel(hdc
, 2, 2);
1301 passed
[1] = passed
[0] & color_match(result
, background
);
1303 if(!passed
[0]&&!passed
[1])
1305 "DrawState failed to draw a 1x1 Icon in the correct size, independent of the "
1306 "width and height settings passed to it, for Icon with: Overlaying Mask %d on "
1307 "Color %06X with flags %08X. Line %d\n",
1308 maskvalue
, color
, (DST_ICON
| flags
), line
);
1311 "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
1312 "parameters passed to it are bigger than the real Icon size, for Icon with: Overlaying "
1313 "Mask %d on Color %06X with flags %08X. Line %d\n",
1314 maskvalue
, color
, (DST_ICON
| flags
), line
);
1317 "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
1318 "parameters passed to it are 0, for Icon with: Overlaying Mask %d on "
1319 "Color %06X with flags %08X. Line %d\n",
1320 maskvalue
, color
, (DST_ICON
| flags
), line
);
1323 static void check_DrawState_Color(HDC hdc
, BOOL maskvalue
, UINT32 color
, int bpp
, HBRUSH hbr
, UINT flags
,
1324 COLORREF background
, COLORREF modern_expected
, COLORREF legacy_expected
, int line
)
1327 HICON hicon
= create_test_icon(hdc
, 1, 1, bpp
, maskvalue
, &color
, sizeof(color
));
1329 /* Set color of the pixel that will be checked afterwards */
1330 SetPixelV(hdc
, 1, 1, background
);
1332 DrawState(hdc
, hbr
, NULL
, (LPARAM
) hicon
, 0, 1, 1, 0, 0, ( DST_ICON
| flags
));
1334 /* Check the color of the pixel is correct */
1335 result
= GetPixel(hdc
, 1, 1);
1337 ok (color_match(result
, modern_expected
) || /* Windows 2000 and up */
1338 broken(color_match(result
, legacy_expected
)), /* Windows NT 4.0, 9X and below */
1339 "DrawState drawing Icon with Overlaying Mask %d on Color %06X with flags %08X. "
1340 "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
1341 maskvalue
, color
, (DST_ICON
| flags
), modern_expected
, legacy_expected
, result
, line
);
1344 static void test_DrawState(void)
1346 BITMAPINFO bitmapInfo
;
1348 HBITMAP bmpDst
= NULL
;
1349 HBITMAP bmpOld
= NULL
;
1352 hdcDst
= CreateCompatibleDC(0);
1353 ok(hdcDst
!= 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1357 if(GetDeviceCaps(hdcDst
, BITSPIXEL
) <= 8)
1359 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n");
1363 memset(&bitmapInfo
, 0, sizeof(bitmapInfo
));
1364 bitmapInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1365 bitmapInfo
.bmiHeader
.biWidth
= 3;
1366 bitmapInfo
.bmiHeader
.biHeight
= 3;
1367 bitmapInfo
.bmiHeader
.biBitCount
= 32;
1368 bitmapInfo
.bmiHeader
.biPlanes
= 1;
1369 bitmapInfo
.bmiHeader
.biCompression
= BI_RGB
;
1370 bitmapInfo
.bmiHeader
.biSizeImage
= sizeof(UINT32
);
1371 bmpDst
= CreateDIBSection(hdcDst
, &bitmapInfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1372 ok (bmpDst
&& bits
, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1373 if (!bmpDst
|| !bits
)
1375 bmpOld
= SelectObject(hdcDst
, bmpDst
);
1377 /* potential flags to test with DrawState are: */
1378 /* DSS_DISABLED embosses the icon */
1379 /* DSS_MONO draw Icon using a brush as parameter 5 */
1380 /* DSS_NORMAL draw Icon without any modifications */
1381 /* DSS_UNION draw the Icon dithered */
1383 check_DrawState_Size(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, DSS_NORMAL
, __LINE__
);
1384 check_DrawState_Color(hdcDst
, FALSE
, 0x00A0B0C0, 32, 0, DSS_NORMAL
, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__
);
1388 SelectObject(hdcDst
, bmpOld
);
1390 DeleteObject(bmpDst
);
1395 static DWORD parent_id
;
1397 static DWORD CALLBACK
set_cursor_thread( void *arg
)
1401 PeekMessage( 0, 0, 0, 0, PM_NOREMOVE
); /* create a msg queue */
1404 BOOL ret
= AttachThreadInput( GetCurrentThreadId(), parent_id
, TRUE
);
1405 ok( ret
, "AttachThreadInput failed\n" );
1407 if (arg
) ret
= SetCursor( (HCURSOR
)arg
);
1408 else ret
= GetCursor();
1409 return (DWORD_PTR
)ret
;
1412 static void test_SetCursor(void)
1414 static const BYTE bmp_bits
[4096];
1415 ICONINFO cursorInfo
;
1416 HCURSOR cursor
, old_cursor
, global_cursor
= 0;
1417 DWORD error
, id
, result
;
1425 memset( &info
, 0, sizeof(info
) );
1426 info
.cbSize
= sizeof(info
);
1427 if (!pGetCursorInfo( &info
))
1429 win_skip( "GetCursorInfo not working\n" );
1430 pGetCursorInfo
= NULL
;
1432 else global_cursor
= info
.hCursor
;
1434 cursor
= GetCursor();
1435 thread
= CreateThread( NULL
, 0, set_cursor_thread
, 0, 0, &id
);
1436 WaitForSingleObject( thread
, 1000 );
1437 GetExitCodeThread( thread
, &result
);
1438 ok( result
== (DWORD_PTR
)cursor
, "wrong thread cursor %x/%p\n", result
, cursor
);
1441 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1444 cursorInfo
.fIcon
= FALSE
;
1445 cursorInfo
.xHotspot
= 0;
1446 cursorInfo
.yHotspot
= 0;
1447 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
1448 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
1450 cursor
= CreateIconIndirect(&cursorInfo
);
1451 ok(cursor
!= NULL
, "CreateIconIndirect returned %p\n", cursor
);
1452 old_cursor
= SetCursor( cursor
);
1456 info
.cbSize
= sizeof(info
);
1457 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1458 /* global cursor doesn't change since we don't have a window */
1459 ok( info
.hCursor
== global_cursor
|| broken(info
.hCursor
!= cursor
), /* win9x */
1460 "wrong info cursor %p/%p\n", info
.hCursor
, global_cursor
);
1462 thread
= CreateThread( NULL
, 0, set_cursor_thread
, 0, 0, &id
);
1463 WaitForSingleObject( thread
, 1000 );
1464 GetExitCodeThread( thread
, &result
);
1465 ok( result
== (DWORD_PTR
)old_cursor
, "wrong thread cursor %x/%p\n", result
, old_cursor
);
1468 ok( GetCursor() == 0, "wrong cursor %p\n", GetCursor() );
1469 thread
= CreateThread( NULL
, 0, set_cursor_thread
, 0, 0, &id
);
1470 WaitForSingleObject( thread
, 1000 );
1471 GetExitCodeThread( thread
, &result
);
1472 ok( result
== (DWORD_PTR
)old_cursor
, "wrong thread cursor %x/%p\n", result
, old_cursor
);
1474 thread
= CreateThread( NULL
, 0, set_cursor_thread
, cursor
, 0, &id
);
1475 WaitForSingleObject( thread
, 1000 );
1476 GetExitCodeThread( thread
, &result
);
1477 ok( result
== (DWORD_PTR
)old_cursor
, "wrong thread cursor %x/%p\n", result
, old_cursor
);
1478 ok( GetCursor() == 0, "wrong cursor %p/0\n", GetCursor() );
1480 parent_id
= GetCurrentThreadId();
1481 thread
= CreateThread( NULL
, 0, set_cursor_thread
, cursor
, 0, &id
);
1482 WaitForSingleObject( thread
, 1000 );
1483 GetExitCodeThread( thread
, &result
);
1484 ok( result
== (DWORD_PTR
)old_cursor
, "wrong thread cursor %x/%p\n", result
, old_cursor
);
1485 ok( GetCursor() == cursor
, "wrong cursor %p/0\n", cursor
);
1489 info
.cbSize
= sizeof(info
);
1490 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1491 ok( info
.hCursor
== global_cursor
|| broken(info
.hCursor
!= cursor
), /* win9x */
1492 "wrong info cursor %p/%p\n", info
.hCursor
, global_cursor
);
1494 SetCursor( old_cursor
);
1495 DestroyCursor( cursor
);
1497 SetLastError( 0xdeadbeef );
1498 cursor
= SetCursor( (HCURSOR
)0xbadbad );
1499 error
= GetLastError();
1500 ok( cursor
== 0, "wrong cursor %p/0\n", cursor
);
1501 ok( error
== ERROR_INVALID_CURSOR_HANDLE
|| broken( error
== 0xdeadbeef ), /* win9x */
1502 "wrong error %u\n", error
);
1506 info
.cbSize
= sizeof(info
);
1507 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1508 ok( info
.hCursor
== global_cursor
|| broken(info
.hCursor
!= cursor
), /* win9x */
1509 "wrong info cursor %p/%p\n", info
.hCursor
, global_cursor
);
1513 static HANDLE event_start
, event_next
;
1515 static DWORD CALLBACK
show_cursor_thread( void *arg
)
1517 DWORD count
= (DWORD_PTR
)arg
;
1520 PeekMessage( 0, 0, 0, 0, PM_NOREMOVE
); /* create a msg queue */
1523 BOOL ret
= AttachThreadInput( GetCurrentThreadId(), parent_id
, TRUE
);
1524 ok( ret
, "AttachThreadInput failed\n" );
1526 if (!count
) ret
= ShowCursor( FALSE
);
1527 else while (count
--) ret
= ShowCursor( TRUE
);
1528 SetEvent( event_start
);
1529 WaitForSingleObject( event_next
, 2000 );
1533 static void test_ShowCursor(void)
1542 memset( &info
, 0, sizeof(info
) );
1543 info
.cbSize
= sizeof(info
);
1544 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1545 ok( info
.flags
& CURSOR_SHOWING
, "cursor not shown in info\n" );
1548 event_start
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1549 event_next
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
1551 count
= ShowCursor( TRUE
);
1552 ok( count
== 1, "wrong count %d\n", count
);
1553 count
= ShowCursor( TRUE
);
1554 ok( count
== 2, "wrong count %d\n", count
);
1555 count
= ShowCursor( FALSE
);
1556 ok( count
== 1, "wrong count %d\n", count
);
1557 count
= ShowCursor( FALSE
);
1558 ok( count
== 0, "wrong count %d\n", count
);
1559 count
= ShowCursor( FALSE
);
1560 ok( count
== -1, "wrong count %d\n", count
);
1561 count
= ShowCursor( FALSE
);
1562 ok( count
== -2, "wrong count %d\n", count
);
1566 info
.cbSize
= sizeof(info
);
1567 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1568 /* global show count is not affected since we don't have a window */
1569 ok( info
.flags
& CURSOR_SHOWING
, "cursor not shown in info\n" );
1573 thread
= CreateThread( NULL
, 0, show_cursor_thread
, NULL
, 0, &id
);
1574 WaitForSingleObject( event_start
, 1000 );
1575 count
= ShowCursor( FALSE
);
1576 ok( count
== -3, "wrong count %d\n", count
);
1577 SetEvent( event_next
);
1578 WaitForSingleObject( thread
, 1000 );
1579 GetExitCodeThread( thread
, &result
);
1580 ok( result
== -1, "wrong thread count %d\n", result
);
1581 count
= ShowCursor( FALSE
);
1582 ok( count
== -4, "wrong count %d\n", count
);
1584 thread
= CreateThread( NULL
, 0, show_cursor_thread
, (void *)1, 0, &id
);
1585 WaitForSingleObject( event_start
, 1000 );
1586 count
= ShowCursor( TRUE
);
1587 ok( count
== -3, "wrong count %d\n", count
);
1588 SetEvent( event_next
);
1589 WaitForSingleObject( thread
, 1000 );
1590 GetExitCodeThread( thread
, &result
);
1591 ok( result
== 1, "wrong thread count %d\n", result
);
1592 count
= ShowCursor( TRUE
);
1593 ok( count
== -2, "wrong count %d\n", count
);
1595 parent_id
= GetCurrentThreadId();
1596 thread
= CreateThread( NULL
, 0, show_cursor_thread
, NULL
, 0, &id
);
1597 WaitForSingleObject( event_start
, 1000 );
1598 count
= ShowCursor( TRUE
);
1599 ok( count
== -2, "wrong count %d\n", count
);
1600 SetEvent( event_next
);
1601 WaitForSingleObject( thread
, 1000 );
1602 GetExitCodeThread( thread
, &result
);
1603 ok( result
== -3, "wrong thread count %d\n", result
);
1604 count
= ShowCursor( FALSE
);
1605 ok( count
== -2, "wrong count %d\n", count
);
1607 thread
= CreateThread( NULL
, 0, show_cursor_thread
, (void *)3, 0, &id
);
1608 WaitForSingleObject( event_start
, 1000 );
1609 count
= ShowCursor( TRUE
);
1610 ok( count
== 2, "wrong count %d\n", count
);
1611 SetEvent( event_next
);
1612 WaitForSingleObject( thread
, 1000 );
1613 GetExitCodeThread( thread
, &result
);
1614 ok( result
== 1, "wrong thread count %d\n", result
);
1615 count
= ShowCursor( FALSE
);
1616 ok( count
== -2, "wrong count %d\n", count
);
1620 info
.cbSize
= sizeof(info
);
1621 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1622 ok( info
.flags
& CURSOR_SHOWING
, "cursor not shown in info\n" );
1625 count
= ShowCursor( TRUE
);
1626 ok( count
== -1, "wrong count %d\n", count
);
1627 count
= ShowCursor( TRUE
);
1628 ok( count
== 0, "wrong count %d\n", count
);
1632 info
.cbSize
= sizeof(info
);
1633 ok( pGetCursorInfo( &info
), "GetCursorInfo failed\n" );
1634 ok( info
.flags
& CURSOR_SHOWING
, "cursor not shown in info\n" );
1639 static void test_DestroyCursor(void)
1641 static const BYTE bmp_bits
[4096];
1642 ICONINFO cursorInfo
;
1643 HCURSOR cursor
, cursor2
;
1650 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
1653 cursorInfo
.fIcon
= FALSE
;
1654 cursorInfo
.xHotspot
= 0;
1655 cursorInfo
.yHotspot
= 0;
1656 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
1657 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
1659 cursor
= CreateIconIndirect(&cursorInfo
);
1660 ok(cursor
!= NULL
, "CreateIconIndirect returned %p\n", cursor
);
1666 SetLastError(0xdeadbeef);
1667 ret
= DestroyCursor(cursor
);
1668 ok(!ret
|| broken(ret
) /* succeeds on win9x */, "DestroyCursor on the active cursor succeeded\n");
1669 error
= GetLastError();
1670 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
1673 cursor2
= GetCursor();
1674 ok(cursor2
== cursor
, "Active was set to %p when trying to destroy it\n", cursor2
);
1677 /* Trying to destroy the cursor properly fails now with
1678 * ERROR_INVALID_CURSOR_HANDLE. This happens because we called
1679 * DestroyCursor() 2+ times after calling SetCursor(). The calls to
1680 * GetCursor() and SetCursor(NULL) in between make no difference. */
1681 SetLastError(0xdeadbeef);
1682 ret
= DestroyCursor(cursor
);
1683 todo_wine
ok(!ret
, "DestroyCursor succeeded.\n");
1684 error
= GetLastError();
1685 ok(error
== ERROR_INVALID_CURSOR_HANDLE
|| error
== 0xdeadbeef, /* vista */
1686 "Last error: 0x%08x\n", error
);
1689 DeleteObject(cursorInfo
.hbmMask
);
1690 DeleteObject(cursorInfo
.hbmColor
);
1692 /* Try testing DestroyCursor() now using LoadCursor() cursors. */
1693 cursor
= LoadCursor(NULL
, IDC_ARROW
);
1695 SetLastError(0xdeadbeef);
1696 ret
= DestroyCursor(cursor
);
1697 ok(ret
|| broken(!ret
) /* fails on win9x */, "DestroyCursor on the active cursor failed.\n");
1698 error
= GetLastError();
1699 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
1701 /* Try setting the cursor to a destroyed OEM cursor. */
1702 SetLastError(0xdeadbeef);
1704 error
= GetLastError();
1705 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
1707 /* Check if LoadCursor() returns the same handle with the same icon. */
1708 cursor2
= LoadCursor(NULL
, IDC_ARROW
);
1709 ok(cursor2
== cursor
, "cursor == %p, cursor2 == %p\n", cursor
, cursor2
);
1711 /* Check if LoadCursor() returns the same handle with a different icon. */
1712 cursor2
= LoadCursor(NULL
, IDC_WAIT
);
1713 ok(cursor2
!= cursor
, "cursor == %p, cursor2 == %p\n", cursor
, cursor2
);
1716 START_TEST(cursoricon
)
1718 pGetCursorInfo
= (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetCursorInfo" );
1719 test_argc
= winetest_get_mainargs(&test_argv
);
1723 /* Child process. */
1724 sscanf (test_argv
[2], "%x", (unsigned int *) &parent
);
1726 ok(parent
!= NULL
, "Parent not found.\n");
1734 test_CopyImage_Bitmap(1);
1735 test_CopyImage_Bitmap(4);
1736 test_CopyImage_Bitmap(8);
1737 test_CopyImage_Bitmap(16);
1738 test_CopyImage_Bitmap(24);
1739 test_CopyImage_Bitmap(32);
1740 test_initial_cursor();
1743 test_CreateIconFromResource();
1749 test_DestroyCursor();
1751 test_child_process();
1752 finish_child_process();