2 * Unit test suite for cursors and icons.
4 * Copyright 2006 Michael Kaufmann
5 * Copyright 2007 Dmitry Timoshkov
6 * Copyright 2007-2008 Andrew Riedi
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/test.h"
47 } CURSORICONFILEDIRENTRY
;
54 CURSORICONFILEDIRENTRY idEntries
[1];
59 static char **test_argv
;
61 static HWND child
= 0;
62 static HWND parent
= 0;
63 static HANDLE child_process
;
65 #define PROC_INIT (WM_USER+1)
67 static LRESULT CALLBACK
callback_child(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
74 /* Destroy the cursor. */
76 SetLastError(0xdeadbeef);
77 ret
= DestroyCursor((HCURSOR
) lParam
);
78 error
= GetLastError();
80 ok(!ret
, "DestroyCursor on the active cursor succeeded.\n");
81 ok(error
== ERROR_DESTROY_OBJECT_OF_OTHER_THREAD
,
82 "Last error: %u\n", error
);
90 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
93 static LRESULT CALLBACK
callback_parent(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
97 child
= (HWND
) wParam
;
101 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
104 static void do_child(void)
110 /* Register a new class. */
111 class.style
= CS_GLOBALCLASS
;
112 class.lpfnWndProc
= callback_child
;
113 class.cbClsExtra
= 0;
114 class.cbWndExtra
= 0;
115 class.hInstance
= GetModuleHandle(NULL
);
117 class.hCursor
= NULL
;
118 class.hbrBackground
= NULL
;
119 class.lpszMenuName
= NULL
;
120 class.lpszClassName
= "cursor_child";
122 SetLastError(0xdeadbeef);
123 ret
= RegisterClass(&class);
124 ok(ret
, "Failed to register window class. Error: %u\n", GetLastError());
126 /* Create a window. */
127 child
= CreateWindowA("cursor_child", "cursor_child", WS_POPUP
| WS_VISIBLE
,
128 0, 0, 200, 200, 0, 0, 0, NULL
);
129 ok(child
!= 0, "CreateWindowA failed. Error: %u\n", GetLastError());
131 /* Let the parent know our HWND. */
132 PostMessage(parent
, PROC_INIT
, (WPARAM
) child
, 0);
134 /* Receive messages. */
135 while ((ret
= GetMessage(&msg
, child
, 0, 0)))
137 ok(ret
!= -1, "GetMessage failed. Error: %u\n", GetLastError());
138 TranslateMessage(&msg
);
139 DispatchMessage(&msg
);
143 static void do_parent(void)
145 char path_name
[MAX_PATH
];
146 PROCESS_INFORMATION info
;
147 STARTUPINFOA startup
;
152 /* Register a new class. */
153 class.style
= CS_GLOBALCLASS
;
154 class.lpfnWndProc
= callback_parent
;
155 class.cbClsExtra
= 0;
156 class.cbWndExtra
= 0;
157 class.hInstance
= GetModuleHandle(NULL
);
159 class.hCursor
= NULL
;
160 class.hbrBackground
= NULL
;
161 class.lpszMenuName
= NULL
;
162 class.lpszClassName
= "cursor_parent";
164 SetLastError(0xdeadbeef);
165 ret
= RegisterClass(&class);
166 ok(ret
, "Failed to register window class. Error: %u\n", GetLastError());
168 /* Create a window. */
169 parent
= CreateWindowA("cursor_parent", "cursor_parent", WS_POPUP
| WS_VISIBLE
,
170 0, 0, 200, 200, 0, 0, 0, NULL
);
171 ok(parent
!= 0, "CreateWindowA failed. Error: %u\n", GetLastError());
173 /* Start child process. */
174 memset(&startup
, 0, sizeof(startup
));
175 startup
.cb
= sizeof(startup
);
176 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
177 startup
.wShowWindow
= SW_SHOWNORMAL
;
179 sprintf(path_name
, "%s cursoricon %x", test_argv
[0], (unsigned int) parent
);
180 ok(CreateProcessA(NULL
, path_name
, NULL
, NULL
, FALSE
, 0L, NULL
, NULL
, &startup
, &info
), "CreateProcess failed.\n");
181 child_process
= info
.hProcess
;
183 /* Wait for child window handle. */
184 while ((child
== 0) && (ret
= GetMessage(&msg
, parent
, 0, 0)))
186 ok(ret
!= -1, "GetMessage failed. Error: %u\n", GetLastError());
187 TranslateMessage(&msg
);
188 DispatchMessage(&msg
);
192 static void finish_child_process(void)
194 SendMessage(child
, WM_CLOSE
, 0, 0);
195 winetest_wait_child_process( child_process
);
196 CloseHandle(child_process
);
199 static void test_child_process(void)
201 static const BYTE bmp_bits
[4096];
207 /* Create and set a dummy cursor. */
209 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
212 cursorInfo
.fIcon
= FALSE
;
213 cursorInfo
.xHotspot
= 0;
214 cursorInfo
.yHotspot
= 0;
215 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
216 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
218 cursor
= CreateIconIndirect(&cursorInfo
);
219 ok(cursor
!= NULL
, "CreateIconIndirect returned %p.\n", cursor
);
223 /* Destroy the cursor. */
224 SendMessage(child
, WM_USER
+1, 0, (LPARAM
) cursor
);
227 static void test_CopyImage_Check(HBITMAP bitmap
, UINT flags
, INT copyWidth
, INT copyHeight
,
228 INT expectedWidth
, INT expectedHeight
, WORD expectedDepth
, BOOL dibExpected
)
236 copy
= (HBITMAP
) CopyImage(bitmap
, IMAGE_BITMAP
, copyWidth
, copyHeight
, flags
);
237 ok(copy
!= NULL
, "CopyImage() failed\n");
240 GetObject(bitmap
, sizeof(origBitmap
), &origBitmap
);
241 GetObject(copy
, sizeof(copyBitmap
), ©Bitmap
);
242 orig_is_dib
= (origBitmap
.bmBits
!= NULL
);
243 copy_is_dib
= (copyBitmap
.bmBits
!= NULL
);
245 if (copy_is_dib
&& dibExpected
246 && copyBitmap
.bmBitsPixel
== 24
247 && (expectedDepth
== 16 || expectedDepth
== 32))
249 /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
250 if (GetVersion() & 0x80000000)
256 if (copy_is_dib
&& !dibExpected
&& !(flags
& LR_CREATEDIBSECTION
))
258 /* It's not forbidden to create a DIB section if the flag
259 LR_CREATEDIBSECTION is absent.
260 Windows 9x does this if the bitmap has a depth that doesn't
261 match the screen depth, Windows NT doesn't */
263 expectedDepth
= origBitmap
.bmBitsPixel
;
266 ok((!(dibExpected
^ copy_is_dib
)
267 && (copyBitmap
.bmWidth
== expectedWidth
)
268 && (copyBitmap
.bmHeight
== expectedHeight
)
269 && (copyBitmap
.bmBitsPixel
== expectedDepth
)),
270 "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
271 orig_is_dib
? "DIB" : "DDB", origBitmap
.bmWidth
, origBitmap
.bmHeight
, origBitmap
.bmBitsPixel
,
272 copyWidth
, copyHeight
, flags
,
273 dibExpected
? "DIB" : "DDB", expectedWidth
, expectedHeight
, expectedDepth
,
274 copy_is_dib
? "DIB" : "DDB", copyBitmap
.bmWidth
, copyBitmap
.bmHeight
, copyBitmap
.bmBitsPixel
);
280 static void test_CopyImage_Bitmap(int depth
)
289 /* Create a device-independent bitmap (DIB) */
290 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
291 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
292 info
->bmiHeader
.biWidth
= 2;
293 info
->bmiHeader
.biHeight
= 2;
294 info
->bmiHeader
.biPlanes
= 1;
295 info
->bmiHeader
.biBitCount
= depth
;
296 info
->bmiHeader
.biCompression
= BI_RGB
;
298 for (i
=0; i
< 256; i
++)
300 info
->bmiColors
[i
].rgbRed
= i
;
301 info
->bmiColors
[i
].rgbGreen
= i
;
302 info
->bmiColors
[i
].rgbBlue
= 255 - i
;
303 info
->bmiColors
[i
].rgbReserved
= 0;
306 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
308 /* Create a device-dependent bitmap (DDB) */
309 screenDC
= GetDC(NULL
);
310 screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
311 if (depth
== 1 || depth
== screen_depth
)
313 ddb
= CreateBitmap(2, 2, 1, depth
, NULL
);
319 ReleaseDC(NULL
, screenDC
);
323 test_CopyImage_Check(ddb
, 0, 0, 0, 2, 2, depth
== 1 ? 1 : screen_depth
, FALSE
);
324 test_CopyImage_Check(ddb
, 0, 0, 5, 2, 5, depth
== 1 ? 1 : screen_depth
, FALSE
);
325 test_CopyImage_Check(ddb
, 0, 5, 0, 5, 2, depth
== 1 ? 1 : screen_depth
, FALSE
);
326 test_CopyImage_Check(ddb
, 0, 5, 5, 5, 5, depth
== 1 ? 1 : screen_depth
, FALSE
);
328 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 0, 0, 2, 2, 1, FALSE
);
329 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 5, 0, 5, 2, 1, FALSE
);
330 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 0, 5, 2, 5, 1, FALSE
);
331 test_CopyImage_Check(ddb
, LR_MONOCHROME
, 5, 5, 5, 5, 1, FALSE
);
333 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
334 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
335 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
336 test_CopyImage_Check(ddb
, LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
338 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
339 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
340 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
341 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
342 test_CopyImage_Check(ddb
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
349 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, screen_depth
, FALSE
);
350 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, screen_depth
, FALSE
);
351 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, screen_depth
, FALSE
);
352 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, screen_depth
, FALSE
);
355 test_CopyImage_Check(dib
, LR_MONOCHROME
, 0, 0, 2, 2, 1, FALSE
);
356 test_CopyImage_Check(dib
, LR_MONOCHROME
, 5, 0, 5, 2, 1, FALSE
);
357 test_CopyImage_Check(dib
, LR_MONOCHROME
, 0, 5, 2, 5, 1, FALSE
);
358 test_CopyImage_Check(dib
, LR_MONOCHROME
, 5, 5, 5, 5, 1, FALSE
);
360 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
361 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
362 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
363 test_CopyImage_Check(dib
, LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
365 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
366 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 0, 2, 2, depth
, TRUE
);
367 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 0, 5, 2, depth
, TRUE
);
368 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 0, 5, 2, 5, depth
, TRUE
);
369 test_CopyImage_Check(dib
, LR_MONOCHROME
| LR_CREATEDIBSECTION
, 5, 5, 5, 5, depth
, TRUE
);
375 /* Special case: A monochrome DIB is converted to a monochrome DDB if
376 the colors in the color table are black and white.
378 Skip this test on Windows 95, it always creates a monochrome DDB
381 if (!(GetVersion() & 0x80000000))
383 info
->bmiHeader
.biBitCount
= 1;
384 info
->bmiColors
[0].rgbRed
= 0xFF;
385 info
->bmiColors
[0].rgbGreen
= 0;
386 info
->bmiColors
[0].rgbBlue
= 0;
387 info
->bmiColors
[1].rgbRed
= 0;
388 info
->bmiColors
[1].rgbGreen
= 0xFF;
389 info
->bmiColors
[1].rgbBlue
= 0;
391 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
392 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, screen_depth
, FALSE
);
393 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, screen_depth
, FALSE
);
394 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, screen_depth
, FALSE
);
395 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, screen_depth
, FALSE
);
398 info
->bmiHeader
.biBitCount
= 1;
399 info
->bmiColors
[0].rgbRed
= 0;
400 info
->bmiColors
[0].rgbGreen
= 0;
401 info
->bmiColors
[0].rgbBlue
= 0;
402 info
->bmiColors
[1].rgbRed
= 0xFF;
403 info
->bmiColors
[1].rgbGreen
= 0xFF;
404 info
->bmiColors
[1].rgbBlue
= 0xFF;
406 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
407 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, 1, FALSE
);
408 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, 1, FALSE
);
409 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, 1, FALSE
);
410 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, 1, FALSE
);
413 info
->bmiHeader
.biBitCount
= 1;
414 info
->bmiColors
[0].rgbRed
= 0xFF;
415 info
->bmiColors
[0].rgbGreen
= 0xFF;
416 info
->bmiColors
[0].rgbBlue
= 0xFF;
417 info
->bmiColors
[1].rgbRed
= 0;
418 info
->bmiColors
[1].rgbGreen
= 0;
419 info
->bmiColors
[1].rgbBlue
= 0;
421 dib
= CreateDIBSection(NULL
, info
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
422 test_CopyImage_Check(dib
, 0, 0, 0, 2, 2, 1, FALSE
);
423 test_CopyImage_Check(dib
, 0, 5, 0, 5, 2, 1, FALSE
);
424 test_CopyImage_Check(dib
, 0, 0, 5, 2, 5, 1, FALSE
);
425 test_CopyImage_Check(dib
, 0, 5, 5, 5, 5, 1, FALSE
);
430 HeapFree(GetProcessHeap(), 0, info
);
433 static void test_initial_cursor(void)
435 HCURSOR cursor
, cursor2
;
438 cursor
= GetCursor();
440 /* Check what handle GetCursor() returns if a cursor is not set yet. */
441 SetLastError(0xdeadbeef);
442 cursor2
= LoadCursor(NULL
, IDC_WAIT
);
444 ok(cursor
== cursor2
, "cursor (%p) is not IDC_WAIT (%p).\n", cursor
, cursor2
);
446 error
= GetLastError();
447 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
450 static void test_icon_info_dbg(HICON hIcon
, UINT exp_cx
, UINT exp_cy
, UINT exp_bpp
, int line
)
454 BITMAP bmMask
, bmColor
;
456 ret
= GetIconInfo(hIcon
, &info
);
457 ok_(__FILE__
, line
)(ret
, "GetIconInfo failed\n");
459 /* CreateIcon under XP causes info.fIcon to be 0 */
460 ok_(__FILE__
, line
)(info
.xHotspot
== exp_cx
/2, "info.xHotspot = %u\n", info
.xHotspot
);
461 ok_(__FILE__
, line
)(info
.yHotspot
== exp_cy
/2, "info.yHotspot = %u\n", info
.yHotspot
);
462 ok_(__FILE__
, line
)(info
.hbmMask
!= 0, "info.hbmMask is NULL\n");
464 ret
= GetObject(info
.hbmMask
, sizeof(bmMask
), &bmMask
);
465 ok_(__FILE__
, line
)(ret
== sizeof(bmMask
), "GetObject(info.hbmMask) failed, ret %u\n", ret
);
468 ok_(__FILE__
, line
)(info
.hbmColor
== 0, "info.hbmColor should be NULL\n");
476 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
479 ret
= GetObject(info
.hbmColor
, sizeof(bmColor
), &bmColor
);
480 ok_(__FILE__
, line
)(ret
== sizeof(bmColor
), "GetObject(info.hbmColor) failed, ret %u\n", ret
);
482 ok_(__FILE__
, line
)(bmColor
.bmBitsPixel
== display_bpp
/* XP */ ||
483 bmColor
.bmBitsPixel
== exp_bpp
/* Win98 */,
484 "bmColor.bmBitsPixel = %d\n", bmColor
.bmBitsPixel
);
485 ok_(__FILE__
, line
)(bmColor
.bmWidth
== exp_cx
, "bmColor.bmWidth = %d\n", bmColor
.bmWidth
);
486 ok_(__FILE__
, line
)(bmColor
.bmHeight
== exp_cy
, "bmColor.bmHeight = %d\n", bmColor
.bmHeight
);
488 ok_(__FILE__
, line
)(bmMask
.bmBitsPixel
== 1, "bmMask.bmBitsPixel = %d\n", bmMask
.bmBitsPixel
);
489 ok_(__FILE__
, line
)(bmMask
.bmWidth
== exp_cx
, "bmMask.bmWidth = %d\n", bmMask
.bmWidth
);
490 ok_(__FILE__
, line
)(bmMask
.bmHeight
== exp_cy
, "bmMask.bmHeight = %d\n", bmMask
.bmHeight
);
494 ok_(__FILE__
, line
)(bmMask
.bmBitsPixel
== 1, "bmMask.bmBitsPixel = %d\n", bmMask
.bmBitsPixel
);
495 ok_(__FILE__
, line
)(bmMask
.bmWidth
== exp_cx
, "bmMask.bmWidth = %d\n", bmMask
.bmWidth
);
496 ok_(__FILE__
, line
)(bmMask
.bmHeight
== exp_cy
* 2, "bmMask.bmHeight = %d\n", bmMask
.bmHeight
);
500 #define test_icon_info(a,b,c,d) test_icon_info_dbg((a),(b),(c),(d),__LINE__)
502 static void test_CreateIcon(void)
504 static const BYTE bmp_bits
[1024];
506 HBITMAP hbmMask
, hbmColor
;
514 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
516 /* these crash under XP
517 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
518 hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits);
521 hIcon
= CreateIcon(0, 16, 16, 1, 1, bmp_bits
, bmp_bits
);
522 ok(hIcon
!= 0, "CreateIcon failed\n");
523 test_icon_info(hIcon
, 16, 16, 1);
526 hIcon
= CreateIcon(0, 16, 16, 1, display_bpp
, bmp_bits
, bmp_bits
);
527 ok(hIcon
!= 0, "CreateIcon failed\n");
528 test_icon_info(hIcon
, 16, 16, display_bpp
);
531 hbmMask
= CreateBitmap(16, 16, 1, 1, bmp_bits
);
532 ok(hbmMask
!= 0, "CreateBitmap failed\n");
533 hbmColor
= CreateBitmap(16, 16, 1, display_bpp
, bmp_bits
);
534 ok(hbmColor
!= 0, "CreateBitmap failed\n");
541 SetLastError(0xdeadbeaf);
542 hIcon
= CreateIconIndirect(&info
);
543 ok(!hIcon
, "CreateIconIndirect should fail\n");
544 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
550 info
.hbmColor
= hbmColor
;
551 SetLastError(0xdeadbeaf);
552 hIcon
= CreateIconIndirect(&info
);
553 ok(!hIcon
, "CreateIconIndirect should fail\n");
554 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
559 info
.hbmMask
= hbmMask
;
560 info
.hbmColor
= hbmColor
;
561 hIcon
= CreateIconIndirect(&info
);
562 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
563 test_icon_info(hIcon
, 16, 16, display_bpp
);
566 DeleteObject(hbmMask
);
567 DeleteObject(hbmColor
);
569 hbmMask
= CreateBitmap(16, 32, 1, 1, bmp_bits
);
570 ok(hbmMask
!= 0, "CreateBitmap failed\n");
575 info
.hbmMask
= hbmMask
;
577 SetLastError(0xdeadbeaf);
578 hIcon
= CreateIconIndirect(&info
);
579 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
580 test_icon_info(hIcon
, 16, 16, 1);
583 DeleteObject(hbmMask
);
584 DeleteObject(hbmColor
);
586 /* test creating an icon from a DIB section */
588 bmpinfo
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, FIELD_OFFSET(BITMAPINFO
,bmiColors
[256]));
589 bmpinfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
590 bmpinfo
->bmiHeader
.biWidth
= 32;
591 bmpinfo
->bmiHeader
.biHeight
= 32;
592 bmpinfo
->bmiHeader
.biPlanes
= 1;
593 bmpinfo
->bmiHeader
.biBitCount
= 8;
594 bmpinfo
->bmiHeader
.biCompression
= BI_RGB
;
595 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
596 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
598 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
599 bmpinfo
->bmiHeader
.biBitCount
= 1;
600 hbmMask
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
601 ok(hbmMask
!= NULL
, "Expected a handle to the DIB\n");
603 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
608 info
.hbmMask
= hbmColor
;
609 info
.hbmColor
= hbmMask
;
610 SetLastError(0xdeadbeaf);
611 hIcon
= CreateIconIndirect(&info
);
612 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
613 test_icon_info(hIcon
, 32, 32, 8);
615 DeleteObject(hbmColor
);
617 bmpinfo
->bmiHeader
.biBitCount
= 16;
618 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
619 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
621 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
626 info
.hbmMask
= hbmColor
;
627 info
.hbmColor
= hbmMask
;
628 SetLastError(0xdeadbeaf);
629 hIcon
= CreateIconIndirect(&info
);
630 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
631 test_icon_info(hIcon
, 32, 32, 8);
633 DeleteObject(hbmColor
);
635 bmpinfo
->bmiHeader
.biBitCount
= 32;
636 hbmColor
= CreateDIBSection( hdc
, bmpinfo
, DIB_RGB_COLORS
, &bits
, NULL
, 0 );
637 ok(hbmColor
!= NULL
, "Expected a handle to the DIB\n");
639 memset( bits
, 0x55, 32 * 32 * bmpinfo
->bmiHeader
.biBitCount
/ 8 );
644 info
.hbmMask
= hbmColor
;
645 info
.hbmColor
= hbmMask
;
646 SetLastError(0xdeadbeaf);
647 hIcon
= CreateIconIndirect(&info
);
648 ok(hIcon
!= 0, "CreateIconIndirect failed\n");
649 test_icon_info(hIcon
, 32, 32, 8);
652 DeleteObject(hbmMask
);
653 DeleteObject(hbmColor
);
654 HeapFree( GetProcessHeap(), 0, bmpinfo
);
659 /* Shamelessly ripped from dlls/oleaut32/tests/olepicture.c */
661 static const unsigned char gifimage
[35] = {
662 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
663 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
668 static const unsigned char jpgimage
[285] = {
669 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
670 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
671 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
672 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
673 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
674 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
675 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
676 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
677 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
678 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
679 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
680 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
681 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
682 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
683 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
684 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
685 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
686 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
690 static const unsigned char pngimage
[285] = {
691 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
692 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
693 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
694 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
695 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
696 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
697 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
701 static const unsigned char bmpimage
[66] = {
702 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
703 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
704 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
705 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
710 static const unsigned char gif4pixel
[42] = {
711 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
712 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
713 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
716 static void test_LoadImageFile(const unsigned char * image_data
,
717 unsigned int image_size
, const char * ext
, BOOL expect_success
)
721 DWORD error
, bytes_written
;
724 strcpy(filename
, "test.");
725 strcat(filename
, ext
);
727 /* Create the test image. */
728 handle
= CreateFileA(filename
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
729 FILE_ATTRIBUTE_NORMAL
, NULL
);
730 ok(handle
!= INVALID_HANDLE_VALUE
, "CreateFileA failed. %u\n", GetLastError());
731 ret
= WriteFile(handle
, image_data
, image_size
, &bytes_written
, NULL
);
732 ok(bytes_written
== image_size
, "test file created improperly.\n");
735 /* Load as cursor. For all tested formats, this should fail */
736 SetLastError(0xdeadbeef);
737 handle
= LoadImageA(NULL
, filename
, IMAGE_CURSOR
, 0, 0, LR_LOADFROMFILE
);
738 ok(handle
== NULL
, "LoadImage(%s) as IMAGE_CURSOR succeeded incorrectly.\n", ext
);
739 error
= GetLastError();
740 ok(error
== 0, "Last error: %u\n", error
);
741 if (handle
!= NULL
) DestroyCursor(handle
);
743 /* Load as icon. For all tested formats, this should fail */
744 SetLastError(0xdeadbeef);
745 handle
= LoadImageA(NULL
, filename
, IMAGE_ICON
, 0, 0, LR_LOADFROMFILE
);
746 ok(handle
== NULL
, "LoadImage(%s) as IMAGE_ICON succeeded incorrectly.\n", ext
);
747 error
= GetLastError();
748 ok(error
== 0, "Last error: %u\n", error
);
749 if (handle
!= NULL
) DestroyIcon(handle
);
751 /* Load as bitmap. Should succeed if bmp, fail for everything else */
752 SetLastError(0xdeadbeef);
753 handle
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
);
755 ok(handle
!= NULL
, "LoadImage(%s) as IMAGE_BITMAP failed.\n", ext
);
756 else ok(handle
== NULL
, "LoadImage(%s) as IMAGE_BITMAP succeeded incorrectly.\n", ext
);
757 error
= GetLastError();
758 ok(error
== 0, "Last error: %u\n", error
);
759 if (handle
!= NULL
) DeleteObject(handle
);
761 DeleteFileA(filename
);
764 static void test_LoadImage(void)
768 DWORD error
, bytes_written
;
769 CURSORICONFILEDIR
*icon_data
;
770 CURSORICONFILEDIRENTRY
*icon_entry
;
771 BITMAPINFOHEADER
*icon_header
;
774 #define ICON_WIDTH 32
775 #define ICON_HEIGHT 32
776 #define ICON_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
779 (sizeof(CURSORICONFILEDIR) + sizeof(BITMAPINFOHEADER) \
780 + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
783 icon_data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ICON_SIZE
);
784 icon_data
->idReserved
= 0;
785 icon_data
->idType
= 1;
786 icon_data
->idCount
= 1;
788 icon_entry
= icon_data
->idEntries
;
789 icon_entry
->bWidth
= ICON_WIDTH
;
790 icon_entry
->bHeight
= ICON_HEIGHT
;
791 icon_entry
->bColorCount
= 0;
792 icon_entry
->bReserved
= 0;
793 icon_entry
->xHotspot
= 1;
794 icon_entry
->yHotspot
= 1;
795 icon_entry
->dwDIBSize
= ICON_SIZE
- sizeof(CURSORICONFILEDIR
);
796 icon_entry
->dwDIBOffset
= sizeof(CURSORICONFILEDIR
);
798 icon_header
= (BITMAPINFOHEADER
*) ((BYTE
*) icon_data
+ icon_entry
->dwDIBOffset
);
799 icon_header
->biSize
= sizeof(BITMAPINFOHEADER
);
800 icon_header
->biWidth
= ICON_WIDTH
;
801 icon_header
->biHeight
= ICON_HEIGHT
*2;
802 icon_header
->biPlanes
= 1;
803 icon_header
->biBitCount
= ICON_BPP
;
804 icon_header
->biSizeImage
= 0; /* Uncompressed bitmap. */
806 /* Create the icon. */
807 handle
= CreateFileA("icon.ico", GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_NEW
,
808 FILE_ATTRIBUTE_NORMAL
, NULL
);
809 ok(handle
!= INVALID_HANDLE_VALUE
, "CreateFileA failed. %u\n", GetLastError());
810 ret
= WriteFile(handle
, icon_data
, ICON_SIZE
, &bytes_written
, NULL
);
811 ok(bytes_written
== ICON_SIZE
, "icon.ico created improperly.\n");
814 /* Test loading an icon as a cursor. */
815 SetLastError(0xdeadbeef);
816 handle
= LoadImageA(NULL
, "icon.ico", IMAGE_CURSOR
, 0, 0, LR_LOADFROMFILE
);
817 ok(handle
!= NULL
, "LoadImage() failed.\n");
818 error
= GetLastError();
819 ok(error
== 0, "Last error: %u\n", error
);
821 /* Test the icon information. */
822 SetLastError(0xdeadbeef);
823 ret
= GetIconInfo(handle
, &icon_info
);
824 ok(ret
, "GetIconInfo() failed.\n");
825 error
= GetLastError();
826 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
830 ok(icon_info
.fIcon
== FALSE
, "fIcon != FALSE.\n");
831 ok(icon_info
.xHotspot
== 1, "xHotspot is %u.\n", icon_info
.xHotspot
);
832 ok(icon_info
.yHotspot
== 1, "yHotspot is %u.\n", icon_info
.yHotspot
);
833 ok(icon_info
.hbmColor
!= NULL
, "No hbmColor!\n");
834 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
838 SetLastError(0xdeadbeef);
839 ret
= DestroyCursor(handle
);
840 ok(ret
, "DestroyCursor() failed.\n");
841 error
= GetLastError();
842 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
844 HeapFree(GetProcessHeap(), 0, icon_data
);
845 DeleteFileA("icon.ico");
847 test_LoadImageFile(bmpimage
, sizeof(bmpimage
), "bmp", 1);
848 test_LoadImageFile(gifimage
, sizeof(gifimage
), "gif", 0);
849 test_LoadImageFile(gif4pixel
, sizeof(gif4pixel
), "gif", 0);
850 test_LoadImageFile(jpgimage
, sizeof(jpgimage
), "jpg", 0);
851 test_LoadImageFile(pngimage
, sizeof(pngimage
), "png", 0);
854 static void test_CreateIconFromResource(void)
859 BITMAPINFOHEADER
*icon_header
;
863 #define ICON_RES_WIDTH 32
864 #define ICON_RES_HEIGHT 32
865 #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
866 #define ICON_RES_BPP 32
867 #define ICON_RES_SIZE \
868 (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
869 #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE)
872 hotspot
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, CRSR_RES_SIZE
);
874 /* Cursor resources have an extra hotspot, icon resources not. */
878 icon_header
= (BITMAPINFOHEADER
*) (hotspot
+ 2);
879 icon_header
->biSize
= sizeof(BITMAPINFOHEADER
);
880 icon_header
->biWidth
= ICON_WIDTH
;
881 icon_header
->biHeight
= ICON_HEIGHT
*2;
882 icon_header
->biPlanes
= 1;
883 icon_header
->biBitCount
= ICON_BPP
;
884 icon_header
->biSizeImage
= 0; /* Uncompressed bitmap. */
886 /* Test creating a cursor. */
887 SetLastError(0xdeadbeef);
888 handle
= CreateIconFromResource((PBYTE
) hotspot
, CRSR_RES_SIZE
, FALSE
, 0x00030000);
889 ok(handle
!= NULL
, "Create cursor failed.\n");
891 /* Test the icon information. */
892 SetLastError(0xdeadbeef);
893 ret
= GetIconInfo(handle
, &icon_info
);
894 ok(ret
, "GetIconInfo() failed.\n");
895 error
= GetLastError();
896 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
900 ok(icon_info
.fIcon
== FALSE
, "fIcon != FALSE.\n");
901 ok(icon_info
.xHotspot
== 3, "xHotspot is %u.\n", icon_info
.xHotspot
);
902 ok(icon_info
.yHotspot
== 3, "yHotspot is %u.\n", icon_info
.yHotspot
);
903 ok(icon_info
.hbmColor
!= NULL
, "No hbmColor!\n");
904 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
908 SetLastError(0xdeadbeef);
909 ret
= DestroyCursor(handle
);
910 ok(ret
, "DestroyCursor() failed.\n");
911 error
= GetLastError();
912 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
914 /* Test creating an icon. */
915 SetLastError(0xdeadbeef);
916 handle
= CreateIconFromResource((PBYTE
) icon_header
, ICON_RES_SIZE
, TRUE
,
918 ok(handle
!= NULL
, "Create icon failed.\n");
920 /* Test the icon information. */
921 SetLastError(0xdeadbeef);
922 ret
= GetIconInfo(handle
, &icon_info
);
923 ok(ret
, "GetIconInfo() failed.\n");
924 error
= GetLastError();
925 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
929 ok(icon_info
.fIcon
== TRUE
, "fIcon != TRUE.\n");
930 /* Icons always have hotspot in the middle */
931 ok(icon_info
.xHotspot
== ICON_WIDTH
/2, "xHotspot is %u.\n", icon_info
.xHotspot
);
932 ok(icon_info
.yHotspot
== ICON_HEIGHT
/2, "yHotspot is %u.\n", icon_info
.yHotspot
);
933 ok(icon_info
.hbmColor
!= NULL
, "No hbmColor!\n");
934 ok(icon_info
.hbmMask
!= NULL
, "No hbmMask!\n");
938 SetLastError(0xdeadbeef);
939 ret
= DestroyCursor(handle
);
940 ok(ret
, "DestroyCursor() failed.\n");
941 error
= GetLastError();
942 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
944 HeapFree(GetProcessHeap(), 0, hotspot
);
947 static void test_DestroyCursor(void)
949 static const BYTE bmp_bits
[4096];
951 HCURSOR cursor
, cursor2
;
958 display_bpp
= GetDeviceCaps(hdc
, BITSPIXEL
);
961 cursorInfo
.fIcon
= FALSE
;
962 cursorInfo
.xHotspot
= 0;
963 cursorInfo
.yHotspot
= 0;
964 cursorInfo
.hbmMask
= CreateBitmap(32, 32, 1, 1, bmp_bits
);
965 cursorInfo
.hbmColor
= CreateBitmap(32, 32, 1, display_bpp
, bmp_bits
);
967 cursor
= CreateIconIndirect(&cursorInfo
);
968 ok(cursor
!= NULL
, "CreateIconIndirect returned %p\n", cursor
);
974 SetLastError(0xdeadbeef);
975 ret
= DestroyCursor(cursor
);
976 ok(!ret
, "DestroyCursor on the active cursor succeeded\n");
977 error
= GetLastError();
978 ok(error
== 0xdeadbeef, "Last error: %u\n", error
);
980 cursor2
= GetCursor();
981 ok(cursor2
== cursor
, "Active was set to %p when trying to destroy it\n", cursor2
);
985 /* Trying to destroy the cursor properly fails now with
986 * ERROR_INVALID_CURSOR_HANDLE. This happens because we called
987 * DestroyCursor() 2+ times after calling SetCursor(). The calls to
988 * GetCursor() and SetCursor(NULL) in between make no difference. */
989 ret
= DestroyCursor(cursor
);
991 ok(!ret
, "DestroyCursor succeeded.\n");
992 error
= GetLastError();
993 ok(error
== ERROR_INVALID_CURSOR_HANDLE
, "Last error: 0x%08x\n", error
);
996 DeleteObject(cursorInfo
.hbmMask
);
997 DeleteObject(cursorInfo
.hbmColor
);
999 /* Try testing DestroyCursor() now using LoadCursor() cursors. */
1000 cursor
= LoadCursor(NULL
, IDC_ARROW
);
1002 SetLastError(0xdeadbeef);
1003 ret
= DestroyCursor(cursor
);
1004 ok(ret
, "DestroyCursor on the active cursor failed.\n");
1005 error
= GetLastError();
1006 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
1008 /* Try setting the cursor to a destroyed OEM cursor. */
1009 SetLastError(0xdeadbeef);
1011 error
= GetLastError();
1013 ok(error
== 0xdeadbeef, "Last error: 0x%08x\n", error
);
1016 /* Check if LoadCursor() returns the same handle with the same icon. */
1017 cursor2
= LoadCursor(NULL
, IDC_ARROW
);
1018 ok(cursor2
== cursor
, "cursor == %p, cursor2 == %p\n", cursor
, cursor2
);
1020 /* Check if LoadCursor() returns the same handle with a different icon. */
1021 cursor2
= LoadCursor(NULL
, IDC_WAIT
);
1022 ok(cursor2
!= cursor
, "cursor == %p, cursor2 == %p\n", cursor
, cursor2
);
1025 START_TEST(cursoricon
)
1027 test_argc
= winetest_get_mainargs(&test_argv
);
1031 /* Child process. */
1032 sscanf (test_argv
[2], "%x", (unsigned int *) &parent
);
1034 ok(parent
!= NULL
, "Parent not found.\n");
1042 test_CopyImage_Bitmap(1);
1043 test_CopyImage_Bitmap(4);
1044 test_CopyImage_Bitmap(8);
1045 test_CopyImage_Bitmap(16);
1046 test_CopyImage_Bitmap(24);
1047 test_CopyImage_Bitmap(32);
1048 test_initial_cursor();
1051 test_CreateIconFromResource();
1052 test_DestroyCursor();
1054 test_child_process();
1055 finish_child_process();