user32: Select more appropriate stretch mode for colored images interpolation.
[wine.git] / dlls / user32 / tests / cursoricon.c
blob8ce1eb163e11309f604ac6e5c141cc5a1cdfc380
1 /*
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
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "wine/test.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "wingdi.h"
32 #include "winuser.h"
34 #include "pshpack1.h"
36 typedef struct
38 BYTE bWidth;
39 BYTE bHeight;
40 BYTE bColorCount;
41 BYTE bReserved;
42 WORD xHotspot;
43 WORD yHotspot;
44 DWORD dwDIBSize;
45 DWORD dwDIBOffset;
46 } CURSORICONFILEDIRENTRY;
48 typedef struct
50 WORD idReserved;
51 WORD idType;
52 WORD idCount;
53 CURSORICONFILEDIRENTRY idEntries[1];
54 } CURSORICONFILEDIR;
56 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
57 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
58 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
60 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
61 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
62 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
63 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
64 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
65 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
66 #define ANI_icon_ID RIFF_FOURCC('i', 'c', 'o', 'n')
67 #define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
69 #define ANI_FLAG_ICON 0x1
70 #define ANI_FLAG_SEQUENCE 0x2
72 typedef struct {
73 DWORD header_size;
74 DWORD num_frames;
75 DWORD num_steps;
76 DWORD width;
77 DWORD height;
78 DWORD bpp;
79 DWORD num_planes;
80 DWORD display_rate;
81 DWORD flags;
82 } ani_header;
84 typedef struct {
85 BYTE data[32*32*4];
86 BYTE mask_data[32*32/8];
87 } ani_data32x32x32;
89 typedef struct {
90 CURSORICONFILEDIR icon_info; /* animated cursor frame information */
91 BITMAPINFOHEADER bmi_header; /* animated cursor frame header */
92 ani_data32x32x32 bmi_data; /* animated cursor frame DIB data */
93 } ani_frame32x32x32;
95 typedef struct {
96 DWORD chunk_id; /* ANI_anih_ID */
97 DWORD chunk_size; /* actual size of data */
98 ani_header header; /* animated cursor header */
99 } riff_header_t;
101 typedef struct {
102 DWORD chunk_id; /* ANI_LIST_ID */
103 DWORD chunk_size; /* actual size of data */
104 DWORD chunk_type; /* ANI_fram_ID */
105 } riff_list_t;
107 typedef struct {
108 DWORD chunk_id; /* ANI_icon_ID */
109 DWORD chunk_size; /* actual size of data */
110 ani_frame32x32x32 data; /* animated cursor frame */
111 } riff_icon32x32x32_t;
113 typedef struct {
114 DWORD chunk_id; /* ANI_RIFF_ID */
115 DWORD chunk_size; /* actual size of data */
116 DWORD chunk_type; /* ANI_ACON_ID */
117 riff_header_t header; /* RIFF animated cursor header */
118 riff_list_t frame_list; /* RIFF animated cursor frame list info */
119 riff_icon32x32x32_t frames[1]; /* array of animated cursor frames */
120 } riff_cursor1_t;
122 typedef struct {
123 DWORD chunk_id; /* ANI_RIFF_ID */
124 DWORD chunk_size; /* actual size of data */
125 DWORD chunk_type; /* ANI_ACON_ID */
126 riff_header_t header; /* RIFF animated cursor header */
127 riff_list_t frame_list; /* RIFF animated cursor frame list info */
128 riff_icon32x32x32_t frames[3]; /* array of three animated cursor frames */
129 } riff_cursor3_t;
131 typedef struct {
132 DWORD chunk_id; /* ANI_rate_ID */
133 DWORD chunk_size; /* actual size of data */
134 DWORD rate[3]; /* animated cursor rate data */
135 } riff_rate3_t;
137 typedef struct {
138 DWORD chunk_id; /* ANI_seq__ID */
139 DWORD chunk_size; /* actual size of data */
140 DWORD order[3]; /* animated cursor sequence data */
141 } riff_seq3_t;
143 typedef struct {
144 DWORD chunk_id; /* ANI_RIFF_ID */
145 DWORD chunk_size; /* actual size of data */
146 DWORD chunk_type; /* ANI_ACON_ID */
147 riff_header_t header; /* RIFF animated cursor header */
148 riff_seq3_t seq; /* sequence data for three cursor frames */
149 riff_rate3_t rates; /* rate data for three cursor frames */
150 riff_list_t frame_list; /* RIFF animated cursor frame list info */
151 riff_icon32x32x32_t frames[3]; /* array of three animated cursor frames */
152 } riff_cursor3_seq_t;
154 #define EMPTY_ICON32 \
156 ANI_icon_ID, \
157 sizeof(ani_frame32x32x32), \
160 0x0, /* reserved */ \
161 0, /* type: icon(1), cursor(2) */ \
162 1, /* count */ \
165 32, /* width */ \
166 32, /* height */ \
167 0, /* color count */ \
168 0x0, /* reserved */ \
169 16, /* x hotspot */ \
170 16, /* y hotspot */ \
171 sizeof(ani_data32x32x32), /* DIB size */ \
172 sizeof(CURSORICONFILEDIR) /* DIB offset */ \
175 }, \
177 sizeof(BITMAPINFOHEADER), /* structure for DIB-type data */ \
178 32, /* width */ \
179 32*2, /* actual height times two */ \
180 1, /* planes */ \
181 32, /* bpp */ \
182 BI_RGB, /* compression */ \
183 0, /* image size */ \
184 0, /* biXPelsPerMeter */ \
185 0, /* biYPelsPerMeter */ \
186 0, /* biClrUsed */ \
187 0 /* biClrImportant */ \
189 /* DIB data: left uninitialized */ \
193 riff_cursor1_t empty_anicursor = {
194 ANI_RIFF_ID,
195 sizeof(empty_anicursor) - sizeof(DWORD)*2,
196 ANI_ACON_ID,
198 ANI_anih_ID,
199 sizeof(ani_header),
201 sizeof(ani_header),
202 1, /* frames */
203 1, /* steps */
204 32, /* width */
205 32, /* height */
206 32, /* depth */
207 1, /* planes */
208 10, /* display rate in jiffies */
209 ANI_FLAG_ICON /* flags */
213 ANI_LIST_ID,
214 sizeof(riff_icon32x32x32_t)*(1 /*frames*/) + sizeof(DWORD),
215 ANI_fram_ID,
218 EMPTY_ICON32
222 riff_cursor3_t empty_anicursor3 = {
223 ANI_RIFF_ID,
224 sizeof(empty_anicursor3) - sizeof(DWORD)*2,
225 ANI_ACON_ID,
227 ANI_anih_ID,
228 sizeof(ani_header),
230 sizeof(ani_header),
231 3, /* frames */
232 3, /* steps */
233 32, /* width */
234 32, /* height */
235 32, /* depth */
236 1, /* planes */
237 0xbeef, /* display rate in jiffies */
238 ANI_FLAG_ICON /* flags */
242 ANI_LIST_ID,
243 sizeof(riff_icon32x32x32_t)*(3 /*frames*/) + sizeof(DWORD),
244 ANI_fram_ID,
247 EMPTY_ICON32,
248 EMPTY_ICON32,
249 EMPTY_ICON32
253 riff_cursor3_seq_t empty_anicursor3_seq = {
254 ANI_RIFF_ID,
255 sizeof(empty_anicursor3_seq) - sizeof(DWORD)*2,
256 ANI_ACON_ID,
258 ANI_anih_ID,
259 sizeof(ani_header),
261 sizeof(ani_header),
262 3, /* frames */
263 3, /* steps */
264 32, /* width */
265 32, /* height */
266 32, /* depth */
267 1, /* planes */
268 0xbeef, /* display rate in jiffies */
269 ANI_FLAG_ICON|ANI_FLAG_SEQUENCE /* flags */
273 ANI_seq__ID,
274 sizeof(riff_seq3_t) - sizeof(DWORD)*2,
275 { 2, 0, 1} /* show frames in a uniquely identifiable order */
278 ANI_rate_ID,
279 sizeof(riff_rate3_t) - sizeof(DWORD)*2,
280 { 0xc0de, 0xcafe, 0xbabe}
283 ANI_LIST_ID,
284 sizeof(riff_icon32x32x32_t)*(3 /*frames*/) + sizeof(DWORD),
285 ANI_fram_ID,
288 EMPTY_ICON32,
289 EMPTY_ICON32,
290 EMPTY_ICON32
294 #include "poppack.h"
296 static char **test_argv;
297 static int test_argc;
298 static HWND child = 0;
299 static HWND parent = 0;
300 static HANDLE child_process;
302 #define PROC_INIT (WM_USER+1)
304 static BOOL (WINAPI *pGetCursorInfo)(CURSORINFO *);
305 static BOOL (WINAPI *pGetIconInfoExA)(HICON,ICONINFOEXA *);
306 static BOOL (WINAPI *pGetIconInfoExW)(HICON,ICONINFOEXW *);
308 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
310 static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
312 switch (msg)
314 /* Destroy the cursor. */
315 case WM_USER+1:
317 HCURSOR cursor = (HCURSOR)lParam;
318 ICONINFO info;
319 BOOL ret;
320 DWORD error;
322 memset(&info, 0, sizeof(info));
323 ret = GetIconInfo(cursor, &info);
324 todo_wine ok(ret, "GetIconInfoEx failed with error %u\n", GetLastError());
325 todo_wine ok(info.hbmColor != NULL, "info.hmbColor was not set\n");
326 todo_wine ok(info.hbmMask != NULL, "info.hmbColor was not set\n");
327 DeleteObject(info.hbmColor);
328 DeleteObject(info.hbmMask);
330 SetLastError(0xdeadbeef);
331 ret = DestroyCursor(cursor);
332 error = GetLastError();
333 ok(!ret || broken(ret) /* win9x */, "DestroyCursor on the active cursor succeeded.\n");
334 ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD ||
335 error == 0xdeadbeef, /* vista */
336 "Last error: %u\n", error);
337 return TRUE;
339 case WM_DESTROY:
340 PostQuitMessage(0);
341 return 0;
344 return DefWindowProcA(hwnd, msg, wParam, lParam);
347 static LRESULT CALLBACK callback_parent(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
349 if (msg == PROC_INIT)
351 child = (HWND) wParam;
352 return TRUE;
355 return DefWindowProcA(hwnd, msg, wParam, lParam);
358 static void do_child(void)
360 WNDCLASSA class;
361 MSG msg;
362 BOOL ret;
364 /* Register a new class. */
365 class.style = CS_GLOBALCLASS;
366 class.lpfnWndProc = callback_child;
367 class.cbClsExtra = 0;
368 class.cbWndExtra = 0;
369 class.hInstance = GetModuleHandleA(NULL);
370 class.hIcon = NULL;
371 class.hCursor = NULL;
372 class.hbrBackground = NULL;
373 class.lpszMenuName = NULL;
374 class.lpszClassName = "cursor_child";
376 SetLastError(0xdeadbeef);
377 ret = RegisterClassA(&class);
378 ok(ret, "Failed to register window class. Error: %u\n", GetLastError());
380 /* Create a window. */
381 child = CreateWindowA("cursor_child", "cursor_child", WS_POPUP | WS_VISIBLE,
382 0, 0, 200, 200, 0, 0, 0, NULL);
383 ok(child != 0, "CreateWindowA failed. Error: %u\n", GetLastError());
385 /* Let the parent know our HWND. */
386 PostMessageA(parent, PROC_INIT, (WPARAM) child, 0);
388 /* Receive messages. */
389 while ((ret = GetMessageA(&msg, 0, 0, 0)))
391 ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError());
392 TranslateMessage(&msg);
393 DispatchMessageA(&msg);
397 static void do_parent(void)
399 char path_name[MAX_PATH];
400 PROCESS_INFORMATION info;
401 STARTUPINFOA startup;
402 WNDCLASSA class;
403 MSG msg;
404 BOOL ret;
406 /* Register a new class. */
407 class.style = CS_GLOBALCLASS;
408 class.lpfnWndProc = callback_parent;
409 class.cbClsExtra = 0;
410 class.cbWndExtra = 0;
411 class.hInstance = GetModuleHandleA(NULL);
412 class.hIcon = NULL;
413 class.hCursor = NULL;
414 class.hbrBackground = NULL;
415 class.lpszMenuName = NULL;
416 class.lpszClassName = "cursor_parent";
418 SetLastError(0xdeadbeef);
419 ret = RegisterClassA(&class);
420 ok(ret, "Failed to register window class. Error: %u\n", GetLastError());
422 /* Create a window. */
423 parent = CreateWindowA("cursor_parent", "cursor_parent", WS_POPUP | WS_VISIBLE,
424 0, 0, 200, 200, 0, 0, 0, NULL);
425 ok(parent != 0, "CreateWindowA failed. Error: %u\n", GetLastError());
427 /* Start child process. */
428 memset(&startup, 0, sizeof(startup));
429 startup.cb = sizeof(startup);
430 startup.dwFlags = STARTF_USESHOWWINDOW;
431 startup.wShowWindow = SW_SHOWNORMAL;
433 sprintf(path_name, "%s cursoricon %lx", test_argv[0], (INT_PTR)parent);
434 ok(CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed.\n");
435 child_process = info.hProcess;
437 /* Wait for child window handle. */
438 while ((child == 0) && (ret = GetMessageA(&msg, parent, 0, 0)))
440 ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError());
441 TranslateMessage(&msg);
442 DispatchMessageA(&msg);
446 static void finish_child_process(void)
448 SendMessageA(child, WM_CLOSE, 0, 0);
449 winetest_wait_child_process( child_process );
450 CloseHandle(child_process);
453 static void test_child_process(void)
455 static const BYTE bmp_bits[4096];
456 HCURSOR cursor;
457 ICONINFO cursorInfo;
458 UINT display_bpp;
459 HDC hdc;
461 /* Create and set a dummy cursor. */
462 hdc = GetDC(0);
463 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
464 ReleaseDC(0, hdc);
466 cursorInfo.fIcon = FALSE;
467 cursorInfo.xHotspot = 0;
468 cursorInfo.yHotspot = 0;
469 cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
470 cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
472 cursor = CreateIconIndirect(&cursorInfo);
473 ok(cursor != NULL, "CreateIconIndirect returned %p.\n", cursor);
475 SetCursor(cursor);
477 /* Destroy the cursor. */
478 SendMessageA(child, WM_USER+1, 0, (LPARAM) cursor);
481 static BOOL color_match(COLORREF a, COLORREF b)
483 /* 5-bit accuracy is a sufficient test. This will match as long as
484 * colors are never truncated to less that 3x5-bit accuracy i.e.
485 * palettized. */
486 return (a & 0x00F8F8F8) == (b & 0x00F8F8F8);
489 static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight,
490 INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected)
492 HBITMAP copy;
493 BITMAP origBitmap;
494 BITMAP copyBitmap;
495 BOOL orig_is_dib;
496 BOOL copy_is_dib;
498 copy = CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
499 ok(copy != NULL, "CopyImage() failed\n");
500 if (copy != NULL)
502 GetObjectA(bitmap, sizeof(origBitmap), &origBitmap);
503 GetObjectA(copy, sizeof(copyBitmap), &copyBitmap);
504 orig_is_dib = (origBitmap.bmBits != NULL);
505 copy_is_dib = (copyBitmap.bmBits != NULL);
507 if (copy_is_dib && dibExpected
508 && copyBitmap.bmBitsPixel == 24
509 && (expectedDepth == 16 || expectedDepth == 32))
511 /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
512 if (GetVersion() & 0x80000000)
514 expectedDepth = 24;
518 if (copy_is_dib && !dibExpected && !(flags & LR_CREATEDIBSECTION))
520 /* It's not forbidden to create a DIB section if the flag
521 LR_CREATEDIBSECTION is absent.
522 Windows 9x does this if the bitmap has a depth that doesn't
523 match the screen depth, Windows NT doesn't */
524 dibExpected = TRUE;
525 expectedDepth = origBitmap.bmBitsPixel;
528 ok((!(dibExpected ^ copy_is_dib)
529 && (copyBitmap.bmWidth == expectedWidth)
530 && (copyBitmap.bmHeight == expectedHeight)
531 && (copyBitmap.bmBitsPixel == expectedDepth)),
532 "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
533 orig_is_dib ? "DIB" : "DDB", origBitmap.bmWidth, origBitmap.bmHeight, origBitmap.bmBitsPixel,
534 copyWidth, copyHeight, flags,
535 dibExpected ? "DIB" : "DDB", expectedWidth, expectedHeight, expectedDepth,
536 copy_is_dib ? "DIB" : "DDB", copyBitmap.bmWidth, copyBitmap.bmHeight, copyBitmap.bmBitsPixel);
538 DeleteObject(copy);
542 static void test_CopyImage_Bitmap(int depth)
544 HBITMAP ddb, dib;
545 HDC screenDC;
546 BITMAPINFO * info;
547 VOID * bits;
548 int screen_depth;
549 unsigned int i;
551 /* Create a device-independent bitmap (DIB) */
552 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
553 info->bmiHeader.biSize = sizeof(info->bmiHeader);
554 info->bmiHeader.biWidth = 2;
555 info->bmiHeader.biHeight = 2;
556 info->bmiHeader.biPlanes = 1;
557 info->bmiHeader.biBitCount = depth;
558 info->bmiHeader.biCompression = BI_RGB;
560 for (i=0; i < 256; i++)
562 info->bmiColors[i].rgbRed = i;
563 info->bmiColors[i].rgbGreen = i;
564 info->bmiColors[i].rgbBlue = 255 - i;
565 info->bmiColors[i].rgbReserved = 0;
568 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
570 /* Create a device-dependent bitmap (DDB) */
571 screenDC = GetDC(NULL);
572 screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
573 if (depth == 1 || depth == screen_depth)
575 ddb = CreateBitmap(2, 2, 1, depth, NULL);
577 else
579 ddb = NULL;
581 ReleaseDC(NULL, screenDC);
583 if (ddb != NULL)
585 test_CopyImage_Check(ddb, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE);
586 test_CopyImage_Check(ddb, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE);
587 test_CopyImage_Check(ddb, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE);
588 test_CopyImage_Check(ddb, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE);
590 test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
591 test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
592 test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
593 test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
595 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
596 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
597 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
598 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
600 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
601 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
602 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
603 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
604 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
606 DeleteObject(ddb);
609 if (depth != 1)
611 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
612 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
613 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
614 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
617 test_CopyImage_Check(dib, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
618 test_CopyImage_Check(dib, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
619 test_CopyImage_Check(dib, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
620 test_CopyImage_Check(dib, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
622 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
623 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
624 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
625 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
627 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
628 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
629 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
630 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
631 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
633 DeleteObject(dib);
635 if (depth == 1)
637 /* Special case: A monochrome DIB is converted to a monochrome DDB if
638 the colors in the color table are black and white.
640 Skip this test on Windows 95, it always creates a monochrome DDB
641 in this case */
643 if (!(GetVersion() & 0x80000000))
645 info->bmiHeader.biBitCount = 1;
646 info->bmiColors[0].rgbRed = 0xFF;
647 info->bmiColors[0].rgbGreen = 0;
648 info->bmiColors[0].rgbBlue = 0;
649 info->bmiColors[1].rgbRed = 0;
650 info->bmiColors[1].rgbGreen = 0xFF;
651 info->bmiColors[1].rgbBlue = 0;
653 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
654 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
655 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
656 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
657 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
658 DeleteObject(dib);
660 info->bmiHeader.biBitCount = 1;
661 info->bmiColors[0].rgbRed = 0;
662 info->bmiColors[0].rgbGreen = 0;
663 info->bmiColors[0].rgbBlue = 0;
664 info->bmiColors[1].rgbRed = 0xFF;
665 info->bmiColors[1].rgbGreen = 0xFF;
666 info->bmiColors[1].rgbBlue = 0xFF;
668 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
669 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
670 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
671 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
672 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
673 DeleteObject(dib);
675 info->bmiHeader.biBitCount = 1;
676 info->bmiColors[0].rgbRed = 0xFF;
677 info->bmiColors[0].rgbGreen = 0xFF;
678 info->bmiColors[0].rgbBlue = 0xFF;
679 info->bmiColors[1].rgbRed = 0;
680 info->bmiColors[1].rgbGreen = 0;
681 info->bmiColors[1].rgbBlue = 0;
683 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
684 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
685 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
686 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
687 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
688 DeleteObject(dib);
692 HeapFree(GetProcessHeap(), 0, info);
695 static void test_initial_cursor(void)
697 HCURSOR cursor, cursor2;
698 DWORD error;
700 cursor = GetCursor();
702 /* Check what handle GetCursor() returns if a cursor is not set yet. */
703 SetLastError(0xdeadbeef);
704 cursor2 = LoadCursorA(NULL, (LPCSTR)IDC_WAIT);
705 todo_wine {
706 ok(cursor == cursor2, "cursor (%p) is not IDC_WAIT (%p).\n", cursor, cursor2);
708 error = GetLastError();
709 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
712 static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_mask_cy, UINT exp_bpp, int line)
714 ICONINFO info;
715 DWORD ret;
716 BITMAP bmMask, bmColor;
718 ret = GetIconInfo(hIcon, &info);
719 ok_(__FILE__, line)(ret, "GetIconInfo failed\n");
721 /* CreateIcon under XP causes info.fIcon to be 0 */
722 ok_(__FILE__, line)(info.xHotspot == exp_cx/2, "info.xHotspot = %u\n", info.xHotspot);
723 ok_(__FILE__, line)(info.yHotspot == exp_cy/2, "info.yHotspot = %u\n", info.yHotspot);
724 ok_(__FILE__, line)(info.hbmMask != 0, "info.hbmMask is NULL\n");
726 ret = GetObjectA(info.hbmMask, sizeof(bmMask), &bmMask);
727 ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %u\n", ret);
729 if (exp_bpp == 1)
730 ok_(__FILE__, line)(info.hbmColor == 0, "info.hbmColor should be NULL\n");
732 if (info.hbmColor)
734 HDC hdc;
735 UINT display_bpp;
737 hdc = GetDC(0);
738 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
739 ReleaseDC(0, hdc);
741 ret = GetObjectA(info.hbmColor, sizeof(bmColor), &bmColor);
742 ok_(__FILE__, line)(ret == sizeof(bmColor), "GetObject(info.hbmColor) failed, ret %u\n", ret);
744 ok_(__FILE__, line)(bmColor.bmBitsPixel == display_bpp /* XP */ ||
745 bmColor.bmBitsPixel == exp_bpp /* Win98 */,
746 "bmColor.bmBitsPixel = %d\n", bmColor.bmBitsPixel);
747 ok_(__FILE__, line)(bmColor.bmWidth == exp_cx, "bmColor.bmWidth = %d\n", bmColor.bmWidth);
748 ok_(__FILE__, line)(bmColor.bmHeight == exp_cy, "bmColor.bmHeight = %d\n", bmColor.bmHeight);
750 ok_(__FILE__, line)(bmMask.bmBitsPixel == 1, "bmMask.bmBitsPixel = %d\n", bmMask.bmBitsPixel);
751 ok_(__FILE__, line)(bmMask.bmWidth == exp_cx, "bmMask.bmWidth = %d\n", bmMask.bmWidth);
752 ok_(__FILE__, line)(bmMask.bmHeight == exp_mask_cy, "bmMask.bmHeight = %d\n", bmMask.bmHeight);
754 else
756 ok_(__FILE__, line)(bmMask.bmBitsPixel == 1, "bmMask.bmBitsPixel = %d\n", bmMask.bmBitsPixel);
757 ok_(__FILE__, line)(bmMask.bmWidth == exp_cx, "bmMask.bmWidth = %d\n", bmMask.bmWidth);
758 ok_(__FILE__, line)(bmMask.bmHeight == exp_mask_cy, "bmMask.bmHeight = %d\n", bmMask.bmHeight);
760 if (pGetIconInfoExA)
762 ICONINFOEXA infoex;
764 memset( &infoex, 0xcc, sizeof(infoex) );
765 SetLastError( 0xdeadbeef );
766 infoex.cbSize = sizeof(infoex) - 1;
767 ret = pGetIconInfoExA( hIcon, &infoex );
768 ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n");
769 ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %d\n", GetLastError());
771 SetLastError( 0xdeadbeef );
772 infoex.cbSize = sizeof(infoex) + 1;
773 ret = pGetIconInfoExA( hIcon, &infoex );
774 ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n");
775 ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %d\n", GetLastError());
777 SetLastError( 0xdeadbeef );
778 infoex.cbSize = sizeof(infoex);
779 ret = pGetIconInfoExA( (HICON)0xdeadbabe, &infoex );
780 ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n");
781 ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_CURSOR_HANDLE,
782 "wrong error %d\n", GetLastError());
784 infoex.cbSize = sizeof(infoex);
785 ret = pGetIconInfoExA( hIcon, &infoex );
786 ok_(__FILE__, line)(ret, "GetIconInfoEx failed err %d\n", GetLastError());
787 ok_(__FILE__, line)(infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID);
788 ok_(__FILE__, line)(infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName);
789 ok_(__FILE__, line)(infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName);
793 #define test_icon_info(a,b,c,d,e) test_icon_info_dbg((a),(b),(c),(d),(e),__LINE__)
795 static void test_CreateIcon(void)
797 static const BYTE bmp_bits[1024];
798 HICON hIcon;
799 HBITMAP hbmMask, hbmColor;
800 BITMAPINFO *bmpinfo;
801 ICONINFO info;
802 HDC hdc;
803 void *bits;
804 UINT display_bpp;
805 int i;
807 hdc = GetDC(0);
808 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
810 /* these crash under XP
811 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
812 hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits);
815 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, bmp_bits);
816 ok(hIcon != 0, "CreateIcon failed\n");
817 test_icon_info(hIcon, 16, 16, 32, 1);
818 DestroyIcon(hIcon);
820 hIcon = CreateIcon(0, 16, 16, 1, display_bpp, bmp_bits, bmp_bits);
821 ok(hIcon != 0, "CreateIcon failed\n");
822 test_icon_info(hIcon, 16, 16, 16, display_bpp);
823 DestroyIcon(hIcon);
825 hbmMask = CreateBitmap(16, 16, 1, 1, bmp_bits);
826 ok(hbmMask != 0, "CreateBitmap failed\n");
827 hbmColor = CreateBitmap(16, 16, 1, display_bpp, bmp_bits);
828 ok(hbmColor != 0, "CreateBitmap failed\n");
830 info.fIcon = TRUE;
831 info.xHotspot = 8;
832 info.yHotspot = 8;
833 info.hbmMask = 0;
834 info.hbmColor = 0;
835 SetLastError(0xdeadbeaf);
836 hIcon = CreateIconIndirect(&info);
837 ok(!hIcon, "CreateIconIndirect should fail\n");
838 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
840 info.fIcon = TRUE;
841 info.xHotspot = 8;
842 info.yHotspot = 8;
843 info.hbmMask = 0;
844 info.hbmColor = hbmColor;
845 SetLastError(0xdeadbeaf);
846 hIcon = CreateIconIndirect(&info);
847 ok(!hIcon, "CreateIconIndirect should fail\n");
848 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
850 info.fIcon = TRUE;
851 info.xHotspot = 8;
852 info.yHotspot = 8;
853 info.hbmMask = hbmMask;
854 info.hbmColor = hbmColor;
855 hIcon = CreateIconIndirect(&info);
856 ok(hIcon != 0, "CreateIconIndirect failed\n");
857 test_icon_info(hIcon, 16, 16, 16, display_bpp);
858 DestroyIcon(hIcon);
860 DeleteObject(hbmMask);
861 DeleteObject(hbmColor);
863 hbmMask = CreateBitmap(16, 32, 1, 1, bmp_bits);
864 ok(hbmMask != 0, "CreateBitmap failed\n");
866 info.fIcon = TRUE;
867 info.xHotspot = 8;
868 info.yHotspot = 8;
869 info.hbmMask = hbmMask;
870 info.hbmColor = 0;
871 SetLastError(0xdeadbeaf);
872 hIcon = CreateIconIndirect(&info);
873 ok(hIcon != 0, "CreateIconIndirect failed\n");
874 test_icon_info(hIcon, 16, 16, 32, 1);
875 DestroyIcon(hIcon);
876 DeleteObject(hbmMask);
878 for (i = 0; i <= 4; i++)
880 hbmMask = CreateBitmap(1, i, 1, 1, bmp_bits);
881 ok(hbmMask != 0, "CreateBitmap failed\n");
883 info.fIcon = TRUE;
884 info.xHotspot = 0;
885 info.yHotspot = 0;
886 info.hbmMask = hbmMask;
887 info.hbmColor = 0;
888 SetLastError(0xdeadbeaf);
889 hIcon = CreateIconIndirect(&info);
890 ok(hIcon != 0, "CreateIconIndirect failed\n");
891 test_icon_info(hIcon, 1, i / 2, max(i,1), 1);
892 DestroyIcon(hIcon);
893 DeleteObject(hbmMask);
896 /* test creating an icon from a DIB section */
898 bmpinfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO,bmiColors[256]));
899 bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
900 bmpinfo->bmiHeader.biWidth = 32;
901 bmpinfo->bmiHeader.biHeight = 32;
902 bmpinfo->bmiHeader.biPlanes = 1;
903 bmpinfo->bmiHeader.biBitCount = 8;
904 bmpinfo->bmiHeader.biCompression = BI_RGB;
905 hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
906 ok(hbmColor != NULL, "Expected a handle to the DIB\n");
907 if (bits)
908 memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
909 bmpinfo->bmiHeader.biBitCount = 1;
910 hbmMask = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
911 ok(hbmMask != NULL, "Expected a handle to the DIB\n");
912 if (bits)
913 memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
915 info.fIcon = TRUE;
916 info.xHotspot = 8;
917 info.yHotspot = 8;
918 info.hbmMask = hbmColor;
919 info.hbmColor = hbmMask;
920 SetLastError(0xdeadbeaf);
921 hIcon = CreateIconIndirect(&info);
922 ok(hIcon != 0, "CreateIconIndirect failed\n");
923 test_icon_info(hIcon, 32, 32, 32, 8);
924 DestroyIcon(hIcon);
925 DeleteObject(hbmColor);
927 bmpinfo->bmiHeader.biBitCount = 16;
928 hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
929 ok(hbmColor != NULL, "Expected a handle to the DIB\n");
930 if (bits)
931 memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
933 info.fIcon = TRUE;
934 info.xHotspot = 8;
935 info.yHotspot = 8;
936 info.hbmMask = hbmColor;
937 info.hbmColor = hbmMask;
938 SetLastError(0xdeadbeaf);
939 hIcon = CreateIconIndirect(&info);
940 ok(hIcon != 0, "CreateIconIndirect failed\n");
941 test_icon_info(hIcon, 32, 32, 32, 8);
942 DestroyIcon(hIcon);
943 DeleteObject(hbmColor);
945 bmpinfo->bmiHeader.biBitCount = 32;
946 hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
947 ok(hbmColor != NULL, "Expected a handle to the DIB\n");
948 if (bits)
949 memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
951 info.fIcon = TRUE;
952 info.xHotspot = 8;
953 info.yHotspot = 8;
954 info.hbmMask = hbmColor;
955 info.hbmColor = hbmMask;
956 SetLastError(0xdeadbeaf);
957 hIcon = CreateIconIndirect(&info);
958 ok(hIcon != 0, "CreateIconIndirect failed\n");
959 test_icon_info(hIcon, 32, 32, 32, 8);
960 DestroyIcon(hIcon);
962 DeleteObject(hbmMask);
963 DeleteObject(hbmColor);
964 HeapFree( GetProcessHeap(), 0, bmpinfo );
966 ReleaseDC(0, hdc);
969 /* Shamelessly ripped from dlls/oleaut32/tests/olepicture.c */
970 /* 1x1 pixel gif */
971 static const unsigned char gifimage[35] = {
972 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
973 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
974 0x01,0x00,0x3b
977 /* 1x1 pixel jpg */
978 static const unsigned char jpgimage[285] = {
979 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
980 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
981 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
982 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
983 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
984 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
985 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
986 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
987 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
988 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
989 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
990 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
991 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
992 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
993 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
994 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
995 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
996 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
999 /* 1x1 pixel png */
1000 static const unsigned char pngimage[285] = {
1001 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
1002 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
1003 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
1004 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
1005 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
1006 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
1007 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
1010 /* 1x1 pixel bmp with gap between palette and bitmap. Correct bitmap contains only
1011 zeroes, gap is 0xFF. */
1012 static unsigned char bmpimage[70] = {
1013 0x42,0x4d,0x46,0x00,0x00,0x00,0xDE,0xAD,0xBE,0xEF,0x42,0x00,0x00,0x00,0x28,0x00,
1014 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
1015 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
1016 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0x55,0x55,0x55,0x00,0xFF,0xFF,
1017 0xFF,0xFF,0x00,0x00,0x00,0x00
1020 /* 1x1 pixel bmp using BITMAPCOREHEADER */
1021 static const unsigned char bmpcoreimage[38] = {
1022 0x42,0x4d,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x0c,0x00,
1023 0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xff,0xff,0xff,0x00,0x55,0x55,
1024 0x55,0x00,0x00,0x00,0x00,0x00
1027 /* 2x2 pixel gif */
1028 static const unsigned char gif4pixel[42] = {
1029 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
1030 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
1031 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
1034 /* An invalid cursor with an invalid dwDIBOffset */
1035 static const unsigned char invalid_dwDIBOffset[] = {
1036 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1037 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00
1040 static const DWORD biSize_tests[] = {
1042 sizeof(BITMAPCOREHEADER) - 1,
1043 sizeof(BITMAPCOREHEADER) + 1,
1044 sizeof(BITMAPINFOHEADER) - 1,
1045 sizeof(BITMAPINFOHEADER) + 1,
1046 sizeof(BITMAPV4HEADER) - 1,
1047 sizeof(BITMAPV4HEADER) + 1,
1048 sizeof(BITMAPV5HEADER) - 1,
1049 sizeof(BITMAPV5HEADER) + 1,
1050 (sizeof(BITMAPCOREHEADER) + sizeof(BITMAPINFOHEADER)) / 2,
1051 (sizeof(BITMAPV4HEADER) + sizeof(BITMAPV5HEADER)) / 2,
1052 0xdeadbeef,
1053 0xffffffff
1056 static void test_LoadImageBitmap(const char * test_desc, HBITMAP hbm)
1058 BITMAP bm;
1059 BITMAPINFO bmi;
1060 DWORD ret, pixel = 0;
1061 HDC hdc = GetDC(NULL);
1063 ret = GetObjectA(hbm, sizeof(bm), &bm);
1064 ok(ret == sizeof(bm), "GetObject returned %d\n", ret);
1066 memset(&bmi, 0, sizeof(bmi));
1067 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1068 bmi.bmiHeader.biWidth = bm.bmWidth;
1069 bmi.bmiHeader.biHeight = bm.bmHeight;
1070 bmi.bmiHeader.biPlanes = 1;
1071 bmi.bmiHeader.biBitCount= 24;
1072 bmi.bmiHeader.biCompression= BI_RGB;
1073 ret = GetDIBits(hdc, hbm, 0, bm.bmHeight, &pixel, &bmi, DIB_RGB_COLORS);
1074 ok(ret == bm.bmHeight, "%s: %d lines were converted, not %d\n", test_desc, ret, bm.bmHeight);
1076 ok(color_match(pixel, 0x00ffffff), "%s: Pixel is 0x%08x\n", test_desc, pixel);
1078 ReleaseDC(NULL, hdc);
1081 static void test_LoadImageFile(const char * test_desc, const unsigned char * image_data,
1082 unsigned int image_size, const char * ext, BOOL expect_success)
1084 HANDLE handle;
1085 BOOL ret;
1086 DWORD error, bytes_written;
1087 char filename[64];
1089 strcpy(filename, "test.");
1090 strcat(filename, ext);
1092 /* Create the test image. */
1093 handle = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW,
1094 FILE_ATTRIBUTE_NORMAL, NULL);
1095 ok(handle != INVALID_HANDLE_VALUE, "CreateFileA failed. %u\n", GetLastError());
1096 ret = WriteFile(handle, image_data, image_size, &bytes_written, NULL);
1097 ok(ret && bytes_written == image_size, "test file created improperly.\n");
1098 CloseHandle(handle);
1100 /* Load as cursor. For all tested formats, this should fail */
1101 SetLastError(0xdeadbeef);
1102 handle = LoadImageA(NULL, filename, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
1103 ok(handle == NULL, "%s: IMAGE_CURSOR succeeded incorrectly.\n", test_desc);
1104 error = GetLastError();
1105 ok(error == 0 ||
1106 broken(error == 0xdeadbeef) || /* Win9x */
1107 broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
1108 "Last error: %u\n", error);
1109 if (handle != NULL) DestroyCursor(handle);
1111 /* Load as icon. For all tested formats, this should fail */
1112 SetLastError(0xdeadbeef);
1113 handle = LoadImageA(NULL, filename, IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
1114 ok(handle == NULL, "%s: IMAGE_ICON succeeded incorrectly.\n", test_desc);
1115 error = GetLastError();
1116 ok(error == 0 ||
1117 broken(error == 0xdeadbeef) || /* Win9x */
1118 broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
1119 "Last error: %u\n", error);
1120 if (handle != NULL) DestroyIcon(handle);
1122 /* Load as bitmap. Should succeed for correct bmp, fail for everything else */
1123 SetLastError(0xdeadbeef);
1124 handle = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
1125 error = GetLastError();
1126 ok(error == 0 ||
1127 error == 0xdeadbeef, /* Win9x, WinMe */
1128 "Last error: %u\n", error);
1130 if (expect_success) {
1131 ok(handle != NULL, "%s: IMAGE_BITMAP failed.\n", test_desc);
1132 if (handle != NULL) test_LoadImageBitmap(test_desc, handle);
1134 else ok(handle == NULL, "%s: IMAGE_BITMAP succeeded incorrectly.\n", test_desc);
1136 if (handle != NULL) DeleteObject(handle);
1137 DeleteFileA(filename);
1140 typedef struct {
1141 unsigned width;
1142 unsigned height;
1143 BOOL invalid_offset;
1144 } test_icon_entries_t;
1146 static void create_ico_file(const char *filename, const test_icon_entries_t *test_icon_entries, unsigned entry_cnt)
1148 CURSORICONFILEDIRENTRY *icon_entry;
1149 BITMAPINFOHEADER *icon_header;
1150 CURSORICONFILEDIR *dir;
1151 BYTE *buf, *bitmap_ptr;
1152 DWORD bytes_written;
1153 size_t icon_size;
1154 HANDLE file;
1155 unsigned i;
1156 BOOL ret;
1158 const unsigned icon_bpp = 32;
1160 icon_size = FIELD_OFFSET(CURSORICONFILEDIR, idEntries[entry_cnt]) + sizeof(BITMAPINFOHEADER)*entry_cnt;
1161 for(i=0; i<entry_cnt; i++)
1162 icon_size += icon_bpp * test_icon_entries[i].width * test_icon_entries[i].height / 8;
1164 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, icon_size);
1165 dir = (CURSORICONFILEDIR*)buf;
1167 dir->idReserved = 0;
1168 dir->idType = 1;
1169 dir->idCount = entry_cnt;
1171 bitmap_ptr = buf + FIELD_OFFSET(CURSORICONFILEDIR, idEntries[entry_cnt]);
1172 for(i=0; i<entry_cnt; i++) {
1173 icon_entry = dir->idEntries+i;
1174 icon_entry->bWidth = test_icon_entries[i].width;
1175 icon_entry->bHeight = test_icon_entries[i].height;
1176 icon_entry->bColorCount = 0;
1177 icon_entry->bReserved = 0;
1178 icon_entry->xHotspot = 1;
1179 icon_entry->yHotspot = 1;
1180 icon_entry->dwDIBSize = sizeof(BITMAPINFOHEADER) + icon_entry->bWidth * icon_entry->bHeight * icon_bpp / 8;
1181 icon_entry->dwDIBOffset = test_icon_entries[i].invalid_offset ? 0xffffffff : bitmap_ptr - buf;
1183 icon_header = (BITMAPINFOHEADER*)bitmap_ptr;
1184 bitmap_ptr += icon_entry->dwDIBSize;
1186 icon_header->biSize = sizeof(BITMAPINFOHEADER);
1187 icon_header->biWidth = icon_entry->bWidth;
1188 icon_header->biHeight = icon_entry->bHeight;
1189 icon_header->biPlanes = 1;
1190 icon_header->biBitCount = icon_bpp;
1191 icon_header->biSizeImage = 0; /* Uncompressed bitmap. */
1194 memset(bitmap_ptr, 0xf0, buf+icon_size-bitmap_ptr);
1196 /* Create the icon. */
1197 file = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
1198 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed. %u\n", GetLastError());
1199 ret = WriteFile(file, buf, icon_size, &bytes_written, NULL);
1200 ok(ret && bytes_written == icon_size, "icon.ico created improperly.\n");
1201 CloseHandle(file);
1203 HeapFree(GetProcessHeap(), 0, buf);
1206 static void create_bitmap_file(const char *filename, const BITMAPINFO *bmi, const unsigned char *bits)
1208 unsigned int clr_used, bmi_size, bits_size, stride;
1209 const BITMAPINFOHEADER *h = &bmi->bmiHeader;
1210 BITMAPFILEHEADER hdr;
1211 DWORD bytes_written;
1212 HANDLE file;
1213 BOOL ret;
1215 clr_used = h->biBitCount <= 8 ? 1u << h->biBitCount : 0;
1216 stride = ((h->biBitCount * h->biWidth + 7) / 8 + 3) & ~3;
1217 bits_size = h->biHeight * stride;
1218 bmi_size = h->biSize + clr_used * sizeof(RGBQUAD);
1220 hdr.bfType = 0x4d42;
1221 hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + bmi_size;
1222 hdr.bfSize = hdr.bfOffBits + bits_size;
1223 hdr.bfReserved1 = 0;
1224 hdr.bfReserved2 = 0;
1226 file = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
1227 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed, result %u.\n", GetLastError());
1228 ret = WriteFile(file, &hdr, sizeof(hdr), &bytes_written, NULL);
1229 ok(ret && bytes_written == sizeof(hdr), "Unexpected WriteFile() result, ret %#x, bytes_written %u.\n",
1230 ret, bytes_written);
1231 ret = WriteFile(file, bmi, bmi_size, &bytes_written, NULL);
1232 ok(ret && bytes_written == bmi_size, "Unexpected WriteFile() result, ret %#x, bytes_written %u.\n",
1233 ret, bytes_written);
1234 ret = WriteFile(file, bits, bits_size, &bytes_written, NULL);
1235 ok(ret && bytes_written == bits_size, "Unexpected WriteFile() result, ret %#x, bytes_written %u.\n",
1236 ret, bytes_written);
1237 CloseHandle(file);
1240 static void test_LoadImage_working_directory_run(char *path)
1242 DWORD bytes_written;
1243 HANDLE handle;
1244 BOOL ret;
1245 char path_icon[MAX_PATH];
1246 char path_image[MAX_PATH];
1247 static const test_icon_entries_t icon_desc = {32, 32};
1249 sprintf(path_icon, "%s\\icon.ico", path);
1250 sprintf(path_image, "%s\\test.bmp", path);
1252 /* Create Files */
1253 create_ico_file(path_icon, &icon_desc, 1);
1255 handle = CreateFileA(path_image, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
1256 ok(handle != INVALID_HANDLE_VALUE, "run %s: CreateFileA failed. %u\n", path, GetLastError());
1257 ret = WriteFile(handle, bmpimage, sizeof(bmpimage), &bytes_written, NULL);
1258 ok(ret && bytes_written == sizeof(bmpimage), "run %s: Test file created improperly.\n", path);
1259 CloseHandle(handle);
1261 /* Test cursor */
1262 handle = LoadImageA(NULL, "icon.ico", IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
1263 ok(handle != NULL, "run %s: LoadImage() failed.\n", path);
1265 ret = DestroyIcon(handle);
1266 ok(ret, "run %s: DestroyIcon failed: %d\n", path, GetLastError());
1268 /* Test image */
1269 handle = LoadImageA(NULL, "test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
1270 ok(handle != NULL, "run %s: LoadImageA failed.\n", path);
1272 ret = DeleteObject(handle);
1273 ok(ret, "run %s: DeleteObject failed: %d\n", path, GetLastError());
1275 /* Cleanup */
1276 ret = DeleteFileA(path_image);
1277 ok(ret, "run %s: DeleteFileA failed: %d\n", path, GetLastError());
1278 ret = DeleteFileA(path_icon);
1279 ok(ret, "run %s: DeleteFileA failed: %d\n", path, GetLastError());
1282 static void test_LoadImage_working_directory(void)
1284 char old_working_dir[MAX_PATH];
1285 char temp_dir_current[MAX_PATH];
1286 char temp_dir_PATH[MAX_PATH];
1287 char executable_path[MAX_PATH];
1288 int pos_slash;
1289 char old_PATH[10000];
1290 char new_PATH[10000];
1291 BOOL ret;
1293 GetCurrentDirectoryA(ARRAY_SIZE(old_working_dir), old_working_dir);
1295 GetTempPathA(ARRAY_SIZE(temp_dir_current), temp_dir_current);
1296 strcat(temp_dir_current, "wine-test-dir-current\\");
1297 GetTempPathA(ARRAY_SIZE(temp_dir_PATH), temp_dir_PATH);
1298 strcat(temp_dir_PATH, "wine-test-dir-path\\");
1300 GetModuleFileNameA(NULL, executable_path, ARRAY_SIZE(executable_path));
1301 pos_slash = strrchr(executable_path, '\\') - executable_path;
1302 executable_path[pos_slash + 1] = 0;
1304 CreateDirectoryA(temp_dir_current, NULL);
1305 CreateDirectoryA(temp_dir_PATH, NULL);
1307 SetCurrentDirectoryA(temp_dir_current);
1309 GetEnvironmentVariableA("PATH", old_PATH, ARRAY_SIZE(old_PATH));
1310 sprintf(new_PATH, "%s;%s", old_PATH, temp_dir_PATH);
1311 SetEnvironmentVariableA("PATH", new_PATH);
1313 test_LoadImage_working_directory_run(temp_dir_current);
1314 test_LoadImage_working_directory_run(executable_path);
1315 test_LoadImage_working_directory_run(temp_dir_PATH);
1317 SetCurrentDirectoryA(old_working_dir);
1318 SetEnvironmentVariableA("PATH", old_PATH);
1320 ret = RemoveDirectoryA(temp_dir_current);
1321 ok(ret, "RemoveDirectoryA failed: %d\n", GetLastError());
1322 ret = RemoveDirectoryA(temp_dir_PATH);
1323 ok(ret, "RemoveDirectoryA failed: %d\n", GetLastError());
1326 static void test_LoadImage(void)
1328 HANDLE handle;
1329 BOOL ret;
1330 DWORD error;
1331 BITMAPINFOHEADER *bitmap_header;
1332 ICONINFO icon_info;
1333 int i;
1335 #define ICON_WIDTH 32
1336 #define ICON_HEIGHT 32
1337 #define ICON_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
1338 #define ICON_BPP 32
1339 #define ICON_SIZE \
1340 (sizeof(CURSORICONFILEDIR) + sizeof(BITMAPINFOHEADER) \
1341 + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
1343 static const test_icon_entries_t icon_desc = {32, 32};
1345 create_ico_file("icon.ico", &icon_desc, 1);
1347 /* Test loading an icon as a cursor. */
1348 SetLastError(0xdeadbeef);
1349 handle = LoadImageA(NULL, "icon.ico", IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
1350 ok(handle != NULL, "LoadImage() failed.\n");
1351 error = GetLastError();
1352 ok(error == 0 ||
1353 broken(error == 0xdeadbeef) || /* Win9x */
1354 broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
1355 "Last error: %u\n", error);
1357 /* Test the icon information. */
1358 SetLastError(0xdeadbeef);
1359 ret = GetIconInfo(handle, &icon_info);
1360 ok(ret, "GetIconInfo() failed.\n");
1361 error = GetLastError();
1362 ok(error == 0xdeadbeef, "Last error: %u\n", error);
1364 if (ret)
1366 ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n");
1367 ok(icon_info.xHotspot == 1, "xHotspot is %u.\n", icon_info.xHotspot);
1368 ok(icon_info.yHotspot == 1, "yHotspot is %u.\n", icon_info.yHotspot);
1369 ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */,
1370 "No hbmColor!\n");
1371 ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
1374 if (pGetIconInfoExA)
1376 ICONINFOEXA infoex;
1377 infoex.cbSize = sizeof(infoex);
1378 ret = pGetIconInfoExA( handle, &infoex );
1379 ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() );
1380 ok( infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID );
1381 ok( infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName );
1382 ok( infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName );
1384 else win_skip( "GetIconInfoEx not available\n" );
1386 /* Clean up. */
1387 SetLastError(0xdeadbeef);
1388 ret = DestroyCursor(handle);
1389 ok(ret, "DestroyCursor() failed.\n");
1390 error = GetLastError();
1391 ok(error == 0xdeadbeef, "Last error: %u\n", error);
1393 DeleteFileA("icon.ico");
1395 /* Test a system icon */
1396 handle = LoadIconA( 0, (LPCSTR)IDI_HAND );
1397 ok(handle != NULL, "LoadImage() failed.\n");
1398 if (pGetIconInfoExA)
1400 ICONINFOEXA infoexA;
1401 ICONINFOEXW infoexW;
1402 infoexA.cbSize = sizeof(infoexA);
1403 ret = pGetIconInfoExA( handle, &infoexA );
1404 ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() );
1405 ok( infoexA.wResID == (UINT_PTR)IDI_HAND, "GetIconInfoEx wrong resid %x\n", infoexA.wResID );
1406 /* the A version is broken on 64-bit, it truncates the string after the first char */
1407 if (is_win64 && infoexA.szModName[0] && infoexA.szModName[1] == 0)
1408 trace( "GetIconInfoExA broken on Win64\n" );
1409 else
1410 ok( GetModuleHandleA(infoexA.szModName) == GetModuleHandleA("user32.dll"),
1411 "GetIconInfoEx wrong module %s\n", infoexA.szModName );
1412 ok( infoexA.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoexA.szResName );
1413 infoexW.cbSize = sizeof(infoexW);
1414 ret = pGetIconInfoExW( handle, &infoexW );
1415 ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() );
1416 ok( infoexW.wResID == (UINT_PTR)IDI_HAND, "GetIconInfoEx wrong resid %x\n", infoexW.wResID );
1417 ok( GetModuleHandleW(infoexW.szModName) == GetModuleHandleA("user32.dll"),
1418 "GetIconInfoEx wrong module %s\n", wine_dbgstr_w(infoexW.szModName) );
1419 ok( infoexW.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", wine_dbgstr_w(infoexW.szResName) );
1421 SetLastError(0xdeadbeef);
1422 DestroyIcon(handle);
1424 test_LoadImageFile("BMP", bmpimage, sizeof(bmpimage), "bmp", 1);
1425 test_LoadImageFile("BMP (coreinfo)", bmpcoreimage, sizeof(bmpcoreimage), "bmp", 1);
1426 test_LoadImageFile("GIF", gifimage, sizeof(gifimage), "gif", 0);
1427 test_LoadImageFile("GIF (2x2 pixel)", gif4pixel, sizeof(gif4pixel), "gif", 0);
1428 test_LoadImageFile("JPG", jpgimage, sizeof(jpgimage), "jpg", 0);
1429 test_LoadImageFile("PNG", pngimage, sizeof(pngimage), "png", 0);
1431 /* Check failure for broken BMP images */
1432 bitmap_header = (BITMAPINFOHEADER *)(bmpimage + sizeof(BITMAPFILEHEADER));
1434 bitmap_header->biHeight = 65536;
1435 test_LoadImageFile("BMP (too high)", bmpimage, sizeof(bmpimage), "bmp", 0);
1436 bitmap_header->biHeight = 1;
1438 bitmap_header->biWidth = 65536;
1439 test_LoadImageFile("BMP (too wide)", bmpimage, sizeof(bmpimage), "bmp", 0);
1440 bitmap_header->biWidth = 1;
1442 for (i = 0; i < ARRAY_SIZE(biSize_tests); i++) {
1443 bitmap_header->biSize = biSize_tests[i];
1444 test_LoadImageFile("BMP (broken biSize)", bmpimage, sizeof(bmpimage), "bmp", 0);
1446 bitmap_header->biSize = sizeof(BITMAPINFOHEADER);
1448 test_LoadImageFile("Cursor (invalid dwDIBOffset)", invalid_dwDIBOffset, sizeof(invalid_dwDIBOffset), "cur", 0);
1450 /* Test in which paths images with a relative path can be found */
1451 test_LoadImage_working_directory();
1454 static void test_CreateIconFromResource(void)
1456 HANDLE handle;
1457 BOOL ret;
1458 DWORD error;
1459 BITMAPINFOHEADER *icon_header;
1460 INT16 *hotspot;
1461 ICONINFO icon_info;
1463 #define ICON_RES_WIDTH 32
1464 #define ICON_RES_HEIGHT 32
1465 #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
1466 #define ICON_RES_BPP 32
1467 #define ICON_RES_SIZE \
1468 (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
1469 #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE)
1471 /* Set icon data. */
1472 hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE);
1474 /* Cursor resources have an extra hotspot, icon resources not. */
1475 hotspot[0] = 3;
1476 hotspot[1] = 3;
1478 icon_header = (BITMAPINFOHEADER *) (hotspot + 2);
1479 icon_header->biSize = sizeof(BITMAPINFOHEADER);
1480 icon_header->biWidth = ICON_WIDTH;
1481 icon_header->biHeight = ICON_HEIGHT*2;
1482 icon_header->biPlanes = 1;
1483 icon_header->biBitCount = ICON_BPP;
1484 icon_header->biSizeImage = 0; /* Uncompressed bitmap. */
1486 /* Test creating a cursor. */
1487 SetLastError(0xdeadbeef);
1488 handle = CreateIconFromResource((PBYTE) hotspot, CRSR_RES_SIZE, FALSE, 0x00030000);
1489 ok(handle != NULL, "Create cursor failed.\n");
1491 /* Test the icon information. */
1492 SetLastError(0xdeadbeef);
1493 ret = GetIconInfo(handle, &icon_info);
1494 ok(ret, "GetIconInfo() failed.\n");
1495 error = GetLastError();
1496 ok(error == 0xdeadbeef, "Last error: %u\n", error);
1498 if (ret)
1500 ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n");
1501 ok(icon_info.xHotspot == 3, "xHotspot is %u.\n", icon_info.xHotspot);
1502 ok(icon_info.yHotspot == 3, "yHotspot is %u.\n", icon_info.yHotspot);
1503 ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */,
1504 "No hbmColor!\n");
1505 ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
1508 if (pGetIconInfoExA)
1510 ICONINFOEXA infoex;
1511 infoex.cbSize = sizeof(infoex);
1512 ret = pGetIconInfoExA( handle, &infoex );
1513 ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() );
1514 ok( infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID );
1515 ok( infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName );
1516 ok( infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName );
1519 /* Clean up. */
1520 SetLastError(0xdeadbeef);
1521 ret = DestroyCursor(handle);
1522 ok(ret, "DestroyCursor() failed.\n");
1523 error = GetLastError();
1524 ok(error == 0xdeadbeef, "Last error: %u\n", error);
1526 /* Test creating an icon. */
1527 SetLastError(0xdeadbeef);
1528 handle = CreateIconFromResource((PBYTE) icon_header, ICON_RES_SIZE, TRUE,
1529 0x00030000);
1530 ok(handle != NULL, "Create icon failed.\n");
1532 /* Test the icon information. */
1533 SetLastError(0xdeadbeef);
1534 ret = GetIconInfo(handle, &icon_info);
1535 ok(ret, "GetIconInfo() failed.\n");
1536 error = GetLastError();
1537 ok(error == 0xdeadbeef, "Last error: %u\n", error);
1539 if (ret)
1541 ok(icon_info.fIcon == TRUE, "fIcon != TRUE.\n");
1542 /* Icons always have hotspot in the middle */
1543 ok(icon_info.xHotspot == ICON_WIDTH/2, "xHotspot is %u.\n", icon_info.xHotspot);
1544 ok(icon_info.yHotspot == ICON_HEIGHT/2, "yHotspot is %u.\n", icon_info.yHotspot);
1545 ok(icon_info.hbmColor != NULL, "No hbmColor!\n");
1546 ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
1549 /* Clean up. */
1550 SetLastError(0xdeadbeef);
1551 ret = DestroyCursor(handle);
1552 ok(ret, "DestroyCursor() failed.\n");
1553 error = GetLastError();
1554 ok(error == 0xdeadbeef, "Last error: %u\n", error);
1556 /* Rejection of NULL pointer crashes at least on WNT4WSSP6, W2KPROSP4, WXPPROSP3
1558 * handle = CreateIconFromResource(NULL, ICON_RES_SIZE, TRUE, 0x00030000);
1559 * ok(handle == NULL, "Invalid pointer accepted (%p)\n", handle);
1561 HeapFree(GetProcessHeap(), 0, hotspot);
1563 /* Test creating an animated cursor. */
1564 empty_anicursor.frames[0].data.icon_info.idType = 2; /* type: cursor */
1565 empty_anicursor.frames[0].data.icon_info.idEntries[0].xHotspot = 3;
1566 empty_anicursor.frames[0].data.icon_info.idEntries[0].yHotspot = 3;
1567 handle = CreateIconFromResource((PBYTE) &empty_anicursor, sizeof(empty_anicursor), FALSE, 0x00030000);
1568 ok(handle != NULL, "Create cursor failed.\n");
1570 /* Test the animated cursor's information. */
1571 SetLastError(0xdeadbeef);
1572 ret = GetIconInfo(handle, &icon_info);
1573 ok(ret, "GetIconInfo() failed.\n");
1574 error = GetLastError();
1575 ok(error == 0xdeadbeef, "Last error: %u\n", error);
1577 if (ret)
1579 ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n");
1580 ok(icon_info.xHotspot == 3, "xHotspot is %u.\n", icon_info.xHotspot);
1581 ok(icon_info.yHotspot == 3, "yHotspot is %u.\n", icon_info.yHotspot);
1582 ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */,
1583 "No hbmColor!\n");
1584 ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
1587 /* Clean up. */
1588 SetLastError(0xdeadbeef);
1589 ret = DestroyCursor(handle);
1590 ok(ret, "DestroyCursor() failed.\n");
1591 error = GetLastError();
1592 ok(error == 0xdeadbeef, "Last error: %u\n", error);
1595 static int check_cursor_data( HDC hdc, HCURSOR hCursor, void *data, int length)
1597 char *image = NULL;
1598 BITMAPINFO *info;
1599 ICONINFO iinfo;
1600 DWORD ret;
1601 int i;
1603 ret = GetIconInfo( hCursor, &iinfo );
1604 ok(ret, "GetIconInfo() failed\n");
1605 if (!ret) return 0;
1606 ret = 0;
1607 info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
1608 ok(info != NULL, "HeapAlloc() failed\n");
1609 if (!info) return 0;
1611 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1612 info->bmiHeader.biWidth = 32;
1613 info->bmiHeader.biHeight = 32;
1614 info->bmiHeader.biPlanes = 1;
1615 info->bmiHeader.biBitCount = 32;
1616 info->bmiHeader.biCompression = BI_RGB;
1617 info->bmiHeader.biSizeImage = 32 * 32 * 4;
1618 info->bmiHeader.biXPelsPerMeter = 0;
1619 info->bmiHeader.biYPelsPerMeter = 0;
1620 info->bmiHeader.biClrUsed = 0;
1621 info->bmiHeader.biClrImportant = 0;
1622 image = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
1623 ok(image != NULL, "HeapAlloc() failed\n");
1624 if (!image) goto cleanup;
1625 ret = GetDIBits( hdc, iinfo.hbmColor, 0, 32, image, info, DIB_RGB_COLORS );
1626 ok(ret, "GetDIBits() failed\n");
1627 for (i = 0; ret && i < length / sizeof(COLORREF); i++)
1629 ret = color_match( ((COLORREF *)data)[i], ((COLORREF *)image)[i] );
1630 ok(ret, "%04x: Expected 0x%x, actually 0x%x\n", i, ((COLORREF *)data)[i], ((COLORREF *)image)[i] );
1632 cleanup:
1633 HeapFree( GetProcessHeap(), 0, image );
1634 HeapFree( GetProcessHeap(), 0, info );
1635 return ret;
1638 static HCURSOR (WINAPI *pGetCursorFrameInfo)(HCURSOR hCursor, DWORD unk1, DWORD istep, DWORD *rate, DWORD *steps);
1639 static void test_GetCursorFrameInfo(void)
1641 DWORD frame_identifier[] = { 0x10Ad, 0xc001, 0x1c05 };
1642 HBITMAP bmp = NULL, bmpOld = NULL;
1643 DWORD rate, steps;
1644 BITMAPINFOHEADER *icon_header;
1645 BITMAPINFO bitmapInfo;
1646 HDC hdc = NULL;
1647 void *bits = 0;
1648 INT16 *hotspot;
1649 HANDLE h1, h2;
1650 BOOL ret;
1651 int i;
1653 if (!pGetCursorFrameInfo)
1655 win_skip( "GetCursorFrameInfo not supported, skipping tests.\n" );
1656 return;
1659 hdc = CreateCompatibleDC(0);
1660 ok(hdc != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1661 if (!hdc)
1662 return;
1664 memset(&bitmapInfo, 0, sizeof(bitmapInfo));
1665 bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1666 bitmapInfo.bmiHeader.biWidth = 3;
1667 bitmapInfo.bmiHeader.biHeight = 3;
1668 bitmapInfo.bmiHeader.biBitCount = 32;
1669 bitmapInfo.bmiHeader.biPlanes = 1;
1670 bitmapInfo.bmiHeader.biCompression = BI_RGB;
1671 bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
1672 bmp = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
1673 ok (bmp && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1674 if (!bmp || !bits)
1675 goto cleanup;
1676 bmpOld = SelectObject(hdc, bmp);
1678 #define ICON_RES_WIDTH 32
1679 #define ICON_RES_HEIGHT 32
1680 #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
1681 #define ICON_RES_BPP 32
1682 #define ICON_RES_SIZE \
1683 (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
1684 #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE)
1686 /* Set icon data. */
1687 hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE);
1689 /* Cursor resources have an extra hotspot, icon resources not. */
1690 hotspot[0] = 3;
1691 hotspot[1] = 3;
1693 icon_header = (BITMAPINFOHEADER *) (hotspot + 2);
1694 icon_header->biSize = sizeof(BITMAPINFOHEADER);
1695 icon_header->biWidth = ICON_WIDTH;
1696 icon_header->biHeight = ICON_HEIGHT*2;
1697 icon_header->biPlanes = 1;
1698 icon_header->biBitCount = ICON_BPP;
1699 icon_header->biSizeImage = 0; /* Uncompressed bitmap. */
1701 /* Creating a static cursor. */
1702 SetLastError(0xdeadbeef);
1703 h1 = CreateIconFromResource((PBYTE) hotspot, CRSR_RES_SIZE, FALSE, 0x00030000);
1704 ok(h1 != NULL, "Create cursor failed (error = %d).\n", GetLastError());
1706 /* Check GetCursorFrameInfo behavior on a static cursor */
1707 rate = steps = 0xdead;
1708 h2 = pGetCursorFrameInfo(h1, 0xdead, 0xdead, &rate, &steps);
1709 ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2);
1710 ok(rate == 0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", rate);
1711 ok(steps == 1, "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", steps);
1713 /* Clean up static cursor. */
1714 SetLastError(0xdeadbeef);
1715 ret = DestroyCursor(h1);
1716 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1718 /* Creating a single-frame animated cursor. */
1719 empty_anicursor.frames[0].data.icon_info.idType = 2; /* type: cursor */
1720 empty_anicursor.frames[0].data.icon_info.idEntries[0].xHotspot = 3;
1721 empty_anicursor.frames[0].data.icon_info.idEntries[0].yHotspot = 3;
1722 memcpy( &empty_anicursor.frames[0].data.bmi_data.data[0], &frame_identifier[0], sizeof(DWORD) );
1723 SetLastError(0xdeadbeef);
1724 h1 = CreateIconFromResource((PBYTE) &empty_anicursor, sizeof(empty_anicursor), FALSE, 0x00030000);
1725 ok(h1 != NULL, "Create cursor failed (error = %d).\n", GetLastError());
1727 /* Check GetCursorFrameInfo behavior on a single-frame animated cursor */
1728 rate = steps = 0xdead;
1729 h2 = pGetCursorFrameInfo(h1, 0xdead, 0, &rate, &steps);
1730 ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2);
1731 ret = check_cursor_data( hdc, h2, &frame_identifier[0], sizeof(DWORD) );
1732 ok(ret, "GetCursorFrameInfo() returned wrong cursor data for frame 0.\n");
1733 ok(rate == 0x0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", rate);
1734 ok(steps == empty_anicursor.header.header.num_steps,
1735 "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", steps);
1737 /* Clean up single-frame animated cursor. */
1738 SetLastError(0xdeadbeef);
1739 ret = DestroyCursor(h1);
1740 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1742 /* Creating a multi-frame animated cursor. */
1743 for (i=0; i<empty_anicursor3.header.header.num_frames; i++)
1745 empty_anicursor3.frames[i].data.icon_info.idType = 2; /* type: cursor */
1746 empty_anicursor3.frames[i].data.icon_info.idEntries[0].xHotspot = 3;
1747 empty_anicursor3.frames[i].data.icon_info.idEntries[0].yHotspot = 3;
1748 memcpy( &empty_anicursor3.frames[i].data.bmi_data.data[0], &frame_identifier[i], sizeof(DWORD) );
1750 SetLastError(0xdeadbeef);
1751 h1 = CreateIconFromResource((PBYTE) &empty_anicursor3, sizeof(empty_anicursor3), FALSE, 0x00030000);
1752 ok(h1 != NULL, "Create cursor failed (error = %d).\n", GetLastError());
1754 /* Check number of steps in multi-frame animated cursor */
1755 i=0;
1756 while (DrawIconEx(hdc, 0, 0, h1, 32, 32, i, NULL, DI_NORMAL))
1757 i++;
1758 ok(i == empty_anicursor3.header.header.num_steps,
1759 "Unexpected number of steps in cursor (%d != %d)\n",
1760 i, empty_anicursor3.header.header.num_steps);
1762 /* Check GetCursorFrameInfo behavior on a multi-frame animated cursor */
1763 for (i=0; i<empty_anicursor3.header.header.num_frames; i++)
1765 rate = steps = 0xdead;
1766 h2 = pGetCursorFrameInfo(h1, 0xdead, i, &rate, &steps);
1767 ok(h1 != h2 && h2 != 0, "GetCursorFrameInfo() failed for cursor %p: (%p, %p).\n", h1, h1, h2);
1768 ret = check_cursor_data( hdc, h2, &frame_identifier[i], sizeof(DWORD) );
1769 ok(ret, "GetCursorFrameInfo() returned wrong cursor data for frame %d.\n", i);
1770 ok(rate == empty_anicursor3.header.header.display_rate,
1771 "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x%x).\n",
1772 rate, empty_anicursor3.header.header.display_rate);
1773 ok(steps == empty_anicursor3.header.header.num_steps,
1774 "GetCursorFrameInfo() unexpected param 5 value (%d != %d).\n",
1775 steps, empty_anicursor3.header.header.num_steps);
1778 /* Check GetCursorFrameInfo behavior on rate 3 of a multi-frame animated cursor */
1779 rate = steps = 0xdead;
1780 h2 = pGetCursorFrameInfo(h1, 0xdead, 3, &rate, &steps);
1781 ok(h2 == 0, "GetCursorFrameInfo() failed for cursor %p: (%p != 0).\n", h1, h2);
1782 ok(rate == 0xdead || broken(rate == empty_anicursor3.header.header.display_rate) /*win2k*/
1783 || broken(rate == ~0) /*win2k (sporadic)*/,
1784 "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0xdead).\n", rate);
1785 ok(steps == 0xdead || broken(steps == empty_anicursor3.header.header.num_steps) /*win2k*/
1786 || broken(steps == 0) /*win2k (sporadic)*/,
1787 "GetCursorFrameInfo() unexpected param 5 value (0x%x != 0xdead).\n", steps);
1789 /* Clean up multi-frame animated cursor. */
1790 SetLastError(0xdeadbeef);
1791 ret = DestroyCursor(h1);
1792 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1794 /* Create a multi-frame animated cursor with num_steps == 1 */
1795 empty_anicursor3.header.header.num_steps = 1;
1796 SetLastError(0xdeadbeef);
1797 h1 = CreateIconFromResource((PBYTE) &empty_anicursor3, sizeof(empty_anicursor3), FALSE, 0x00030000);
1798 ok(h1 != NULL, "Create cursor failed (error = %d).\n", GetLastError());
1800 /* Check number of steps in multi-frame animated cursor (mismatch between steps and frames) */
1801 i=0;
1802 while (DrawIconEx(hdc, 0, 0, h1, 32, 32, i, NULL, DI_NORMAL))
1803 i++;
1804 ok(i == empty_anicursor3.header.header.num_steps,
1805 "Unexpected number of steps in cursor (%d != %d)\n",
1806 i, empty_anicursor3.header.header.num_steps);
1808 /* Check GetCursorFrameInfo behavior on rate 0 for a multi-frame animated cursor (with num_steps == 1) */
1809 rate = steps = 0xdead;
1810 h2 = pGetCursorFrameInfo(h1, 0xdead, 0, &rate, &steps);
1811 ok(h1 != h2 && h2 != 0, "GetCursorFrameInfo() failed for cursor %p: (%p, %p).\n", h1, h1, h2);
1812 ret = check_cursor_data( hdc, h2, &frame_identifier[0], sizeof(DWORD) );
1813 ok(ret, "GetCursorFrameInfo() returned wrong cursor data for frame 0.\n");
1814 ok(rate == empty_anicursor3.header.header.display_rate,
1815 "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x%x).\n",
1816 rate, empty_anicursor3.header.header.display_rate);
1817 ok(steps == ~0 || broken(steps == empty_anicursor3.header.header.num_steps) /*win2k*/,
1818 "GetCursorFrameInfo() unexpected param 5 value (%d != ~0).\n", steps);
1820 /* Check GetCursorFrameInfo behavior on rate 1 for a multi-frame animated cursor (with num_steps == 1) */
1821 rate = steps = 0xdead;
1822 h2 = pGetCursorFrameInfo(h1, 0xdead, 1, &rate, &steps);
1823 ok(h2 == 0, "GetCursorFrameInfo() failed for cursor %p: (%p != 0).\n", h1, h2);
1824 ok(rate == 0xdead || broken(rate == empty_anicursor3.header.header.display_rate) /*win2k*/
1825 || broken(rate == ~0) /*win2k (sporadic)*/,
1826 "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0xdead).\n", rate);
1827 ok(steps == 0xdead || broken(steps == empty_anicursor3.header.header.num_steps) /*win2k*/
1828 || broken(steps == 0) /*win2k (sporadic)*/,
1829 "GetCursorFrameInfo() unexpected param 5 value (%d != 0xdead).\n", steps);
1831 /* Clean up multi-frame animated cursor. */
1832 SetLastError(0xdeadbeef);
1833 ret = DestroyCursor(h1);
1834 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1836 /* Creating a multi-frame animated cursor with rate data. */
1837 for (i=0; i<empty_anicursor3_seq.header.header.num_frames; i++)
1839 empty_anicursor3_seq.frames[i].data.icon_info.idType = 2; /* type: cursor */
1840 empty_anicursor3_seq.frames[i].data.icon_info.idEntries[0].xHotspot = 3;
1841 empty_anicursor3_seq.frames[i].data.icon_info.idEntries[0].yHotspot = 3;
1842 memcpy( &empty_anicursor3_seq.frames[i].data.bmi_data.data[0], &frame_identifier[i], sizeof(DWORD) );
1844 SetLastError(0xdeadbeef);
1845 h1 = CreateIconFromResource((PBYTE) &empty_anicursor3_seq, sizeof(empty_anicursor3_seq), FALSE, 0x00030000);
1846 ok(h1 != NULL, "Create cursor failed (error = %x).\n", GetLastError());
1848 /* Check number of steps in multi-frame animated cursor with rate data */
1849 i=0;
1850 while (DrawIconEx(hdc, 0, 0, h1, 32, 32, i, NULL, DI_NORMAL))
1851 i++;
1852 ok(i == empty_anicursor3_seq.header.header.num_steps,
1853 "Unexpected number of steps in cursor (%d != %d)\n",
1854 i, empty_anicursor3_seq.header.header.num_steps);
1856 /* Check GetCursorFrameInfo behavior on a multi-frame animated cursor with rate data */
1857 for (i=0; i<empty_anicursor3_seq.header.header.num_frames; i++)
1859 int frame_id = empty_anicursor3_seq.seq.order[i];
1861 rate = steps = 0xdead;
1862 h2 = pGetCursorFrameInfo(h1, 0xdead, i, &rate, &steps);
1863 ok(h1 != h2 && h2 != 0, "GetCursorFrameInfo() failed for cursor %p: (%p, %p).\n", h1, h1, h2);
1864 ret = check_cursor_data( hdc, h2, &frame_identifier[frame_id], sizeof(DWORD) );
1865 ok(ret, "GetCursorFrameInfo() returned wrong cursor data for frame %d.\n", i);
1866 ok(rate == empty_anicursor3_seq.rates.rate[i],
1867 "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x%x).\n",
1868 rate, empty_anicursor3_seq.rates.rate[i]);
1869 ok(steps == empty_anicursor3_seq.header.header.num_steps,
1870 "GetCursorFrameInfo() unexpected param 5 value (%d != %d).\n",
1871 steps, empty_anicursor3_seq.header.header.num_steps);
1874 /* Clean up multi-frame animated cursor with rate data. */
1875 SetLastError(0xdeadbeef);
1876 ret = DestroyCursor(h1);
1877 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1879 HeapFree(GetProcessHeap(), 0, hotspot);
1880 cleanup:
1881 if(bmpOld) SelectObject(hdc, bmpOld);
1882 if(bmp) DeleteObject(bmp);
1883 if(hdc) DeleteDC(hdc);
1886 static HICON create_test_icon(HDC hdc, int width, int height, int bpp,
1887 BOOL maskvalue, UINT32 *color, int colorSize)
1889 ICONINFO iconInfo;
1890 BITMAPINFO bitmapInfo;
1891 void *buffer = NULL;
1892 UINT32 mask = maskvalue ? 0xFFFFFFFF : 0x00000000;
1894 memset(&bitmapInfo, 0, sizeof(bitmapInfo));
1895 bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1896 bitmapInfo.bmiHeader.biWidth = width;
1897 bitmapInfo.bmiHeader.biHeight = height;
1898 bitmapInfo.bmiHeader.biPlanes = 1;
1899 bitmapInfo.bmiHeader.biBitCount = bpp;
1900 bitmapInfo.bmiHeader.biCompression = BI_RGB;
1901 bitmapInfo.bmiHeader.biSizeImage = colorSize;
1903 iconInfo.fIcon = TRUE;
1904 iconInfo.xHotspot = 0;
1905 iconInfo.yHotspot = 0;
1907 iconInfo.hbmMask = CreateBitmap( width, height, 1, 1, &mask );
1908 if(!iconInfo.hbmMask) return NULL;
1910 iconInfo.hbmColor = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &buffer, NULL, 0);
1911 if(!iconInfo.hbmColor || !buffer)
1913 DeleteObject(iconInfo.hbmMask);
1914 return NULL;
1917 memcpy(buffer, color, colorSize);
1919 return CreateIconIndirect(&iconInfo);
1922 static void check_alpha_draw(HDC hdc, BOOL drawiconex, BOOL alpha, int bpp, int line)
1924 HICON hicon;
1925 UINT32 color[2];
1926 COLORREF modern_expected, legacy_expected, result;
1928 color[0] = 0x00A0B0C0;
1929 color[1] = alpha ? 0xFF000000 : 0x00000000;
1930 modern_expected = alpha ? 0x00FFFFFF : 0x00C0B0A0;
1931 legacy_expected = 0x00C0B0A0;
1933 hicon = create_test_icon(hdc, 2, 1, bpp, 0, color, sizeof(color));
1934 if (!hicon) return;
1936 SetPixelV(hdc, 0, 0, 0x00FFFFFF);
1938 if(drawiconex)
1939 DrawIconEx(hdc, 0, 0, hicon, 2, 1, 0, NULL, DI_NORMAL);
1940 else
1941 DrawIcon(hdc, 0, 0, hicon);
1943 result = GetPixel(hdc, 0, 0);
1944 ok (color_match(result, modern_expected) || /* Windows 2000 and up */
1945 broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */
1946 "%s. Expected a close match to %06X (modern) or %06X (legacy) with %s. "
1947 "Got %06X from line %d\n",
1948 alpha ? "Alpha blending" : "Not alpha blending", modern_expected, legacy_expected,
1949 drawiconex ? "DrawIconEx" : "DrawIcon", result, line);
1952 static void check_DrawIcon(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, COLORREF background,
1953 COLORREF modern_expected, COLORREF legacy_expected, int line)
1955 COLORREF result;
1956 HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
1957 if (!hicon) return;
1958 SetPixelV(hdc, 0, 0, background);
1959 SetPixelV(hdc, GetSystemMetrics(SM_CXICON)-1, GetSystemMetrics(SM_CYICON)-1, background);
1960 SetPixelV(hdc, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), background);
1961 DrawIcon(hdc, 0, 0, hicon);
1962 result = GetPixel(hdc, 0, 0);
1964 ok (color_match(result, modern_expected) || /* Windows 2000 and up */
1965 broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */
1966 "Overlaying Mask %d on Color %06X with DrawIcon. "
1967 "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1968 maskvalue, color, modern_expected, legacy_expected, result, line);
1970 result = GetPixel(hdc, GetSystemMetrics(SM_CXICON)-1, GetSystemMetrics(SM_CYICON)-1);
1972 ok (color_match(result, modern_expected) || /* Windows 2000 and up */
1973 broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */
1974 "Overlaying Mask %d on Color %06X with DrawIcon. "
1975 "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1976 maskvalue, color, modern_expected, legacy_expected, result, line);
1978 result = GetPixel(hdc, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
1980 ok (color_match(result, background),
1981 "Overlaying Mask %d on Color %06X with DrawIcon. "
1982 "Expected unchanged background color %06X. Got %06X from line %d\n",
1983 maskvalue, color, background, result, line);
1986 static void test_DrawIcon(void)
1988 BITMAPINFO bitmapInfo;
1989 HDC hdcDst = NULL;
1990 HBITMAP bmpDst = NULL;
1991 HBITMAP bmpOld = NULL;
1992 void *bits = 0;
1994 hdcDst = CreateCompatibleDC(0);
1995 ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1996 if (!hdcDst)
1997 return;
1999 if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
2001 skip("Windows will distort DrawIcon colors at 8-bpp and less due to palettizing.\n");
2002 goto cleanup;
2005 memset(&bitmapInfo, 0, sizeof(bitmapInfo));
2006 bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2007 bitmapInfo.bmiHeader.biWidth = GetSystemMetrics(SM_CXICON)+1;
2008 bitmapInfo.bmiHeader.biHeight = GetSystemMetrics(SM_CYICON)+1;
2009 bitmapInfo.bmiHeader.biBitCount = 32;
2010 bitmapInfo.bmiHeader.biPlanes = 1;
2011 bitmapInfo.bmiHeader.biCompression = BI_RGB;
2012 bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
2014 bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
2015 ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
2016 if (!bmpDst || !bits)
2017 goto cleanup;
2018 bmpOld = SelectObject(hdcDst, bmpDst);
2020 /* Mask is only heeded if alpha channel is always zero */
2021 check_DrawIcon(hdcDst, FALSE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
2022 check_DrawIcon(hdcDst, TRUE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__);
2024 /* Test alpha blending */
2025 /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
2026 check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
2027 check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
2029 check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
2030 check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
2031 check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__);
2032 check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__);
2034 check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
2035 check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
2037 /* Test detecting of alpha channel */
2038 /* If a single pixel's alpha channel is non-zero, the icon
2039 will be alpha blended, otherwise it will be draw with
2040 and + xor blts. */
2041 check_alpha_draw(hdcDst, FALSE, FALSE, 32, __LINE__);
2042 check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__);
2044 cleanup:
2045 if(bmpOld)
2046 SelectObject(hdcDst, bmpOld);
2047 if(bmpDst)
2048 DeleteObject(bmpDst);
2049 if(hdcDst)
2050 DeleteDC(hdcDst);
2053 static void check_DrawIconEx(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, UINT flags, COLORREF background,
2054 COLORREF modern_expected, COLORREF legacy_expected, int line)
2056 COLORREF result;
2057 HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
2058 if (!hicon) return;
2059 SetPixelV(hdc, 0, 0, background);
2060 DrawIconEx(hdc, 0, 0, hicon, 1, 1, 0, NULL, flags);
2061 result = GetPixel(hdc, 0, 0);
2063 ok (color_match(result, modern_expected) || /* Windows 2000 and up */
2064 broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */
2065 "Overlaying Mask %d on Color %06X with DrawIconEx flags %08X. "
2066 "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
2067 maskvalue, color, flags, modern_expected, legacy_expected, result, line);
2070 static void test_DrawIconEx(void)
2072 BITMAPINFO bitmapInfo;
2073 HDC hdcDst = NULL;
2074 HBITMAP bmpDst = NULL;
2075 HBITMAP bmpOld = NULL;
2076 void *bits = 0;
2078 hdcDst = CreateCompatibleDC(0);
2079 ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
2080 if (!hdcDst)
2081 return;
2083 if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
2085 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palettizing.\n");
2086 goto cleanup;
2089 memset(&bitmapInfo, 0, sizeof(bitmapInfo));
2090 bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2091 bitmapInfo.bmiHeader.biWidth = 1;
2092 bitmapInfo.bmiHeader.biHeight = 1;
2093 bitmapInfo.bmiHeader.biBitCount = 32;
2094 bitmapInfo.bmiHeader.biPlanes = 1;
2095 bitmapInfo.bmiHeader.biCompression = BI_RGB;
2096 bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
2097 bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
2098 ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
2099 if (!bmpDst || !bits)
2100 goto cleanup;
2101 bmpOld = SelectObject(hdcDst, bmpDst);
2103 /* Test null, image only, and mask only drawing */
2104 check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__);
2105 check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__);
2107 check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_MASK, 0x00123456, 0x00000000, 0x00000000, __LINE__);
2108 check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_MASK, 0x00123456, 0x00FFFFFF, 0x00FFFFFF, __LINE__);
2110 check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
2111 check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
2113 /* Test normal drawing */
2114 check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
2115 check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__);
2116 check_DrawIconEx(hdcDst, FALSE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
2118 /* Test alpha blending */
2119 /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
2120 check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
2122 check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
2123 check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
2124 check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__);
2125 check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__);
2127 check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
2128 check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
2130 /* Test detecting of alpha channel */
2131 /* If a single pixel's alpha channel is non-zero, the icon
2132 will be alpha blended, otherwise it will be draw with
2133 and + xor blts. */
2134 check_alpha_draw(hdcDst, TRUE, FALSE, 32, __LINE__);
2135 check_alpha_draw(hdcDst, TRUE, TRUE, 32, __LINE__);
2137 cleanup:
2138 if(bmpOld)
2139 SelectObject(hdcDst, bmpOld);
2140 if(bmpDst)
2141 DeleteObject(bmpDst);
2142 if(hdcDst)
2143 DeleteDC(hdcDst);
2146 static void check_DrawState_Size(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, HBRUSH hbr, UINT flags, int line)
2148 COLORREF result, background;
2149 BOOL passed[2];
2150 HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
2151 background = 0x00FFFFFF;
2152 /* Set color of the 2 pixels that will be checked afterwards */
2153 SetPixelV(hdc, 0, 0, background);
2154 SetPixelV(hdc, 2, 2, background);
2156 /* Let DrawState calculate the size of the icon (it's 1x1) */
2157 DrawStateA(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 0, 0, (DST_ICON | flags ));
2159 result = GetPixel(hdc, 0, 0);
2160 passed[0] = color_match(result, background);
2161 result = GetPixel(hdc, 2, 2);
2162 passed[0] = passed[0] & color_match(result, background);
2164 /* Check if manually specifying the icon size DOESN'T work */
2166 /* IMPORTANT: For Icons, DrawState wants the size of the source image, not the
2167 * size in which it should be ultimately drawn. Therefore giving
2168 * width/height 2x2 if the icon is only 1x1 pixels in size should
2169 * result in drawing it with size 1x1. The size parameters must be
2170 * ignored if a Icon has to be drawn! */
2171 DrawStateA(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 2, 2, (DST_ICON | flags ));
2173 result = GetPixel(hdc, 0, 0);
2174 passed[1] = color_match(result, background);
2175 result = GetPixel(hdc, 2, 2);
2176 passed[1] = passed[0] & color_match(result, background);
2178 if(!passed[0]&&!passed[1])
2179 ok (passed[1],
2180 "DrawState failed to draw a 1x1 Icon in the correct size, independent of the "
2181 "width and height settings passed to it, for Icon with: Overlaying Mask %d on "
2182 "Color %06X with flags %08X. Line %d\n",
2183 maskvalue, color, (DST_ICON | flags), line);
2184 else if(!passed[1])
2185 ok (passed[1],
2186 "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
2187 "parameters passed to it are bigger than the real Icon size, for Icon with: Overlaying "
2188 "Mask %d on Color %06X with flags %08X. Line %d\n",
2189 maskvalue, color, (DST_ICON | flags), line);
2190 else
2191 ok (passed[0],
2192 "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
2193 "parameters passed to it are 0, for Icon with: Overlaying Mask %d on "
2194 "Color %06X with flags %08X. Line %d\n",
2195 maskvalue, color, (DST_ICON | flags), line);
2198 static void check_DrawState_Color(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, HBRUSH hbr, UINT flags,
2199 COLORREF background, COLORREF modern_expected, COLORREF legacy_expected, int line)
2201 COLORREF result;
2202 HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
2203 if (!hicon) return;
2204 /* Set color of the pixel that will be checked afterwards */
2205 SetPixelV(hdc, 1, 1, background);
2207 DrawStateA(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 0, 0, ( DST_ICON | flags ));
2209 /* Check the color of the pixel is correct */
2210 result = GetPixel(hdc, 1, 1);
2212 ok (color_match(result, modern_expected) || /* Windows 2000 and up */
2213 broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */
2214 "DrawState drawing Icon with Overlaying Mask %d on Color %06X with flags %08X. "
2215 "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
2216 maskvalue, color, (DST_ICON | flags), modern_expected, legacy_expected, result, line);
2219 static void test_DrawState(void)
2221 BITMAPINFO bitmapInfo;
2222 HDC hdcDst = NULL;
2223 HBITMAP bmpDst = NULL;
2224 HBITMAP bmpOld = NULL;
2225 void *bits = 0;
2227 hdcDst = CreateCompatibleDC(0);
2228 ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
2229 if (!hdcDst)
2230 return;
2232 if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
2234 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palettizing.\n");
2235 goto cleanup;
2238 memset(&bitmapInfo, 0, sizeof(bitmapInfo));
2239 bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2240 bitmapInfo.bmiHeader.biWidth = 3;
2241 bitmapInfo.bmiHeader.biHeight = 3;
2242 bitmapInfo.bmiHeader.biBitCount = 32;
2243 bitmapInfo.bmiHeader.biPlanes = 1;
2244 bitmapInfo.bmiHeader.biCompression = BI_RGB;
2245 bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
2246 bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
2247 ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
2248 if (!bmpDst || !bits)
2249 goto cleanup;
2250 bmpOld = SelectObject(hdcDst, bmpDst);
2252 /* potential flags to test with DrawState are: */
2253 /* DSS_DISABLED embosses the icon */
2254 /* DSS_MONO draw Icon using a brush as parameter 5 */
2255 /* DSS_NORMAL draw Icon without any modifications */
2256 /* DSS_UNION draw the Icon dithered */
2258 check_DrawState_Size(hdcDst, FALSE, 0x00A0B0C0, 32, 0, DSS_NORMAL, __LINE__);
2259 check_DrawState_Color(hdcDst, FALSE, 0x00A0B0C0, 32, 0, DSS_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
2261 cleanup:
2262 if(bmpOld)
2263 SelectObject(hdcDst, bmpOld);
2264 if(bmpDst)
2265 DeleteObject(bmpDst);
2266 if(hdcDst)
2267 DeleteDC(hdcDst);
2270 static DWORD parent_id;
2272 static DWORD CALLBACK set_cursor_thread( void *arg )
2274 HCURSOR ret;
2276 PeekMessageA( 0, 0, 0, 0, PM_NOREMOVE ); /* create a msg queue */
2277 if (parent_id)
2279 BOOL ret = AttachThreadInput( GetCurrentThreadId(), parent_id, TRUE );
2280 ok( ret, "AttachThreadInput failed\n" );
2282 if (arg) ret = SetCursor( (HCURSOR)arg );
2283 else ret = GetCursor();
2284 return (DWORD_PTR)ret;
2287 static void test_SetCursor(void)
2289 static const BYTE bmp_bits[4096];
2290 ICONINFO cursorInfo;
2291 HCURSOR cursor, old_cursor, global_cursor = 0;
2292 DWORD error, id, result;
2293 UINT display_bpp;
2294 HDC hdc;
2295 HANDLE thread;
2296 CURSORINFO info;
2298 if (pGetCursorInfo)
2300 memset( &info, 0, sizeof(info) );
2301 info.cbSize = sizeof(info);
2302 if (!pGetCursorInfo( &info ))
2304 win_skip( "GetCursorInfo not working\n" );
2305 pGetCursorInfo = NULL;
2307 else global_cursor = info.hCursor;
2309 cursor = GetCursor();
2310 thread = CreateThread( NULL, 0, set_cursor_thread, 0, 0, &id );
2311 WaitForSingleObject( thread, 1000 );
2312 GetExitCodeThread( thread, &result );
2313 ok( result == (DWORD_PTR)cursor, "wrong thread cursor %x/%p\n", result, cursor );
2315 hdc = GetDC(0);
2316 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
2317 ReleaseDC(0, hdc);
2319 cursorInfo.fIcon = FALSE;
2320 cursorInfo.xHotspot = 0;
2321 cursorInfo.yHotspot = 0;
2322 cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
2323 cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
2325 cursor = CreateIconIndirect(&cursorInfo);
2326 ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
2327 old_cursor = SetCursor( cursor );
2329 if (pGetCursorInfo)
2331 info.cbSize = sizeof(info);
2332 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2333 /* global cursor doesn't change since we don't have a window */
2334 ok( info.hCursor == global_cursor || broken(info.hCursor != cursor), /* win9x */
2335 "wrong info cursor %p/%p\n", info.hCursor, global_cursor );
2337 thread = CreateThread( NULL, 0, set_cursor_thread, 0, 0, &id );
2338 WaitForSingleObject( thread, 1000 );
2339 GetExitCodeThread( thread, &result );
2340 ok( result == (DWORD_PTR)old_cursor, "wrong thread cursor %x/%p\n", result, old_cursor );
2342 SetCursor( 0 );
2343 ok( GetCursor() == 0, "wrong cursor %p\n", GetCursor() );
2344 thread = CreateThread( NULL, 0, set_cursor_thread, 0, 0, &id );
2345 WaitForSingleObject( thread, 1000 );
2346 GetExitCodeThread( thread, &result );
2347 ok( result == (DWORD_PTR)old_cursor, "wrong thread cursor %x/%p\n", result, old_cursor );
2349 thread = CreateThread( NULL, 0, set_cursor_thread, cursor, 0, &id );
2350 WaitForSingleObject( thread, 1000 );
2351 GetExitCodeThread( thread, &result );
2352 ok( result == (DWORD_PTR)old_cursor, "wrong thread cursor %x/%p\n", result, old_cursor );
2353 ok( GetCursor() == 0, "wrong cursor %p/0\n", GetCursor() );
2355 parent_id = GetCurrentThreadId();
2356 thread = CreateThread( NULL, 0, set_cursor_thread, cursor, 0, &id );
2357 WaitForSingleObject( thread, 1000 );
2358 GetExitCodeThread( thread, &result );
2359 ok( result == (DWORD_PTR)old_cursor, "wrong thread cursor %x/%p\n", result, old_cursor );
2360 ok( GetCursor() == cursor, "wrong cursor %p/0\n", cursor );
2362 if (pGetCursorInfo)
2364 info.cbSize = sizeof(info);
2365 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2366 ok( info.hCursor == global_cursor || broken(info.hCursor != cursor), /* win9x */
2367 "wrong info cursor %p/%p\n", info.hCursor, global_cursor );
2369 SetCursor( old_cursor );
2370 DestroyCursor( cursor );
2372 SetLastError( 0xdeadbeef );
2373 cursor = SetCursor( (HCURSOR)0xbadbad );
2374 error = GetLastError();
2375 ok( cursor == 0, "wrong cursor %p/0\n", cursor );
2376 ok( error == ERROR_INVALID_CURSOR_HANDLE || broken( error == 0xdeadbeef ), /* win9x */
2377 "wrong error %u\n", error );
2379 if (pGetCursorInfo)
2381 info.cbSize = sizeof(info);
2382 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2383 ok( info.hCursor == global_cursor || broken(info.hCursor != cursor), /* win9x */
2384 "wrong info cursor %p/%p\n", info.hCursor, global_cursor );
2388 static HANDLE event_start, event_next;
2390 static DWORD CALLBACK show_cursor_thread( void *arg )
2392 DWORD count = (DWORD_PTR)arg;
2393 int ret;
2395 PeekMessageA( 0, 0, 0, 0, PM_NOREMOVE ); /* create a msg queue */
2396 if (parent_id)
2398 BOOL ret = AttachThreadInput( GetCurrentThreadId(), parent_id, TRUE );
2399 ok( ret, "AttachThreadInput failed\n" );
2401 if (!count) ret = ShowCursor( FALSE );
2402 else while (count--) ret = ShowCursor( TRUE );
2403 SetEvent( event_start );
2404 WaitForSingleObject( event_next, 2000 );
2405 return ret;
2408 static void test_ShowCursor(void)
2410 int count;
2411 DWORD id, result;
2412 HANDLE thread;
2413 CURSORINFO info;
2415 if (pGetCursorInfo)
2417 memset( &info, 0, sizeof(info) );
2418 info.cbSize = sizeof(info);
2419 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2420 ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
2423 event_start = CreateEventW( NULL, FALSE, FALSE, NULL );
2424 event_next = CreateEventW( NULL, FALSE, FALSE, NULL );
2426 count = ShowCursor( TRUE );
2427 ok( count == 1, "wrong count %d\n", count );
2428 count = ShowCursor( TRUE );
2429 ok( count == 2, "wrong count %d\n", count );
2430 count = ShowCursor( FALSE );
2431 ok( count == 1, "wrong count %d\n", count );
2432 count = ShowCursor( FALSE );
2433 ok( count == 0, "wrong count %d\n", count );
2434 count = ShowCursor( FALSE );
2435 ok( count == -1, "wrong count %d\n", count );
2436 count = ShowCursor( FALSE );
2437 ok( count == -2, "wrong count %d\n", count );
2439 if (pGetCursorInfo)
2441 info.cbSize = sizeof(info);
2442 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2443 /* global show count is not affected since we don't have a window */
2444 ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
2447 parent_id = 0;
2448 thread = CreateThread( NULL, 0, show_cursor_thread, NULL, 0, &id );
2449 WaitForSingleObject( event_start, 1000 );
2450 count = ShowCursor( FALSE );
2451 ok( count == -3, "wrong count %d\n", count );
2452 SetEvent( event_next );
2453 WaitForSingleObject( thread, 1000 );
2454 GetExitCodeThread( thread, &result );
2455 ok( result == -1, "wrong thread count %d\n", result );
2456 count = ShowCursor( FALSE );
2457 ok( count == -4, "wrong count %d\n", count );
2459 thread = CreateThread( NULL, 0, show_cursor_thread, (void *)1, 0, &id );
2460 WaitForSingleObject( event_start, 1000 );
2461 count = ShowCursor( TRUE );
2462 ok( count == -3, "wrong count %d\n", count );
2463 SetEvent( event_next );
2464 WaitForSingleObject( thread, 1000 );
2465 GetExitCodeThread( thread, &result );
2466 ok( result == 1, "wrong thread count %d\n", result );
2467 count = ShowCursor( TRUE );
2468 ok( count == -2, "wrong count %d\n", count );
2470 parent_id = GetCurrentThreadId();
2471 thread = CreateThread( NULL, 0, show_cursor_thread, NULL, 0, &id );
2472 WaitForSingleObject( event_start, 1000 );
2473 count = ShowCursor( TRUE );
2474 ok( count == -2, "wrong count %d\n", count );
2475 SetEvent( event_next );
2476 WaitForSingleObject( thread, 1000 );
2477 GetExitCodeThread( thread, &result );
2478 ok( result == -3, "wrong thread count %d\n", result );
2479 count = ShowCursor( FALSE );
2480 ok( count == -2, "wrong count %d\n", count );
2482 thread = CreateThread( NULL, 0, show_cursor_thread, (void *)3, 0, &id );
2483 WaitForSingleObject( event_start, 1000 );
2484 count = ShowCursor( TRUE );
2485 ok( count == 2, "wrong count %d\n", count );
2486 SetEvent( event_next );
2487 WaitForSingleObject( thread, 1000 );
2488 GetExitCodeThread( thread, &result );
2489 ok( result == 1, "wrong thread count %d\n", result );
2490 count = ShowCursor( FALSE );
2491 ok( count == -2, "wrong count %d\n", count );
2493 if (pGetCursorInfo)
2495 info.cbSize = sizeof(info);
2496 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2497 ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
2500 count = ShowCursor( TRUE );
2501 ok( count == -1, "wrong count %d\n", count );
2502 count = ShowCursor( TRUE );
2503 ok( count == 0, "wrong count %d\n", count );
2505 if (pGetCursorInfo)
2507 info.cbSize = sizeof(info);
2508 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2509 ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
2514 static void test_DestroyCursor(void)
2516 static const BYTE bmp_bits[4096];
2517 ICONINFO cursorInfo, new_info;
2518 HCURSOR cursor, cursor2, new_cursor;
2519 BOOL ret;
2520 DWORD error;
2521 UINT display_bpp;
2522 HDC hdc;
2524 hdc = GetDC(0);
2525 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
2526 ReleaseDC(0, hdc);
2528 cursorInfo.fIcon = FALSE;
2529 cursorInfo.xHotspot = 0;
2530 cursorInfo.yHotspot = 0;
2531 cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
2532 cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
2534 cursor = CreateIconIndirect(&cursorInfo);
2535 ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
2536 if(!cursor) {
2537 return;
2539 SetCursor(cursor);
2541 SetLastError(0xdeadbeef);
2542 ret = DestroyCursor(cursor);
2543 ok(!ret || broken(ret) /* succeeds on win9x */, "DestroyCursor on the active cursor succeeded\n");
2544 error = GetLastError();
2545 ok(error == 0xdeadbeef, "Last error: %u\n", error);
2547 new_cursor = GetCursor();
2548 if (ret) /* win9x replaces cursor by another one on destroy */
2549 ok(new_cursor != cursor, "GetCursor returned %p/%p\n", new_cursor, cursor);
2550 else
2551 ok(new_cursor == cursor, "GetCursor returned %p/%p\n", new_cursor, cursor);
2553 SetLastError(0xdeadbeef);
2554 ret = GetIconInfo( cursor, &new_info );
2555 ok( !ret || broken(ret), /* nt4 */ "GetIconInfo succeeded\n" );
2556 ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE ||
2557 broken(GetLastError() == 0xdeadbeef), /* win9x */
2558 "wrong error %u\n", GetLastError() );
2560 if (ret) /* nt4 delays destruction until cursor changes */
2562 DeleteObject( new_info.hbmColor );
2563 DeleteObject( new_info.hbmMask );
2565 SetLastError(0xdeadbeef);
2566 ret = DestroyCursor( cursor );
2567 ok( !ret, "DestroyCursor succeeded\n" );
2568 ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
2569 "wrong error %u\n", GetLastError() );
2571 SetLastError(0xdeadbeef);
2572 cursor2 = SetCursor( cursor );
2573 ok( cursor2 == cursor, "SetCursor returned %p/%p\n", cursor2, cursor);
2574 ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
2575 "wrong error %u\n", GetLastError() );
2577 else
2579 SetLastError(0xdeadbeef);
2580 cursor2 = CopyCursor( cursor );
2581 ok(!cursor2, "CopyCursor succeeded\n" );
2582 ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE ||
2583 broken(GetLastError() == 0xdeadbeef), /* win9x */
2584 "wrong error %u\n", GetLastError() );
2586 SetLastError(0xdeadbeef);
2587 ret = DestroyCursor( cursor );
2588 if (new_cursor != cursor) /* win9x */
2589 ok( ret, "DestroyCursor succeeded\n" );
2590 else
2591 ok( !ret, "DestroyCursor succeeded\n" );
2592 ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
2593 "wrong error %u\n", GetLastError() );
2595 SetLastError(0xdeadbeef);
2596 cursor2 = SetCursor( cursor );
2597 ok(!cursor2, "SetCursor returned %p/%p\n", cursor2, cursor);
2598 ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
2599 "wrong error %u\n", GetLastError() );
2602 cursor2 = GetCursor();
2603 ok(cursor2 == new_cursor, "GetCursor returned %p/%p\n", cursor2, new_cursor);
2605 SetLastError(0xdeadbeef);
2606 cursor2 = SetCursor( 0 );
2607 if (new_cursor != cursor) /* win9x */
2608 ok(cursor2 == new_cursor, "SetCursor returned %p/%p\n", cursor2, cursor);
2609 else
2610 ok(!cursor2, "SetCursor returned %p/%p\n", cursor2, cursor);
2611 ok( GetLastError() == 0xdeadbeef, "wrong error %u\n", GetLastError() );
2613 cursor2 = GetCursor();
2614 ok(!cursor2, "GetCursor returned %p/%p\n", cursor2, cursor);
2616 SetLastError(0xdeadbeef);
2617 ret = DestroyCursor(cursor);
2618 if (new_cursor != cursor) /* win9x */
2619 ok( ret, "DestroyCursor succeeded\n" );
2620 else
2621 ok( !ret, "DestroyCursor succeeded\n" );
2622 ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
2623 "wrong error %u\n", GetLastError() );
2625 DeleteObject(cursorInfo.hbmMask);
2626 DeleteObject(cursorInfo.hbmColor);
2628 /* Try testing DestroyCursor() now using LoadCursor() cursors. */
2629 cursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
2631 SetLastError(0xdeadbeef);
2632 ret = DestroyCursor(cursor);
2633 ok(ret || broken(!ret) /* fails on win9x */, "DestroyCursor on the active cursor failed.\n");
2634 error = GetLastError();
2635 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
2637 /* Try setting the cursor to a destroyed OEM cursor. */
2638 SetLastError(0xdeadbeef);
2639 SetCursor(cursor);
2640 error = GetLastError();
2641 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
2643 /* Check if LoadCursor() returns the same handle with the same icon. */
2644 cursor2 = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
2645 ok(cursor2 == cursor, "cursor == %p, cursor2 == %p\n", cursor, cursor2);
2647 /* Check if LoadCursor() returns the same handle with a different icon. */
2648 cursor2 = LoadCursorA(NULL, (LPCSTR)IDC_WAIT);
2649 ok(cursor2 != cursor, "cursor == %p, cursor2 == %p\n", cursor, cursor2);
2652 static void test_PrivateExtractIcons(void)
2654 HICON icon;
2655 UINT ret;
2657 static const test_icon_entries_t icon_desc[] = {{0,0,TRUE}, {16,16,TRUE}, {32,32}, {64,64,TRUE}};
2659 create_ico_file("extract.ico", icon_desc, ARRAY_SIZE(icon_desc));
2661 ret = PrivateExtractIconsA("extract.ico", 0, 32, 32, &icon, NULL, 1, 0);
2662 ok(ret == 1, "PrivateExtractIconsA returned %u\n", ret);
2663 ok(icon != NULL, "icon == NULL\n");
2665 test_icon_info(icon, 32, 32, 32, 32);
2666 DestroyIcon(icon);
2668 DeleteFileA("extract.ico");
2671 static void test_monochrome_icon(void)
2673 HANDLE handle;
2674 BOOL ret;
2675 DWORD bytes_written;
2676 CURSORICONFILEDIR *icon_data;
2677 CURSORICONFILEDIRENTRY *icon_entry;
2678 BITMAPINFO *bitmap_info;
2679 BITMAPCOREINFO *core_info;
2680 ICONINFO icon_info;
2681 ULONG icon_size;
2682 BOOL monochrome, use_core_info;
2684 icon_data = HeapAlloc(GetProcessHeap(), 0, sizeof(CURSORICONFILEDIR) + sizeof(BITMAPINFOHEADER) +
2685 2 * sizeof(RGBQUAD) + sizeof(ULONG));
2687 for (monochrome = FALSE; monochrome <= TRUE; monochrome++)
2688 for (use_core_info = FALSE; use_core_info <= TRUE; use_core_info++)
2690 trace("%s, %s\n",
2691 monochrome ? "monochrome" : "colored",
2692 use_core_info ? "core info" : "bitmap info");
2694 icon_size = sizeof(CURSORICONFILEDIR) +
2695 (use_core_info ? sizeof(BITMAPCOREHEADER) : sizeof(BITMAPINFOHEADER)) +
2696 /* 2 * sizeof(RGBTRIPLE) + padding comes out the same */
2697 2 * sizeof(RGBQUAD) +
2698 sizeof(ULONG);
2699 ZeroMemory(icon_data, icon_size);
2700 icon_data->idReserved = 0;
2701 icon_data->idType = 1;
2702 icon_data->idCount = 1;
2704 icon_entry = icon_data->idEntries;
2705 icon_entry->bWidth = 1;
2706 icon_entry->bHeight = 1;
2707 icon_entry->bColorCount = 0;
2708 icon_entry->bReserved = 0;
2709 icon_entry->xHotspot = 0;
2710 icon_entry->yHotspot = 0;
2711 icon_entry->dwDIBSize = icon_size - sizeof(CURSORICONFILEDIR);
2712 icon_entry->dwDIBOffset = sizeof(CURSORICONFILEDIR);
2714 if (use_core_info)
2716 core_info = (BITMAPCOREINFO *) ((BYTE *) icon_data + icon_entry->dwDIBOffset);
2717 core_info->bmciHeader.bcSize = sizeof(BITMAPCOREHEADER);
2718 core_info->bmciHeader.bcWidth = 1;
2719 core_info->bmciHeader.bcHeight = 2;
2720 core_info->bmciHeader.bcPlanes = 1;
2721 core_info->bmciHeader.bcBitCount = 1;
2722 core_info->bmciColors[0].rgbtBlue = monochrome ? 0x00 : 0xff;
2723 core_info->bmciColors[0].rgbtGreen = 0x00;
2724 core_info->bmciColors[0].rgbtRed = 0x00;
2725 core_info->bmciColors[1].rgbtBlue = 0xff;
2726 core_info->bmciColors[1].rgbtGreen = 0xff;
2727 core_info->bmciColors[1].rgbtRed = 0xff;
2729 else
2731 bitmap_info = (BITMAPINFO *) ((BYTE *) icon_data + icon_entry->dwDIBOffset);
2732 bitmap_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2733 bitmap_info->bmiHeader.biWidth = 1;
2734 bitmap_info->bmiHeader.biHeight = 2;
2735 bitmap_info->bmiHeader.biPlanes = 1;
2736 bitmap_info->bmiHeader.biBitCount = 1;
2737 bitmap_info->bmiHeader.biSizeImage = 0; /* Uncompressed bitmap. */
2738 bitmap_info->bmiColors[0].rgbBlue = monochrome ? 0x00 : 0xff;
2739 bitmap_info->bmiColors[0].rgbGreen = 0x00;
2740 bitmap_info->bmiColors[0].rgbRed = 0x00;
2741 bitmap_info->bmiColors[1].rgbBlue = 0xff;
2742 bitmap_info->bmiColors[1].rgbGreen = 0xff;
2743 bitmap_info->bmiColors[1].rgbRed = 0xff;
2746 handle = CreateFileA("icon.ico", GENERIC_WRITE, 0, NULL, CREATE_NEW,
2747 FILE_ATTRIBUTE_NORMAL, NULL);
2748 ok(handle != INVALID_HANDLE_VALUE, "CreateFileA failed. %u\n", GetLastError());
2749 ret = WriteFile(handle, icon_data, icon_size, &bytes_written, NULL);
2750 ok(ret && bytes_written == icon_size, "icon.ico created improperly.\n");
2751 CloseHandle(handle);
2753 handle = LoadImageA(NULL, "icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
2754 ok(handle != NULL ||
2755 broken(use_core_info && handle == NULL), /* Win 8, 10 */
2756 "LoadImage() failed with %u.\n", GetLastError());
2757 if (handle == NULL)
2759 skip("Icon failed to load: %s, %s\n",
2760 monochrome ? "monochrome" : "colored",
2761 use_core_info ? "core info" : "bitmap info");
2762 DeleteFileA("icon.ico");
2763 continue;
2766 ret = GetIconInfo(handle, &icon_info);
2767 ok(ret, "GetIconInfo() failed with %u.\n", GetLastError());
2768 if (ret)
2770 ok(icon_info.fIcon == TRUE, "fIcon is %u.\n", icon_info.fIcon);
2771 ok(icon_info.xHotspot == 0, "xHotspot is %u.\n", icon_info.xHotspot);
2772 ok(icon_info.yHotspot == 0, "yHotspot is %u.\n", icon_info.yHotspot);
2773 if (monochrome)
2774 ok(icon_info.hbmColor == NULL, "Got hbmColor %p!\n", icon_info.hbmColor);
2775 else
2776 ok(icon_info.hbmColor != NULL, "No hbmColor!\n");
2777 ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
2780 ret = DestroyIcon(handle);
2781 ok(ret, "DestroyIcon() failed with %u.\n", GetLastError());
2782 DeleteFileA("icon.ico");
2785 HeapFree(GetProcessHeap(), 0, icon_data);
2788 static COLORREF get_color_from_bits(const unsigned char *bits, const BITMAPINFO *bmi,
2789 unsigned int row, unsigned int column)
2791 const BITMAPINFOHEADER *h = &bmi->bmiHeader;
2792 unsigned int stride, shift, mask;
2793 const unsigned char *data;
2794 RGBQUAD color;
2795 WORD color16;
2797 stride = ((h->biBitCount * h->biWidth + 7) / 8 + 3) & ~3;
2798 data = bits + row * stride + column * h->biBitCount / 8;
2799 if (h->biBitCount >= 24)
2800 return RGB(data[2], data[1], data[0]);
2802 if (h->biBitCount == 16)
2804 color16 = ((WORD)data[1] << 8) | data[0];
2805 return RGB(((color16 >> 10) & 0x1f) << 3, ((color16 >> 5) & 0x1f) << 3,
2806 (color16 & 0x1f) << 3);
2808 shift = 8 - h->biBitCount - (column * h->biBitCount) % 8;
2809 mask = ~(~0u << h->biBitCount);
2810 color = bmi->bmiColors[(data[0] >> shift) & mask];
2811 return RGB(color.rgbRed, color.rgbGreen, color.rgbBlue);
2814 #define compare_bitmap_bits(a, b, c, d, e, f, g) compare_bitmap_bits_(__LINE__, a, b, c, d, e, f, g)
2815 static void compare_bitmap_bits_(unsigned int line, HDC hdc, HBITMAP bitmap, BITMAPINFO *bmi,
2816 size_t result_bits_size, const unsigned char *expected_bits, unsigned int test_index, BOOL todo)
2818 unsigned char *result_bits;
2819 unsigned int row, column;
2820 int ret;
2822 result_bits = HeapAlloc(GetProcessHeap(), 0, result_bits_size);
2823 ret = GetDIBits(hdc, bitmap, 0, bmi->bmiHeader.biHeight,
2824 result_bits, bmi, DIB_RGB_COLORS);
2825 ok(ret == bmi->bmiHeader.biHeight, "Unexpected GetDIBits result %d, GetLastError() %u.\n",
2826 ret, GetLastError());
2827 for (row = 0; row < bmi->bmiHeader.biHeight; ++row)
2828 for (column = 0; column < bmi->bmiHeader.biWidth; ++column)
2830 COLORREF result, expected;
2832 result = get_color_from_bits(result_bits, bmi, row, column);
2833 expected = get_color_from_bits(expected_bits, bmi, row, column);
2835 todo_wine_if(todo)
2836 ok_(__FILE__, line)(result == expected, "Colors do not match, "
2837 "got 0x%06x, expected 0x%06x, test_index %u, row %u, column %u.\n",
2838 result, expected, test_index, row, column);
2840 HeapFree(GetProcessHeap(), 0, result_bits);
2843 static void test_Image_StretchMode(void)
2845 static const unsigned char test_bits_24[] =
2847 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
2848 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00,
2849 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
2850 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
2852 static const unsigned char expected_bits_24[] =
2854 0x3f, 0xff, 0x00, 0x3f, 0xff, 0x3f, 0x00, 0x00,
2855 0x3f, 0xff, 0x7f, 0x00, 0xff, 0x3f, 0x00, 0x00,
2857 #define rgb16(r, g, b) ((WORD)(((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3)))
2858 static const WORD test_bits_16[] =
2860 rgb16(0x00, 0x20, 0x00), rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x40, 0xff), rgb16(0x00, 0x20, 0x00),
2861 rgb16(0x00, 0x60, 0x00), rgb16(0xff, 0x80, 0x00), rgb16(0xff, 0x60, 0x00), rgb16(0x00, 0x80, 0x00),
2862 rgb16(0x00, 0x20, 0xff), rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x40, 0xff), rgb16(0x00, 0x20, 0x00),
2863 rgb16(0xff, 0x80, 0x00), rgb16(0x00, 0x60, 0xff), rgb16(0x00, 0x80, 0x00), rgb16(0x00, 0x60, 0x00),
2865 static const WORD expected_bits_16[] =
2867 rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x20, 0x00),
2868 rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x20, 0x00),
2870 #undef rgb16
2871 static const unsigned char test_bits_8[] =
2873 0x00, 0xff, 0x00, 0xff,
2874 0x00, 0x00, 0x00, 0x00,
2875 0xff, 0x55, 0x00, 0xff,
2876 0x00, 0xff, 0xff, 0x00,
2878 static const unsigned char expected_bits_8[] =
2880 0xff, 0xff, 0x00, 0x00,
2881 0x55, 0xff, 0x00, 0x00,
2883 static const unsigned char test_bits_1[] =
2885 0x30, 0x0, 0x0, 0x0,
2886 0x30, 0x0, 0x0, 0x0,
2887 0x40, 0x0, 0x0, 0x0,
2888 0xc0, 0x0, 0x0, 0x0,
2890 static const unsigned char expected_bits_1[] =
2892 0x40, 0x0, 0x0, 0x0,
2893 0x0, 0x0, 0x0, 0x0,
2895 static const RGBQUAD colors_bits_1[] =
2897 {0, 0, 0},
2898 {0xff, 0xff, 0xff},
2900 static RGBQUAD colors_bits_8[256];
2902 static const struct
2904 LONG width, height, output_width, output_height;
2905 WORD bit_count;
2906 const unsigned char *test_bits, *expected_bits;
2907 size_t test_bits_size, result_bits_size;
2908 const RGBQUAD *bmi_colors;
2909 size_t bmi_colors_size;
2910 BOOL todo;
2912 tests[] =
2914 {4, 4, 2, 2, 24, test_bits_24, expected_bits_24,
2915 sizeof(test_bits_24), sizeof(expected_bits_24), NULL, 0, TRUE},
2916 {4, 4, 2, 2, 1, test_bits_1, expected_bits_1,
2917 sizeof(test_bits_1), sizeof(expected_bits_1), colors_bits_1,
2918 sizeof(colors_bits_1), FALSE},
2919 {4, 4, 2, 2, 8, test_bits_8, expected_bits_8,
2920 sizeof(test_bits_8), sizeof(expected_bits_8), colors_bits_8,
2921 sizeof(colors_bits_8), FALSE},
2922 {4, 4, 2, 2, 16, (const unsigned char *)test_bits_16, (const unsigned char *)expected_bits_16,
2923 sizeof(test_bits_16), sizeof(expected_bits_16), NULL, 0, FALSE},
2925 static const char filename[] = "test.bmp";
2926 BITMAPINFO *bmi, *bmi_output;
2927 HBITMAP bitmap, bitmap_copy;
2928 unsigned int test_index;
2929 unsigned char *bits;
2930 size_t bmi_size;
2931 unsigned int i;
2932 HDC hdc;
2934 bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
2935 bmi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bmi_size);
2936 bmi_output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bmi_size);
2937 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2938 bmi->bmiHeader.biPlanes = 1;
2939 bmi->bmiHeader.biCompression = BI_RGB;
2941 for (i = 0; i < 256; ++i)
2942 colors_bits_8[i].rgbRed = colors_bits_8[i].rgbGreen = colors_bits_8[i].rgbBlue = i;
2944 hdc = GetDC(NULL);
2946 for (test_index = 0; test_index < ARRAY_SIZE(tests); ++test_index)
2948 if (tests[test_index].bmi_colors)
2949 memcpy(bmi->bmiColors, tests[test_index].bmi_colors, tests[test_index].bmi_colors_size);
2950 else
2951 memset(bmi->bmiColors, 0, 256 * sizeof(RGBQUAD));
2953 bmi->bmiHeader.biWidth = tests[test_index].width;
2954 bmi->bmiHeader.biHeight = tests[test_index].height;
2955 bmi->bmiHeader.biBitCount = tests[test_index].bit_count;
2956 memcpy(bmi_output, bmi, bmi_size);
2957 bmi_output->bmiHeader.biWidth = tests[test_index].output_width;
2958 bmi_output->bmiHeader.biHeight = tests[test_index].output_height;
2960 bitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, (void **)&bits, NULL, 0);
2961 ok(bitmap && bits, "CreateDIBSection() failed, result %u.\n", GetLastError());
2962 memcpy(bits, tests[test_index].test_bits, tests[test_index].test_bits_size);
2964 bitmap_copy = CopyImage(bitmap, IMAGE_BITMAP, tests[test_index].output_width,
2965 tests[test_index].output_height, LR_CREATEDIBSECTION);
2966 ok(!!bitmap_copy, "CopyImage() failed, result %u.\n", GetLastError());
2968 compare_bitmap_bits(hdc, bitmap_copy, bmi_output, tests[test_index].result_bits_size,
2969 tests[test_index].expected_bits, test_index, tests[test_index].todo);
2970 DeleteObject(bitmap);
2971 DeleteObject(bitmap_copy);
2973 create_bitmap_file(filename, bmi, tests[test_index].test_bits);
2974 bitmap = LoadImageA(NULL, filename, IMAGE_BITMAP, tests[test_index].output_width,
2975 tests[test_index].output_height, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
2976 ok(!!bitmap, "LoadImageA() failed, result %u.\n", GetLastError());
2977 DeleteFileA(filename);
2978 compare_bitmap_bits(hdc, bitmap, bmi_output, tests[test_index].result_bits_size,
2979 tests[test_index].expected_bits, test_index, tests[test_index].todo);
2980 DeleteObject(bitmap);
2982 ReleaseDC(0, hdc);
2983 HeapFree(GetProcessHeap(), 0, bmi_output);
2984 HeapFree(GetProcessHeap(), 0, bmi);
2987 START_TEST(cursoricon)
2989 pGetCursorInfo = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetCursorInfo" );
2990 pGetIconInfoExA = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetIconInfoExA" );
2991 pGetIconInfoExW = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetIconInfoExW" );
2992 pGetCursorFrameInfo = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetCursorFrameInfo" );
2993 test_argc = winetest_get_mainargs(&test_argv);
2995 if (test_argc >= 3)
2997 /* Child process. */
2998 sscanf (test_argv[2], "%x", (unsigned int *) &parent);
3000 ok(parent != NULL, "Parent not found.\n");
3001 if (parent == NULL)
3002 ExitProcess(1);
3004 do_child();
3005 return;
3008 test_CopyImage_Bitmap(1);
3009 test_CopyImage_Bitmap(4);
3010 test_CopyImage_Bitmap(8);
3011 test_CopyImage_Bitmap(16);
3012 test_CopyImage_Bitmap(24);
3013 test_CopyImage_Bitmap(32);
3014 test_Image_StretchMode();
3015 test_initial_cursor();
3016 test_CreateIcon();
3017 test_LoadImage();
3018 test_CreateIconFromResource();
3019 test_GetCursorFrameInfo();
3020 test_DrawIcon();
3021 test_DrawIconEx();
3022 test_DrawState();
3023 test_SetCursor();
3024 test_ShowCursor();
3025 test_DestroyCursor();
3026 test_PrivateExtractIcons();
3027 test_monochrome_icon();
3028 do_parent();
3029 test_child_process();
3030 finish_child_process();