1 /*
2 * Unit test suite for cursors and icons.
3 *
4 * Copyright 2006 Michael Kaufmann
5 * Copyright 2007 Dmitry Timoshkov
6 * Copyright 2007-2008 Andrew Riedi
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
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"
33
34 #include "pshpack1.h"
35
36 typedef struct
37 {
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;
47
48 typedef struct
49 {
50 WORD idReserved;
51 WORD idType;
52 WORD idCount;
53 CURSORICONFILEDIRENTRY idEntries[1];
54 } CURSORICONFILEDIR;
55
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 ) )
59
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')
68
69 #define ANI_FLAG_ICON 0x1
70 #define ANI_FLAG_SEQUENCE 0x2
71
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;
83
84 typedef struct {
85 BYTE data[32*32*4];
86 BYTE mask_data[32*32/8];
87 } ani_data32x32x32;
88
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;
94
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;
100
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;
106
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;
112
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;
121
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;
130
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;
136
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;
142
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;
153
154 #define EMPTY_ICON32 \
155 { \
156 ANI_icon_ID, \
157 sizeof(ani_frame32x32x32), \
158 { \
159 { \
160 0x0, /* reserved */ \
161 0, /* type: icon(1), cursor(2) */ \
162 1, /* count */ \
163 { \
164 { \
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 */ \
173 } \
174 } \
175 }, \
176 { \
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 */ \
188 } \
189 /* DIB data: left uninitialized */ \
190 } \
191 }
192
193 riff_cursor1_t empty_anicursor = {
194 ANI_RIFF_ID,
195 sizeof(empty_anicursor) - sizeof(DWORD)*2,
196 ANI_ACON_ID,
197 {
198 ANI_anih_ID,
199 sizeof(ani_header),
200 {
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 */
210 }
211 },
212 {
213 ANI_LIST_ID,
214 sizeof(riff_icon32x32x32_t)*(1 /*frames*/) + sizeof(DWORD),
215 ANI_fram_ID,
216 },
217 {
218 EMPTY_ICON32
219 }
220 };
221
222 riff_cursor3_t empty_anicursor3 = {
223 ANI_RIFF_ID,
224 sizeof(empty_anicursor3) - sizeof(DWORD)*2,
225 ANI_ACON_ID,
226 {
227 ANI_anih_ID,
228 sizeof(ani_header),
229 {
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 */
239 }
240 },
241 {
242 ANI_LIST_ID,
243 sizeof(riff_icon32x32x32_t)*(3 /*frames*/) + sizeof(DWORD),
244 ANI_fram_ID,
245 },
246 {
247 EMPTY_ICON32,
248 EMPTY_ICON32,
249 EMPTY_ICON32
250 }
251 };
252
253 riff_cursor3_seq_t empty_anicursor3_seq = {
254 ANI_RIFF_ID,
255 sizeof(empty_anicursor3_seq) - sizeof(DWORD)*2,
256 ANI_ACON_ID,
257 {
258 ANI_anih_ID,
259 sizeof(ani_header),
260 {
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 */
270 }
271 },
272 {
273 ANI_seq__ID,
274 sizeof(riff_seq3_t) - sizeof(DWORD)*2,
275 { 2, 0, 1} /* show frames in a uniquely identifiable order */
276 },
277 {
278 ANI_rate_ID,
279 sizeof(riff_rate3_t) - sizeof(DWORD)*2,
280 { 0xc0de, 0xcafe, 0xbabe}
281 },
282 {
283 ANI_LIST_ID,
284 sizeof(riff_icon32x32x32_t)*(3 /*frames*/) + sizeof(DWORD),
285 ANI_fram_ID,
286 },
287 {
288 EMPTY_ICON32,
289 EMPTY_ICON32,
290 EMPTY_ICON32
291 }
292 };
293
294 #include "poppack.h"
295
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;
301
302 #define PROC_INIT (WM_USER+1)
303
304 static BOOL (WINAPI *pGetCursorInfo)(CURSORINFO *);
305 static BOOL (WINAPI *pGetIconInfoExA)(HICON,ICONINFOEXA *);
306 static BOOL (WINAPI *pGetIconInfoExW)(HICON,ICONINFOEXW *);
307
308 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
309
callback_child(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)310 static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
311 {
312 switch (msg)
313 {
314 /* Destroy the cursor. */
315 case WM_USER+1:
316 {
317 HCURSOR cursor = (HCURSOR)lParam;
318 ICONINFO info;
319 BOOL ret;
320 DWORD error;
321
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);
329
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;
338 }
339 case WM_DESTROY:
340 PostQuitMessage(0);
341 return 0;
342 }
343
344 return DefWindowProcA(hwnd, msg, wParam, lParam);
345 }
346
callback_parent(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)347 static LRESULT CALLBACK callback_parent(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
348 {
349 if (msg == PROC_INIT)
350 {
351 child = (HWND) wParam;
352 return TRUE;
353 }
354
355 return DefWindowProcA(hwnd, msg, wParam, lParam);
356 }
357
do_child(void)358 static void do_child(void)
359 {
360 WNDCLASSA class;
361 MSG msg;
362 BOOL ret;
363
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";
375
376 SetLastError(0xdeadbeef);
377 ret = RegisterClassA(&class);
378 ok(ret, "Failed to register window class. Error: %u\n", GetLastError());
379
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());
384
385 /* Let the parent know our HWND. */
386 PostMessageA(parent, PROC_INIT, (WPARAM) child, 0);
387
388 /* Receive messages. */
389 while ((ret = GetMessageA(&msg, 0, 0, 0)))
390 {
391 ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError());
392 TranslateMessage(&msg);
393 DispatchMessageA(&msg);
394 }
395 }
396
do_parent(void)397 static void do_parent(void)
398 {
399 char path_name[MAX_PATH];
400 PROCESS_INFORMATION info;
401 STARTUPINFOA startup;
402 WNDCLASSA class;
403 MSG msg;
404 BOOL ret;
405
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";
417
418 SetLastError(0xdeadbeef);
419 ret = RegisterClassA(&class);
420 ok(ret, "Failed to register window class. Error: %u\n", GetLastError());
421
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());
426
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;
432
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;
436
437 /* Wait for child window handle. */
438 while ((child == 0) && (ret = GetMessageA(&msg, parent, 0, 0)))
439 {
440 ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError());
441 TranslateMessage(&msg);
442 DispatchMessageA(&msg);
443 }
444 }
445
finish_child_process(void)446 static void finish_child_process(void)
447 {
448 SendMessageA(child, WM_CLOSE, 0, 0);
449 winetest_wait_child_process( child_process );
450 CloseHandle(child_process);
451 }
452
test_child_process(void)453 static void test_child_process(void)
454 {
455 static const BYTE bmp_bits[4096];
456 HCURSOR cursor;
457 ICONINFO cursorInfo;
458 UINT display_bpp;
459 HDC hdc;
460
461 /* Create and set a dummy cursor. */
462 hdc = GetDC(0);
463 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
464 ReleaseDC(0, hdc);
465
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);
471
472 cursor = CreateIconIndirect(&cursorInfo);
473 ok(cursor != NULL, "CreateIconIndirect returned %p.\n", cursor);
474
475 SetCursor(cursor);
476
477 /* Destroy the cursor. */
478 SendMessageA(child, WM_USER+1, 0, (LPARAM) cursor);
479 }
480
color_match(COLORREF a,COLORREF b)481 static BOOL color_match(COLORREF a, COLORREF b)
482 {
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);
487 }
488
test_CopyImage_Check(HBITMAP bitmap,UINT flags,INT copyWidth,INT copyHeight,INT expectedWidth,INT expectedHeight,WORD expectedDepth,BOOL dibExpected)489 static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight,
490 INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected)
491 {
492 HBITMAP copy;
493 BITMAP origBitmap;
494 BITMAP copyBitmap;
495 BOOL orig_is_dib;
496 BOOL copy_is_dib;
497
498 copy = CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
499 ok(copy != NULL, "CopyImage() failed\n");
500 if (copy != NULL)
501 {
502 GetObjectA(bitmap, sizeof(origBitmap), &origBitmap);
503 GetObjectA(copy, sizeof(copyBitmap), ©Bitmap);
504 orig_is_dib = (origBitmap.bmBits != NULL);
505 copy_is_dib = (copyBitmap.bmBits != NULL);
506
507 if (copy_is_dib && dibExpected
508 && copyBitmap.bmBitsPixel == 24
509 && (expectedDepth == 16 || expectedDepth == 32))
510 {
511 /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
512 if (GetVersion() & 0x80000000)
513 {
514 expectedDepth = 24;
515 }
516 }
517
518 if (copy_is_dib && !dibExpected && !(flags & LR_CREATEDIBSECTION))
519 {
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;
526 }
527
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);
537
538 DeleteObject(copy);
539 }
540 }
541
test_CopyImage_Bitmap(int depth)542 static void test_CopyImage_Bitmap(int depth)
543 {
544 HBITMAP ddb, dib;
545 HDC screenDC;
546 BITMAPINFO * info;
547 VOID * bits;
548 int screen_depth;
549 unsigned int i;
550
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;
559
560 for (i=0; i < 256; i++)
561 {
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;
566 }
567
568 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
569
570 /* Create a device-dependent bitmap (DDB) */
571 screenDC = GetDC(NULL);
572 screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
573 if (depth == 1 || depth == screen_depth)
574 {
575 ddb = CreateBitmap(2, 2, 1, depth, NULL);
576 }
577 else
578 {
579 ddb = NULL;
580 }
581 ReleaseDC(NULL, screenDC);
582
583 if (ddb != NULL)
584 {
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);
589
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);
594
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);
599
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);
605
606 DeleteObject(ddb);
607 }
608
609 if (depth != 1)
610 {
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);
615 }
616
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);
621
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);
626
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);
632
633 DeleteObject(dib);
634
635 if (depth == 1)
636 {
637 /* Special case: A monochrome DIB is converted to a monochrome DDB if
638 the colors in the color table are black and white.
639
640 Skip this test on Windows 95, it always creates a monochrome DDB
641 in this case */
642
643 if (!(GetVersion() & 0x80000000))
644 {
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;
652
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);
659
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;
667
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);
674
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;
682
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);
689 }
690 }
691
692 HeapFree(GetProcessHeap(), 0, info);
693 }
694
test_initial_cursor(void)695 static void test_initial_cursor(void)
696 {
697 HCURSOR cursor, cursor2;
698 DWORD error;
699
700 cursor = GetCursor();
701
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);
707 }
708 error = GetLastError();
709 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
710 }
711
test_icon_info_dbg(HICON hIcon,UINT exp_cx,UINT exp_cy,UINT exp_mask_cy,UINT exp_bpp,int line)712 static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_mask_cy, UINT exp_bpp, int line)
713 {
714 ICONINFO info;
715 DWORD ret;
716 BITMAP bmMask, bmColor;
717
718 ret = GetIconInfo(hIcon, &info);
719 ok_(__FILE__, line)(ret, "GetIconInfo failed\n");
720
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");
725
726 ret = GetObjectA(info.hbmMask, sizeof(bmMask), &bmMask);
727 ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %u\n", ret);
728
729 if (exp_bpp == 1)
730 ok_(__FILE__, line)(info.hbmColor == 0, "info.hbmColor should be NULL\n");
731
732 if (info.hbmColor)
733 {
734 HDC hdc;
735 UINT display_bpp;
736
737 hdc = GetDC(0);
738 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
739 ReleaseDC(0, hdc);
740
741 ret = GetObjectA(info.hbmColor, sizeof(bmColor), &bmColor);
742 ok_(__FILE__, line)(ret == sizeof(bmColor), "GetObject(info.hbmColor) failed, ret %u\n", ret);
743
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);
749
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);
753 }
754 else
755 {
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);
759 }
760 if (pGetIconInfoExA)
761 {
762 ICONINFOEXA infoex;
763
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());
770
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());
776
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());
783
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);
790 }
791 }
792
793 #define test_icon_info(a,b,c,d,e) test_icon_info_dbg((a),(b),(c),(d),(e),__LINE__)
794
test_CreateIcon(void)795 static void test_CreateIcon(void)
796 {
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;
806
807 hdc = GetDC(0);
808 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
809
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);
813 */
814
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);
819
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);
824
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");
829
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());
839
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());
849
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);
859
860 DeleteObject(hbmMask);
861 DeleteObject(hbmColor);
862
863 hbmMask = CreateBitmap(16, 32, 1, 1, bmp_bits);
864 ok(hbmMask != 0, "CreateBitmap failed\n");
865
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);
877
878 for (i = 0; i <= 4; i++)
879 {
880 hbmMask = CreateBitmap(1, i, 1, 1, bmp_bits);
881 ok(hbmMask != 0, "CreateBitmap failed\n");
882
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);
894 }
895
896 /* test creating an icon from a DIB section */
897
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 );
914
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);
926
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 );
932
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);
944
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 );
950
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);
961
962 DeleteObject(hbmMask);
963 DeleteObject(hbmColor);
964 HeapFree( GetProcessHeap(), 0, bmpinfo );
965
966 ReleaseDC(0, hdc);
967 }
968
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
975 };
976
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
997 };
998
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
1008 };
1009
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
1018 };
1019
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
1025 };
1026
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
1032 };
1033
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
1038 };
1039
1040 static const DWORD biSize_tests[] = {
1041 0,
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
1054 };
1055
test_LoadImageBitmap(const char * test_desc,HBITMAP hbm)1056 static void test_LoadImageBitmap(const char * test_desc, HBITMAP hbm)
1057 {
1058 BITMAP bm;
1059 BITMAPINFO bmi;
1060 DWORD ret, pixel = 0;
1061 HDC hdc = GetDC(NULL);
1062
1063 ret = GetObjectA(hbm, sizeof(bm), &bm);
1064 ok(ret == sizeof(bm), "GetObject returned %d\n", ret);
1065
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);
1075
1076 ok(color_match(pixel, 0x00ffffff), "%s: Pixel is 0x%08x\n", test_desc, pixel);
1077
1078 ReleaseDC(NULL, hdc);
1079 }
1080
test_LoadImageFile(const char * test_desc,const unsigned char * image_data,unsigned int image_size,const char * ext,BOOL expect_success)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)
1083 {
1084 HANDLE handle;
1085 BOOL ret;
1086 DWORD error, bytes_written;
1087 char filename[64];
1088
1089 strcpy(filename, "test.");
1090 strcat(filename, ext);
1091
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);
1099
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);
1110
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);
1121
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);
1129
1130 if (expect_success) {
1131 ok(handle != NULL, "%s: IMAGE_BITMAP failed.\n", test_desc);
1132 if (handle != NULL) test_LoadImageBitmap(test_desc, handle);
1133 }
1134 else ok(handle == NULL, "%s: IMAGE_BITMAP succeeded incorrectly.\n", test_desc);
1135
1136 if (handle != NULL) DeleteObject(handle);
1137 DeleteFileA(filename);
1138 }
1139
1140 typedef struct {
1141 unsigned width;
1142 unsigned height;
1143 BOOL invalid_offset;
1144 } test_icon_entries_t;
1145
create_ico_file(const char * filename,const test_icon_entries_t * test_icon_entries,unsigned entry_cnt)1146 static void create_ico_file(const char *filename, const test_icon_entries_t *test_icon_entries, unsigned entry_cnt)
1147 {
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;
1157
1158 const unsigned icon_bpp = 32;
1159
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;
1163
1164 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, icon_size);
1165 dir = (CURSORICONFILEDIR*)buf;
1166
1167 dir->idReserved = 0;
1168 dir->idType = 1;
1169 dir->idCount = entry_cnt;
1170
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;
1182
1183 icon_header = (BITMAPINFOHEADER*)bitmap_ptr;
1184 bitmap_ptr += icon_entry->dwDIBSize;
1185
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. */
1192 }
1193
1194 memset(bitmap_ptr, 0xf0, buf+icon_size-bitmap_ptr);
1195
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);
1202
1203 HeapFree(GetProcessHeap(), 0, buf);
1204 }
1205
create_bitmap_file(const char * filename,const BITMAPINFO * bmi,const unsigned char * bits)1206 static void create_bitmap_file(const char *filename, const BITMAPINFO *bmi, const unsigned char *bits)
1207 {
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;
1214
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);
1219
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;
1225
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);
1238 }
1239
test_LoadImage_working_directory_run(char * path)1240 static void test_LoadImage_working_directory_run(char *path)
1241 {
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};
1248
1249 sprintf(path_icon, "%s\\icon.ico", path);
1250 sprintf(path_image, "%s\\test.bmp", path);
1251
1252 /* Create Files */
1253 create_ico_file(path_icon, &icon_desc, 1);
1254
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);
1260
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);
1264
1265 ret = DestroyIcon(handle);
1266 ok(ret, "run %s: DestroyIcon failed: %d\n", path, GetLastError());
1267
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);
1271
1272 ret = DeleteObject(handle);
1273 ok(ret, "run %s: DeleteObject failed: %d\n", path, GetLastError());
1274
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());
1280 }
1281
test_LoadImage_working_directory(void)1282 static void test_LoadImage_working_directory(void)
1283 {
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;
1292
1293 GetCurrentDirectoryA(ARRAY_SIZE(old_working_dir), old_working_dir);
1294
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\\");
1299
1300 GetModuleFileNameA(NULL, executable_path, ARRAY_SIZE(executable_path));
1301 pos_slash = strrchr(executable_path, '\\') - executable_path;
1302 executable_path[pos_slash + 1] = 0;
1303
1304 CreateDirectoryA(temp_dir_current, NULL);
1305 CreateDirectoryA(temp_dir_PATH, NULL);
1306
1307 SetCurrentDirectoryA(temp_dir_current);
1308
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);
1312
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);
1316
1317 SetCurrentDirectoryA(old_working_dir);
1318 SetEnvironmentVariableA("PATH", old_PATH);
1319
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());
1324 }
1325
test_LoadImage(void)1326 static void test_LoadImage(void)
1327 {
1328 HANDLE handle;
1329 BOOL ret;
1330 DWORD error;
1331 BITMAPINFOHEADER *bitmap_header;
1332 ICONINFO icon_info;
1333 int i;
1334
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)
1342
1343 static const test_icon_entries_t icon_desc = {32, 32};
1344
1345 create_ico_file("icon.ico", &icon_desc, 1);
1346
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);
1356
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);
1363
1364 if (ret)
1365 {
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");
1372 }
1373
1374 if (pGetIconInfoExA)
1375 {
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 );
1383 }
1384 else win_skip( "GetIconInfoEx not available\n" );
1385
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);
1392
1393 DeleteFileA("icon.ico");
1394
1395 /* Test a system icon */
1396 handle = LoadIconA( 0, (LPCSTR)IDI_HAND );
1397 ok(handle != NULL, "LoadImage() failed.\n");
1398 if (pGetIconInfoExA)
1399 {
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) );
1420 }
1421 SetLastError(0xdeadbeef);
1422 DestroyIcon(handle);
1423
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);
1430
1431 /* Check failure for broken BMP images */
1432 bitmap_header = (BITMAPINFOHEADER *)(bmpimage + sizeof(BITMAPFILEHEADER));
1433
1434 bitmap_header->biHeight = 65536;
1435 test_LoadImageFile("BMP (too high)", bmpimage, sizeof(bmpimage), "bmp", 0);
1436 bitmap_header->biHeight = 1;
1437
1438 bitmap_header->biWidth = 65536;
1439 test_LoadImageFile("BMP (too wide)", bmpimage, sizeof(bmpimage), "bmp", 0);
1440 bitmap_header->biWidth = 1;
1441
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);
1445 }
1446 bitmap_header->biSize = sizeof(BITMAPINFOHEADER);
1447
1448 test_LoadImageFile("Cursor (invalid dwDIBOffset)", invalid_dwDIBOffset, sizeof(invalid_dwDIBOffset), "cur", 0);
1449
1450 /* Test in which paths images with a relative path can be found */
1451 test_LoadImage_working_directory();
1452 }
1453
test_CreateIconFromResource(void)1454 static void test_CreateIconFromResource(void)
1455 {
1456 HANDLE handle;
1457 BOOL ret;
1458 DWORD error;
1459 BITMAPINFOHEADER *icon_header;
1460 INT16 *hotspot;
1461 ICONINFO icon_info;
1462
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)
1470
1471 /* Set icon data. */
1472 hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE);
1473
1474 /* Cursor resources have an extra hotspot, icon resources not. */
1475 hotspot[0] = 3;
1476 hotspot[1] = 3;
1477
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. */
1485
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");
1490
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);
1497
1498 if (ret)
1499 {
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");
1506 }
1507
1508 if (pGetIconInfoExA)
1509 {
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 );
1517 }
1518
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);
1525
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");
1531
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);
1538
1539 if (ret)
1540 {
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");
1547 }
1548
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);
1555
1556 /* Rejection of NULL pointer crashes at least on WNT4WSSP6, W2KPROSP4, WXPPROSP3
1557 *
1558 * handle = CreateIconFromResource(NULL, ICON_RES_SIZE, TRUE, 0x00030000);
1559 * ok(handle == NULL, "Invalid pointer accepted (%p)\n", handle);
1560 */
1561 HeapFree(GetProcessHeap(), 0, hotspot);
1562
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");
1569
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);
1576
1577 if (ret)
1578 {
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");
1585 }
1586
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);
1593 }
1594
check_cursor_data(HDC hdc,HCURSOR hCursor,void * data,int length)1595 static int check_cursor_data( HDC hdc, HCURSOR hCursor, void *data, int length)
1596 {
1597 char *image = NULL;
1598 BITMAPINFO *info;
1599 ICONINFO iinfo;
1600 DWORD ret;
1601 int i;
1602
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;
1610
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++)
1628 {
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] );
1631 }
1632 cleanup:
1633 HeapFree( GetProcessHeap(), 0, image );
1634 HeapFree( GetProcessHeap(), 0, info );
1635 return ret;
1636 }
1637
1638 static HCURSOR (WINAPI *pGetCursorFrameInfo)(HCURSOR hCursor, DWORD unk1, DWORD istep, DWORD *rate, DWORD *steps);
test_GetCursorFrameInfo(void)1639 static void test_GetCursorFrameInfo(void)
1640 {
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;
1652
1653 if (!pGetCursorFrameInfo)
1654 {
1655 win_skip( "GetCursorFrameInfo not supported, skipping tests.\n" );
1656 return;
1657 }
1658
1659 hdc = CreateCompatibleDC(0);
1660 ok(hdc != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1661 if (!hdc)
1662 return;
1663
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);
1677
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)
1685
1686 /* Set icon data. */
1687 hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE);
1688
1689 /* Cursor resources have an extra hotspot, icon resources not. */
1690 hotspot[0] = 3;
1691 hotspot[1] = 3;
1692
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. */
1700
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());
1705
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);
1712
1713 /* Clean up static cursor. */
1714 SetLastError(0xdeadbeef);
1715 ret = DestroyCursor(h1);
1716 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1717
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());
1726
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);
1736
1737 /* Clean up single-frame animated cursor. */
1738 SetLastError(0xdeadbeef);
1739 ret = DestroyCursor(h1);
1740 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1741
1742 /* Creating a multi-frame animated cursor. */
1743 for (i=0; i<empty_anicursor3.header.header.num_frames; i++)
1744 {
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) );
1749 }
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());
1753
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);
1761
1762 /* Check GetCursorFrameInfo behavior on a multi-frame animated cursor */
1763 for (i=0; i<empty_anicursor3.header.header.num_frames; i++)
1764 {
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);
1776 }
1777
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);
1788
1789 /* Clean up multi-frame animated cursor. */
1790 SetLastError(0xdeadbeef);
1791 ret = DestroyCursor(h1);
1792 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1793
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());
1799
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);
1807
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);
1819
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);
1830
1831 /* Clean up multi-frame animated cursor. */
1832 SetLastError(0xdeadbeef);
1833 ret = DestroyCursor(h1);
1834 ok(ret, "DestroyCursor() failed (error = %d).\n", GetLastError());
1835
1836 /* Creating a multi-frame animated cursor with rate data. */
1837 for (i=0; i<empty_anicursor3_seq.header.header.num_frames; i++)
1838 {
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) );
1843 }
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());
1847
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);
1855
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++)
1858 {
1859 int frame_id = empty_anicursor3_seq.seq.order[i];
1860
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);
1872 }
1873
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());
1878
1879 HeapFree(GetProcessHeap(), 0, hotspot);
1880 cleanup:
1881 if(bmpOld) SelectObject(hdc, bmpOld);
1882 if(bmp) DeleteObject(bmp);
1883 if(hdc) DeleteDC(hdc);
1884 }
1885
create_test_icon(HDC hdc,int width,int height,int bpp,BOOL maskvalue,UINT32 * color,int colorSize)1886 static HICON create_test_icon(HDC hdc, int width, int height, int bpp,
1887 BOOL maskvalue, UINT32 *color, int colorSize)
1888 {
1889 ICONINFO iconInfo;
1890 BITMAPINFO bitmapInfo;
1891 void *buffer = NULL;
1892 UINT32 mask = maskvalue ? 0xFFFFFFFF : 0x00000000;
1893
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;
1902
1903 iconInfo.fIcon = TRUE;
1904 iconInfo.xHotspot = 0;
1905 iconInfo.yHotspot = 0;
1906
1907 iconInfo.hbmMask = CreateBitmap( width, height, 1, 1, &mask );
1908 if(!iconInfo.hbmMask) return NULL;
1909
1910 iconInfo.hbmColor = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &buffer, NULL, 0);
1911 if(!iconInfo.hbmColor || !buffer)
1912 {
1913 DeleteObject(iconInfo.hbmMask);
1914 return NULL;
1915 }
1916
1917 memcpy(buffer, color, colorSize);
1918
1919 return CreateIconIndirect(&iconInfo);
1920 }
1921
check_alpha_draw(HDC hdc,BOOL drawiconex,BOOL alpha,int bpp,int line)1922 static void check_alpha_draw(HDC hdc, BOOL drawiconex, BOOL alpha, int bpp, int line)
1923 {
1924 HICON hicon;
1925 UINT32 color[2];
1926 COLORREF modern_expected, legacy_expected, result;
1927
1928 color[0] = 0x00A0B0C0;
1929 color[1] = alpha ? 0xFF000000 : 0x00000000;
1930 modern_expected = alpha ? 0x00FFFFFF : 0x00C0B0A0;
1931 legacy_expected = 0x00C0B0A0;
1932
1933 hicon = create_test_icon(hdc, 2, 1, bpp, 0, color, sizeof(color));
1934 if (!hicon) return;
1935
1936 SetPixelV(hdc, 0, 0, 0x00FFFFFF);
1937
1938 if(drawiconex)
1939 DrawIconEx(hdc, 0, 0, hicon, 2, 1, 0, NULL, DI_NORMAL);
1940 else
1941 DrawIcon(hdc, 0, 0, hicon);
1942
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);
1950 }
1951
check_DrawIcon(HDC hdc,BOOL maskvalue,UINT32 color,int bpp,COLORREF background,COLORREF modern_expected,COLORREF legacy_expected,int 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)
1954 {
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);
1963
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);
1969
1970 result = GetPixel(hdc, GetSystemMetrics(SM_CXICON)-1, GetSystemMetrics(SM_CYICON)-1);
1971
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);
1977
1978 result = GetPixel(hdc, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
1979
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);
1984 }
1985
test_DrawIcon(void)1986 static void test_DrawIcon(void)
1987 {
1988 BITMAPINFO bitmapInfo;
1989 HDC hdcDst = NULL;
1990 HBITMAP bmpDst = NULL;
1991 HBITMAP bmpOld = NULL;
1992 void *bits = 0;
1993
1994 hdcDst = CreateCompatibleDC(0);
1995 ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1996 if (!hdcDst)
1997 return;
1998
1999 if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
2000 {
2001 skip("Windows will distort DrawIcon colors at 8-bpp and less due to palettizing.\n");
2002 goto cleanup;
2003 }
2004
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);
2013
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);
2019
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__);
2023
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__);
2028
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__);
2033
2034 check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
2035 check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
2036
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__);
2043
2044 cleanup:
2045 if(bmpOld)
2046 SelectObject(hdcDst, bmpOld);
2047 if(bmpDst)
2048 DeleteObject(bmpDst);
2049 if(hdcDst)
2050 DeleteDC(hdcDst);
2051 }
2052
check_DrawIconEx(HDC hdc,BOOL maskvalue,UINT32 color,int bpp,UINT flags,COLORREF background,COLORREF modern_expected,COLORREF legacy_expected,int line)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)
2055 {
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);
2062
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);
2068 }
2069
test_DrawIconEx(void)2070 static void test_DrawIconEx(void)
2071 {
2072 BITMAPINFO bitmapInfo;
2073 HDC hdcDst = NULL;
2074 HBITMAP bmpDst = NULL;
2075 HBITMAP bmpOld = NULL;
2076 void *bits = 0;
2077
2078 hdcDst = CreateCompatibleDC(0);
2079 ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
2080 if (!hdcDst)
2081 return;
2082
2083 if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
2084 {
2085 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palettizing.\n");
2086 goto cleanup;
2087 }
2088
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);
2102
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__);
2106
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__);
2109
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__);
2112
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__);
2117
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__);
2121
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__);
2126
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__);
2129
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__);
2136
2137 cleanup:
2138 if(bmpOld)
2139 SelectObject(hdcDst, bmpOld);
2140 if(bmpDst)
2141 DeleteObject(bmpDst);
2142 if(hdcDst)
2143 DeleteDC(hdcDst);
2144 }
2145
check_DrawState_Size(HDC hdc,BOOL maskvalue,UINT32 color,int bpp,HBRUSH hbr,UINT flags,int line)2146 static void check_DrawState_Size(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, HBRUSH hbr, UINT flags, int line)
2147 {
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);
2155
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 ));
2158
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);
2163
2164 /* Check if manually specifying the icon size DOESN'T work */
2165
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 ));
2172
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);
2177
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);
2196 }
2197
check_DrawState_Color(HDC hdc,BOOL maskvalue,UINT32 color,int bpp,HBRUSH hbr,UINT flags,COLORREF background,COLORREF modern_expected,COLORREF legacy_expected,int 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)
2200 {
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);
2206
2207 DrawStateA(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 0, 0, ( DST_ICON | flags ));
2208
2209 /* Check the color of the pixel is correct */
2210 result = GetPixel(hdc, 1, 1);
2211
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);
2217 }
2218
test_DrawState(void)2219 static void test_DrawState(void)
2220 {
2221 BITMAPINFO bitmapInfo;
2222 HDC hdcDst = NULL;
2223 HBITMAP bmpDst = NULL;
2224 HBITMAP bmpOld = NULL;
2225 void *bits = 0;
2226
2227 hdcDst = CreateCompatibleDC(0);
2228 ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
2229 if (!hdcDst)
2230 return;
2231
2232 if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
2233 {
2234 skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palettizing.\n");
2235 goto cleanup;
2236 }
2237
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);
2251
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 */
2257
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__);
2260
2261 cleanup:
2262 if(bmpOld)
2263 SelectObject(hdcDst, bmpOld);
2264 if(bmpDst)
2265 DeleteObject(bmpDst);
2266 if(hdcDst)
2267 DeleteDC(hdcDst);
2268 }
2269
2270 static DWORD parent_id;
2271
set_cursor_thread(void * arg)2272 static DWORD CALLBACK set_cursor_thread( void *arg )
2273 {
2274 HCURSOR ret;
2275
2276 PeekMessageA( 0, 0, 0, 0, PM_NOREMOVE ); /* create a msg queue */
2277 if (parent_id)
2278 {
2279 BOOL ret = AttachThreadInput( GetCurrentThreadId(), parent_id, TRUE );
2280 ok( ret, "AttachThreadInput failed\n" );
2281 }
2282 if (arg) ret = SetCursor( (HCURSOR)arg );
2283 else ret = GetCursor();
2284 return (DWORD_PTR)ret;
2285 }
2286
test_SetCursor(void)2287 static void test_SetCursor(void)
2288 {
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;
2297
2298 if (pGetCursorInfo)
2299 {
2300 memset( &info, 0, sizeof(info) );
2301 info.cbSize = sizeof(info);
2302 if (!pGetCursorInfo( &info ))
2303 {
2304 win_skip( "GetCursorInfo not working\n" );
2305 pGetCursorInfo = NULL;
2306 }
2307 else global_cursor = info.hCursor;
2308 }
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 );
2314
2315 hdc = GetDC(0);
2316 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
2317 ReleaseDC(0, hdc);
2318
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);
2324
2325 cursor = CreateIconIndirect(&cursorInfo);
2326 ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
2327 old_cursor = SetCursor( cursor );
2328
2329 if (pGetCursorInfo)
2330 {
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 );
2336 }
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 );
2341
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 );
2348
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() );
2354
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 );
2361
2362 if (pGetCursorInfo)
2363 {
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 );
2368 }
2369 SetCursor( old_cursor );
2370 DestroyCursor( cursor );
2371
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 );
2378
2379 if (pGetCursorInfo)
2380 {
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 );
2385 }
2386 }
2387
2388 static HANDLE event_start, event_next;
2389
show_cursor_thread(void * arg)2390 static DWORD CALLBACK show_cursor_thread( void *arg )
2391 {
2392 DWORD count = (DWORD_PTR)arg;
2393 int ret;
2394
2395 PeekMessageA( 0, 0, 0, 0, PM_NOREMOVE ); /* create a msg queue */
2396 if (parent_id)
2397 {
2398 BOOL ret = AttachThreadInput( GetCurrentThreadId(), parent_id, TRUE );
2399 ok( ret, "AttachThreadInput failed\n" );
2400 }
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;
2406 }
2407
test_ShowCursor(void)2408 static void test_ShowCursor(void)
2409 {
2410 int count;
2411 DWORD id, result;
2412 HANDLE thread;
2413 CURSORINFO info;
2414
2415 if (pGetCursorInfo)
2416 {
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" );
2421 }
2422
2423 event_start = CreateEventW( NULL, FALSE, FALSE, NULL );
2424 event_next = CreateEventW( NULL, FALSE, FALSE, NULL );
2425
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 );
2438
2439 if (pGetCursorInfo)
2440 {
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" );
2445 }
2446
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 );
2458
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 );
2469
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 );
2481
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 );
2492
2493 if (pGetCursorInfo)
2494 {
2495 info.cbSize = sizeof(info);
2496 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2497 ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
2498 }
2499
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 );
2504
2505 if (pGetCursorInfo)
2506 {
2507 info.cbSize = sizeof(info);
2508 ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
2509 ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
2510 }
2511 }
2512
2513
test_DestroyCursor(void)2514 static void test_DestroyCursor(void)
2515 {
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;
2523
2524 hdc = GetDC(0);
2525 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
2526 ReleaseDC(0, hdc);
2527
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);
2533
2534 cursor = CreateIconIndirect(&cursorInfo);
2535 ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
2536 if(!cursor) {
2537 return;
2538 }
2539 SetCursor(cursor);
2540
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);
2546
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);
2552
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() );
2559
2560 if (ret) /* nt4 delays destruction until cursor changes */
2561 {
2562 DeleteObject( new_info.hbmColor );
2563 DeleteObject( new_info.hbmMask );
2564
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() );
2570
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() );
2576 }
2577 else
2578 {
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() );
2585
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() );
2594
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() );
2600 }
2601
2602 cursor2 = GetCursor();
2603 ok(cursor2 == new_cursor, "GetCursor returned %p/%p\n", cursor2, new_cursor);
2604
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() );
2612
2613 cursor2 = GetCursor();
2614 ok(!cursor2, "GetCursor returned %p/%p\n", cursor2, cursor);
2615
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() );
2624
2625 DeleteObject(cursorInfo.hbmMask);
2626 DeleteObject(cursorInfo.hbmColor);
2627
2628 /* Try testing DestroyCursor() now using LoadCursor() cursors. */
2629 cursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
2630
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);
2636
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);
2642
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);
2646
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);
2650 }
2651
test_PrivateExtractIcons(void)2652 static void test_PrivateExtractIcons(void)
2653 {
2654 HICON icon;
2655 UINT ret;
2656
2657 static const test_icon_entries_t icon_desc[] = {{0,0,TRUE}, {16,16,TRUE}, {32,32}, {64,64,TRUE}};
2658
2659 create_ico_file("extract.ico", icon_desc, ARRAY_SIZE(icon_desc));
2660
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");
2664
2665 test_icon_info(icon, 32, 32, 32, 32);
2666 DestroyIcon(icon);
2667
2668 DeleteFileA("extract.ico");
2669 }
2670
test_monochrome_icon(void)2671 static void test_monochrome_icon(void)
2672 {
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;
2683
2684 icon_data = HeapAlloc(GetProcessHeap(), 0, sizeof(CURSORICONFILEDIR) + sizeof(BITMAPINFOHEADER) +
2685 2 * sizeof(RGBQUAD) + sizeof(ULONG));
2686
2687 for (monochrome = FALSE; monochrome <= TRUE; monochrome++)
2688 for (use_core_info = FALSE; use_core_info <= TRUE; use_core_info++)
2689 {
2690 trace("%s, %s\n",
2691 monochrome ? "monochrome" : "colored",
2692 use_core_info ? "core info" : "bitmap info");
2693
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;
2703
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);
2713
2714 if (use_core_info)
2715 {
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;
2728 }
2729 else
2730 {
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;
2744 }
2745
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);
2752
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)
2758 {
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;
2764 }
2765
2766 ret = GetIconInfo(handle, &icon_info);
2767 ok(ret, "GetIconInfo() failed with %u.\n", GetLastError());
2768 if (ret)
2769 {
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");
2778 }
2779
2780 ret = DestroyIcon(handle);
2781 ok(ret, "DestroyIcon() failed with %u.\n", GetLastError());
2782 DeleteFileA("icon.ico");
2783 }
2784
2785 HeapFree(GetProcessHeap(), 0, icon_data);
2786 }
2787
get_color_from_bits(const unsigned char * bits,const BITMAPINFO * bmi,unsigned int row,unsigned int column)2788 static COLORREF get_color_from_bits(const unsigned char *bits, const BITMAPINFO *bmi,
2789 unsigned int row, unsigned int column)
2790 {
2791 const BITMAPINFOHEADER *h = &bmi->bmiHeader;
2792 unsigned int stride, shift, mask;
2793 const unsigned char *data;
2794 RGBQUAD color;
2795 WORD color16;
2796
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]);
2801
2802 if (h->biBitCount == 16)
2803 {
2804 color16 = ((WORD)data[1] << 8) | data[0];
2805 return RGB(((color16 >> 10) & 0x1f) << 3, ((color16 >> 5) & 0x1f) << 3,
2806 (color16 & 0x1f) << 3);
2807 }
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);
2812 }
2813
2814 #define compare_bitmap_bits(a, b, c, d, e, f, g) compare_bitmap_bits_(__LINE__, a, b, c, d, e, f, g)
compare_bitmap_bits_(unsigned int line,HDC hdc,HBITMAP bitmap,BITMAPINFO * bmi,size_t result_bits_size,const unsigned char * expected_bits,unsigned int test_index,BOOL todo)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)
2817 {
2818 unsigned char *result_bits;
2819 unsigned int row, column;
2820 int ret;
2821
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)
2829 {
2830 COLORREF result, expected;
2831
2832 result = get_color_from_bits(result_bits, bmi, row, column);
2833 expected = get_color_from_bits(expected_bits, bmi, row, column);
2834
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);
2839 }
2840 HeapFree(GetProcessHeap(), 0, result_bits);
2841 }
2842
test_Image_StretchMode(void)2843 static void test_Image_StretchMode(void)
2844 {
2845 static const unsigned char test_bits_24[] =
2846 {
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,
2851 };
2852 static const unsigned char expected_bits_24[] =
2853 {
2854 0x3f, 0xff, 0x00, 0x3f, 0xff, 0x3f, 0x00, 0x00,
2855 0x3f, 0xff, 0x7f, 0x00, 0xff, 0x3f, 0x00, 0x00,
2856 };
2857 #define rgb16(r, g, b) ((WORD)(((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3)))
2858 static const WORD test_bits_16[] =
2859 {
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),
2864 };
2865 static const WORD expected_bits_16[] =
2866 {
2867 rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x20, 0x00),
2868 rgb16(0x00, 0x40, 0x00), rgb16(0x00, 0x20, 0x00),
2869 };
2870 #undef rgb16
2871 static const unsigned char test_bits_8[] =
2872 {
2873 0x00, 0xff, 0x00, 0xff,
2874 0x00, 0x00, 0x00, 0x00,
2875 0xff, 0x55, 0x00, 0xff,
2876 0x00, 0xff, 0xff, 0x00,
2877 };
2878 static const unsigned char expected_bits_8[] =
2879 {
2880 0xff, 0xff, 0x00, 0x00,
2881 0x55, 0xff, 0x00, 0x00,
2882 };
2883 static const unsigned char test_bits_1[] =
2884 {
2885 0x30, 0x0, 0x0, 0x0,
2886 0x30, 0x0, 0x0, 0x0,
2887 0x40, 0x0, 0x0, 0x0,
2888 0xc0, 0x0, 0x0, 0x0,
2889 };
2890 static const unsigned char expected_bits_1[] =
2891 {
2892 0x40, 0x0, 0x0, 0x0,
2893 0x0, 0x0, 0x0, 0x0,
2894 };
2895 static const RGBQUAD colors_bits_1[] =
2896 {
2897 {0, 0, 0},
2898 {0xff, 0xff, 0xff},
2899 };
2900 static RGBQUAD colors_bits_8[256];
2901
2902 static const struct
2903 {
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;
2911 }
2912 tests[] =
2913 {
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},
2924 };
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;
2933
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;
2940
2941 for (i = 0; i < 256; ++i)
2942 colors_bits_8[i].rgbRed = colors_bits_8[i].rgbGreen = colors_bits_8[i].rgbBlue = i;
2943
2944 hdc = GetDC(NULL);
2945
2946 for (test_index = 0; test_index < ARRAY_SIZE(tests); ++test_index)
2947 {
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));
2952
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;
2959
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);
2963
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());
2967
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);
2972
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);
2981 }
2982 ReleaseDC(0, hdc);
2983 HeapFree(GetProcessHeap(), 0, bmi_output);
2984 HeapFree(GetProcessHeap(), 0, bmi);
2985 }
2986
START_TEST(cursoricon)2987 START_TEST(cursoricon)
2988 {
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);
2994
2995 if (test_argc >= 3)
2996 {
2997 /* Child process. */
2998 sscanf (test_argv[2], "%x", (unsigned int *) &parent);
2999
3000 ok(parent != NULL, "Parent not found.\n");
3001 if (parent == NULL)
3002 ExitProcess(1);
3003
3004 do_child();
3005 return;
3006 }
3007
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();
3031 }
3032