d3dcompiler: Add argument check in D3DReflect().
[wine] / dlls / user32 / tests / cursoricon.c
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 <assert.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "wine/test.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34
35 #include "pshpack1.h"
36
37 typedef struct
38 {
39     BYTE bWidth;
40     BYTE bHeight;
41     BYTE bColorCount;
42     BYTE bReserved;
43     WORD xHotspot;
44     WORD yHotspot;
45     DWORD dwDIBSize;
46     DWORD dwDIBOffset;
47 } CURSORICONFILEDIRENTRY;
48
49 typedef struct
50 {
51     WORD idReserved;
52     WORD idType;
53     WORD idCount;
54     CURSORICONFILEDIRENTRY idEntries[1];
55 } CURSORICONFILEDIR;
56
57 #include "poppack.h"
58
59 static char **test_argv;
60 static int test_argc;
61 static HWND child = 0;
62 static HWND parent = 0;
63 static HANDLE child_process;
64
65 #define PROC_INIT (WM_USER+1)
66
67 static BOOL (WINAPI *pGetCursorInfo)(CURSORINFO *);
68 static BOOL (WINAPI *pGetIconInfoExA)(HICON,ICONINFOEXA *);
69 static BOOL (WINAPI *pGetIconInfoExW)(HICON,ICONINFOEXW *);
70
71 static const int is_win64 = (sizeof(void *) > sizeof(int));
72
73 static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
74 {
75     BOOL ret;
76     DWORD error;
77
78     switch (msg)
79     {
80         /* Destroy the cursor. */
81         case WM_USER+1:
82             SetLastError(0xdeadbeef);
83             ret = DestroyCursor((HCURSOR) lParam);
84             error = GetLastError();
85             ok(!ret || broken(ret) /* win9x */, "DestroyCursor on the active cursor succeeded.\n");
86             ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD ||
87                error == 0xdeadbeef,  /* vista */
88                 "Last error: %u\n", error);
89             return TRUE;
90         case WM_DESTROY:
91             PostQuitMessage(0);
92             return 0;
93     }
94
95     return DefWindowProc(hwnd, msg, wParam, lParam);
96 }
97
98 static LRESULT CALLBACK callback_parent(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
99 {
100     if (msg == PROC_INIT)
101     {
102         child = (HWND) wParam;
103         return TRUE;
104     }
105
106     return DefWindowProc(hwnd, msg, wParam, lParam);
107 }
108
109 static void do_child(void)
110 {
111     WNDCLASS class;
112     MSG msg;
113     BOOL ret;
114
115     /* Register a new class. */
116     class.style = CS_GLOBALCLASS;
117     class.lpfnWndProc = callback_child;
118     class.cbClsExtra = 0;
119     class.cbWndExtra = 0;
120     class.hInstance = GetModuleHandle(NULL);
121     class.hIcon = NULL;
122     class.hCursor = NULL;
123     class.hbrBackground = NULL;
124     class.lpszMenuName = NULL;
125     class.lpszClassName = "cursor_child";
126
127     SetLastError(0xdeadbeef);
128     ret = RegisterClass(&class);
129     ok(ret, "Failed to register window class.  Error: %u\n", GetLastError());
130
131     /* Create a window. */
132     child = CreateWindowA("cursor_child", "cursor_child", WS_POPUP | WS_VISIBLE,
133         0, 0, 200, 200, 0, 0, 0, NULL);
134     ok(child != 0, "CreateWindowA failed.  Error: %u\n", GetLastError());
135
136     /* Let the parent know our HWND. */
137     PostMessage(parent, PROC_INIT, (WPARAM) child, 0);
138
139     /* Receive messages. */
140     while ((ret = GetMessage(&msg, 0, 0, 0)))
141     {
142         ok(ret != -1, "GetMessage failed.  Error: %u\n", GetLastError());
143         TranslateMessage(&msg);
144         DispatchMessage(&msg);
145     }
146 }
147
148 static void do_parent(void)
149 {
150     char path_name[MAX_PATH];
151     PROCESS_INFORMATION info;
152     STARTUPINFOA startup;
153     WNDCLASS class;
154     MSG msg;
155     BOOL ret;
156
157     /* Register a new class. */
158     class.style = CS_GLOBALCLASS;
159     class.lpfnWndProc = callback_parent;
160     class.cbClsExtra = 0;
161     class.cbWndExtra = 0;
162     class.hInstance = GetModuleHandle(NULL);
163     class.hIcon = NULL;
164     class.hCursor = NULL;
165     class.hbrBackground = NULL;
166     class.lpszMenuName = NULL;
167     class.lpszClassName = "cursor_parent";
168
169     SetLastError(0xdeadbeef);
170     ret = RegisterClass(&class);
171     ok(ret, "Failed to register window class.  Error: %u\n", GetLastError());
172
173     /* Create a window. */
174     parent = CreateWindowA("cursor_parent", "cursor_parent", WS_POPUP | WS_VISIBLE,
175         0, 0, 200, 200, 0, 0, 0, NULL);
176     ok(parent != 0, "CreateWindowA failed.  Error: %u\n", GetLastError());
177
178     /* Start child process. */
179     memset(&startup, 0, sizeof(startup));
180     startup.cb = sizeof(startup);
181     startup.dwFlags = STARTF_USESHOWWINDOW;
182     startup.wShowWindow = SW_SHOWNORMAL;
183
184     sprintf(path_name, "%s cursoricon %lx", test_argv[0], (INT_PTR)parent);
185     ok(CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed.\n");
186     child_process = info.hProcess;
187
188     /* Wait for child window handle. */
189     while ((child == 0) && (ret = GetMessage(&msg, parent, 0, 0)))
190     {
191         ok(ret != -1, "GetMessage failed.  Error: %u\n", GetLastError());
192         TranslateMessage(&msg);
193         DispatchMessage(&msg);
194     }
195 }
196
197 static void finish_child_process(void)
198 {
199     SendMessage(child, WM_CLOSE, 0, 0);
200     winetest_wait_child_process( child_process );
201     CloseHandle(child_process);
202 }
203
204 static void test_child_process(void)
205 {
206     static const BYTE bmp_bits[4096];
207     HCURSOR cursor;
208     ICONINFO cursorInfo;
209     UINT display_bpp;
210     HDC hdc;
211
212     /* Create and set a dummy cursor. */
213     hdc = GetDC(0);
214     display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
215     ReleaseDC(0, hdc);
216
217     cursorInfo.fIcon = FALSE;
218     cursorInfo.xHotspot = 0;
219     cursorInfo.yHotspot = 0;
220     cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
221     cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
222
223     cursor = CreateIconIndirect(&cursorInfo);
224     ok(cursor != NULL, "CreateIconIndirect returned %p.\n", cursor);
225
226     SetCursor(cursor);
227
228     /* Destroy the cursor. */
229     SendMessage(child, WM_USER+1, 0, (LPARAM) cursor);
230 }
231
232 static BOOL color_match(COLORREF a, COLORREF b)
233 {
234     /* 5-bit accuracy is a sufficient test. This will match as long as
235      * colors are never truncated to less that 3x5-bit accuracy i.e.
236      * palettized. */
237     return (a & 0x00F8F8F8) == (b & 0x00F8F8F8);
238 }
239
240 static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight,
241                                   INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected)
242 {
243     HBITMAP copy;
244     BITMAP origBitmap;
245     BITMAP copyBitmap;
246     BOOL orig_is_dib;
247     BOOL copy_is_dib;
248
249     copy = CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
250     ok(copy != NULL, "CopyImage() failed\n");
251     if (copy != NULL)
252     {
253         GetObject(bitmap, sizeof(origBitmap), &origBitmap);
254         GetObject(copy, sizeof(copyBitmap), &copyBitmap);
255         orig_is_dib = (origBitmap.bmBits != NULL);
256         copy_is_dib = (copyBitmap.bmBits != NULL);
257
258         if (copy_is_dib && dibExpected
259             && copyBitmap.bmBitsPixel == 24
260             && (expectedDepth == 16 || expectedDepth == 32))
261         {
262             /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
263             if (GetVersion() & 0x80000000)
264             {
265                 expectedDepth = 24;
266             }
267         }
268
269         if (copy_is_dib && !dibExpected && !(flags & LR_CREATEDIBSECTION))
270         {
271             /* It's not forbidden to create a DIB section if the flag
272                LR_CREATEDIBSECTION is absent.
273                Windows 9x does this if the bitmap has a depth that doesn't
274                match the screen depth, Windows NT doesn't */
275             dibExpected = TRUE;
276             expectedDepth = origBitmap.bmBitsPixel;
277         }
278
279         ok((!(dibExpected ^ copy_is_dib)
280              && (copyBitmap.bmWidth == expectedWidth)
281              && (copyBitmap.bmHeight == expectedHeight)
282              && (copyBitmap.bmBitsPixel == expectedDepth)),
283              "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
284                   orig_is_dib ? "DIB" : "DDB", origBitmap.bmWidth, origBitmap.bmHeight, origBitmap.bmBitsPixel,
285                   copyWidth, copyHeight, flags,
286                   dibExpected ? "DIB" : "DDB", expectedWidth, expectedHeight, expectedDepth,
287                   copy_is_dib ? "DIB" : "DDB", copyBitmap.bmWidth, copyBitmap.bmHeight, copyBitmap.bmBitsPixel);
288
289         DeleteObject(copy);
290     }
291 }
292
293 static void test_CopyImage_Bitmap(int depth)
294 {
295     HBITMAP ddb, dib;
296     HDC screenDC;
297     BITMAPINFO * info;
298     VOID * bits;
299     int screen_depth;
300     unsigned int i;
301
302     /* Create a device-independent bitmap (DIB) */
303     info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
304     info->bmiHeader.biSize = sizeof(info->bmiHeader);
305     info->bmiHeader.biWidth = 2;
306     info->bmiHeader.biHeight = 2;
307     info->bmiHeader.biPlanes = 1;
308     info->bmiHeader.biBitCount = depth;
309     info->bmiHeader.biCompression = BI_RGB;
310
311     for (i=0; i < 256; i++)
312     {
313         info->bmiColors[i].rgbRed = i;
314         info->bmiColors[i].rgbGreen = i;
315         info->bmiColors[i].rgbBlue = 255 - i;
316         info->bmiColors[i].rgbReserved = 0;
317     }
318
319     dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
320
321     /* Create a device-dependent bitmap (DDB) */
322     screenDC = GetDC(NULL);
323     screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
324     if (depth == 1 || depth == screen_depth)
325     {
326         ddb = CreateBitmap(2, 2, 1, depth, NULL);
327     }
328     else
329     {
330         ddb = NULL;
331     }
332     ReleaseDC(NULL, screenDC);
333
334     if (ddb != NULL)
335     {
336         test_CopyImage_Check(ddb, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE);
337         test_CopyImage_Check(ddb, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE);
338         test_CopyImage_Check(ddb, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE);
339         test_CopyImage_Check(ddb, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE);
340
341         test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
342         test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
343         test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
344         test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
345
346         test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
347         test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
348         test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
349         test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
350
351         /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
352         test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
353         test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
354         test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
355         test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
356
357         DeleteObject(ddb);
358     }
359
360     if (depth != 1)
361     {
362         test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
363         test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
364         test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
365         test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
366     }
367
368     test_CopyImage_Check(dib, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
369     test_CopyImage_Check(dib, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
370     test_CopyImage_Check(dib, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
371     test_CopyImage_Check(dib, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
372
373     test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
374     test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
375     test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
376     test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
377
378     /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
379     test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
380     test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
381     test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
382     test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
383
384     DeleteObject(dib);
385
386     if (depth == 1)
387     {
388         /* Special case: A monochrome DIB is converted to a monochrome DDB if
389            the colors in the color table are black and white.
390
391            Skip this test on Windows 95, it always creates a monochrome DDB
392            in this case */
393
394         if (!(GetVersion() & 0x80000000))
395         {
396             info->bmiHeader.biBitCount = 1;
397             info->bmiColors[0].rgbRed = 0xFF;
398             info->bmiColors[0].rgbGreen = 0;
399             info->bmiColors[0].rgbBlue = 0;
400             info->bmiColors[1].rgbRed = 0;
401             info->bmiColors[1].rgbGreen = 0xFF;
402             info->bmiColors[1].rgbBlue = 0;
403
404             dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
405             test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
406             test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
407             test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
408             test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
409             DeleteObject(dib);
410
411             info->bmiHeader.biBitCount = 1;
412             info->bmiColors[0].rgbRed = 0;
413             info->bmiColors[0].rgbGreen = 0;
414             info->bmiColors[0].rgbBlue = 0;
415             info->bmiColors[1].rgbRed = 0xFF;
416             info->bmiColors[1].rgbGreen = 0xFF;
417             info->bmiColors[1].rgbBlue = 0xFF;
418
419             dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
420             test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
421             test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
422             test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
423             test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
424             DeleteObject(dib);
425
426             info->bmiHeader.biBitCount = 1;
427             info->bmiColors[0].rgbRed = 0xFF;
428             info->bmiColors[0].rgbGreen = 0xFF;
429             info->bmiColors[0].rgbBlue = 0xFF;
430             info->bmiColors[1].rgbRed = 0;
431             info->bmiColors[1].rgbGreen = 0;
432             info->bmiColors[1].rgbBlue = 0;
433
434             dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
435             test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
436             test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
437             test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
438             test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
439             DeleteObject(dib);
440         }
441     }
442
443     HeapFree(GetProcessHeap(), 0, info);
444 }
445
446 static void test_initial_cursor(void)
447 {
448     HCURSOR cursor, cursor2;
449     DWORD error;
450
451     cursor = GetCursor();
452
453     /* Check what handle GetCursor() returns if a cursor is not set yet. */
454     SetLastError(0xdeadbeef);
455     cursor2 = LoadCursor(NULL, IDC_WAIT);
456     todo_wine {
457         ok(cursor == cursor2, "cursor (%p) is not IDC_WAIT (%p).\n", cursor, cursor2);
458     }
459     error = GetLastError();
460     ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
461 }
462
463 static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_bpp, int line)
464 {
465     ICONINFO info;
466     DWORD ret;
467     BITMAP bmMask, bmColor;
468
469     ret = GetIconInfo(hIcon, &info);
470     ok_(__FILE__, line)(ret, "GetIconInfo failed\n");
471
472     /* CreateIcon under XP causes info.fIcon to be 0 */
473     ok_(__FILE__, line)(info.xHotspot == exp_cx/2, "info.xHotspot = %u\n", info.xHotspot);
474     ok_(__FILE__, line)(info.yHotspot == exp_cy/2, "info.yHotspot = %u\n", info.yHotspot);
475     ok_(__FILE__, line)(info.hbmMask != 0, "info.hbmMask is NULL\n");
476
477     ret = GetObject(info.hbmMask, sizeof(bmMask), &bmMask);
478     ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %u\n", ret);
479
480     if (exp_bpp == 1)
481         ok_(__FILE__, line)(info.hbmColor == 0, "info.hbmColor should be NULL\n");
482
483     if (info.hbmColor)
484     {
485         HDC hdc;
486         UINT display_bpp;
487
488         hdc = GetDC(0);
489         display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
490         ReleaseDC(0, hdc);
491
492         ret = GetObject(info.hbmColor, sizeof(bmColor), &bmColor);
493         ok_(__FILE__, line)(ret == sizeof(bmColor), "GetObject(info.hbmColor) failed, ret %u\n", ret);
494
495         ok_(__FILE__, line)(bmColor.bmBitsPixel == display_bpp /* XP */ ||
496            bmColor.bmBitsPixel == exp_bpp /* Win98 */,
497            "bmColor.bmBitsPixel = %d\n", bmColor.bmBitsPixel);
498         ok_(__FILE__, line)(bmColor.bmWidth == exp_cx, "bmColor.bmWidth = %d\n", bmColor.bmWidth);
499         ok_(__FILE__, line)(bmColor.bmHeight == exp_cy, "bmColor.bmHeight = %d\n", bmColor.bmHeight);
500
501         ok_(__FILE__, line)(bmMask.bmBitsPixel == 1, "bmMask.bmBitsPixel = %d\n", bmMask.bmBitsPixel);
502         ok_(__FILE__, line)(bmMask.bmWidth == exp_cx, "bmMask.bmWidth = %d\n", bmMask.bmWidth);
503         ok_(__FILE__, line)(bmMask.bmHeight == exp_cy, "bmMask.bmHeight = %d\n", bmMask.bmHeight);
504     }
505     else
506     {
507         ok_(__FILE__, line)(bmMask.bmBitsPixel == 1, "bmMask.bmBitsPixel = %d\n", bmMask.bmBitsPixel);
508         ok_(__FILE__, line)(bmMask.bmWidth == exp_cx, "bmMask.bmWidth = %d\n", bmMask.bmWidth);
509         ok_(__FILE__, line)(bmMask.bmHeight == exp_cy * 2, "bmMask.bmHeight = %d\n", bmMask.bmHeight);
510     }
511     if (pGetIconInfoExA)
512     {
513         ICONINFOEXA infoex;
514
515         memset( &infoex, 0xcc, sizeof(infoex) );
516         SetLastError( 0xdeadbeef );
517         infoex.cbSize = sizeof(infoex) - 1;
518         ret = pGetIconInfoExA( hIcon, &infoex );
519         ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n");
520         ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %d\n", GetLastError());
521
522         SetLastError( 0xdeadbeef );
523         infoex.cbSize = sizeof(infoex) + 1;
524         ret = pGetIconInfoExA( hIcon, &infoex );
525         ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n");
526         ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %d\n", GetLastError());
527
528         SetLastError( 0xdeadbeef );
529         infoex.cbSize = sizeof(infoex);
530         ret = pGetIconInfoExA( (HICON)0xdeadbabe, &infoex );
531         ok_(__FILE__, line)(!ret, "GetIconInfoEx succeeded\n");
532         ok_(__FILE__, line)(GetLastError() == ERROR_INVALID_CURSOR_HANDLE,
533                             "wrong error %d\n", GetLastError());
534
535         infoex.cbSize = sizeof(infoex);
536         ret = pGetIconInfoExA( hIcon, &infoex );
537         ok_(__FILE__, line)(ret, "GetIconInfoEx failed err %d\n", GetLastError());
538         ok_(__FILE__, line)(infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID);
539         ok_(__FILE__, line)(infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName);
540         ok_(__FILE__, line)(infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName);
541     }
542 }
543
544 #define test_icon_info(a,b,c,d) test_icon_info_dbg((a),(b),(c),(d),__LINE__)
545
546 static void test_CreateIcon(void)
547 {
548     static const BYTE bmp_bits[1024];
549     HICON hIcon;
550     HBITMAP hbmMask, hbmColor;
551     BITMAPINFO *bmpinfo;
552     ICONINFO info;
553     HDC hdc;
554     void *bits;
555     UINT display_bpp;
556
557     hdc = GetDC(0);
558     display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
559
560     /* these crash under XP
561     hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
562     hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits);
563     */
564
565     hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, bmp_bits);
566     ok(hIcon != 0, "CreateIcon failed\n");
567     test_icon_info(hIcon, 16, 16, 1);
568     DestroyIcon(hIcon);
569
570     hIcon = CreateIcon(0, 16, 16, 1, display_bpp, bmp_bits, bmp_bits);
571     ok(hIcon != 0, "CreateIcon failed\n");
572     test_icon_info(hIcon, 16, 16, display_bpp);
573     DestroyIcon(hIcon);
574
575     hbmMask = CreateBitmap(16, 16, 1, 1, bmp_bits);
576     ok(hbmMask != 0, "CreateBitmap failed\n");
577     hbmColor = CreateBitmap(16, 16, 1, display_bpp, bmp_bits);
578     ok(hbmColor != 0, "CreateBitmap failed\n");
579
580     info.fIcon = TRUE;
581     info.xHotspot = 8;
582     info.yHotspot = 8;
583     info.hbmMask = 0;
584     info.hbmColor = 0;
585     SetLastError(0xdeadbeaf);
586     hIcon = CreateIconIndirect(&info);
587     ok(!hIcon, "CreateIconIndirect should fail\n");
588     ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
589
590     info.fIcon = TRUE;
591     info.xHotspot = 8;
592     info.yHotspot = 8;
593     info.hbmMask = 0;
594     info.hbmColor = hbmColor;
595     SetLastError(0xdeadbeaf);
596     hIcon = CreateIconIndirect(&info);
597     ok(!hIcon, "CreateIconIndirect should fail\n");
598     ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
599
600     info.fIcon = TRUE;
601     info.xHotspot = 8;
602     info.yHotspot = 8;
603     info.hbmMask = hbmMask;
604     info.hbmColor = hbmColor;
605     hIcon = CreateIconIndirect(&info);
606     ok(hIcon != 0, "CreateIconIndirect failed\n");
607     test_icon_info(hIcon, 16, 16, display_bpp);
608     DestroyIcon(hIcon);
609
610     DeleteObject(hbmMask);
611     DeleteObject(hbmColor);
612
613     hbmMask = CreateBitmap(16, 32, 1, 1, bmp_bits);
614     ok(hbmMask != 0, "CreateBitmap failed\n");
615
616     info.fIcon = TRUE;
617     info.xHotspot = 8;
618     info.yHotspot = 8;
619     info.hbmMask = hbmMask;
620     info.hbmColor = 0;
621     SetLastError(0xdeadbeaf);
622     hIcon = CreateIconIndirect(&info);
623     ok(hIcon != 0, "CreateIconIndirect failed\n");
624     test_icon_info(hIcon, 16, 16, 1);
625     DestroyIcon(hIcon);
626
627     DeleteObject(hbmMask);
628     DeleteObject(hbmColor);
629
630     /* test creating an icon from a DIB section */
631
632     bmpinfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO,bmiColors[256]));
633     bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
634     bmpinfo->bmiHeader.biWidth = 32;
635     bmpinfo->bmiHeader.biHeight = 32;
636     bmpinfo->bmiHeader.biPlanes = 1;
637     bmpinfo->bmiHeader.biBitCount = 8;
638     bmpinfo->bmiHeader.biCompression = BI_RGB;
639     hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
640     ok(hbmColor != NULL, "Expected a handle to the DIB\n");
641     if (bits)
642         memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
643     bmpinfo->bmiHeader.biBitCount = 1;
644     hbmMask = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
645     ok(hbmMask != NULL, "Expected a handle to the DIB\n");
646     if (bits)
647         memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
648
649     info.fIcon = TRUE;
650     info.xHotspot = 8;
651     info.yHotspot = 8;
652     info.hbmMask = hbmColor;
653     info.hbmColor = hbmMask;
654     SetLastError(0xdeadbeaf);
655     hIcon = CreateIconIndirect(&info);
656     ok(hIcon != 0, "CreateIconIndirect failed\n");
657     test_icon_info(hIcon, 32, 32, 8);
658     DestroyIcon(hIcon);
659     DeleteObject(hbmColor);
660
661     bmpinfo->bmiHeader.biBitCount = 16;
662     hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
663     ok(hbmColor != NULL, "Expected a handle to the DIB\n");
664     if (bits)
665         memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
666
667     info.fIcon = TRUE;
668     info.xHotspot = 8;
669     info.yHotspot = 8;
670     info.hbmMask = hbmColor;
671     info.hbmColor = hbmMask;
672     SetLastError(0xdeadbeaf);
673     hIcon = CreateIconIndirect(&info);
674     ok(hIcon != 0, "CreateIconIndirect failed\n");
675     test_icon_info(hIcon, 32, 32, 8);
676     DestroyIcon(hIcon);
677     DeleteObject(hbmColor);
678
679     bmpinfo->bmiHeader.biBitCount = 32;
680     hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 );
681     ok(hbmColor != NULL, "Expected a handle to the DIB\n");
682     if (bits)
683         memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 );
684
685     info.fIcon = TRUE;
686     info.xHotspot = 8;
687     info.yHotspot = 8;
688     info.hbmMask = hbmColor;
689     info.hbmColor = hbmMask;
690     SetLastError(0xdeadbeaf);
691     hIcon = CreateIconIndirect(&info);
692     ok(hIcon != 0, "CreateIconIndirect failed\n");
693     test_icon_info(hIcon, 32, 32, 8);
694     DestroyIcon(hIcon);
695
696     DeleteObject(hbmMask);
697     DeleteObject(hbmColor);
698     HeapFree( GetProcessHeap(), 0, bmpinfo );
699
700     ReleaseDC(0, hdc);
701 }
702
703 /* Shamelessly ripped from dlls/oleaut32/tests/olepicture.c */
704 /* 1x1 pixel gif */
705 static unsigned char gifimage[35] = {
706 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
707 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
708 0x01,0x00,0x3b
709 };
710
711 /* 1x1 pixel jpg */
712 static unsigned char jpgimage[285] = {
713 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
714 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
715 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
716 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
717 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
718 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
719 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
720 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
721 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
722 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
723 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
724 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
725 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
726 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
727 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
728 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
729 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
730 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
731 };
732
733 /* 1x1 pixel png */
734 static unsigned char pngimage[285] = {
735 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
736 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
737 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
738 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
739 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
740 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
741 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
742 };
743
744 /* 1x1 pixel bmp with gap between palette and bitmap. Correct bitmap contains only
745    zeroes, gap is 0xFF. */
746 static unsigned char bmpimage[70] = {
747 0x42,0x4d,0x46,0x00,0x00,0x00,0xDE,0xAD,0xBE,0xEF,0x42,0x00,0x00,0x00,0x28,0x00,
748 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
749 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
750 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0x55,0x55,0x55,0x00,0xFF,0xFF,
751 0xFF,0xFF,0x00,0x00,0x00,0x00
752 };
753
754 /* 1x1 pixel bmp using BITMAPCOREHEADER */
755 static unsigned char bmpcoreimage[38] = {
756 0x42,0x4d,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x0c,0x00,
757 0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xff,0xff,0xff,0x00,0x55,0x55,
758 0x55,0x00,0x00,0x00,0x00,0x00
759 };
760
761 /* 2x2 pixel gif */
762 static unsigned char gif4pixel[42] = {
763 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
764 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
765 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
766 };
767
768 static void test_LoadImageBitmap(const char * test_desc, HBITMAP hbm)
769 {
770     BITMAP bm;
771     BITMAPINFO bmi;
772     DWORD ret, pixel = 0;
773     HDC hdc = GetDC(NULL);
774
775     ret = GetObject(hbm, sizeof(bm), &bm);
776     ok(ret == sizeof(bm), "GetObject returned %d\n", ret);
777
778     memset(&bmi, 0, sizeof(bmi));
779     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
780     bmi.bmiHeader.biWidth = bm.bmWidth;
781     bmi.bmiHeader.biHeight = bm.bmHeight;
782     bmi.bmiHeader.biPlanes = 1;
783     bmi.bmiHeader.biBitCount= 24;
784     bmi.bmiHeader.biCompression= BI_RGB;
785     ret = GetDIBits(hdc, hbm, 0, bm.bmHeight, &pixel, &bmi, DIB_RGB_COLORS);
786     ok(ret == bm.bmHeight, "%s: %d lines were converted, not %d\n", test_desc, ret, bm.bmHeight);
787
788     ok(color_match(pixel, 0x00ffffff), "%s: Pixel is 0x%08x\n", test_desc, pixel);
789 }
790
791 static void test_LoadImageFile(const char * test_desc, unsigned char * image_data,
792     unsigned int image_size, const char * ext, BOOL expect_success)
793 {
794     HANDLE handle;
795     BOOL ret;
796     DWORD error, bytes_written;
797     char filename[64];
798
799     strcpy(filename, "test.");
800     strcat(filename, ext);
801
802     /* Create the test image. */
803     handle = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW,
804         FILE_ATTRIBUTE_NORMAL, NULL);
805     ok(handle != INVALID_HANDLE_VALUE, "CreateFileA failed. %u\n", GetLastError());
806     ret = WriteFile(handle, image_data, image_size, &bytes_written, NULL);
807     ok(ret && bytes_written == image_size, "test file created improperly.\n");
808     CloseHandle(handle);
809
810     /* Load as cursor. For all tested formats, this should fail */
811     SetLastError(0xdeadbeef);
812     handle = LoadImageA(NULL, filename, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
813     ok(handle == NULL, "%s: IMAGE_CURSOR succeeded incorrectly.\n", test_desc);
814     error = GetLastError();
815     ok(error == 0 ||
816         broken(error == 0xdeadbeef) || /* Win9x */
817         broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
818         "Last error: %u\n", error);
819     if (handle != NULL) DestroyCursor(handle);
820
821     /* Load as icon. For all tested formats, this should fail */
822     SetLastError(0xdeadbeef);
823     handle = LoadImageA(NULL, filename, IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
824     ok(handle == NULL, "%s: IMAGE_ICON succeeded incorrectly.\n", test_desc);
825     error = GetLastError();
826     ok(error == 0 ||
827         broken(error == 0xdeadbeef) || /* Win9x */
828         broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
829         "Last error: %u\n", error);
830     if (handle != NULL) DestroyIcon(handle);
831
832     /* Load as bitmap. Should succeed for correct bmp, fail for everything else */
833     SetLastError(0xdeadbeef);
834     handle = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
835     error = GetLastError();
836     ok(error == 0 ||
837         error == 0xdeadbeef, /* Win9x, WinMe */
838         "Last error: %u\n", error);
839
840     if (expect_success) {
841         ok(handle != NULL, "%s: IMAGE_BITMAP failed.\n", test_desc);
842         if (handle != NULL) test_LoadImageBitmap(test_desc, handle);
843     }
844     else ok(handle == NULL, "%s: IMAGE_BITMAP succeeded incorrectly.\n", test_desc);
845
846     if (handle != NULL) DeleteObject(handle);
847     DeleteFileA(filename);
848 }
849
850 static void test_LoadImage(void)
851 {
852     HANDLE handle;
853     BOOL ret;
854     DWORD error, bytes_written;
855     CURSORICONFILEDIR *icon_data;
856     CURSORICONFILEDIRENTRY *icon_entry;
857     BITMAPINFOHEADER *icon_header;
858     ICONINFO icon_info;
859
860 #define ICON_WIDTH 32
861 #define ICON_HEIGHT 32
862 #define ICON_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
863 #define ICON_BPP 32
864 #define ICON_SIZE \
865     (sizeof(CURSORICONFILEDIR) + sizeof(BITMAPINFOHEADER) \
866     + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
867
868     /* Set icon data. */
869     icon_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ICON_SIZE);
870     icon_data->idReserved = 0;
871     icon_data->idType = 1;
872     icon_data->idCount = 1;
873
874     icon_entry = icon_data->idEntries;
875     icon_entry->bWidth = ICON_WIDTH;
876     icon_entry->bHeight = ICON_HEIGHT;
877     icon_entry->bColorCount = 0;
878     icon_entry->bReserved = 0;
879     icon_entry->xHotspot = 1;
880     icon_entry->yHotspot = 1;
881     icon_entry->dwDIBSize = ICON_SIZE - sizeof(CURSORICONFILEDIR);
882     icon_entry->dwDIBOffset = sizeof(CURSORICONFILEDIR);
883
884     icon_header = (BITMAPINFOHEADER *) ((BYTE *) icon_data + icon_entry->dwDIBOffset);
885     icon_header->biSize = sizeof(BITMAPINFOHEADER);
886     icon_header->biWidth = ICON_WIDTH;
887     icon_header->biHeight = ICON_HEIGHT*2;
888     icon_header->biPlanes = 1;
889     icon_header->biBitCount = ICON_BPP;
890     icon_header->biSizeImage = 0; /* Uncompressed bitmap. */
891
892     /* Create the icon. */
893     handle = CreateFileA("icon.ico", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW,
894         FILE_ATTRIBUTE_NORMAL, NULL);
895     ok(handle != INVALID_HANDLE_VALUE, "CreateFileA failed. %u\n", GetLastError());
896     ret = WriteFile(handle, icon_data, ICON_SIZE, &bytes_written, NULL);
897     ok(ret && bytes_written == ICON_SIZE, "icon.ico created improperly.\n");
898     CloseHandle(handle);
899
900     /* Test loading an icon as a cursor. */
901     SetLastError(0xdeadbeef);
902     handle = LoadImageA(NULL, "icon.ico", IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
903     ok(handle != NULL, "LoadImage() failed.\n");
904     error = GetLastError();
905     ok(error == 0 ||
906         broken(error == 0xdeadbeef) || /* Win9x */
907         broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */
908         "Last error: %u\n", error);
909
910     /* Test the icon information. */
911     SetLastError(0xdeadbeef);
912     ret = GetIconInfo(handle, &icon_info);
913     ok(ret, "GetIconInfo() failed.\n");
914     error = GetLastError();
915     ok(error == 0xdeadbeef, "Last error: %u\n", error);
916
917     if (ret)
918     {
919         ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n");
920         ok(icon_info.xHotspot == 1, "xHotspot is %u.\n", icon_info.xHotspot);
921         ok(icon_info.yHotspot == 1, "yHotspot is %u.\n", icon_info.yHotspot);
922         ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */,
923            "No hbmColor!\n");
924         ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
925     }
926
927     if (pGetIconInfoExA)
928     {
929         ICONINFOEXA infoex;
930         infoex.cbSize = sizeof(infoex);
931         ret = pGetIconInfoExA( handle, &infoex );
932         ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() );
933         ok( infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID );
934         ok( infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName );
935         ok( infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName );
936     }
937     else win_skip( "GetIconInfoEx not available\n" );
938
939     /* Clean up. */
940     SetLastError(0xdeadbeef);
941     ret = DestroyCursor(handle);
942     ok(ret, "DestroyCursor() failed.\n");
943     error = GetLastError();
944     ok(error == 0xdeadbeef, "Last error: %u\n", error);
945
946     HeapFree(GetProcessHeap(), 0, icon_data);
947     DeleteFileA("icon.ico");
948
949     /* Test a system icon */
950     handle = LoadIcon( 0, IDI_HAND );
951     ok(handle != NULL, "LoadImage() failed.\n");
952     if (pGetIconInfoExA)
953     {
954         ICONINFOEXA infoexA;
955         ICONINFOEXW infoexW;
956         infoexA.cbSize = sizeof(infoexA);
957         ret = pGetIconInfoExA( handle, &infoexA );
958         ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() );
959         ok( infoexA.wResID == (UINT_PTR)IDI_HAND, "GetIconInfoEx wrong resid %x\n", infoexA.wResID );
960         /* the A version is broken on 64-bit, it truncates the string after the first char */
961         if (is_win64 && infoexA.szModName[0] && infoexA.szModName[1] == 0)
962             trace( "GetIconInfoExA broken on Win64\n" );
963         else
964             ok( GetModuleHandleA(infoexA.szModName) == GetModuleHandleA("user32.dll"),
965                 "GetIconInfoEx wrong module %s\n", infoexA.szModName );
966         ok( infoexA.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoexA.szResName );
967         infoexW.cbSize = sizeof(infoexW);
968         ret = pGetIconInfoExW( handle, &infoexW );
969         ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() );
970         ok( infoexW.wResID == (UINT_PTR)IDI_HAND, "GetIconInfoEx wrong resid %x\n", infoexW.wResID );
971         ok( GetModuleHandleW(infoexW.szModName) == GetModuleHandleA("user32.dll"),
972             "GetIconInfoEx wrong module %s\n", wine_dbgstr_w(infoexW.szModName) );
973         ok( infoexW.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", wine_dbgstr_w(infoexW.szResName) );
974     }
975     SetLastError(0xdeadbeef);
976     DestroyIcon(handle);
977
978     test_LoadImageFile("BMP", bmpimage, sizeof(bmpimage), "bmp", 1);
979     test_LoadImageFile("BMP (coreinfo)", bmpcoreimage, sizeof(bmpcoreimage), "bmp", 1);
980     test_LoadImageFile("GIF", gifimage, sizeof(gifimage), "gif", 0);
981     test_LoadImageFile("GIF (2x2 pixel)", gif4pixel, sizeof(gif4pixel), "gif", 0);
982     test_LoadImageFile("JPG", jpgimage, sizeof(jpgimage), "jpg", 0);
983     test_LoadImageFile("PNG", pngimage, sizeof(pngimage), "png", 0);
984     /* Check failure for broken BMP images */
985     bmpimage[0x14]++; /* biHeight > 65535 */
986     test_LoadImageFile("BMP (too high)", bmpimage, sizeof(bmpimage), "bmp", 0);
987     bmpimage[0x14]--;
988     bmpimage[0x18]++; /* biWidth > 65535 */
989     test_LoadImageFile("BMP (too wide)", bmpimage, sizeof(bmpimage), "bmp", 0);
990     bmpimage[0x18]--;
991 }
992
993 static void test_CreateIconFromResource(void)
994 {
995     HANDLE handle;
996     BOOL ret;
997     DWORD error;
998     BITMAPINFOHEADER *icon_header;
999     INT16 *hotspot;
1000     ICONINFO icon_info;
1001
1002 #define ICON_RES_WIDTH 32
1003 #define ICON_RES_HEIGHT 32
1004 #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8)
1005 #define ICON_RES_BPP 32
1006 #define ICON_RES_SIZE \
1007     (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP)
1008 #define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE)
1009
1010     /* Set icon data. */
1011     hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE);
1012
1013     /* Cursor resources have an extra hotspot, icon resources not. */
1014     hotspot[0] = 3;
1015     hotspot[1] = 3;
1016
1017     icon_header = (BITMAPINFOHEADER *) (hotspot + 2);
1018     icon_header->biSize = sizeof(BITMAPINFOHEADER);
1019     icon_header->biWidth = ICON_WIDTH;
1020     icon_header->biHeight = ICON_HEIGHT*2;
1021     icon_header->biPlanes = 1;
1022     icon_header->biBitCount = ICON_BPP;
1023     icon_header->biSizeImage = 0; /* Uncompressed bitmap. */
1024
1025     /* Test creating a cursor. */
1026     SetLastError(0xdeadbeef);
1027     handle = CreateIconFromResource((PBYTE) hotspot, CRSR_RES_SIZE, FALSE, 0x00030000);
1028     ok(handle != NULL, "Create cursor failed.\n");
1029
1030     /* Test the icon information. */
1031     SetLastError(0xdeadbeef);
1032     ret = GetIconInfo(handle, &icon_info);
1033     ok(ret, "GetIconInfo() failed.\n");
1034     error = GetLastError();
1035     ok(error == 0xdeadbeef, "Last error: %u\n", error);
1036
1037     if (ret)
1038     {
1039         ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n");
1040         ok(icon_info.xHotspot == 3, "xHotspot is %u.\n", icon_info.xHotspot);
1041         ok(icon_info.yHotspot == 3, "yHotspot is %u.\n", icon_info.yHotspot);
1042         ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */,
1043            "No hbmColor!\n");
1044         ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
1045     }
1046
1047     if (pGetIconInfoExA)
1048     {
1049         ICONINFOEXA infoex;
1050         infoex.cbSize = sizeof(infoex);
1051         ret = pGetIconInfoExA( handle, &infoex );
1052         ok( ret, "GetIconInfoEx failed err %d\n", GetLastError() );
1053         ok( infoex.wResID == 0, "GetIconInfoEx wrong resid %x\n", infoex.wResID );
1054         ok( infoex.szModName[0] == 0, "GetIconInfoEx wrong module %s\n", infoex.szModName );
1055         ok( infoex.szResName[0] == 0, "GetIconInfoEx wrong name %s\n", infoex.szResName );
1056     }
1057
1058     /* Clean up. */
1059     SetLastError(0xdeadbeef);
1060     ret = DestroyCursor(handle);
1061     ok(ret, "DestroyCursor() failed.\n");
1062     error = GetLastError();
1063     ok(error == 0xdeadbeef, "Last error: %u\n", error);
1064
1065     /* Test creating an icon. */
1066     SetLastError(0xdeadbeef);
1067     handle = CreateIconFromResource((PBYTE) icon_header, ICON_RES_SIZE, TRUE,
1068                                     0x00030000);
1069     ok(handle != NULL, "Create icon failed.\n");
1070
1071     /* Test the icon information. */
1072     SetLastError(0xdeadbeef);
1073     ret = GetIconInfo(handle, &icon_info);
1074     ok(ret, "GetIconInfo() failed.\n");
1075     error = GetLastError();
1076     ok(error == 0xdeadbeef, "Last error: %u\n", error);
1077
1078     if (ret)
1079     {
1080         ok(icon_info.fIcon == TRUE, "fIcon != TRUE.\n");
1081         /* Icons always have hotspot in the middle */
1082         ok(icon_info.xHotspot == ICON_WIDTH/2, "xHotspot is %u.\n", icon_info.xHotspot);
1083         ok(icon_info.yHotspot == ICON_HEIGHT/2, "yHotspot is %u.\n", icon_info.yHotspot);
1084         ok(icon_info.hbmColor != NULL, "No hbmColor!\n");
1085         ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
1086     }
1087
1088     /* Clean up. */
1089     SetLastError(0xdeadbeef);
1090     ret = DestroyCursor(handle);
1091     ok(ret, "DestroyCursor() failed.\n");
1092     error = GetLastError();
1093     ok(error == 0xdeadbeef, "Last error: %u\n", error);
1094
1095     /* Rejection of NULL pointer crashes at least on WNT4WSSP6, W2KPROSP4, WXPPROSP3
1096      *
1097      * handle = CreateIconFromResource(NULL, ICON_RES_SIZE, TRUE, 0x00030000);
1098      * ok(handle == NULL, "Invalid pointer accepted (%p)\n", handle);
1099      */
1100     HeapFree(GetProcessHeap(), 0, hotspot);
1101 }
1102
1103 static HICON create_test_icon(HDC hdc, int width, int height, int bpp,
1104                               BOOL maskvalue, UINT32 *color, int colorSize)
1105 {
1106     ICONINFO iconInfo;
1107     BITMAPINFO bitmapInfo;
1108     void *buffer = NULL;
1109     UINT32 mask = maskvalue ? 0xFFFFFFFF : 0x00000000;
1110
1111     memset(&bitmapInfo, 0, sizeof(bitmapInfo));
1112     bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1113     bitmapInfo.bmiHeader.biWidth = width;
1114     bitmapInfo.bmiHeader.biHeight = height;
1115     bitmapInfo.bmiHeader.biPlanes = 1;
1116     bitmapInfo.bmiHeader.biBitCount = bpp;
1117     bitmapInfo.bmiHeader.biCompression = BI_RGB;
1118     bitmapInfo.bmiHeader.biSizeImage = colorSize;
1119
1120     iconInfo.fIcon = TRUE;
1121     iconInfo.xHotspot = 0;
1122     iconInfo.yHotspot = 0;
1123
1124     iconInfo.hbmMask = CreateBitmap( width, height, 1, 1, &mask );
1125     if(!iconInfo.hbmMask) return NULL;
1126
1127     iconInfo.hbmColor = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &buffer, NULL, 0);
1128     if(!iconInfo.hbmColor || !buffer)
1129     {
1130         DeleteObject(iconInfo.hbmMask);
1131         return NULL;
1132     }
1133
1134     memcpy(buffer, color, colorSize);
1135
1136     return CreateIconIndirect(&iconInfo);
1137 }
1138
1139 static void check_alpha_draw(HDC hdc, BOOL drawiconex, BOOL alpha, int bpp, int line)
1140 {
1141     HICON hicon;
1142     UINT32 color[2];
1143     COLORREF modern_expected, legacy_expected, result;
1144
1145     color[0] = 0x00A0B0C0;
1146     color[1] = alpha ? 0xFF000000 : 0x00000000;
1147     modern_expected = alpha ? 0x00FFFFFF : 0x00C0B0A0;
1148     legacy_expected = 0x00C0B0A0;
1149
1150     hicon = create_test_icon(hdc, 2, 1, bpp, 0, color, sizeof(color));
1151     if (!hicon) return;
1152
1153     SetPixelV(hdc, 0, 0, 0x00FFFFFF);
1154
1155     if(drawiconex)
1156         DrawIconEx(hdc, 0, 0, hicon, 2, 1, 0, NULL, DI_NORMAL);
1157     else
1158         DrawIcon(hdc, 0, 0, hicon);
1159
1160     result = GetPixel(hdc, 0, 0);
1161     ok (color_match(result, modern_expected) ||         /* Windows 2000 and up */
1162         broken(color_match(result, legacy_expected)),   /* Windows NT 4.0, 9X and below */
1163         "%s. Expected a close match to %06X (modern) or %06X (legacy) with %s. "
1164         "Got %06X from line %d\n",
1165         alpha ? "Alpha blending" : "Not alpha blending", modern_expected, legacy_expected,
1166         drawiconex ? "DrawIconEx" : "DrawIcon", result, line);
1167 }
1168
1169 static void check_DrawIcon(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, COLORREF background,
1170                            COLORREF modern_expected, COLORREF legacy_expected, int line)
1171 {
1172     COLORREF result;
1173     HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
1174     if (!hicon) return;
1175     SetPixelV(hdc, 0, 0, background);
1176     SetPixelV(hdc, GetSystemMetrics(SM_CXICON)-1, GetSystemMetrics(SM_CYICON)-1, background);
1177     SetPixelV(hdc, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), background);
1178     DrawIcon(hdc, 0, 0, hicon);
1179     result = GetPixel(hdc, 0, 0);
1180
1181     ok (color_match(result, modern_expected) ||         /* Windows 2000 and up */
1182         broken(color_match(result, legacy_expected)),   /* Windows NT 4.0, 9X and below */
1183         "Overlaying Mask %d on Color %06X with DrawIcon. "
1184         "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1185         maskvalue, color, modern_expected, legacy_expected, result, line);
1186
1187     result = GetPixel(hdc, GetSystemMetrics(SM_CXICON)-1, GetSystemMetrics(SM_CYICON)-1);
1188
1189     ok (color_match(result, modern_expected) ||         /* Windows 2000 and up */
1190         broken(color_match(result, legacy_expected)),   /* Windows NT 4.0, 9X and below */
1191         "Overlaying Mask %d on Color %06X with DrawIcon. "
1192         "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n",
1193         maskvalue, color, modern_expected, legacy_expected, result, line);
1194
1195     result = GetPixel(hdc, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
1196
1197     ok (color_match(result, background),
1198         "Overlaying Mask %d on Color %06X with DrawIcon. "
1199         "Expected unchanged background color %06X. Got %06X from line %d\n",
1200         maskvalue, color, background, result, line);
1201 }
1202
1203 static void test_DrawIcon(void)
1204 {
1205     BITMAPINFO bitmapInfo;
1206     HDC hdcDst = NULL;
1207     HBITMAP bmpDst = NULL;
1208     HBITMAP bmpOld = NULL;
1209     void *bits = 0;
1210
1211     hdcDst = CreateCompatibleDC(0);
1212     ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1213     if (!hdcDst)
1214         return;
1215
1216     if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
1217     {
1218         skip("Windows will distort DrawIcon colors at 8-bpp and less due to palletizing.\n");
1219         goto cleanup;
1220     }
1221
1222     memset(&bitmapInfo, 0, sizeof(bitmapInfo));
1223     bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1224     bitmapInfo.bmiHeader.biWidth = GetSystemMetrics(SM_CXICON)+1;
1225     bitmapInfo.bmiHeader.biHeight = GetSystemMetrics(SM_CYICON)+1;
1226     bitmapInfo.bmiHeader.biBitCount = 32;
1227     bitmapInfo.bmiHeader.biPlanes = 1;
1228     bitmapInfo.bmiHeader.biCompression = BI_RGB;
1229     bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
1230
1231     bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
1232     ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1233     if (!bmpDst || !bits)
1234         goto cleanup;
1235     bmpOld = SelectObject(hdcDst, bmpDst);
1236
1237     /* Mask is only heeded if alpha channel is always zero */
1238     check_DrawIcon(hdcDst, FALSE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
1239     check_DrawIcon(hdcDst, TRUE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__);
1240
1241     /* Test alpha blending */
1242     /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
1243     check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
1244     check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
1245
1246     check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
1247     check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
1248     check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__);
1249     check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__);
1250
1251     check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
1252     check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
1253
1254     /* Test detecting of alpha channel */
1255     /* If a single pixel's alpha channel is non-zero, the icon
1256        will be alpha blended, otherwise it will be draw with
1257        and + xor blts. */
1258     check_alpha_draw(hdcDst, FALSE, FALSE, 32, __LINE__);
1259     check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__);
1260
1261 cleanup:
1262     if(bmpOld)
1263         SelectObject(hdcDst, bmpOld);
1264     if(bmpDst)
1265         DeleteObject(bmpDst);
1266     if(hdcDst)
1267         DeleteDC(hdcDst);
1268 }
1269
1270 static void check_DrawIconEx(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, UINT flags, COLORREF background,
1271                              COLORREF modern_expected, COLORREF legacy_expected, int line)
1272 {
1273     COLORREF result;
1274     HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
1275     if (!hicon) return;
1276     SetPixelV(hdc, 0, 0, background);
1277     DrawIconEx(hdc, 0, 0, hicon, 1, 1, 0, NULL, flags);
1278     result = GetPixel(hdc, 0, 0);
1279
1280     ok (color_match(result, modern_expected) ||         /* Windows 2000 and up */
1281         broken(color_match(result, legacy_expected)),   /* Windows NT 4.0, 9X and below */
1282         "Overlaying Mask %d on Color %06X with DrawIconEx flags %08X. "
1283         "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
1284         maskvalue, color, flags, modern_expected, legacy_expected, result, line);
1285 }
1286
1287 static void test_DrawIconEx(void)
1288 {
1289     BITMAPINFO bitmapInfo;
1290     HDC hdcDst = NULL;
1291     HBITMAP bmpDst = NULL;
1292     HBITMAP bmpOld = NULL;
1293     void *bits = 0;
1294
1295     hdcDst = CreateCompatibleDC(0);
1296     ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1297     if (!hdcDst)
1298         return;
1299
1300     if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
1301     {
1302         skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n");
1303         goto cleanup;
1304     }
1305
1306     memset(&bitmapInfo, 0, sizeof(bitmapInfo));
1307     bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1308     bitmapInfo.bmiHeader.biWidth = 1;
1309     bitmapInfo.bmiHeader.biHeight = 1;
1310     bitmapInfo.bmiHeader.biBitCount = 32;
1311     bitmapInfo.bmiHeader.biPlanes = 1;
1312     bitmapInfo.bmiHeader.biCompression = BI_RGB;
1313     bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
1314     bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
1315     ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1316     if (!bmpDst || !bits)
1317         goto cleanup;
1318     bmpOld = SelectObject(hdcDst, bmpDst);
1319
1320     /* Test null, image only, and mask only drawing */
1321     check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__);
1322     check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__);
1323
1324     check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00000000, 0x00000000, __LINE__);
1325     check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, __LINE__);
1326
1327     check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
1328     check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
1329
1330     /* Test normal drawing */
1331     check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
1332     check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__);
1333     check_DrawIconEx(hdcDst, FALSE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
1334
1335     /* Test alpha blending */
1336     /* Windows 2000 and up will alpha blend, earlier Windows versions will not */
1337     check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
1338
1339     check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
1340     check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
1341     check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__);
1342     check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__);
1343
1344     check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
1345     check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
1346
1347     /* Test detecting of alpha channel */
1348     /* If a single pixel's alpha channel is non-zero, the icon
1349        will be alpha blended, otherwise it will be draw with
1350        and + xor blts. */
1351     check_alpha_draw(hdcDst, TRUE, FALSE, 32, __LINE__);
1352     check_alpha_draw(hdcDst, TRUE, TRUE, 32, __LINE__);
1353
1354 cleanup:
1355     if(bmpOld)
1356         SelectObject(hdcDst, bmpOld);
1357     if(bmpDst)
1358         DeleteObject(bmpDst);
1359     if(hdcDst)
1360         DeleteDC(hdcDst);
1361 }
1362
1363 static void check_DrawState_Size(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, HBRUSH hbr, UINT flags, int line)
1364 {
1365     COLORREF result, background;
1366     BOOL passed[2];
1367     HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
1368     background = 0x00FFFFFF;
1369     /* Set color of the 2 pixels that will be checked afterwards */
1370     SetPixelV(hdc, 0, 0, background);
1371     SetPixelV(hdc, 2, 2, background);
1372
1373     /* Let DrawState calculate the size of the icon (it's 1x1) */
1374     DrawState(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 0, 0, (DST_ICON | flags ));
1375
1376     result = GetPixel(hdc, 0, 0);
1377     passed[0] = color_match(result, background);
1378     result = GetPixel(hdc, 2, 2);
1379     passed[0] = passed[0] & color_match(result, background);
1380
1381     /* Check if manually specifying the icon size DOESN'T work */
1382
1383     /* IMPORTANT: For Icons, DrawState wants the size of the source image, not the
1384      *            size in which it should be ultimately drawn. Therefore giving
1385      *            width/height 2x2 if the icon is only 1x1 pixels in size should
1386      *            result in drawing it with size 1x1. The size parameters must be
1387      *            ignored if a Icon has to be drawn! */
1388     DrawState(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 2, 2, (DST_ICON | flags ));
1389
1390     result = GetPixel(hdc, 0, 0);
1391     passed[1] = color_match(result, background);
1392     result = GetPixel(hdc, 2, 2);
1393     passed[1] = passed[0] & color_match(result, background);
1394
1395     if(!passed[0]&&!passed[1])
1396         ok (passed[1],
1397         "DrawState failed to draw a 1x1 Icon in the correct size, independent of the "
1398         "width and height settings passed to it, for Icon with: Overlaying Mask %d on "
1399         "Color %06X with flags %08X. Line %d\n",
1400         maskvalue, color, (DST_ICON | flags), line);
1401     else if(!passed[1])
1402         ok (passed[1],
1403         "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
1404         "parameters passed to it are bigger than the real Icon size, for Icon with: Overlaying "
1405         "Mask %d on Color %06X with flags %08X. Line %d\n",
1406         maskvalue, color, (DST_ICON | flags), line);
1407     else
1408         ok (passed[0],
1409         "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height "
1410         "parameters passed to it are 0, for Icon with: Overlaying Mask %d on "
1411         "Color %06X with flags %08X. Line %d\n",
1412         maskvalue, color, (DST_ICON | flags), line);
1413 }
1414
1415 static void check_DrawState_Color(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, HBRUSH hbr, UINT flags,
1416                              COLORREF background, COLORREF modern_expected, COLORREF legacy_expected, int line)
1417 {
1418     COLORREF result;
1419     HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color));
1420     if (!hicon) return;
1421     /* Set color of the pixel that will be checked afterwards */
1422     SetPixelV(hdc, 1, 1, background);
1423
1424     DrawState(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 0, 0, ( DST_ICON | flags ));
1425
1426     /* Check the color of the pixel is correct */
1427     result = GetPixel(hdc, 1, 1);
1428
1429     ok (color_match(result, modern_expected) ||         /* Windows 2000 and up */
1430         broken(color_match(result, legacy_expected)),   /* Windows NT 4.0, 9X and below */
1431         "DrawState drawing Icon with Overlaying Mask %d on Color %06X with flags %08X. "
1432         "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n",
1433         maskvalue, color, (DST_ICON | flags), modern_expected, legacy_expected, result, line);
1434 }
1435
1436 static void test_DrawState(void)
1437 {
1438     BITMAPINFO bitmapInfo;
1439     HDC hdcDst = NULL;
1440     HBITMAP bmpDst = NULL;
1441     HBITMAP bmpOld = NULL;
1442     void *bits = 0;
1443
1444     hdcDst = CreateCompatibleDC(0);
1445     ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1446     if (!hdcDst)
1447         return;
1448
1449     if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8)
1450     {
1451         skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n");
1452         goto cleanup;
1453     }
1454
1455     memset(&bitmapInfo, 0, sizeof(bitmapInfo));
1456     bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1457     bitmapInfo.bmiHeader.biWidth = 3;
1458     bitmapInfo.bmiHeader.biHeight = 3;
1459     bitmapInfo.bmiHeader.biBitCount = 32;
1460     bitmapInfo.bmiHeader.biPlanes = 1;
1461     bitmapInfo.bmiHeader.biCompression = BI_RGB;
1462     bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32);
1463     bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0);
1464     ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1465     if (!bmpDst || !bits)
1466         goto cleanup;
1467     bmpOld = SelectObject(hdcDst, bmpDst);
1468
1469     /* potential flags to test with DrawState are: */
1470     /* DSS_DISABLED embosses the icon */
1471     /* DSS_MONO draw Icon using a brush as parameter 5 */
1472     /* DSS_NORMAL draw Icon without any modifications */
1473     /* DSS_UNION draw the Icon dithered */
1474
1475     check_DrawState_Size(hdcDst, FALSE, 0x00A0B0C0, 32, 0, DSS_NORMAL, __LINE__);
1476     check_DrawState_Color(hdcDst, FALSE, 0x00A0B0C0, 32, 0, DSS_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
1477
1478 cleanup:
1479     if(bmpOld)
1480         SelectObject(hdcDst, bmpOld);
1481     if(bmpDst)
1482         DeleteObject(bmpDst);
1483     if(hdcDst)
1484         DeleteDC(hdcDst);
1485 }
1486
1487 static DWORD parent_id;
1488
1489 static DWORD CALLBACK set_cursor_thread( void *arg )
1490 {
1491     HCURSOR ret;
1492
1493     PeekMessage( 0, 0, 0, 0, PM_NOREMOVE );  /* create a msg queue */
1494     if (parent_id)
1495     {
1496         BOOL ret = AttachThreadInput( GetCurrentThreadId(), parent_id, TRUE );
1497         ok( ret, "AttachThreadInput failed\n" );
1498     }
1499     if (arg) ret = SetCursor( (HCURSOR)arg );
1500     else ret = GetCursor();
1501     return (DWORD_PTR)ret;
1502 }
1503
1504 static void test_SetCursor(void)
1505 {
1506     static const BYTE bmp_bits[4096];
1507     ICONINFO cursorInfo;
1508     HCURSOR cursor, old_cursor, global_cursor = 0;
1509     DWORD error, id, result;
1510     UINT display_bpp;
1511     HDC hdc;
1512     HANDLE thread;
1513     CURSORINFO info;
1514
1515     if (pGetCursorInfo)
1516     {
1517         memset( &info, 0, sizeof(info) );
1518         info.cbSize = sizeof(info);
1519         if (!pGetCursorInfo( &info ))
1520         {
1521             win_skip( "GetCursorInfo not working\n" );
1522             pGetCursorInfo = NULL;
1523         }
1524         else global_cursor = info.hCursor;
1525     }
1526     cursor = GetCursor();
1527     thread = CreateThread( NULL, 0, set_cursor_thread, 0, 0, &id );
1528     WaitForSingleObject( thread, 1000 );
1529     GetExitCodeThread( thread, &result );
1530     ok( result == (DWORD_PTR)cursor, "wrong thread cursor %x/%p\n", result, cursor );
1531
1532     hdc = GetDC(0);
1533     display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
1534     ReleaseDC(0, hdc);
1535
1536     cursorInfo.fIcon = FALSE;
1537     cursorInfo.xHotspot = 0;
1538     cursorInfo.yHotspot = 0;
1539     cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
1540     cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
1541
1542     cursor = CreateIconIndirect(&cursorInfo);
1543     ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
1544     old_cursor = SetCursor( cursor );
1545
1546     if (pGetCursorInfo)
1547     {
1548         info.cbSize = sizeof(info);
1549         ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
1550         /* global cursor doesn't change since we don't have a window */
1551         ok( info.hCursor == global_cursor || broken(info.hCursor != cursor), /* win9x */
1552             "wrong info cursor %p/%p\n", info.hCursor, global_cursor );
1553     }
1554     thread = CreateThread( NULL, 0, set_cursor_thread, 0, 0, &id );
1555     WaitForSingleObject( thread, 1000 );
1556     GetExitCodeThread( thread, &result );
1557     ok( result == (DWORD_PTR)old_cursor, "wrong thread cursor %x/%p\n", result, old_cursor );
1558
1559     SetCursor( 0 );
1560     ok( GetCursor() == 0, "wrong cursor %p\n", GetCursor() );
1561     thread = CreateThread( NULL, 0, set_cursor_thread, 0, 0, &id );
1562     WaitForSingleObject( thread, 1000 );
1563     GetExitCodeThread( thread, &result );
1564     ok( result == (DWORD_PTR)old_cursor, "wrong thread cursor %x/%p\n", result, old_cursor );
1565
1566     thread = CreateThread( NULL, 0, set_cursor_thread, cursor, 0, &id );
1567     WaitForSingleObject( thread, 1000 );
1568     GetExitCodeThread( thread, &result );
1569     ok( result == (DWORD_PTR)old_cursor, "wrong thread cursor %x/%p\n", result, old_cursor );
1570     ok( GetCursor() == 0, "wrong cursor %p/0\n", GetCursor() );
1571
1572     parent_id = GetCurrentThreadId();
1573     thread = CreateThread( NULL, 0, set_cursor_thread, cursor, 0, &id );
1574     WaitForSingleObject( thread, 1000 );
1575     GetExitCodeThread( thread, &result );
1576     ok( result == (DWORD_PTR)old_cursor, "wrong thread cursor %x/%p\n", result, old_cursor );
1577     ok( GetCursor() == cursor, "wrong cursor %p/0\n", cursor );
1578
1579     if (pGetCursorInfo)
1580     {
1581         info.cbSize = sizeof(info);
1582         ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
1583         ok( info.hCursor == global_cursor || broken(info.hCursor != cursor), /* win9x */
1584             "wrong info cursor %p/%p\n", info.hCursor, global_cursor );
1585     }
1586     SetCursor( old_cursor );
1587     DestroyCursor( cursor );
1588
1589     SetLastError( 0xdeadbeef );
1590     cursor = SetCursor( (HCURSOR)0xbadbad );
1591     error = GetLastError();
1592     ok( cursor == 0, "wrong cursor %p/0\n", cursor );
1593     ok( error == ERROR_INVALID_CURSOR_HANDLE || broken( error == 0xdeadbeef ),  /* win9x */
1594         "wrong error %u\n", error );
1595
1596     if (pGetCursorInfo)
1597     {
1598         info.cbSize = sizeof(info);
1599         ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
1600         ok( info.hCursor == global_cursor || broken(info.hCursor != cursor), /* win9x */
1601             "wrong info cursor %p/%p\n", info.hCursor, global_cursor );
1602     }
1603 }
1604
1605 static HANDLE event_start, event_next;
1606
1607 static DWORD CALLBACK show_cursor_thread( void *arg )
1608 {
1609     DWORD count = (DWORD_PTR)arg;
1610     int ret;
1611
1612     PeekMessage( 0, 0, 0, 0, PM_NOREMOVE );  /* create a msg queue */
1613     if (parent_id)
1614     {
1615         BOOL ret = AttachThreadInput( GetCurrentThreadId(), parent_id, TRUE );
1616         ok( ret, "AttachThreadInput failed\n" );
1617     }
1618     if (!count) ret = ShowCursor( FALSE );
1619     else while (count--) ret = ShowCursor( TRUE );
1620     SetEvent( event_start );
1621     WaitForSingleObject( event_next, 2000 );
1622     return ret;
1623 }
1624
1625 static void test_ShowCursor(void)
1626 {
1627     int count;
1628     DWORD id, result;
1629     HANDLE thread;
1630     CURSORINFO info;
1631
1632     if (pGetCursorInfo)
1633     {
1634         memset( &info, 0, sizeof(info) );
1635         info.cbSize = sizeof(info);
1636         ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
1637         ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
1638     }
1639
1640     event_start = CreateEvent( NULL, FALSE, FALSE, NULL );
1641     event_next = CreateEvent( NULL, FALSE, FALSE, NULL );
1642
1643     count = ShowCursor( TRUE );
1644     ok( count == 1, "wrong count %d\n", count );
1645     count = ShowCursor( TRUE );
1646     ok( count == 2, "wrong count %d\n", count );
1647     count = ShowCursor( FALSE );
1648     ok( count == 1, "wrong count %d\n", count );
1649     count = ShowCursor( FALSE );
1650     ok( count == 0, "wrong count %d\n", count );
1651     count = ShowCursor( FALSE );
1652     ok( count == -1, "wrong count %d\n", count );
1653     count = ShowCursor( FALSE );
1654     ok( count == -2, "wrong count %d\n", count );
1655
1656     if (pGetCursorInfo)
1657     {
1658         info.cbSize = sizeof(info);
1659         ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
1660         /* global show count is not affected since we don't have a window */
1661         ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
1662     }
1663
1664     parent_id = 0;
1665     thread = CreateThread( NULL, 0, show_cursor_thread, NULL, 0, &id );
1666     WaitForSingleObject( event_start, 1000 );
1667     count = ShowCursor( FALSE );
1668     ok( count == -3, "wrong count %d\n", count );
1669     SetEvent( event_next );
1670     WaitForSingleObject( thread, 1000 );
1671     GetExitCodeThread( thread, &result );
1672     ok( result == -1, "wrong thread count %d\n", result );
1673     count = ShowCursor( FALSE );
1674     ok( count == -4, "wrong count %d\n", count );
1675
1676     thread = CreateThread( NULL, 0, show_cursor_thread, (void *)1, 0, &id );
1677     WaitForSingleObject( event_start, 1000 );
1678     count = ShowCursor( TRUE );
1679     ok( count == -3, "wrong count %d\n", count );
1680     SetEvent( event_next );
1681     WaitForSingleObject( thread, 1000 );
1682     GetExitCodeThread( thread, &result );
1683     ok( result == 1, "wrong thread count %d\n", result );
1684     count = ShowCursor( TRUE );
1685     ok( count == -2, "wrong count %d\n", count );
1686
1687     parent_id = GetCurrentThreadId();
1688     thread = CreateThread( NULL, 0, show_cursor_thread, NULL, 0, &id );
1689     WaitForSingleObject( event_start, 1000 );
1690     count = ShowCursor( TRUE );
1691     ok( count == -2, "wrong count %d\n", count );
1692     SetEvent( event_next );
1693     WaitForSingleObject( thread, 1000 );
1694     GetExitCodeThread( thread, &result );
1695     ok( result == -3, "wrong thread count %d\n", result );
1696     count = ShowCursor( FALSE );
1697     ok( count == -2, "wrong count %d\n", count );
1698
1699     thread = CreateThread( NULL, 0, show_cursor_thread, (void *)3, 0, &id );
1700     WaitForSingleObject( event_start, 1000 );
1701     count = ShowCursor( TRUE );
1702     ok( count == 2, "wrong count %d\n", count );
1703     SetEvent( event_next );
1704     WaitForSingleObject( thread, 1000 );
1705     GetExitCodeThread( thread, &result );
1706     ok( result == 1, "wrong thread count %d\n", result );
1707     count = ShowCursor( FALSE );
1708     ok( count == -2, "wrong count %d\n", count );
1709
1710     if (pGetCursorInfo)
1711     {
1712         info.cbSize = sizeof(info);
1713         ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
1714         ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
1715     }
1716
1717     count = ShowCursor( TRUE );
1718     ok( count == -1, "wrong count %d\n", count );
1719     count = ShowCursor( TRUE );
1720     ok( count == 0, "wrong count %d\n", count );
1721
1722     if (pGetCursorInfo)
1723     {
1724         info.cbSize = sizeof(info);
1725         ok( pGetCursorInfo( &info ), "GetCursorInfo failed\n" );
1726         ok( info.flags & CURSOR_SHOWING, "cursor not shown in info\n" );
1727     }
1728 }
1729
1730
1731 static void test_DestroyCursor(void)
1732 {
1733     static const BYTE bmp_bits[4096];
1734     ICONINFO cursorInfo, new_info;
1735     HCURSOR cursor, cursor2, new_cursor;
1736     BOOL ret;
1737     DWORD error;
1738     UINT display_bpp;
1739     HDC hdc;
1740
1741     hdc = GetDC(0);
1742     display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
1743     ReleaseDC(0, hdc);
1744
1745     cursorInfo.fIcon = FALSE;
1746     cursorInfo.xHotspot = 0;
1747     cursorInfo.yHotspot = 0;
1748     cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
1749     cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
1750
1751     cursor = CreateIconIndirect(&cursorInfo);
1752     ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
1753     if(!cursor) {
1754         return;
1755     }
1756     SetCursor(cursor);
1757
1758     SetLastError(0xdeadbeef);
1759     ret = DestroyCursor(cursor);
1760     ok(!ret || broken(ret)  /* succeeds on win9x */, "DestroyCursor on the active cursor succeeded\n");
1761     error = GetLastError();
1762     ok(error == 0xdeadbeef, "Last error: %u\n", error);
1763
1764     new_cursor = GetCursor();
1765     if (ret)  /* win9x replaces cursor by another one on destroy */
1766         ok(new_cursor != cursor, "GetCursor returned %p/%p\n", new_cursor, cursor);
1767     else
1768         ok(new_cursor == cursor, "GetCursor returned %p/%p\n", new_cursor, cursor);
1769
1770     SetLastError(0xdeadbeef);
1771     ret = GetIconInfo( cursor, &new_info );
1772     ok( !ret || broken(ret), /* nt4 */ "GetIconInfo succeeded\n" );
1773     ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE ||
1774         broken(GetLastError() == 0xdeadbeef), /* win9x */
1775         "wrong error %u\n", GetLastError() );
1776
1777     if (ret)  /* nt4 delays destruction until cursor changes */
1778     {
1779         DeleteObject( new_info.hbmColor );
1780         DeleteObject( new_info.hbmMask );
1781
1782         SetLastError(0xdeadbeef);
1783         ret = DestroyCursor( cursor );
1784         ok( !ret, "DestroyCursor succeeded\n" );
1785         ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
1786             "wrong error %u\n", GetLastError() );
1787
1788         SetLastError(0xdeadbeef);
1789         cursor2 = SetCursor( cursor );
1790         ok( cursor2 == cursor, "SetCursor returned %p/%p\n", cursor2, cursor);
1791         ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
1792             "wrong error %u\n", GetLastError() );
1793     }
1794     else
1795     {
1796         SetLastError(0xdeadbeef);
1797         cursor2 = CopyCursor( cursor );
1798         ok(!cursor2, "CopyCursor succeeded\n" );
1799         ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE ||
1800             broken(GetLastError() == 0xdeadbeef), /* win9x */
1801             "wrong error %u\n", GetLastError() );
1802
1803         SetLastError(0xdeadbeef);
1804         ret = DestroyCursor( cursor );
1805         if (new_cursor != cursor)  /* win9x */
1806             ok( ret, "DestroyCursor succeeded\n" );
1807         else
1808             ok( !ret, "DestroyCursor succeeded\n" );
1809         ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
1810             "wrong error %u\n", GetLastError() );
1811
1812         SetLastError(0xdeadbeef);
1813         cursor2 = SetCursor( cursor );
1814         ok(!cursor2, "SetCursor returned %p/%p\n", cursor2, cursor);
1815         ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
1816             "wrong error %u\n", GetLastError() );
1817     }
1818
1819     cursor2 = GetCursor();
1820     ok(cursor2 == new_cursor, "GetCursor returned %p/%p\n", cursor2, new_cursor);
1821
1822     SetLastError(0xdeadbeef);
1823     cursor2 = SetCursor( 0 );
1824     if (new_cursor != cursor)  /* win9x */
1825         ok(cursor2 == new_cursor, "SetCursor returned %p/%p\n", cursor2, cursor);
1826     else
1827         ok(!cursor2, "SetCursor returned %p/%p\n", cursor2, cursor);
1828     ok( GetLastError() == 0xdeadbeef, "wrong error %u\n", GetLastError() );
1829
1830     cursor2 = GetCursor();
1831     ok(!cursor2, "GetCursor returned %p/%p\n", cursor2, cursor);
1832
1833     SetLastError(0xdeadbeef);
1834     ret = DestroyCursor(cursor);
1835     if (new_cursor != cursor)  /* win9x */
1836         ok( ret, "DestroyCursor succeeded\n" );
1837     else
1838         ok( !ret, "DestroyCursor succeeded\n" );
1839     ok( GetLastError() == ERROR_INVALID_CURSOR_HANDLE || GetLastError() == 0xdeadbeef,
1840         "wrong error %u\n", GetLastError() );
1841
1842     DeleteObject(cursorInfo.hbmMask);
1843     DeleteObject(cursorInfo.hbmColor);
1844
1845     /* Try testing DestroyCursor() now using LoadCursor() cursors. */
1846     cursor = LoadCursor(NULL, IDC_ARROW);
1847
1848     SetLastError(0xdeadbeef);
1849     ret = DestroyCursor(cursor);
1850     ok(ret || broken(!ret) /* fails on win9x */, "DestroyCursor on the active cursor failed.\n");
1851     error = GetLastError();
1852     ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
1853
1854     /* Try setting the cursor to a destroyed OEM cursor. */
1855     SetLastError(0xdeadbeef);
1856     SetCursor(cursor);
1857     error = GetLastError();
1858     ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
1859
1860     /* Check if LoadCursor() returns the same handle with the same icon. */
1861     cursor2 = LoadCursor(NULL, IDC_ARROW);
1862     ok(cursor2 == cursor, "cursor == %p, cursor2 == %p\n", cursor, cursor2);
1863
1864     /* Check if LoadCursor() returns the same handle with a different icon. */
1865     cursor2 = LoadCursor(NULL, IDC_WAIT);
1866     ok(cursor2 != cursor, "cursor == %p, cursor2 == %p\n", cursor, cursor2);
1867 }
1868
1869 START_TEST(cursoricon)
1870 {
1871     pGetCursorInfo = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetCursorInfo" );
1872     pGetIconInfoExA = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetIconInfoExA" );
1873     pGetIconInfoExW = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetIconInfoExW" );
1874     test_argc = winetest_get_mainargs(&test_argv);
1875
1876     if (test_argc >= 3)
1877     {
1878         /* Child process. */
1879         sscanf (test_argv[2], "%x", (unsigned int *) &parent);
1880
1881         ok(parent != NULL, "Parent not found.\n");
1882         if (parent == NULL)
1883             ExitProcess(1);
1884
1885         do_child();
1886         return;
1887     }
1888
1889     test_CopyImage_Bitmap(1);
1890     test_CopyImage_Bitmap(4);
1891     test_CopyImage_Bitmap(8);
1892     test_CopyImage_Bitmap(16);
1893     test_CopyImage_Bitmap(24);
1894     test_CopyImage_Bitmap(32);
1895     test_initial_cursor();
1896     test_CreateIcon();
1897     test_LoadImage();
1898     test_CreateIconFromResource();
1899     test_DrawIcon();
1900     test_DrawIconEx();
1901     test_DrawState();
1902     test_SetCursor();
1903     test_ShowCursor();
1904     test_DestroyCursor();
1905     do_parent();
1906     test_child_process();
1907     finish_child_process();
1908 }