push a18c97e3310ae68c9cf1d09430f25ca292f320eb
[wine/hacks.git] / dlls / user32 / tests / cursoricon.c
blobca4b1185120c38261d970b0247165f1e446b916d
1 /*
2 * Unit test suite for cursors and icons.
4 * Copyright 2006 Michael Kaufmann
5 * Copyright 2007 Dmitry Timoshkov
6 * Copyright 2007 Andrew Riedi
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
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"
35 static char **test_argv;
36 static int test_argc;
37 static HWND child = 0;
38 static HWND parent = 0;
39 static HANDLE child_process;
41 #define PROC_INIT (WM_USER+1)
43 static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
45 BOOL ret;
46 DWORD error;
48 switch (msg)
50 /* Destroy the cursor. */
51 case WM_USER+1:
52 SetLastError(0xdeadbeef);
53 ret = DestroyCursor((HCURSOR) lParam);
54 error = GetLastError();
55 todo_wine {
56 ok(!ret, "DestroyCursor on the active cursor succeeded.\n");
57 ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD,
58 "Last error: %u\n", error);
60 return TRUE;
61 case WM_DESTROY:
62 PostQuitMessage(0);
63 return 0;
66 return DefWindowProc(hwnd, msg, wParam, lParam);
69 static LRESULT CALLBACK callback_parent(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
71 if (msg == PROC_INIT)
73 child = (HWND) wParam;
74 return TRUE;
77 return DefWindowProc(hwnd, msg, wParam, lParam);
80 static void do_child(void)
82 WNDCLASS class;
83 MSG msg;
84 BOOL ret;
86 /* Register a new class. */
87 class.style = CS_GLOBALCLASS;
88 class.lpfnWndProc = callback_child;
89 class.cbClsExtra = 0;
90 class.cbWndExtra = 0;
91 class.hInstance = GetModuleHandle(NULL);
92 class.hIcon = NULL;
93 class.hCursor = NULL;
94 class.hbrBackground = NULL;
95 class.lpszMenuName = NULL;
96 class.lpszClassName = "cursor_child";
98 SetLastError(0xdeadbeef);
99 ret = RegisterClass(&class);
100 ok(ret, "Failed to register window class. Error: %u\n", GetLastError());
102 /* Create a window. */
103 child = CreateWindowA("cursor_child", "cursor_child", WS_POPUP | WS_VISIBLE,
104 0, 0, 200, 200, 0, 0, 0, NULL);
105 ok(child != 0, "CreateWindowA failed. Error: %u\n", GetLastError());
107 /* Let the parent know our HWND. */
108 PostMessage(parent, PROC_INIT, (WPARAM) child, 0);
110 /* Receive messages. */
111 while ((ret = GetMessage(&msg, child, 0, 0)))
113 ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError());
114 TranslateMessage(&msg);
115 DispatchMessage(&msg);
119 static void do_parent(void)
121 char path_name[MAX_PATH];
122 PROCESS_INFORMATION info;
123 STARTUPINFOA startup;
124 WNDCLASS class;
125 MSG msg;
126 BOOL ret;
128 /* Register a new class. */
129 class.style = CS_GLOBALCLASS;
130 class.lpfnWndProc = callback_parent;
131 class.cbClsExtra = 0;
132 class.cbWndExtra = 0;
133 class.hInstance = GetModuleHandle(NULL);
134 class.hIcon = NULL;
135 class.hCursor = NULL;
136 class.hbrBackground = NULL;
137 class.lpszMenuName = NULL;
138 class.lpszClassName = "cursor_parent";
140 SetLastError(0xdeadbeef);
141 ret = RegisterClass(&class);
142 ok(ret, "Failed to register window class. Error: %u\n", GetLastError());
144 /* Create a window. */
145 parent = CreateWindowA("cursor_parent", "cursor_parent", WS_POPUP | WS_VISIBLE,
146 0, 0, 200, 200, 0, 0, 0, NULL);
147 ok(parent != 0, "CreateWindowA failed. Error: %u\n", GetLastError());
149 /* Start child process. */
150 memset(&startup, 0, sizeof(startup));
151 startup.cb = sizeof(startup);
152 startup.dwFlags = STARTF_USESHOWWINDOW;
153 startup.wShowWindow = SW_SHOWNORMAL;
155 sprintf(path_name, "%s cursoricon %x", test_argv[0], (unsigned int) parent);
156 ok(CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed.\n");
157 child_process = info.hProcess;
159 /* Wait for child window handle. */
160 while ((child == 0) && (ret = GetMessage(&msg, parent, 0, 0)))
162 ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError());
163 TranslateMessage(&msg);
164 DispatchMessage(&msg);
168 static void finish_child_process(void)
170 SendMessage(child, WM_CLOSE, 0, 0);
171 winetest_wait_child_process( child_process );
172 CloseHandle(child_process);
175 static void test_child_process(void)
177 static const BYTE bmp_bits[4096];
178 HCURSOR cursor;
179 ICONINFO cursorInfo;
180 UINT display_bpp;
181 HDC hdc;
183 /* Create and set a dummy cursor. */
184 hdc = GetDC(0);
185 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
186 ReleaseDC(0, hdc);
188 cursorInfo.fIcon = FALSE;
189 cursorInfo.xHotspot = 0;
190 cursorInfo.yHotspot = 0;
191 cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
192 cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
194 cursor = CreateIconIndirect(&cursorInfo);
195 ok(cursor != NULL, "CreateIconIndirect returned %p.\n", cursor);
197 SetCursor(cursor);
199 /* Destroy the cursor. */
200 SendMessage(child, WM_USER+1, 0, (LPARAM) cursor);
203 static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight,
204 INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected)
206 HBITMAP copy;
207 BITMAP origBitmap;
208 BITMAP copyBitmap;
209 BOOL orig_is_dib;
210 BOOL copy_is_dib;
212 copy = (HBITMAP) CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
213 ok(copy != NULL, "CopyImage() failed\n");
214 if (copy != NULL)
216 GetObject(bitmap, sizeof(origBitmap), &origBitmap);
217 GetObject(copy, sizeof(copyBitmap), &copyBitmap);
218 orig_is_dib = (origBitmap.bmBits != NULL);
219 copy_is_dib = (copyBitmap.bmBits != NULL);
221 if (copy_is_dib && dibExpected
222 && copyBitmap.bmBitsPixel == 24
223 && (expectedDepth == 16 || expectedDepth == 32))
225 /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
226 if (GetVersion() & 0x80000000)
228 expectedDepth = 24;
232 if (copy_is_dib && !dibExpected && !(flags & LR_CREATEDIBSECTION))
234 /* It's not forbidden to create a DIB section if the flag
235 LR_CREATEDIBSECTION is absent.
236 Windows 9x does this if the bitmap has a depth that doesn't
237 match the screen depth, Windows NT doesn't */
238 dibExpected = TRUE;
239 expectedDepth = origBitmap.bmBitsPixel;
242 ok((!(dibExpected ^ copy_is_dib)
243 && (copyBitmap.bmWidth == expectedWidth)
244 && (copyBitmap.bmHeight == expectedHeight)
245 && (copyBitmap.bmBitsPixel == expectedDepth)),
246 "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
247 orig_is_dib ? "DIB" : "DDB", origBitmap.bmWidth, origBitmap.bmHeight, origBitmap.bmBitsPixel,
248 copyWidth, copyHeight, flags,
249 dibExpected ? "DIB" : "DDB", expectedWidth, expectedHeight, expectedDepth,
250 copy_is_dib ? "DIB" : "DDB", copyBitmap.bmWidth, copyBitmap.bmHeight, copyBitmap.bmBitsPixel);
252 DeleteObject(copy);
256 static void test_CopyImage_Bitmap(int depth)
258 HBITMAP ddb, dib;
259 HDC screenDC;
260 BITMAPINFO * info;
261 VOID * bits;
262 int screen_depth;
263 unsigned int i;
265 /* Create a device-independent bitmap (DIB) */
266 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
267 info->bmiHeader.biSize = sizeof(info->bmiHeader);
268 info->bmiHeader.biWidth = 2;
269 info->bmiHeader.biHeight = 2;
270 info->bmiHeader.biPlanes = 1;
271 info->bmiHeader.biBitCount = depth;
272 info->bmiHeader.biCompression = BI_RGB;
274 for (i=0; i < 256; i++)
276 info->bmiColors[i].rgbRed = i;
277 info->bmiColors[i].rgbGreen = i;
278 info->bmiColors[i].rgbBlue = 255 - i;
279 info->bmiColors[i].rgbReserved = 0;
282 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
284 /* Create a device-dependent bitmap (DDB) */
285 screenDC = GetDC(NULL);
286 screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
287 if (depth == 1 || depth == screen_depth)
289 ddb = CreateBitmap(2, 2, 1, depth, NULL);
291 else
293 ddb = NULL;
295 ReleaseDC(NULL, screenDC);
297 if (ddb != NULL)
299 test_CopyImage_Check(ddb, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE);
300 test_CopyImage_Check(ddb, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE);
301 test_CopyImage_Check(ddb, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE);
302 test_CopyImage_Check(ddb, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE);
304 test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
305 test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
306 test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
307 test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
309 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
310 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
311 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
312 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
314 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
315 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
316 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
317 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
318 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
320 DeleteObject(ddb);
323 if (depth != 1)
325 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
326 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
327 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
328 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
331 test_CopyImage_Check(dib, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
332 test_CopyImage_Check(dib, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
333 test_CopyImage_Check(dib, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
334 test_CopyImage_Check(dib, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
336 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
337 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
338 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
339 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
341 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
342 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
343 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
344 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
345 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
347 DeleteObject(dib);
349 if (depth == 1)
351 /* Special case: A monochrome DIB is converted to a monochrome DDB if
352 the colors in the color table are black and white.
354 Skip this test on Windows 95, it always creates a monochrome DDB
355 in this case */
357 if (!(GetVersion() & 0x80000000))
359 info->bmiHeader.biBitCount = 1;
360 info->bmiColors[0].rgbRed = 0xFF;
361 info->bmiColors[0].rgbGreen = 0;
362 info->bmiColors[0].rgbBlue = 0;
363 info->bmiColors[1].rgbRed = 0;
364 info->bmiColors[1].rgbGreen = 0xFF;
365 info->bmiColors[1].rgbBlue = 0;
367 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
368 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
369 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
370 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
371 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
372 DeleteObject(dib);
374 info->bmiHeader.biBitCount = 1;
375 info->bmiColors[0].rgbRed = 0;
376 info->bmiColors[0].rgbGreen = 0;
377 info->bmiColors[0].rgbBlue = 0;
378 info->bmiColors[1].rgbRed = 0xFF;
379 info->bmiColors[1].rgbGreen = 0xFF;
380 info->bmiColors[1].rgbBlue = 0xFF;
382 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
383 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
384 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
385 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
386 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
387 DeleteObject(dib);
389 info->bmiHeader.biBitCount = 1;
390 info->bmiColors[0].rgbRed = 0xFF;
391 info->bmiColors[0].rgbGreen = 0xFF;
392 info->bmiColors[0].rgbBlue = 0xFF;
393 info->bmiColors[1].rgbRed = 0;
394 info->bmiColors[1].rgbGreen = 0;
395 info->bmiColors[1].rgbBlue = 0;
397 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
398 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
399 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
400 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
401 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
402 DeleteObject(dib);
406 HeapFree(GetProcessHeap(), 0, info);
409 static void test_initial_cursor(void)
411 HCURSOR cursor, cursor2;
412 DWORD error;
414 cursor = GetCursor();
416 /* Check what handle GetCursor() returns if a cursor is not set yet. */
417 SetLastError(0xdeadbeef);
418 cursor2 = LoadCursor(NULL, IDC_WAIT);
419 todo_wine {
420 ok(cursor == cursor2, "cursor (%p) is not IDC_WAIT (%p).\n", cursor, cursor2);
422 error = GetLastError();
423 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
426 static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_bpp, int line)
428 ICONINFO info;
429 DWORD ret;
430 BITMAP bmMask, bmColor;
432 ret = GetIconInfo(hIcon, &info);
433 ok_(__FILE__, line)(ret, "GetIconInfo failed\n");
435 /* CreateIcon under XP causes info.fIcon to be 0 */
436 ok_(__FILE__, line)(info.xHotspot == exp_cx/2, "info.xHotspot = %u\n", info.xHotspot);
437 ok_(__FILE__, line)(info.yHotspot == exp_cy/2, "info.yHotspot = %u\n", info.yHotspot);
438 ok_(__FILE__, line)(info.hbmMask != 0, "info.hbmMask is NULL\n");
440 ret = GetObject(info.hbmMask, sizeof(bmMask), &bmMask);
441 ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %u\n", ret);
443 if (exp_bpp == 1)
444 ok_(__FILE__, line)(info.hbmColor == 0, "info.hbmColor should be NULL\n");
446 if (info.hbmColor)
448 HDC hdc;
449 UINT display_bpp;
451 hdc = GetDC(0);
452 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
453 ReleaseDC(0, hdc);
455 ret = GetObject(info.hbmColor, sizeof(bmColor), &bmColor);
456 ok_(__FILE__, line)(ret == sizeof(bmColor), "GetObject(info.hbmColor) failed, ret %u\n", ret);
458 ok_(__FILE__, line)(bmColor.bmBitsPixel == display_bpp /* XP */ ||
459 bmColor.bmBitsPixel == exp_bpp /* Win98 */,
460 "bmColor.bmBitsPixel = %d\n", bmColor.bmBitsPixel);
461 ok_(__FILE__, line)(bmColor.bmWidth == exp_cx, "bmColor.bmWidth = %d\n", bmColor.bmWidth);
462 ok_(__FILE__, line)(bmColor.bmHeight == exp_cy, "bmColor.bmHeight = %d\n", bmColor.bmHeight);
464 ok_(__FILE__, line)(bmMask.bmBitsPixel == 1, "bmMask.bmBitsPixel = %d\n", bmMask.bmBitsPixel);
465 ok_(__FILE__, line)(bmMask.bmWidth == exp_cx, "bmMask.bmWidth = %d\n", bmMask.bmWidth);
466 ok_(__FILE__, line)(bmMask.bmHeight == exp_cy, "bmMask.bmHeight = %d\n", bmMask.bmHeight);
468 else
470 ok_(__FILE__, line)(bmMask.bmBitsPixel == 1, "bmMask.bmBitsPixel = %d\n", bmMask.bmBitsPixel);
471 ok_(__FILE__, line)(bmMask.bmWidth == exp_cx, "bmMask.bmWidth = %d\n", bmMask.bmWidth);
472 ok_(__FILE__, line)(bmMask.bmHeight == exp_cy * 2, "bmMask.bmHeight = %d\n", bmMask.bmHeight);
476 #define test_icon_info(a,b,c,d) test_icon_info_dbg((a),(b),(c),(d),__LINE__)
478 static void test_CreateIcon(void)
480 static const BYTE bmp_bits[1024];
481 HICON hIcon;
482 HBITMAP hbmMask, hbmColor;
483 ICONINFO info;
484 HDC hdc;
485 UINT display_bpp;
487 hdc = GetDC(0);
488 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
489 ReleaseDC(0, hdc);
491 /* these crash under XP
492 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
493 hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits);
496 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, bmp_bits);
497 ok(hIcon != 0, "CreateIcon failed\n");
498 test_icon_info(hIcon, 16, 16, 1);
499 DestroyIcon(hIcon);
501 hIcon = CreateIcon(0, 16, 16, 1, display_bpp, bmp_bits, bmp_bits);
502 ok(hIcon != 0, "CreateIcon failed\n");
503 test_icon_info(hIcon, 16, 16, display_bpp);
504 DestroyIcon(hIcon);
506 hbmMask = CreateBitmap(16, 16, 1, 1, bmp_bits);
507 ok(hbmMask != 0, "CreateBitmap failed\n");
508 hbmColor = CreateBitmap(16, 16, 1, display_bpp, bmp_bits);
509 ok(hbmColor != 0, "CreateBitmap failed\n");
511 info.fIcon = TRUE;
512 info.xHotspot = 8;
513 info.yHotspot = 8;
514 info.hbmMask = 0;
515 info.hbmColor = 0;
516 SetLastError(0xdeadbeaf);
517 hIcon = CreateIconIndirect(&info);
518 ok(!hIcon, "CreateIconIndirect should fail\n");
519 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
521 info.fIcon = TRUE;
522 info.xHotspot = 8;
523 info.yHotspot = 8;
524 info.hbmMask = 0;
525 info.hbmColor = hbmColor;
526 SetLastError(0xdeadbeaf);
527 hIcon = CreateIconIndirect(&info);
528 ok(!hIcon, "CreateIconIndirect should fail\n");
529 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
531 info.fIcon = TRUE;
532 info.xHotspot = 8;
533 info.yHotspot = 8;
534 info.hbmMask = hbmMask;
535 info.hbmColor = hbmColor;
536 hIcon = CreateIconIndirect(&info);
537 ok(hIcon != 0, "CreateIconIndirect failed\n");
538 test_icon_info(hIcon, 16, 16, display_bpp);
539 DestroyIcon(hIcon);
541 DeleteObject(hbmMask);
542 DeleteObject(hbmColor);
544 hbmMask = CreateBitmap(16, 32, 1, 1, bmp_bits);
545 ok(hbmMask != 0, "CreateBitmap failed\n");
547 info.fIcon = TRUE;
548 info.xHotspot = 8;
549 info.yHotspot = 8;
550 info.hbmMask = hbmMask;
551 info.hbmColor = 0;
552 SetLastError(0xdeadbeaf);
553 hIcon = CreateIconIndirect(&info);
554 ok(hIcon != 0, "CreateIconIndirect failed\n");
555 test_icon_info(hIcon, 16, 16, 1);
556 DestroyIcon(hIcon);
558 DeleteObject(hbmMask);
559 DeleteObject(hbmColor);
562 static void test_DestroyCursor(void)
564 static const BYTE bmp_bits[4096];
565 ICONINFO cursorInfo;
566 HCURSOR cursor, cursor2;
567 BOOL ret;
568 DWORD error;
569 UINT display_bpp;
570 HDC hdc;
572 hdc = GetDC(0);
573 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
574 ReleaseDC(0, hdc);
576 cursorInfo.fIcon = FALSE;
577 cursorInfo.xHotspot = 0;
578 cursorInfo.yHotspot = 0;
579 cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
580 cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
582 cursor = CreateIconIndirect(&cursorInfo);
583 ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
584 if(!cursor) {
585 return;
587 SetCursor(cursor);
589 SetLastError(0xdeadbeef);
590 ret = DestroyCursor(cursor);
591 ok(!ret, "DestroyCursor on the active cursor succeeded\n");
592 error = GetLastError();
593 ok(error == 0xdeadbeef, "Last error: %u\n", error);
595 cursor2 = GetCursor();
596 ok(cursor2 == cursor, "Active was set to %p when trying to destroy it\n", cursor2);
598 SetCursor(NULL);
600 /* Trying to destroy the cursor properly fails now with
601 * ERROR_INVALID_CURSOR_HANDLE. This happens because we called
602 * DestroyCursor() 2+ times after calling SetCursor(). The calls to
603 * GetCursor() and SetCursor(NULL) in between make no difference. */
604 ret = DestroyCursor(cursor);
605 todo_wine {
606 ok(!ret, "DestroyCursor succeeded.\n");
607 error = GetLastError();
608 ok(error == ERROR_INVALID_CURSOR_HANDLE, "Last error: 0x%08x\n", error);
611 DeleteObject(cursorInfo.hbmMask);
612 DeleteObject(cursorInfo.hbmColor);
614 /* Try testing DestroyCursor() now using LoadCursor() cursors. */
615 cursor = LoadCursor(NULL, IDC_ARROW);
617 SetLastError(0xdeadbeef);
618 ret = DestroyCursor(cursor);
619 ok(ret, "DestroyCursor on the active cursor failed.\n");
620 error = GetLastError();
621 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
623 /* Try setting the cursor to a destroyed OEM cursor. */
624 SetLastError(0xdeadbeef);
625 SetCursor(cursor);
626 error = GetLastError();
627 todo_wine {
628 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
631 /* Check if LoadCursor() returns the same handle with the same icon. */
632 cursor2 = LoadCursor(NULL, IDC_ARROW);
633 ok(cursor2 == cursor, "cursor == %p, cursor2 == %p\n", cursor, cursor2);
635 /* Check if LoadCursor() returns the same handle with a different icon. */
636 cursor2 = LoadCursor(NULL, IDC_WAIT);
637 ok(cursor2 != cursor, "cursor == %p, cursor2 == %p\n", cursor, cursor2);
640 START_TEST(cursoricon)
642 test_argc = winetest_get_mainargs(&test_argv);
644 if (test_argc >= 3)
646 /* Child process. */
647 sscanf (test_argv[2], "%x", (unsigned int *) &parent);
649 ok(parent != NULL, "Parent not found.\n");
650 if (parent == NULL)
651 ExitProcess(1);
653 do_child();
654 return;
657 test_CopyImage_Bitmap(1);
658 test_CopyImage_Bitmap(4);
659 test_CopyImage_Bitmap(8);
660 test_CopyImage_Bitmap(16);
661 test_CopyImage_Bitmap(24);
662 test_CopyImage_Bitmap(32);
663 test_initial_cursor();
664 test_CreateIcon();
665 test_DestroyCursor();
666 do_parent();
667 test_child_process();
668 finish_child_process();