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
28 #include "wine/test.h"
35 static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight,
36 INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected)
44 copy = (HBITMAP) CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
45 ok(copy != NULL, "CopyImage() failed\n");
48 GetObject(bitmap, sizeof(origBitmap), &origBitmap);
49 GetObject(copy, sizeof(copyBitmap), ©Bitmap);
50 orig_is_dib = (origBitmap.bmBits != NULL);
51 copy_is_dib = (copyBitmap.bmBits != NULL);
53 if (copy_is_dib && dibExpected
54 && copyBitmap.bmBitsPixel == 24
55 && (expectedDepth == 16 || expectedDepth == 32))
57 /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
58 if (GetVersion() & 0x80000000)
64 if (copy_is_dib && !dibExpected && !(flags & LR_CREATEDIBSECTION))
66 /* It's not forbidden to create a DIB section if the flag
67 LR_CREATEDIBSECTION is absent.
68 Windows 9x does this if the bitmap has a depth that doesn't
69 match the screen depth, Windows NT doesn't */
71 expectedDepth = origBitmap.bmBitsPixel;
74 ok((!(dibExpected ^ copy_is_dib)
75 && (copyBitmap.bmWidth == expectedWidth)
76 && (copyBitmap.bmHeight == expectedHeight)
77 && (copyBitmap.bmBitsPixel == expectedDepth)),
78 "CopyImage ((%s, %dx%d, %u bpp), %d, %d, %#x): Expected (%s, %dx%d, %u bpp), got (%s, %dx%d, %u bpp)\n",
79 orig_is_dib ? "DIB" : "DDB", origBitmap.bmWidth, origBitmap.bmHeight, origBitmap.bmBitsPixel,
80 copyWidth, copyHeight, flags,
81 dibExpected ? "DIB" : "DDB", expectedWidth, expectedHeight, expectedDepth,
82 copy_is_dib ? "DIB" : "DDB", copyBitmap.bmWidth, copyBitmap.bmHeight, copyBitmap.bmBitsPixel);
88 static void test_CopyImage_Bitmap(int depth)
97 /* Create a device-independent bitmap (DIB) */
98 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
99 info->bmiHeader.biSize = sizeof(info->bmiHeader);
100 info->bmiHeader.biWidth = 2;
101 info->bmiHeader.biHeight = 2;
102 info->bmiHeader.biPlanes = 1;
103 info->bmiHeader.biBitCount = depth;
104 info->bmiHeader.biCompression = BI_RGB;
106 for (i=0; i < 256; i++)
108 info->bmiColors[i].rgbRed = i;
109 info->bmiColors[i].rgbGreen = i;
110 info->bmiColors[i].rgbBlue = 255 - i;
111 info->bmiColors[i].rgbReserved = 0;
114 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
116 /* Create a device-dependent bitmap (DDB) */
117 screenDC = GetDC(NULL);
118 screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
119 if (depth == 1 || depth == screen_depth)
121 ddb = CreateBitmap(2, 2, 1, depth, NULL);
127 ReleaseDC(NULL, screenDC);
131 test_CopyImage_Check(ddb, 0, 0, 0, 2, 2, depth == 1 ? 1 : screen_depth, FALSE);
132 test_CopyImage_Check(ddb, 0, 0, 5, 2, 5, depth == 1 ? 1 : screen_depth, FALSE);
133 test_CopyImage_Check(ddb, 0, 5, 0, 5, 2, depth == 1 ? 1 : screen_depth, FALSE);
134 test_CopyImage_Check(ddb, 0, 5, 5, 5, 5, depth == 1 ? 1 : screen_depth, FALSE);
136 test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
137 test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
138 test_CopyImage_Check(ddb, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
139 test_CopyImage_Check(ddb, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
141 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
142 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
143 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
144 test_CopyImage_Check(ddb, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
146 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
147 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
148 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
149 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
150 test_CopyImage_Check(ddb, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
157 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
158 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
159 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
160 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
163 test_CopyImage_Check(dib, LR_MONOCHROME, 0, 0, 2, 2, 1, FALSE);
164 test_CopyImage_Check(dib, LR_MONOCHROME, 5, 0, 5, 2, 1, FALSE);
165 test_CopyImage_Check(dib, LR_MONOCHROME, 0, 5, 2, 5, 1, FALSE);
166 test_CopyImage_Check(dib, LR_MONOCHROME, 5, 5, 5, 5, 1, FALSE);
168 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
169 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
170 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
171 test_CopyImage_Check(dib, LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
173 /* LR_MONOCHROME is ignored if LR_CREATEDIBSECTION is present */
174 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 0, 2, 2, depth, TRUE);
175 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 0, 5, 2, depth, TRUE);
176 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 0, 5, 2, 5, depth, TRUE);
177 test_CopyImage_Check(dib, LR_MONOCHROME | LR_CREATEDIBSECTION, 5, 5, 5, 5, depth, TRUE);
183 /* Special case: A monochrome DIB is converted to a monochrome DDB if
184 the colors in the color table are black and white.
186 Skip this test on Windows 95, it always creates a monochrome DDB
189 if (!(GetVersion() & 0x80000000))
191 info->bmiHeader.biBitCount = 1;
192 info->bmiColors[0].rgbRed = 0xFF;
193 info->bmiColors[0].rgbGreen = 0;
194 info->bmiColors[0].rgbBlue = 0;
195 info->bmiColors[1].rgbRed = 0;
196 info->bmiColors[1].rgbGreen = 0xFF;
197 info->bmiColors[1].rgbBlue = 0;
199 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
200 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, screen_depth, FALSE);
201 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, screen_depth, FALSE);
202 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, screen_depth, FALSE);
203 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, screen_depth, FALSE);
206 info->bmiHeader.biBitCount = 1;
207 info->bmiColors[0].rgbRed = 0;
208 info->bmiColors[0].rgbGreen = 0;
209 info->bmiColors[0].rgbBlue = 0;
210 info->bmiColors[1].rgbRed = 0xFF;
211 info->bmiColors[1].rgbGreen = 0xFF;
212 info->bmiColors[1].rgbBlue = 0xFF;
214 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
215 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
216 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
217 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
218 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
221 info->bmiHeader.biBitCount = 1;
222 info->bmiColors[0].rgbRed = 0xFF;
223 info->bmiColors[0].rgbGreen = 0xFF;
224 info->bmiColors[0].rgbBlue = 0xFF;
225 info->bmiColors[1].rgbRed = 0;
226 info->bmiColors[1].rgbGreen = 0;
227 info->bmiColors[1].rgbBlue = 0;
229 dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
230 test_CopyImage_Check(dib, 0, 0, 0, 2, 2, 1, FALSE);
231 test_CopyImage_Check(dib, 0, 5, 0, 5, 2, 1, FALSE);
232 test_CopyImage_Check(dib, 0, 0, 5, 2, 5, 1, FALSE);
233 test_CopyImage_Check(dib, 0, 5, 5, 5, 5, 1, FALSE);
238 HeapFree(GetProcessHeap(), 0, info);
241 static void test_initial_cursor(void)
243 HCURSOR cursor, cursor2;
246 cursor = GetCursor();
248 /* Check what handle GetCursor() returns if a cursor is not set yet. */
249 SetLastError(0xdeadbeef);
250 cursor2 = LoadCursor(NULL, IDC_WAIT);
252 ok(cursor == cursor2, "cursor (%p) is not IDC_WAIT (%p).\n", cursor, cursor2);
254 error = GetLastError();
255 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
258 static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_bpp, int line)
262 BITMAP bmMask, bmColor;
264 ret = GetIconInfo(hIcon, &info);
265 ok_(__FILE__, line)(ret, "GetIconInfo failed\n");
267 /* CreateIcon under XP causes info.fIcon to be 0 */
268 ok_(__FILE__, line)(info.xHotspot == exp_cx/2, "info.xHotspot = %u\n", info.xHotspot);
269 ok_(__FILE__, line)(info.yHotspot == exp_cy/2, "info.yHotspot = %u\n", info.yHotspot);
270 ok_(__FILE__, line)(info.hbmMask != 0, "info.hbmMask is NULL\n");
272 ret = GetObject(info.hbmMask, sizeof(bmMask), &bmMask);
273 ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %u\n", ret);
276 ok_(__FILE__, line)(info.hbmColor == 0, "info.hbmColor should be NULL\n");
284 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
287 ret = GetObject(info.hbmColor, sizeof(bmColor), &bmColor);
288 ok_(__FILE__, line)(ret == sizeof(bmColor), "GetObject(info.hbmColor) failed, ret %u\n", ret);
290 ok_(__FILE__, line)(bmColor.bmBitsPixel == display_bpp /* XP */ ||
291 bmColor.bmBitsPixel == exp_bpp /* Win98 */,
292 "bmColor.bmBitsPixel = %d\n", bmColor.bmBitsPixel);
293 ok_(__FILE__, line)(bmColor.bmWidth == exp_cx, "bmColor.bmWidth = %d\n", bmColor.bmWidth);
294 ok_(__FILE__, line)(bmColor.bmHeight == exp_cy, "bmColor.bmHeight = %d\n", bmColor.bmHeight);
296 ok_(__FILE__, line)(bmMask.bmBitsPixel == 1, "bmMask.bmBitsPixel = %d\n", bmMask.bmBitsPixel);
297 ok_(__FILE__, line)(bmMask.bmWidth == exp_cx, "bmMask.bmWidth = %d\n", bmMask.bmWidth);
298 ok_(__FILE__, line)(bmMask.bmHeight == exp_cy, "bmMask.bmHeight = %d\n", bmMask.bmHeight);
302 ok_(__FILE__, line)(bmMask.bmBitsPixel == 1, "bmMask.bmBitsPixel = %d\n", bmMask.bmBitsPixel);
303 ok_(__FILE__, line)(bmMask.bmWidth == exp_cx, "bmMask.bmWidth = %d\n", bmMask.bmWidth);
304 ok_(__FILE__, line)(bmMask.bmHeight == exp_cy * 2, "bmMask.bmHeight = %d\n", bmMask.bmHeight);
308 #define test_icon_info(a,b,c,d) test_icon_info_dbg((a),(b),(c),(d),__LINE__)
310 static void test_CreateIcon(void)
312 static const BYTE bmp_bits[1024];
314 HBITMAP hbmMask, hbmColor;
320 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
323 /* these crash under XP
324 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL);
325 hIcon = CreateIcon(0, 16, 16, 1, 1, NULL, bmp_bits);
328 hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, bmp_bits);
329 ok(hIcon != 0, "CreateIcon failed\n");
330 test_icon_info(hIcon, 16, 16, 1);
333 hIcon = CreateIcon(0, 16, 16, 1, display_bpp, bmp_bits, bmp_bits);
334 ok(hIcon != 0, "CreateIcon failed\n");
335 test_icon_info(hIcon, 16, 16, display_bpp);
338 hbmMask = CreateBitmap(16, 16, 1, 1, bmp_bits);
339 ok(hbmMask != 0, "CreateBitmap failed\n");
340 hbmColor = CreateBitmap(16, 16, 1, display_bpp, bmp_bits);
341 ok(hbmColor != 0, "CreateBitmap failed\n");
348 SetLastError(0xdeadbeaf);
349 hIcon = CreateIconIndirect(&info);
350 ok(!hIcon, "CreateIconIndirect should fail\n");
351 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
357 info.hbmColor = hbmColor;
358 SetLastError(0xdeadbeaf);
359 hIcon = CreateIconIndirect(&info);
360 ok(!hIcon, "CreateIconIndirect should fail\n");
361 ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
366 info.hbmMask = hbmMask;
367 info.hbmColor = hbmColor;
368 hIcon = CreateIconIndirect(&info);
369 ok(hIcon != 0, "CreateIconIndirect failed\n");
370 test_icon_info(hIcon, 16, 16, display_bpp);
373 DeleteObject(hbmMask);
374 DeleteObject(hbmColor);
376 hbmMask = CreateBitmap(16, 32, 1, 1, bmp_bits);
377 ok(hbmMask != 0, "CreateBitmap failed\n");
382 info.hbmMask = hbmMask;
384 SetLastError(0xdeadbeaf);
385 hIcon = CreateIconIndirect(&info);
386 ok(hIcon != 0, "CreateIconIndirect failed\n");
387 test_icon_info(hIcon, 16, 16, 1);
390 DeleteObject(hbmMask);
391 DeleteObject(hbmColor);
394 static void test_DestroyCursor(void)
396 static const BYTE bmp_bits[4096];
398 HCURSOR cursor, cursor2;
405 display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
408 cursorInfo.fIcon = FALSE;
409 cursorInfo.xHotspot = 0;
410 cursorInfo.yHotspot = 0;
411 cursorInfo.hbmMask = CreateBitmap(32, 32, 1, 1, bmp_bits);
412 cursorInfo.hbmColor = CreateBitmap(32, 32, 1, display_bpp, bmp_bits);
414 cursor = CreateIconIndirect(&cursorInfo);
415 ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
421 SetLastError(0xdeadbeef);
422 ret = DestroyCursor(cursor);
423 ok(!ret, "DestroyCursor on the active cursor succeeded\n");
424 error = GetLastError();
425 ok(error == 0xdeadbeef, "Last error: %u\n", error);
427 cursor2 = GetCursor();
428 ok(cursor2 == cursor, "Active was set to %p when trying to destroy it\n", cursor2);
432 /* Trying to destroy the cursor properly fails now with
433 * ERROR_INVALID_CURSOR_HANDLE. This happens because we called
434 * DestroyCursor() 2+ times after calling SetCursor(). The calls to
435 * GetCursor() and SetCursor(NULL) in between make no difference. */
436 ret = DestroyCursor(cursor);
438 ok(!ret, "DestroyCursor succeeded.\n");
439 error = GetLastError();
440 ok(error == ERROR_INVALID_CURSOR_HANDLE, "Last error: 0x%08x\n", error);
443 DeleteObject(cursorInfo.hbmMask);
444 DeleteObject(cursorInfo.hbmColor);
446 /* Try testing DestroyCursor() now using LoadCursor() cursors. */
447 cursor = LoadCursor(NULL, IDC_ARROW);
449 SetLastError(0xdeadbeef);
450 ret = DestroyCursor(cursor);
451 ok(ret, "DestroyCursor on the active cursor failed.\n");
452 error = GetLastError();
453 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
455 /* Try setting the cursor to a destroyed OEM cursor. */
456 SetLastError(0xdeadbeef);
458 error = GetLastError();
460 ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
463 /* Check if LoadCursor() returns the same handle with the same icon. */
464 cursor2 = LoadCursor(NULL, IDC_ARROW);
465 ok(cursor2 == cursor, "cursor == %p, cursor2 == %p\n", cursor, cursor2);
467 /* Check if LoadCursor() returns the same handle with a different icon. */
468 cursor2 = LoadCursor(NULL, IDC_WAIT);
469 ok(cursor2 != cursor, "cursor == %p, cursor2 == %p\n", cursor, cursor2);
472 START_TEST(cursoricon)
474 test_CopyImage_Bitmap(1);
475 test_CopyImage_Bitmap(4);
476 test_CopyImage_Bitmap(8);
477 test_CopyImage_Bitmap(16);
478 test_CopyImage_Bitmap(24);
479 test_CopyImage_Bitmap(32);
480 test_initial_cursor();
482 test_DestroyCursor();