urlmon: Don't create stgmed_obj for binding to object.
[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 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 static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT copyHeight,
36                                   INT expectedWidth, INT expectedHeight, WORD expectedDepth, BOOL dibExpected)
37 {
38     HBITMAP copy;
39     BITMAP origBitmap;
40     BITMAP copyBitmap;
41     BOOL orig_is_dib;
42     BOOL copy_is_dib;
43
44     copy = (HBITMAP) CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags);
45     ok(copy != NULL, "CopyImage() failed\n");
46     if (copy != NULL)
47     {
48         GetObject(bitmap, sizeof(origBitmap), &origBitmap);
49         GetObject(copy, sizeof(copyBitmap), &copyBitmap);
50         orig_is_dib = (origBitmap.bmBits != NULL);
51         copy_is_dib = (copyBitmap.bmBits != NULL);
52
53         if (copy_is_dib && dibExpected
54             && copyBitmap.bmBitsPixel == 24
55             && (expectedDepth == 16 || expectedDepth == 32))
56         {
57             /* Windows 95 doesn't create DIBs with a depth of 16 or 32 bit */
58             if (GetVersion() & 0x80000000)
59             {
60                 expectedDepth = 24;
61             }
62         }
63
64         if (copy_is_dib && !dibExpected && !(flags & LR_CREATEDIBSECTION))
65         {
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 */
70             dibExpected = TRUE;
71             expectedDepth = origBitmap.bmBitsPixel;
72         }
73
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);
83
84         DeleteObject(copy);
85     }
86 }
87
88 static void test_CopyImage_Bitmap(int depth)
89 {
90     HBITMAP ddb, dib;
91     HDC screenDC;
92     BITMAPINFO * info;
93     VOID * bits;
94     int screen_depth;
95     unsigned int i;
96
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;
105
106     for (i=0; i < 256; i++)
107     {
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;
112     }
113
114     dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
115
116     /* Create a device-dependent bitmap (DDB) */
117     screenDC = GetDC(NULL);
118     screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
119     if (depth == 1 || depth == screen_depth)
120     {
121         ddb = CreateBitmap(2, 2, 1, depth, NULL);
122     }
123     else
124     {
125         ddb = NULL;
126     }
127     ReleaseDC(NULL, screenDC);
128
129     if (ddb != NULL)
130     {
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);
135
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);
140
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);
145
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);
151
152         DeleteObject(ddb);
153     }
154
155     if (depth != 1)
156     {
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);
161     }
162
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);
167
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);
172
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);
178
179     DeleteObject(dib);
180
181     if (depth == 1)
182     {
183         /* Special case: A monochrome DIB is converted to a monochrome DDB if
184            the colors in the color table are black and white.
185
186            Skip this test on Windows 95, it always creates a monochrome DDB
187            in this case */
188
189         if (!(GetVersion() & 0x80000000))
190         {
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;
198
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);
204             DeleteObject(dib);
205
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;
213
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);
219             DeleteObject(dib);
220
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;
228
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);
234             DeleteObject(dib);
235         }
236     }
237
238     HeapFree(GetProcessHeap(), 0, info);
239 }
240
241 static void test_initial_cursor(void)
242 {
243     HCURSOR cursor, cursor2;
244     DWORD error;
245
246     cursor = GetCursor();
247
248     /* Check what handle GetCursor() returns if a cursor is not set yet. */
249     SetLastError(0xdeadbeef);
250     cursor2 = LoadCursor(NULL, IDC_WAIT);
251     todo_wine {
252         ok(cursor == cursor2, "cursor (%p) is not IDC_WAIT (%p).\n", cursor, cursor2);
253     }
254     error = GetLastError();
255     ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
256 }
257
258 static void test_icon_info_dbg(HICON hIcon, UINT exp_cx, UINT exp_cy, UINT exp_bpp, int line)
259 {
260     ICONINFO info;
261     DWORD ret;
262     BITMAP bmMask, bmColor;
263
264     ret = GetIconInfo(hIcon, &info);
265     ok_(__FILE__, line)(ret, "GetIconInfo failed\n");
266
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");
271
272     ret = GetObject(info.hbmMask, sizeof(bmMask), &bmMask);
273     ok_(__FILE__, line)(ret == sizeof(bmMask), "GetObject(info.hbmMask) failed, ret %u\n", ret);
274
275     if (exp_bpp == 1)
276         ok_(__FILE__, line)(info.hbmColor == 0, "info.hbmColor should be NULL\n");
277
278     if (info.hbmColor)
279     {
280         HDC hdc;
281         UINT display_bpp;
282
283         hdc = GetDC(0);
284         display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
285         ReleaseDC(0, hdc);
286
287         ret = GetObject(info.hbmColor, sizeof(bmColor), &bmColor);
288         ok_(__FILE__, line)(ret == sizeof(bmColor), "GetObject(info.hbmColor) failed, ret %u\n", ret);
289
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);
295
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);
299     }
300     else
301     {
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);
305     }
306 }
307
308 #define test_icon_info(a,b,c,d) test_icon_info_dbg((a),(b),(c),(d),__LINE__)
309
310 static void test_CreateIcon(void)
311 {
312     static const BYTE bmp_bits[1024];
313     HICON hIcon;
314     HBITMAP hbmMask, hbmColor;
315     ICONINFO info;
316     HDC hdc;
317     UINT display_bpp;
318
319     hdc = GetDC(0);
320     display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
321     ReleaseDC(0, hdc);
322
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);
326     */
327
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);
331     DestroyIcon(hIcon);
332
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);
336     DestroyIcon(hIcon);
337
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");
342
343     info.fIcon = TRUE;
344     info.xHotspot = 8;
345     info.yHotspot = 8;
346     info.hbmMask = 0;
347     info.hbmColor = 0;
348     SetLastError(0xdeadbeaf);
349     hIcon = CreateIconIndirect(&info);
350     ok(!hIcon, "CreateIconIndirect should fail\n");
351     ok(GetLastError() == 0xdeadbeaf, "wrong error %u\n", GetLastError());
352
353     info.fIcon = TRUE;
354     info.xHotspot = 8;
355     info.yHotspot = 8;
356     info.hbmMask = 0;
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());
362
363     info.fIcon = TRUE;
364     info.xHotspot = 8;
365     info.yHotspot = 8;
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);
371     DestroyIcon(hIcon);
372
373     DeleteObject(hbmMask);
374     DeleteObject(hbmColor);
375
376     hbmMask = CreateBitmap(16, 32, 1, 1, bmp_bits);
377     ok(hbmMask != 0, "CreateBitmap failed\n");
378
379     info.fIcon = TRUE;
380     info.xHotspot = 8;
381     info.yHotspot = 8;
382     info.hbmMask = hbmMask;
383     info.hbmColor = 0;
384     SetLastError(0xdeadbeaf);
385     hIcon = CreateIconIndirect(&info);
386     ok(hIcon != 0, "CreateIconIndirect failed\n");
387     test_icon_info(hIcon, 16, 16, 1);
388     DestroyIcon(hIcon);
389
390     DeleteObject(hbmMask);
391     DeleteObject(hbmColor);
392 }
393
394 static void test_DestroyCursor(void)
395 {
396     static const BYTE bmp_bits[4096];
397     ICONINFO cursorInfo;
398     HCURSOR cursor, cursor2;
399     BOOL ret;
400     DWORD error;
401     UINT display_bpp;
402     HDC hdc;
403
404     hdc = GetDC(0);
405     display_bpp = GetDeviceCaps(hdc, BITSPIXEL);
406     ReleaseDC(0, hdc);
407
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);
413
414     cursor = CreateIconIndirect(&cursorInfo);
415     ok(cursor != NULL, "CreateIconIndirect returned %p\n", cursor);
416     if(!cursor) {
417         return;
418     }
419     SetCursor(cursor);
420
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);
426
427     cursor2 = GetCursor();
428     ok(cursor2 == cursor, "Active was set to %p when trying to destroy it\n", cursor2);
429
430     SetCursor(NULL);
431
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);
437     todo_wine {
438         ok(!ret, "DestroyCursor succeeded.\n");
439         error = GetLastError();
440         ok(error == ERROR_INVALID_CURSOR_HANDLE, "Last error: 0x%08x\n", error);
441     }
442
443     DeleteObject(cursorInfo.hbmMask);
444     DeleteObject(cursorInfo.hbmColor);
445
446     /* Try testing DestroyCursor() now using LoadCursor() cursors. */
447     cursor = LoadCursor(NULL, IDC_ARROW);
448
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);
454
455     /* Try setting the cursor to a destroyed OEM cursor. */
456     SetLastError(0xdeadbeef);
457     SetCursor(cursor);
458     error = GetLastError();
459     todo_wine {
460         ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
461     }
462
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);
466
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);
470 }
471
472 START_TEST(cursoricon)
473 {
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();
481     test_CreateIcon();
482     test_DestroyCursor();
483 }