Release 1.5.29.
[wine] / dlls / comctl32 / tests / imagelist.c
1 /*
2  * Unit test suite for imagelist control.
3  *
4  * Copyright 2004 Michael Stefaniuc
5  * Copyright 2002 Mike McCormack for CodeWeavers
6  * Copyright 2007 Dmitry Timoshkov
7  * Copyright 2009 Owen Rudge for CodeWeavers
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #define COBJMACROS
25 #define CONST_VTABLE
26
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <assert.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "objbase.h"
36 #include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */
37 #include "initguid.h"
38 #include "commoncontrols.h"
39 #include "shellapi.h"
40
41 #include "wine/test.h"
42 #include "v6util.h"
43
44 #undef VISIBLE
45
46 #ifdef VISIBLE
47 #define WAIT Sleep (1000)
48 #define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW)
49 #else
50 #define WAIT
51 #define REDRAW(hwnd)
52 #endif
53
54 #define IMAGELIST_MAGIC (('L' << 8) | 'I')
55
56 #include "pshpack2.h"
57 /* Header used by ImageList_Read() and ImageList_Write() */
58 typedef struct _ILHEAD
59 {
60     USHORT      usMagic;
61     USHORT      usVersion;
62     WORD        cCurImage;
63     WORD        cMaxImage;
64     WORD        cGrow;
65     WORD        cx;
66     WORD        cy;
67     COLORREF    bkcolor;
68     WORD        flags;
69     SHORT       ovls[4];
70 } ILHEAD;
71 #include "poppack.h"
72
73 static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
74 static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
75 static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
76 static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
77 static HRESULT (WINAPI *pImageList_CoCreateInstance)(REFCLSID,const IUnknown *,
78     REFIID,void **);
79 static HRESULT (WINAPI *pHIMAGELIST_QueryInterface)(HIMAGELIST,REFIID,void **);
80
81 static HINSTANCE hinst;
82
83 /* These macros build cursor/bitmap data in 4x4 pixel blocks */
84 #define B(x,y) ((x?0xf0:0)|(y?0xf:0))
85 #define ROW1(a,b,c,d,e,f,g,h) B(a,b),B(c,d),B(e,f),B(g,h)
86 #define ROW32(a,b,c,d,e,f,g,h) ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h), \
87   ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h)
88 #define ROW2(a,b,c,d,e,f,g,h,i,j,k,l) ROW1(a,b,c,d,e,f,g,h),B(i,j),B(k,l)
89 #define ROW48(a,b,c,d,e,f,g,h,i,j,k,l) ROW2(a,b,c,d,e,f,g,h,i,j,k,l), \
90   ROW2(a,b,c,d,e,f,g,h,i,j,k,l), ROW2(a,b,c,d,e,f,g,h,i,j,k,l), \
91   ROW2(a,b,c,d,e,f,g,h,i,j,k,l)
92
93 static const BYTE empty_bits[48*48/8];
94
95 static const BYTE icon_bits[32*32/8] =
96 {
97   ROW32(0,0,0,0,0,0,0,0),
98   ROW32(0,0,1,1,1,1,0,0),
99   ROW32(0,1,1,1,1,1,1,0),
100   ROW32(0,1,1,0,0,1,1,0),
101   ROW32(0,1,1,0,0,1,1,0),
102   ROW32(0,1,1,1,1,1,1,0),
103   ROW32(0,0,1,1,1,1,0,0),
104   ROW32(0,0,0,0,0,0,0,0)
105 };
106
107 static const BYTE bitmap_bits[48*48/8] =
108 {
109   ROW48(0,0,0,0,0,0,0,0,0,0,0,0),
110   ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
111   ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
112   ROW48(0,1,0,0,0,0,0,0,1,0,1,0),
113   ROW48(0,1,0,0,0,0,0,1,0,0,1,0),
114   ROW48(0,1,0,0,0,0,1,0,0,0,1,0),
115   ROW48(0,1,0,0,0,1,0,0,0,0,1,0),
116   ROW48(0,1,0,0,1,0,0,0,0,0,1,0),
117   ROW48(0,1,0,1,0,0,0,0,0,0,1,0),
118   ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
119   ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
120   ROW48(0,0,0,0,0,0,0,0,0,0,0,0)
121 };
122
123 static HIMAGELIST createImageList(int cx, int cy)
124 {
125     /* Create an ImageList and put an image into it */
126     HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1);
127     HBITMAP hbm = CreateBitmap(48, 48, 1, 1, bitmap_bits);
128     ImageList_Add(himl, hbm, NULL);
129     DeleteObject(hbm);
130     return himl;
131 }
132
133 static HWND create_a_window(void)
134 {
135     char className[] = "bmwnd";
136     char winName[]   = "Test Bitmap";
137     HWND hWnd;
138     static int registered = 0;
139
140     if (!registered)
141     {
142         WNDCLASSA cls;
143
144         cls.style         = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
145         cls.lpfnWndProc   = DefWindowProcA;
146         cls.cbClsExtra    = 0;
147         cls.cbWndExtra    = 0;
148         cls.hInstance     = 0;
149         cls.hIcon         = LoadIconA (0, IDI_APPLICATION);
150         cls.hCursor       = LoadCursorA (0, IDC_ARROW);
151         cls.hbrBackground = GetStockObject (WHITE_BRUSH);
152         cls.lpszMenuName  = 0;
153         cls.lpszClassName = className;
154
155         RegisterClassA (&cls);
156         registered = 1;
157     }
158
159     /* Setup window */
160     hWnd = CreateWindowA (className, winName,
161        WS_OVERLAPPEDWINDOW ,
162        CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
163        0, hinst, 0);
164
165 #ifdef VISIBLE
166     ShowWindow (hWnd, SW_SHOW);
167 #endif
168     REDRAW(hWnd);
169     WAIT;
170
171     return hWnd;
172 }
173
174 static HDC show_image(HWND hwnd, HIMAGELIST himl, int idx, int size,
175                       LPCSTR loc, BOOL clear)
176 {
177     HDC hdc = NULL;
178 #ifdef VISIBLE
179     if (!himl) return NULL;
180
181     SetWindowText(hwnd, loc);
182     hdc = GetDC(hwnd);
183     ImageList_Draw(himl, idx, hdc, 0, 0, ILD_TRANSPARENT);
184
185     REDRAW(hwnd);
186     WAIT;
187
188     if (clear)
189     {
190         BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
191         ReleaseDC(hwnd, hdc);
192         hdc = NULL;
193     }
194 #endif /* VISIBLE */
195     return hdc;
196 }
197
198 /* Useful for checking differences */
199 #if 0
200 static void dump_bits(const BYTE *p, const BYTE *q, int size)
201 {
202   int i, j;
203
204   size /= 8;
205
206   for (i = 0; i < size * 2; i++)
207   {
208       printf("|");
209       for (j = 0; j < size; j++)
210           printf("%c%c", p[j] & 0xf0 ? 'X' : ' ', p[j] & 0xf ? 'X' : ' ');
211       printf(" -- ");
212       for (j = 0; j < size; j++)
213           printf("%c%c", q[j] & 0xf0 ? 'X' : ' ', q[j] & 0xf ? 'X' : ' ');
214       printf("|\n");
215       p += size * 4;
216       q += size * 4;
217   }
218   printf("\n");
219 }
220 #endif
221
222 static void check_bits(HWND hwnd, HIMAGELIST himl, int idx, int size,
223                        const BYTE *checkbits, LPCSTR loc)
224 {
225 #ifdef VISIBLE
226     BYTE bits[100*100/8];
227     COLORREF c;
228     HDC hdc;
229     int x, y, i = -1;
230
231     if (!himl) return;
232
233     memset(bits, 0, sizeof(bits));
234     hdc = show_image(hwnd, himl, idx, size, loc, FALSE);
235
236     c = GetPixel(hdc, 0, 0);
237
238     for (y = 0; y < size; y ++)
239     {
240         for (x = 0; x < size; x++)
241         {
242             if (!(x & 0x7)) i++;
243             if (GetPixel(hdc, x, y) != c) bits[i] |= (0x80 >> (x & 0x7));
244         }
245     }
246
247     BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
248     ReleaseDC(hwnd, hdc);
249
250     ok (memcmp(bits, checkbits, (size * size)/8) == 0,
251         "%s: bits different\n", loc);
252     if (memcmp(bits, checkbits, (size * size)/8))
253         dump_bits(bits, checkbits, size);
254 #endif /* VISIBLE */
255 }
256
257 static void test_hotspot(void)
258 {
259     struct hotspot {
260         int dx;
261         int dy;
262     };
263
264 #define SIZEX1 47
265 #define SIZEY1 31
266 #define SIZEX2 11
267 #define SIZEY2 17
268 #define HOTSPOTS_MAX 4       /* Number of entries in hotspots */
269     static const struct hotspot hotspots[HOTSPOTS_MAX] = {
270         { 10, 7 },
271         { SIZEX1, SIZEY1 },
272         { -9, -8 },
273         { -7, 35 }
274     };
275     int i, j, ret;
276     HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
277     HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
278     HWND hwnd = create_a_window();
279
280
281     for (i = 0; i < HOTSPOTS_MAX; i++) {
282         for (j = 0; j < HOTSPOTS_MAX; j++) {
283             int dx1 = hotspots[i].dx;
284             int dy1 = hotspots[i].dy;
285             int dx2 = hotspots[j].dx;
286             int dy2 = hotspots[j].dy;
287             int correctx, correcty, newx, newy;
288             char loc[256];
289             HIMAGELIST himlNew;
290             POINT ppt;
291
292             ret = ImageList_BeginDrag(himl1, 0, dx1, dy1);
293             ok(ret != 0, "BeginDrag failed for { %d, %d }\n", dx1, dy1);
294             sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
295             show_image(hwnd, himl1, 0, max(SIZEX1, SIZEY1), loc, TRUE);
296
297             /* check merging the dragged image with a second image */
298             ret = ImageList_SetDragCursorImage(himl2, 0, dx2, dy2);
299             ok(ret != 0, "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
300                     dx1, dy1, dx2, dy2);
301             sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
302             show_image(hwnd, himl2, 0, max(SIZEX2, SIZEY2), loc, TRUE);
303
304             /* check new hotspot, it should be the same like the old one */
305             himlNew = ImageList_GetDragImage(NULL, &ppt);
306             ok(ppt.x == dx1 && ppt.y == dy1,
307                     "Expected drag hotspot [%d,%d] got [%d,%d]\n",
308                     dx1, dy1, ppt.x, ppt.y);
309             /* check size of new dragged image */
310             ImageList_GetIconSize(himlNew, &newx, &newy);
311             correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
312             correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
313             ok(newx == correctx && newy == correcty,
314                     "Expected drag image size [%d,%d] got [%d,%d]\n",
315                     correctx, correcty, newx, newy);
316             sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
317             show_image(hwnd, himlNew, 0, max(correctx, correcty), loc, TRUE);
318             ImageList_EndDrag();
319         }
320     }
321 #undef SIZEX1
322 #undef SIZEY1
323 #undef SIZEX2
324 #undef SIZEY2
325 #undef HOTSPOTS_MAX
326     ImageList_Destroy(himl2);
327     ImageList_Destroy(himl1);
328     DestroyWindow(hwnd);
329 }
330
331 static void test_add_remove(void)
332 {
333     HIMAGELIST himl ;
334
335     HICON hicon1 ;
336     HICON hicon2 ;
337     HICON hicon3 ;
338
339     /* create an imagelist to play with */
340     himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
341     ok(himl!=0,"failed to create imagelist\n");
342
343     /* load the icons to add to the image list */
344     hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
345     ok(hicon1 != 0, "no hicon1\n");
346     hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
347     ok(hicon2 != 0, "no hicon2\n");
348     hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
349     ok(hicon3 != 0, "no hicon3\n");
350
351     /* remove when nothing exists */
352     ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
353     /* removing everything from an empty imagelist should succeed */
354     ok(ImageList_RemoveAll(himl),"removed nonexistent icon\n");
355
356     /* add three */
357     ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
358     ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
359     ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
360
361     /* remove an index out of range */
362     ok(!ImageList_Remove(himl,4711),"removed nonexistent icon\n");
363
364     /* remove three */
365     ok(ImageList_Remove(himl,0),"can't remove 0\n");
366     ok(ImageList_Remove(himl,0),"can't remove 0\n");
367     ok(ImageList_Remove(himl,0),"can't remove 0\n");
368
369     /* remove one extra */
370     ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
371
372     /* destroy it */
373     ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
374
375     ok(-1==ImageList_AddIcon((HIMAGELIST)0xdeadbeef, hicon1),"don't crash on bad handle\n");
376
377     ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
378     ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
379     ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
380 }
381
382 static void test_imagecount(void)
383 {
384     HIMAGELIST himl;
385
386     ok(0==ImageList_GetImageCount((HIMAGELIST)0xdeadbeef),"don't crash on bad handle\n");
387
388     if (!pImageList_SetImageCount)
389     {
390         win_skip("ImageList_SetImageCount not available\n");
391         return;
392     }
393
394     himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
395     ok(himl!=0,"failed to create imagelist\n");
396
397     ok(pImageList_SetImageCount(himl, 3), "couldn't increase image count\n");
398     ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
399     ok(pImageList_SetImageCount(himl, 1), "couldn't decrease image count\n");
400     ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
401     ok(pImageList_SetImageCount(himl, 0), "couldn't decrease image count\n");
402     ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
403
404     ok(ImageList_Destroy(himl), "destroy imagelist failed\n");
405 }
406
407 static void test_DrawIndirect(void)
408 {
409     HIMAGELIST himl;
410
411     HBITMAP hbm1;
412     HBITMAP hbm2;
413     HBITMAP hbm3;
414
415     IMAGELISTDRAWPARAMS imldp;
416     HDC hdc;
417     HWND hwndfortest;
418
419     if (!pImageList_DrawIndirect)
420     {
421         win_skip("ImageList_DrawIndirect not available, skipping test\n");
422         return;
423     }
424
425     hwndfortest = create_a_window();
426     hdc = GetDC(hwndfortest);
427     ok(hdc!=NULL, "couldn't get DC\n");
428
429     /* create an imagelist to play with */
430     himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3);
431     ok(himl!=0,"failed to create imagelist\n");
432
433     /* load the icons to add to the image list */
434     hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
435     ok(hbm1 != 0, "no bitmap 1\n");
436     hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
437     ok(hbm2 != 0, "no bitmap 2\n");
438     hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
439     ok(hbm3 != 0, "no bitmap 3\n");
440
441     /* add three */
442     ok(0==ImageList_Add(himl, hbm1, 0),"failed to add bitmap 1\n");
443     ok(1==ImageList_Add(himl, hbm2, 0),"failed to add bitmap 2\n");
444
445     if (pImageList_SetImageCount)
446     {
447         ok(pImageList_SetImageCount(himl,3),"Setimage count failed\n");
448         /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
449         ok(ImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
450     }
451
452     memset(&imldp, 0, sizeof (imldp));
453     ok(!pImageList_DrawIndirect(&imldp), "zero data succeeded!\n");
454     imldp.cbSize = IMAGELISTDRAWPARAMS_V3_SIZE;
455     ok(!pImageList_DrawIndirect(&imldp), "zero hdc succeeded!\n");
456     imldp.hdcDst = hdc;
457     ok(!pImageList_DrawIndirect(&imldp),"zero himl succeeded!\n");
458     imldp.himl = (HIMAGELIST)0xdeadbeef;
459     ok(!pImageList_DrawIndirect(&imldp),"bad himl succeeded!\n");
460     imldp.himl = himl;
461
462     REDRAW(hwndfortest);
463     WAIT;
464
465     imldp.fStyle = SRCCOPY;
466     imldp.rgbBk = CLR_DEFAULT;
467     imldp.rgbFg = CLR_DEFAULT;
468     imldp.y = 100;
469     imldp.x = 100;
470     ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
471     imldp.i ++;
472     ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
473     imldp.i ++;
474     ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
475     imldp.i ++;
476     ok(!pImageList_DrawIndirect(&imldp),"should fail\n");
477
478     /* remove three */
479     ok(ImageList_Remove(himl, 0), "removing 1st bitmap\n");
480     ok(ImageList_Remove(himl, 0), "removing 2nd bitmap\n");
481     ok(ImageList_Remove(himl, 0), "removing 3rd bitmap\n");
482
483     /* destroy it */
484     ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
485
486     /* bitmaps should not be deleted by the imagelist */
487     ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
488     ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
489     ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");
490
491     ReleaseDC(hwndfortest, hdc);
492     DestroyWindow(hwndfortest);
493 }
494
495 static int get_color_format(HBITMAP bmp)
496 {
497     BITMAPINFO bmi;
498     HDC hdc = CreateCompatibleDC(0);
499     HBITMAP hOldBmp = SelectObject(hdc, bmp);
500     int ret;
501
502     memset(&bmi, 0, sizeof(bmi));
503     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
504     ret = GetDIBits(hdc, bmp, 0, 0, 0, &bmi, DIB_RGB_COLORS);
505     ok(ret, "GetDIBits failed\n");
506
507     SelectObject(hdc, hOldBmp);
508     DeleteDC(hdc);
509     return bmi.bmiHeader.biBitCount;
510 }
511
512 static void test_merge_colors(void)
513 {
514     HIMAGELIST himl[8], hmerge;
515     int sizes[] = { ILC_COLOR, ILC_COLOR | ILC_MASK, ILC_COLOR4, ILC_COLOR8, ILC_COLOR16, ILC_COLOR24, ILC_COLOR32, ILC_COLORDDB };
516     HICON hicon1;
517     IMAGEINFO info;
518     int bpp, i, j;
519
520     hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
521     ok(hicon1 != NULL, "failed to create hicon1\n");
522
523     for (i = 0; i < 8; i++)
524     {
525         himl[i] = ImageList_Create(32, 32, sizes[i], 0, 3);
526         ok(himl[i] != NULL, "failed to create himl[%d]\n", i);
527         ok(0 == ImageList_AddIcon(himl[i], hicon1), "add icon1 to himl[%d] failed\n", i);
528         if (i == 0 || i == 1 || i == 7)
529         {
530             ImageList_GetImageInfo(himl[i], 0, &info);
531             sizes[i] = get_color_format(info.hbmImage);
532         }
533     }
534     DestroyIcon(hicon1);
535     for (i = 0; i < 8; i++)
536         for (j = 0; j < 8; j++)
537         {
538             hmerge = ImageList_Merge(himl[i], 0, himl[j], 0, 0, 0);
539             ok(hmerge != NULL, "merge himl[%d], himl[%d] failed\n", i, j);
540
541             ImageList_GetImageInfo(hmerge, 0, &info);
542             bpp = get_color_format(info.hbmImage);
543             /* ILC_COLOR[X] is defined as [X] */
544             if (i == 4 && j == 7)
545                 ok(bpp == 16, /* merging ILC_COLOR16 with ILC_COLORDDB seems to be a special case */
546                     "wrong biBitCount %d when merging lists %d (%d) and %d (%d)\n", bpp, i, sizes[i], j, sizes[j]);
547             else
548                 ok(bpp == (i > j ? sizes[i] : sizes[j]),
549                     "wrong biBitCount %d when merging lists %d (%d) and %d (%d)\n", bpp, i, sizes[i], j, sizes[j]);
550             ok(info.hbmMask != 0, "Imagelist merged from %d and %d had no mask\n", i, j);
551
552             if (hmerge) ImageList_Destroy(hmerge);
553         }
554
555     for (i = 0; i < 8; i++)
556         ImageList_Destroy(himl[i]);
557 }
558
559 static void test_merge(void)
560 {
561     HIMAGELIST himl1, himl2, hmerge;
562     HICON hicon1;
563     HWND hwnd = create_a_window();
564
565     himl1 = ImageList_Create(32,32,0,0,3);
566     ok(himl1 != NULL,"failed to create himl1\n");
567
568     himl2 = ImageList_Create(32,32,0,0,3);
569     ok(himl2 != NULL,"failed to create himl2\n");
570
571     hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
572     ok(hicon1 != NULL, "failed to create hicon1\n");
573
574     if (!himl1 || !himl2 || !hicon1)
575         return;
576
577     ok(0==ImageList_AddIcon(himl2, hicon1),"add icon1 to himl2 failed\n");
578     check_bits(hwnd, himl2, 0, 32, icon_bits, "add icon1 to himl2");
579
580     /* If himl1 has no images, merge still succeeds */
581     hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
582     ok(hmerge != NULL, "merge himl1,-1 failed\n");
583     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,-1");
584     if (hmerge) ImageList_Destroy(hmerge);
585
586     hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
587     ok(hmerge != NULL,"merge himl1,0 failed\n");
588     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,0");
589     if (hmerge) ImageList_Destroy(hmerge);
590
591     /* Same happens if himl2 is empty */
592     ImageList_Destroy(himl2);
593     himl2 = ImageList_Create(32,32,0,0,3);
594     ok(himl2 != NULL,"failed to recreate himl2\n");
595     if (!himl2)
596         return;
597
598     hmerge = ImageList_Merge(himl1, -1, himl2, -1, 0, 0);
599     ok(hmerge != NULL, "merge himl2,-1 failed\n");
600     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,-1");
601     if (hmerge) ImageList_Destroy(hmerge);
602
603     hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
604     ok(hmerge != NULL, "merge himl2,0 failed\n");
605     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,0");
606     if (hmerge) ImageList_Destroy(hmerge);
607
608     /* Now try merging an image with itself */
609     ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n");
610
611     hmerge = ImageList_Merge(himl2, 0, himl2, 0, 0, 0);
612     ok(hmerge != NULL, "merge himl2 with itself failed\n");
613     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2 with itself");
614     if (hmerge) ImageList_Destroy(hmerge);
615
616     /* Try merging 2 different image lists */
617     ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n");
618
619     hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
620     ok(hmerge != NULL, "merge himl1 with himl2 failed\n");
621     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2");
622     if (hmerge) ImageList_Destroy(hmerge);
623
624     hmerge = ImageList_Merge(himl1, 0, himl2, 0, 8, 16);
625     ok(hmerge != NULL, "merge himl1 with himl2 8,16 failed\n");
626     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2, 8,16");
627     if (hmerge) ImageList_Destroy(hmerge);
628
629     ImageList_Destroy(himl1);
630     ImageList_Destroy(himl2);
631     DestroyIcon(hicon1);
632     DestroyWindow(hwnd);
633 }
634
635 /*********************** imagelist storage test ***************************/
636
637 #define BMP_CX 48
638
639 struct my_IStream
640 {
641     IStream IStream_iface;
642     char *iml_data; /* written imagelist data */
643     ULONG iml_data_size;
644 };
645
646 static struct my_IStream *impl_from_IStream(IStream *iface)
647 {
648     return CONTAINING_RECORD(iface, struct my_IStream, IStream_iface);
649 }
650
651 static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface(IStream *iface, REFIID riid,
652                                                             void **ppvObject)
653 {
654     assert(0);
655     return E_NOTIMPL;
656 }
657
658 static ULONG STDMETHODCALLTYPE Test_Stream_AddRef(IStream *iface)
659 {
660     assert(0);
661     return 2;
662 }
663
664 static ULONG STDMETHODCALLTYPE Test_Stream_Release(IStream *iface)
665 {
666     assert(0);
667     return 1;
668 }
669
670 static HRESULT STDMETHODCALLTYPE Test_Stream_Read(IStream *iface, void *pv, ULONG cb,
671                                                   ULONG *pcbRead)
672 {
673     assert(0);
674     return E_NOTIMPL;
675 }
676
677 static BOOL allocate_storage(struct my_IStream *my_is, ULONG add)
678 {
679     my_is->iml_data_size += add;
680
681     if (!my_is->iml_data)
682         my_is->iml_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data_size);
683     else
684         my_is->iml_data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data, my_is->iml_data_size);
685
686     return my_is->iml_data != NULL;
687 }
688
689 static HRESULT STDMETHODCALLTYPE Test_Stream_Write(IStream *iface, const void *pv, ULONG cb,
690                                                    ULONG *pcbWritten)
691 {
692     struct my_IStream *my_is = impl_from_IStream(iface);
693     ULONG current_iml_data_size = my_is->iml_data_size;
694
695     if (!allocate_storage(my_is, cb)) return E_FAIL;
696
697     memcpy(my_is->iml_data + current_iml_data_size, pv, cb);
698     if (pcbWritten) *pcbWritten = cb;
699
700     return S_OK;
701 }
702
703 static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
704                                                   DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
705 {
706     assert(0);
707     return E_NOTIMPL;
708 }
709
710 static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
711 {
712     assert(0);
713     return E_NOTIMPL;
714 }
715
716 static HRESULT STDMETHODCALLTYPE Test_Stream_CopyTo(IStream *iface, IStream *pstm,
717                                                     ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead,
718                                                     ULARGE_INTEGER *pcbWritten)
719 {
720     assert(0);
721     return E_NOTIMPL;
722 }
723
724 static HRESULT STDMETHODCALLTYPE Test_Stream_Commit(IStream *iface, DWORD grfCommitFlags)
725 {
726     assert(0);
727     return E_NOTIMPL;
728 }
729
730 static HRESULT STDMETHODCALLTYPE Test_Stream_Revert(IStream *iface)
731 {
732     assert(0);
733     return E_NOTIMPL;
734 }
735
736 static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
737                                                         ULARGE_INTEGER cb, DWORD dwLockType)
738 {
739     assert(0);
740     return E_NOTIMPL;
741 }
742
743 static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
744                                                           ULARGE_INTEGER cb, DWORD dwLockType)
745 {
746     assert(0);
747     return E_NOTIMPL;
748 }
749
750 static HRESULT STDMETHODCALLTYPE Test_Stream_Stat(IStream *iface, STATSTG *pstatstg,
751                                                   DWORD grfStatFlag)
752 {
753     assert(0);
754     return E_NOTIMPL;
755 }
756
757 static HRESULT STDMETHODCALLTYPE Test_Stream_Clone(IStream *iface, IStream **ppstm)
758 {
759     assert(0);
760     return E_NOTIMPL;
761 }
762
763 static const IStreamVtbl Test_Stream_Vtbl =
764 {
765     Test_Stream_QueryInterface,
766     Test_Stream_AddRef,
767     Test_Stream_Release,
768     Test_Stream_Read,
769     Test_Stream_Write,
770     Test_Stream_Seek,
771     Test_Stream_SetSize,
772     Test_Stream_CopyTo,
773     Test_Stream_Commit,
774     Test_Stream_Revert,
775     Test_Stream_LockRegion,
776     Test_Stream_UnlockRegion,
777     Test_Stream_Stat,
778     Test_Stream_Clone
779 };
780
781 static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 };
782
783 static INT DIB_GetWidthBytes( int width, int bpp )
784 {
785     return ((width * bpp + 31) / 8) & ~3;
786 }
787
788 static ULONG check_bitmap_data(const char *bm_data, ULONG bm_data_size,
789                                INT width, INT height, INT bpp,
790                                const char *comment)
791 {
792     const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data;
793     const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh));
794     ULONG hdr_size, image_size;
795
796     hdr_size = sizeof(*bmfh) + sizeof(*bmih);
797     if (bmih->biBitCount <= 8) hdr_size += (1 << bpp) * sizeof(RGBQUAD);
798
799     ok(bmfh->bfType == (('M' << 8) | 'B'), "wrong bfType 0x%02x\n", bmfh->bfType);
800     ok(bmfh->bfSize == hdr_size, "wrong bfSize 0x%02x\n", bmfh->bfSize);
801     ok(bmfh->bfReserved1 == 0, "wrong bfReserved1 0x%02x\n", bmfh->bfReserved1);
802     ok(bmfh->bfReserved2 == 0, "wrong bfReserved2 0x%02x\n", bmfh->bfReserved2);
803     ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits);
804
805     ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize);
806     ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width);
807     ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height);
808     ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes);
809     ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount);
810
811     image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight;
812     ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage);
813 #if 0
814 {
815     char fname[256];
816     FILE *f;
817     sprintf(fname, "bmp_%s.bmp", comment);
818     f = fopen(fname, "wb");
819     fwrite(bm_data, 1, bm_data_size, f);
820     fclose(f);
821 }
822 #endif
823     return hdr_size + image_size;
824 }
825
826 static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max, INT grow, INT flags)
827 {
828     const ILHEAD *ilh = (const ILHEAD *)ilh_data;
829
830     ok(ilh->usMagic == IMAGELIST_MAGIC, "wrong usMagic %4x (expected %02x)\n", ilh->usMagic, IMAGELIST_MAGIC);
831     ok(ilh->usVersion == 0x101, "wrong usVersion %x (expected 0x101)\n", ilh->usVersion);
832     ok(ilh->cCurImage == cur, "wrong cCurImage %d (expected %d)\n", ilh->cCurImage, cur);
833     ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
834     ok(ilh->cGrow == grow, "wrong cGrow %d (expected %d)\n", ilh->cGrow, grow);
835     ok(ilh->cx == cx, "wrong cx %d (expected %d)\n", ilh->cx, cx);
836     ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy);
837     ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor);
838     ok(ilh->flags == flags || broken(!(ilh->flags & 0xfe) && (flags & 0xfe) == ILC_COLOR4),  /* <= w2k */
839        "wrong flags %04x\n", ilh->flags);
840     ok(ilh->ovls[0] == -1, "wrong ovls[0] %04x\n", ilh->ovls[0]);
841     ok(ilh->ovls[1] == -1, "wrong ovls[1] %04x\n", ilh->ovls[1]);
842     ok(ilh->ovls[2] == -1, "wrong ovls[2] %04x\n", ilh->ovls[2]);
843     ok(ilh->ovls[3] == -1, "wrong ovls[3] %04x\n", ilh->ovls[3]);
844 }
845
846 static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment)
847 {
848     HDC hdc;
849     BITMAPINFO bmi;
850     HBITMAP hbmp, hbmp_old;
851     HBRUSH hbrush;
852     RECT rc = { 0, 0, cx, cy };
853
854     hdc = CreateCompatibleDC(0);
855
856     memset(&bmi, 0, sizeof(bmi));
857     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
858     bmi.bmiHeader.biHeight = cx;
859     bmi.bmiHeader.biWidth = cy;
860     bmi.bmiHeader.biBitCount = 24;
861     bmi.bmiHeader.biPlanes = 1;
862     bmi.bmiHeader.biCompression = BI_RGB;
863     hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
864
865     hbmp_old = SelectObject(hdc, hbmp);
866
867     hbrush = CreateSolidBrush(color);
868     FillRect(hdc, &rc, hbrush);
869     DeleteObject(hbrush);
870
871     DrawText(hdc, comment, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
872
873     SelectObject(hdc, hbmp_old);
874     DeleteDC(hdc);
875
876     return hbmp;
877 }
878
879 #define iml_clear_stream_data() \
880     HeapFree(GetProcessHeap(), 0, Test_Stream.iml_data); \
881     Test_Stream.iml_data = NULL; \
882     Test_Stream.iml_data_size = 0;
883
884 static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max, INT grow,
885                            INT width, INT height, INT flags, const char *comment)
886 {
887     INT ret, cxx, cyy, size;
888
889     trace("%s\n", comment);
890
891     ret = ImageList_GetImageCount(himl);
892     ok(ret == cur, "expected image count %d got %d\n", cur, ret);
893
894     ret = ImageList_GetIconSize(himl, &cxx, &cyy);
895     ok(ret, "ImageList_GetIconSize failed\n");
896     ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx);
897     ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy);
898
899     iml_clear_stream_data();
900     ret = ImageList_Write(himl, &Test_Stream.IStream_iface);
901     ok(ret, "ImageList_Write failed\n");
902
903     ok(Test_Stream.iml_data != 0, "ImageList_Write didn't write any data\n");
904     ok(Test_Stream.iml_data_size > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n");
905
906     check_ilhead_data(Test_Stream.iml_data, cx, cy, cur, max, grow, flags);
907     size = check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD),
908                              Test_Stream.iml_data_size - sizeof(ILHEAD),
909                              width, height, flags & 0xfe, comment);
910     if (size < Test_Stream.iml_data_size - sizeof(ILHEAD))  /* mask is present */
911     {
912         ok( flags & ILC_MASK, "extra data %u/%u but mask not expected\n",
913             Test_Stream.iml_data_size, size );
914         check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD) + size,
915                           Test_Stream.iml_data_size - sizeof(ILHEAD) - size,
916                           width, height, 1, comment);
917     }
918 }
919
920 static void image_list_init(HIMAGELIST himl)
921 {
922     HBITMAP hbm;
923     char comment[16];
924     INT n = 1;
925     DWORD i;
926     static const struct test_data
927     {
928         BYTE grey;
929         INT cx, cy, cur, max, grow, width, height, bpp;
930         const char *comment;
931     } td[] =
932     {
933         { 255, BMP_CX, BMP_CX, 1, 2, 4, BMP_CX * 4, BMP_CX * 1, 24, "total 1" },
934         { 170, BMP_CX, BMP_CX, 2, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 2" },
935         { 85, BMP_CX, BMP_CX, 3, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 3" },
936         { 0, BMP_CX, BMP_CX, 4, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 4" },
937         { 0, BMP_CX, BMP_CX, 5, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 5" },
938         { 85, BMP_CX, BMP_CX, 6, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 6" },
939         { 170, BMP_CX, BMP_CX, 7, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 7" },
940         { 255, BMP_CX, BMP_CX, 8, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 8" },
941         { 255, BMP_CX, BMP_CX, 9, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 9" },
942         { 170, BMP_CX, BMP_CX, 10, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 10" },
943         { 85, BMP_CX, BMP_CX, 11, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 11" },
944         { 0, BMP_CX, BMP_CX, 12, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 12" },
945         { 0, BMP_CX, BMP_CX, 13, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 13" },
946         { 85, BMP_CX, BMP_CX, 14, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 14" },
947         { 170, BMP_CX, BMP_CX, 15, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 15" },
948         { 255, BMP_CX, BMP_CX, 16, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 16" },
949         { 255, BMP_CX, BMP_CX, 17, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 17" },
950         { 170, BMP_CX, BMP_CX, 18, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 18" },
951         { 85, BMP_CX, BMP_CX, 19, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 19" },
952         { 0, BMP_CX, BMP_CX, 20, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 20" },
953         { 0, BMP_CX, BMP_CX, 21, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 21" },
954         { 85, BMP_CX, BMP_CX, 22, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 22" },
955         { 170, BMP_CX, BMP_CX, 23, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 23" },
956         { 255, BMP_CX, BMP_CX, 24, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 24" }
957     };
958
959     check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "total 0");
960
961 #define add_bitmap(grey) \
962     sprintf(comment, "%d", n++); \
963     hbm = create_bitmap(BMP_CX, BMP_CX, RGB((grey),(grey),(grey)), comment); \
964     ImageList_Add(himl, hbm, NULL); \
965     DeleteObject(hbm);
966
967     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
968     {
969         add_bitmap(td[i].grey);
970         check_iml_data(himl, td[i].cx, td[i].cy, td[i].cur, td[i].max, td[i].grow,
971                        td[i].width, td[i].height, td[i].bpp, td[i].comment);
972     }
973 #undef add_bitmap
974 }
975
976 static void test_imagelist_storage(void)
977 {
978     HIMAGELIST himl;
979     HBITMAP hbm;
980     HICON icon;
981     INT ret;
982
983     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
984     ok(himl != 0, "ImageList_Create failed\n");
985
986     check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "empty");
987
988     image_list_init(himl);
989     check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "orig");
990
991     ret = ImageList_Remove(himl, 4);
992     ok(ret, "ImageList_Remove failed\n");
993     check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "1");
994
995     ret = ImageList_Remove(himl, 5);
996     ok(ret, "ImageList_Remove failed\n");
997     check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "2");
998
999     ret = ImageList_Remove(himl, 6);
1000     ok(ret, "ImageList_Remove failed\n");
1001     check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "3");
1002
1003     ret = ImageList_Remove(himl, 7);
1004     ok(ret, "ImageList_Remove failed\n");
1005     check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "4");
1006
1007     ret = ImageList_Remove(himl, -2);
1008     ok(!ret, "ImageList_Remove(-2) should fail\n");
1009     check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "5");
1010
1011     ret = ImageList_Remove(himl, 20);
1012     ok(!ret, "ImageList_Remove(20) should fail\n");
1013     check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "6");
1014
1015     ret = ImageList_Remove(himl, -1);
1016     ok(ret, "ImageList_Remove(-1) failed\n");
1017     check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "7");
1018
1019     ret = ImageList_Destroy(himl);
1020     ok(ret, "ImageList_Destroy failed\n");
1021
1022     iml_clear_stream_data();
1023
1024     /* test ImageList_Create storage allocation */
1025
1026     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 0, 32);
1027     ok(himl != 0, "ImageList_Create failed\n");
1028     check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 32, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "init 0 grow 32");
1029     hbm = create_bitmap(BMP_CX * 9, BMP_CX, 0, "9");
1030     ret = ImageList_Add(himl, hbm, NULL);
1031     ok(ret == 0, "ImageList_Add returned %d, expected 0\n", ret);
1032     check_iml_data(himl, BMP_CX, BMP_CX, 1, 34, 32, BMP_CX * 4, BMP_CX * 9, ILC_COLOR24, "add 1 x 9");
1033     DeleteObject(hbm);
1034     ret = ImageList_Destroy(himl);
1035     ok(ret, "ImageList_Destroy failed\n");
1036     iml_clear_stream_data();
1037
1038     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 4);
1039     ok(himl != 0, "ImageList_Create failed\n");
1040     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 4 grow 4");
1041     hbm = create_bitmap(BMP_CX, BMP_CX * 9, 0, "9");
1042     ret = ImageList_Add(himl, hbm, NULL);
1043     ok(ret == 0, "ImageList_Add returned %d, expected 0\n", ret);
1044     check_iml_data(himl, BMP_CX, BMP_CX, 9, 15, 4, BMP_CX * 4, BMP_CX * 4, ILC_COLOR24, "add 9 x 1");
1045     ret = ImageList_Add(himl, hbm, NULL);
1046     ok(ret == 9, "ImageList_Add returned %d, expected 9\n", ret);
1047     check_iml_data(himl, BMP_CX, BMP_CX, 18, 25, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "add 9 x 1");
1048     DeleteObject(hbm);
1049     ret = ImageList_Destroy(himl);
1050     ok(ret, "ImageList_Destroy failed\n");
1051     iml_clear_stream_data();
1052
1053     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 207, 209);
1054     ok(himl != 0, "ImageList_Create failed\n");
1055     check_iml_data(himl, BMP_CX, BMP_CX, 0, 208, 212, BMP_CX * 4, BMP_CX * 52, ILC_COLOR24, "init 207 grow 209");
1056     ret = ImageList_Destroy(himl);
1057     ok(ret, "ImageList_Destroy failed\n");
1058     iml_clear_stream_data();
1059
1060     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 209, 207);
1061     ok(himl != 0, "ImageList_Create failed\n");
1062     check_iml_data(himl, BMP_CX, BMP_CX, 0, 210, 208, BMP_CX * 4, BMP_CX * 53, ILC_COLOR24, "init 209 grow 207");
1063     ret = ImageList_Destroy(himl);
1064     ok(ret, "ImageList_Destroy failed\n");
1065     iml_clear_stream_data();
1066
1067     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 14, 4);
1068     ok(himl != 0, "ImageList_Create failed\n");
1069     check_iml_data(himl, BMP_CX, BMP_CX, 0, 15, 4, BMP_CX * 4, BMP_CX * 4, ILC_COLOR24, "init 14 grow 4");
1070     ret = ImageList_Destroy(himl);
1071     ok(ret, "ImageList_Destroy failed\n");
1072     iml_clear_stream_data();
1073
1074     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 5, 9);
1075     ok(himl != 0, "ImageList_Create failed\n");
1076     check_iml_data(himl, BMP_CX, BMP_CX, 0, 6, 12, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 5 grow 9");
1077     ret = ImageList_Destroy(himl);
1078     ok(ret, "ImageList_Destroy failed\n");
1079     iml_clear_stream_data();
1080
1081     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 9, 5);
1082     ok(himl != 0, "ImageList_Create failed\n");
1083     check_iml_data(himl, BMP_CX, BMP_CX, 0, 10, 8, BMP_CX * 4, BMP_CX * 3, ILC_COLOR24, "init 9 grow 5");
1084     ret = ImageList_Destroy(himl);
1085     ok(ret, "ImageList_Destroy failed\n");
1086     iml_clear_stream_data();
1087
1088     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 2, 4);
1089     ok(himl != 0, "ImageList_Create failed\n");
1090     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "init 2 grow 4");
1091     ret = ImageList_Destroy(himl);
1092     ok(ret, "ImageList_Destroy failed\n");
1093     iml_clear_stream_data();
1094
1095     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 2);
1096     ok(himl != 0, "ImageList_Create failed\n");
1097     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 4 grow 2");
1098     ret = ImageList_Destroy(himl);
1099     ok(ret, "ImageList_Destroy failed\n");
1100     iml_clear_stream_data();
1101
1102     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR8, 4, 2);
1103     ok(himl != 0, "ImageList_Create failed\n");
1104     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR8, "bpp 8");
1105     ret = ImageList_Destroy(himl);
1106     ok(ret, "ImageList_Destroy failed\n");
1107     iml_clear_stream_data();
1108
1109     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4, 4, 2);
1110     ok(himl != 0, "ImageList_Create failed\n");
1111     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp 4");
1112     ret = ImageList_Destroy(himl);
1113     ok(ret, "ImageList_Destroy failed\n");
1114     iml_clear_stream_data();
1115
1116     himl = ImageList_Create(BMP_CX, BMP_CX, 0, 4, 2);
1117     ok(himl != 0, "ImageList_Create failed\n");
1118     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp default");
1119     icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1120     ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
1121     ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
1122     DestroyIcon( icon );
1123     check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp default");
1124     ret = ImageList_Destroy(himl);
1125     ok(ret, "ImageList_Destroy failed\n");
1126     iml_clear_stream_data();
1127
1128     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24|ILC_MASK, 4, 2);
1129     ok(himl != 0, "ImageList_Create failed\n");
1130     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24|ILC_MASK,
1131                    "bpp 24 + mask");
1132     icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1133     ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
1134     ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
1135     DestroyIcon( icon );
1136     check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24|ILC_MASK,
1137                    "bpp 24 + mask");
1138     ret = ImageList_Destroy(himl);
1139     ok(ret, "ImageList_Destroy failed\n");
1140     iml_clear_stream_data();
1141
1142     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 4, 2);
1143     ok(himl != 0, "ImageList_Create failed\n");
1144     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4|ILC_MASK,
1145                    "bpp 4 + mask");
1146     icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1147     ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
1148     ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
1149     DestroyIcon( icon );
1150     check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4|ILC_MASK,
1151                    "bpp 4 + mask");
1152     ret = ImageList_Destroy(himl);
1153     ok(ret, "ImageList_Destroy failed\n");
1154     iml_clear_stream_data();
1155
1156     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 99);
1157     ok(himl != 0, "ImageList_Create failed\n");
1158     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1159                    "init 2 grow 99");
1160     icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1161     ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
1162     ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
1163     check_iml_data(himl, BMP_CX, BMP_CX, 2, 3, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1164                    "init 2 grow 99 2 icons");
1165     ok( ImageList_AddIcon(himl, icon) == 2,"failed to add icon\n");
1166     DestroyIcon( icon );
1167     check_iml_data(himl, BMP_CX, BMP_CX, 3, 104, 100, BMP_CX * 4, BMP_CX * 104/4, ILC_COLOR4|ILC_MASK,
1168                    "init 2 grow 99 3 icons");
1169     ok( ImageList_Remove(himl, -1) == TRUE,"failed to remove icon\n");
1170     check_iml_data(himl, BMP_CX, BMP_CX, 0, 100, 100, BMP_CX * 4, BMP_CX * 100/4, ILC_COLOR4|ILC_MASK,
1171                    "init 2 grow 99 empty");
1172     ok( ImageList_SetImageCount(himl, 22) == TRUE,"failed to set image count\n");
1173     check_iml_data(himl, BMP_CX, BMP_CX, 22, 23, 100, BMP_CX * 4, BMP_CX * 24/4, ILC_COLOR4|ILC_MASK,
1174                    "init 2 grow 99 set count 22");
1175     ok( ImageList_SetImageCount(himl, 0) == TRUE,"failed to set image count\n");
1176     check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1177                    "init 2 grow 99 set count 0");
1178     ok( ImageList_SetImageCount(himl, 42) == TRUE,"failed to set image count\n");
1179     check_iml_data(himl, BMP_CX, BMP_CX, 42, 43, 100, BMP_CX * 4, BMP_CX * 44/4, ILC_COLOR4|ILC_MASK,
1180                    "init 2 grow 99 set count 42");
1181     ret = ImageList_Destroy(himl);
1182     ok(ret, "ImageList_Destroy failed\n");
1183     iml_clear_stream_data();
1184
1185     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 65536+12);
1186     ok(himl != 0, "ImageList_Create failed\n");
1187     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 12, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1188                    "init 2 grow 65536+12");
1189     ret = ImageList_Destroy(himl);
1190     ok(ret, "ImageList_Destroy failed\n");
1191     iml_clear_stream_data();
1192
1193     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 65535);
1194     ok(himl != 0, "ImageList_Create failed\n");
1195     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 0, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1196                    "init 2 grow 65535");
1197     ret = ImageList_Destroy(himl);
1198     ok(ret, "ImageList_Destroy failed\n");
1199     iml_clear_stream_data();
1200
1201     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, -20);
1202     ok(himl != 0, "ImageList_Create failed\n");
1203     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1204                    "init 2 grow -20");
1205     ret = ImageList_Destroy(himl);
1206     ok(ret, "ImageList_Destroy failed\n");
1207     iml_clear_stream_data();
1208 }
1209
1210 static void test_shell_imagelist(void)
1211 {
1212     BOOL (WINAPI *pSHGetImageList)(INT, REFIID, void**);
1213     IImageList *iml = NULL;
1214     HMODULE hShell32;
1215     HRESULT hr;
1216     int out = 0;
1217     RECT rect;
1218     int cx, cy;
1219
1220     /* Try to load function from shell32 */
1221     hShell32 = LoadLibrary("shell32.dll");
1222     pSHGetImageList = (void*)GetProcAddress(hShell32, (LPCSTR) 727);
1223
1224     if (!pSHGetImageList)
1225     {
1226         win_skip("SHGetImageList not available, skipping test\n");
1227         FreeLibrary(hShell32);
1228         return;
1229     }
1230
1231     /* Get system image list */
1232     hr = (pSHGetImageList)(SHIL_SYSSMALL, &IID_IImageList, (void**)&iml);
1233
1234     ok(SUCCEEDED(hr), "SHGetImageList failed, hr=%x\n", hr);
1235
1236     if (hr != S_OK) {
1237         FreeLibrary(hShell32);
1238         return;
1239     }
1240
1241     IImageList_GetImageCount(iml, &out);
1242     ok(out > 0, "IImageList_GetImageCount returned out <= 0\n");
1243
1244     /* Fetch the small icon size */
1245     cx = GetSystemMetrics(SM_CXSMICON);
1246     cy = GetSystemMetrics(SM_CYSMICON);
1247
1248     /* Check icon size matches */
1249     IImageList_GetImageRect(iml, 0, &rect);
1250     ok(((rect.right == cx) && (rect.bottom == cy)),
1251                  "IImageList_GetImageRect returned r:%d,b:%d\n",
1252                  rect.right, rect.bottom);
1253
1254     IImageList_Release(iml);
1255     FreeLibrary(hShell32);
1256 }
1257
1258 static HBITMAP create_test_bitmap(HDC hdc, int bpp, UINT32 pixel1, UINT32 pixel2)
1259 {
1260     HBITMAP hBitmap;
1261     UINT32 *buffer = NULL;
1262     BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, bpp, BI_RGB,
1263                                 0, 0, 0, 0, 0}};
1264
1265     hBitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, NULL, 0);
1266     ok(hBitmap != NULL && buffer != NULL, "CreateDIBSection failed.\n");
1267
1268     if(!hBitmap || !buffer)
1269     {
1270         DeleteObject(hBitmap);
1271         return NULL;
1272     }
1273
1274     buffer[0] = pixel1;
1275     buffer[1] = pixel2;
1276
1277     return hBitmap;
1278 }
1279
1280 static BOOL colour_match(UINT32 x, UINT32 y)
1281 {
1282     const INT32 tolerance = 8;
1283
1284     const INT32 dr = abs((INT32)(x & 0x000000FF) - (INT32)(y & 0x000000FF));
1285     const INT32 dg = abs((INT32)((x & 0x0000FF00) >> 8) - (INT32)((y & 0x0000FF00) >> 8));
1286     const INT32 db = abs((INT32)((x & 0x00FF0000) >> 16) - (INT32)((y & 0x00FF0000) >> 16));
1287
1288     return (dr <= tolerance && dg <= tolerance && db <= tolerance);
1289 }
1290
1291 static void check_ImageList_DrawIndirect(IMAGELISTDRAWPARAMS *ildp, UINT32 *bits,
1292                                          UINT32 expected, int line)
1293 {
1294     bits[0] = 0x00FFFFFF;
1295     pImageList_DrawIndirect(ildp);
1296     ok(colour_match(bits[0], expected),
1297        "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n",
1298        bits[0] & 0x00FFFFFF, expected, line);
1299 }
1300
1301
1302 static void check_ImageList_DrawIndirect_fStyle(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
1303                                                 UINT fStyle, UINT32 expected, int line)
1304 {
1305     IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
1306         0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, ILS_NORMAL, 0, 0x00000000};
1307     check_ImageList_DrawIndirect(&ildp, bits, expected, line);
1308 }
1309
1310 static void check_ImageList_DrawIndirect_ILD_ROP(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
1311                                                 DWORD dwRop, UINT32 expected, int line)
1312 {
1313     IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
1314         0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, ILD_IMAGE | ILD_ROP, dwRop, ILS_NORMAL, 0, 0x00000000};
1315     check_ImageList_DrawIndirect(&ildp, bits, expected, line);
1316 }
1317
1318 static void check_ImageList_DrawIndirect_fState(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i, UINT fStyle,
1319                                                 UINT fState, DWORD Frame, UINT32 expected, int line)
1320 {
1321     IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
1322         0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000};
1323     check_ImageList_DrawIndirect(&ildp, bits, expected, line);
1324 }
1325
1326 static void check_ImageList_DrawIndirect_broken(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
1327                                                 UINT fStyle, UINT fState, DWORD Frame, UINT32 expected,
1328                                                 UINT32 broken_expected, int line)
1329 {
1330     IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
1331         0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000};
1332     bits[0] = 0x00FFFFFF;
1333     pImageList_DrawIndirect(&ildp);
1334     ok(colour_match(bits[0], expected) ||
1335        broken(colour_match(bits[0], broken_expected)),
1336        "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n",
1337        bits[0] & 0x00FFFFFF, expected, line);
1338 }
1339
1340 static void test_ImageList_DrawIndirect(void)
1341 {
1342     HIMAGELIST himl = NULL;
1343     int ret;
1344     HDC hdcDst = NULL;
1345     HBITMAP hbmOld = NULL, hbmDst = NULL;
1346     HBITMAP hbmMask = NULL, hbmInverseMask = NULL;
1347     HBITMAP hbmImage = NULL, hbmAlphaImage = NULL, hbmTransparentImage = NULL;
1348     int iImage = -1, iAlphaImage = -1, iTransparentImage = -1;
1349     UINT32 *bits = 0;
1350     UINT32 maskBits = 0x00000000, inverseMaskBits = 0xFFFFFFFF;
1351     int bpp, broken_value;
1352
1353     BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, 32, BI_RGB,
1354                                 0, 0, 0, 0, 0}};
1355
1356     hdcDst = CreateCompatibleDC(0);
1357     ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1358     if (!hdcDst)
1359         return;
1360     bpp = GetDeviceCaps(hdcDst, BITSPIXEL);
1361
1362     hbmMask = CreateBitmap(2, 1, 1, 1, &maskBits);
1363     ok(hbmMask != 0, "CreateBitmap failed\n");
1364     if(!hbmMask) goto cleanup;
1365
1366     hbmInverseMask = CreateBitmap(2, 1, 1, 1, &inverseMaskBits);
1367     ok(hbmInverseMask != 0, "CreateBitmap failed\n");
1368     if(!hbmInverseMask) goto cleanup;
1369
1370     himl = pImageList_Create(2, 1, ILC_COLOR32, 0, 1);
1371     ok(himl != 0, "ImageList_Create failed\n");
1372     if(!himl) goto cleanup;
1373
1374     /* Add a no-alpha image */
1375     hbmImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x00ABCDEF);
1376     if(!hbmImage) goto cleanup;
1377
1378     iImage = pImageList_Add(himl, hbmImage, hbmMask);
1379     ok(iImage != -1, "ImageList_Add failed\n");
1380     if(iImage == -1) goto cleanup;
1381
1382     /* Add an alpha image */
1383     hbmAlphaImage = create_test_bitmap(hdcDst, 32, 0x89ABCDEF, 0x89ABCDEF);
1384     if(!hbmAlphaImage) goto cleanup;
1385
1386     iAlphaImage = pImageList_Add(himl, hbmAlphaImage, hbmMask);
1387     ok(iAlphaImage != -1, "ImageList_Add failed\n");
1388     if(iAlphaImage == -1) goto cleanup;
1389
1390     /* Add a transparent alpha image */
1391     hbmTransparentImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x89ABCDEF);
1392     if(!hbmTransparentImage) goto cleanup;
1393
1394     iTransparentImage = pImageList_Add(himl, hbmTransparentImage, hbmMask);
1395     ok(iTransparentImage != -1, "ImageList_Add failed\n");
1396     if(iTransparentImage == -1) goto cleanup;
1397
1398     /* 32-bit Tests */
1399     bitmapInfo.bmiHeader.biBitCount = 32;
1400     hbmDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1401     ok (hbmDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1402     if (!hbmDst || !bits)
1403         goto cleanup;
1404     hbmOld = SelectObject(hdcDst, hbmDst);
1405
1406     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_NORMAL, 0x00ABCDEF, __LINE__);
1407     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_TRANSPARENT, 0x00ABCDEF, __LINE__);
1408     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, 0x00D4D9DD, __LINE__);
1409     if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
1410     else broken_value = 0x00B4BDC4;
1411     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
1412     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_MASK, 0x00ABCDEF, __LINE__);
1413     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_IMAGE, 0x00ABCDEF, __LINE__);
1414     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_PRESERVEALPHA, 0x00ABCDEF, __LINE__);
1415
1416     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, 0x00D3E5F7, __LINE__);
1417     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_TRANSPARENT, 0x00D3E5F7, __LINE__);
1418
1419     if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
1420     else broken_value =  0x009DA8B1;
1421     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
1422     if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
1423     else broken_value =  0x008C99A3;
1424     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
1425     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_MASK, 0x00D3E5F7, __LINE__);
1426     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_IMAGE, 0x00D3E5F7, __LINE__);
1427     todo_wine check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_PRESERVEALPHA, 0x005D6F81, __LINE__);
1428
1429     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iTransparentImage, ILD_NORMAL, 0x00FFFFFF, __LINE__);
1430
1431     check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCCOPY, 0x00ABCDEF, __LINE__);
1432     check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCINVERT, 0x00543210, __LINE__);
1433
1434     /* ILD_ROP is ignored when the image has an alpha channel */
1435     check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCCOPY, 0x00D3E5F7, __LINE__);
1436     check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCINVERT, 0x00D3E5F7, __LINE__);
1437
1438     todo_wine check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00CCCCCC, __LINE__);
1439     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00AFAFAF, 0x00F0F0F0, __LINE__);
1440
1441     check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_GLOW, 0, 0x00ABCDEF, __LINE__);
1442     check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SHADOW, 0, 0x00ABCDEF, __LINE__);
1443
1444     check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00D5E6F7, __LINE__);
1445     check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00E9F2FB, 0x00AEB7C0, __LINE__);
1446     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_NORMAL, 127, 0x00E9F2FB, 0x00D3E5F7, __LINE__);
1447
1448 cleanup:
1449
1450     if(hbmOld)
1451         SelectObject(hdcDst, hbmOld);
1452     if(hbmDst)
1453         DeleteObject(hbmDst);
1454
1455     if(hdcDst)
1456         DeleteDC(hdcDst);
1457
1458     if(hbmMask)
1459         DeleteObject(hbmMask);
1460     if(hbmInverseMask)
1461         DeleteObject(hbmInverseMask);
1462
1463     if(hbmImage)
1464         DeleteObject(hbmImage);
1465     if(hbmAlphaImage)
1466         DeleteObject(hbmAlphaImage);
1467     if(hbmTransparentImage)
1468         DeleteObject(hbmTransparentImage);
1469
1470     if(himl)
1471     {
1472         ret = ImageList_Destroy(himl);
1473         ok(ret, "ImageList_Destroy failed\n");
1474     }
1475 }
1476
1477 static void test_iimagelist(void)
1478 {
1479     IImageList *imgl, *imgl2;
1480     HIMAGELIST himl;
1481     HRESULT hr;
1482     ULONG ret;
1483
1484     if (!pHIMAGELIST_QueryInterface)
1485     {
1486         win_skip("XP imagelist functions not available\n");
1487         return;
1488     }
1489
1490     /* test reference counting on destruction */
1491     imgl = (IImageList*)createImageList(32, 32);
1492     ret = IImageList_AddRef(imgl);
1493     ok(ret == 2, "Expected 2, got %d\n", ret);
1494     ret = ImageList_Destroy((HIMAGELIST)imgl);
1495     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1496     ret = ImageList_Destroy((HIMAGELIST)imgl);
1497     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1498     ret = ImageList_Destroy((HIMAGELIST)imgl);
1499     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
1500
1501     imgl = (IImageList*)createImageList(32, 32);
1502     ret = IImageList_AddRef(imgl);
1503     ok(ret == 2, "Expected 2, got %d\n", ret);
1504     ret = ImageList_Destroy((HIMAGELIST)imgl);
1505     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1506     ret = IImageList_Release(imgl);
1507     ok(ret == 0, "Expected 0, got %d\n", ret);
1508     ret = ImageList_Destroy((HIMAGELIST)imgl);
1509     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
1510
1511     /* ref counting, HIMAGELIST_QueryInterface adds a reference */
1512     imgl = (IImageList*)createImageList(32, 32);
1513     hr = pHIMAGELIST_QueryInterface((HIMAGELIST)imgl, &IID_IImageList, (void**)&imgl2);
1514     ok(hr == S_OK, "got 0x%08x\n", hr);
1515     ok(imgl2 == imgl, "got different pointer\n");
1516     ret = IImageList_Release(imgl);
1517     ok(ret == 1, "got %u\n", ret);
1518     IImageList_Release(imgl);
1519
1520     if (!pImageList_CoCreateInstance)
1521     {
1522         win_skip("Vista imagelist functions not available\n");
1523         return;
1524     }
1525
1526     hr = pImageList_CoCreateInstance(&CLSID_ImageList, NULL, &IID_IImageList, (void **) &imgl);
1527     ok(SUCCEEDED(hr), "ImageList_CoCreateInstance failed, hr=%x\n", hr);
1528
1529     if (hr == S_OK)
1530         IImageList_Release(imgl);
1531
1532     himl = createImageList(32, 32);
1533
1534     if (!himl)
1535         return;
1536
1537     hr = (pHIMAGELIST_QueryInterface)(himl, &IID_IImageList, (void **) &imgl);
1538     ok(SUCCEEDED(hr), "HIMAGELIST_QueryInterface failed, hr=%x\n", hr);
1539
1540     if (hr == S_OK)
1541         IImageList_Release(imgl);
1542
1543     ImageList_Destroy(himl);
1544 }
1545
1546 static void test_hotspot_v6(void)
1547 {
1548     struct hotspot {
1549         int dx;
1550         int dy;
1551     };
1552
1553 #define SIZEX1 47
1554 #define SIZEY1 31
1555 #define SIZEX2 11
1556 #define SIZEY2 17
1557 #define HOTSPOTS_MAX 4       /* Number of entries in hotspots */
1558     static const struct hotspot hotspots[HOTSPOTS_MAX] = {
1559         { 10, 7 },
1560         { SIZEX1, SIZEY1 },
1561         { -9, -8 },
1562         { -7, 35 }
1563     };
1564     int i, j;
1565     HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
1566     HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
1567     IImageList *imgl1, *imgl2;
1568     HRESULT hr;
1569
1570     /* cast to IImageList */
1571     imgl1 = (IImageList *) himl1;
1572     imgl2 = (IImageList *) himl2;
1573
1574     for (i = 0; i < HOTSPOTS_MAX; i++) {
1575         for (j = 0; j < HOTSPOTS_MAX; j++) {
1576             int dx1 = hotspots[i].dx;
1577             int dy1 = hotspots[i].dy;
1578             int dx2 = hotspots[j].dx;
1579             int dy2 = hotspots[j].dy;
1580             int correctx, correcty, newx, newy;
1581             char loc[256];
1582             IImageList *imglNew;
1583             POINT ppt;
1584
1585             hr = IImageList_BeginDrag(imgl1, 0, dx1, dy1);
1586             ok(SUCCEEDED(hr), "BeginDrag failed for { %d, %d }\n", dx1, dy1);
1587             sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
1588
1589             /* check merging the dragged image with a second image */
1590             hr = IImageList_SetDragCursorImage(imgl2, (IUnknown *) imgl2, 0, dx2, dy2);
1591             ok(SUCCEEDED(hr), "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
1592                     dx1, dy1, dx2, dy2);
1593             sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
1594
1595             /* check new hotspot, it should be the same like the old one */
1596             hr = IImageList_GetDragImage(imgl2, NULL, &ppt, &IID_IImageList, (PVOID *) &imglNew);
1597             ok(SUCCEEDED(hr), "GetDragImage failed\n");
1598             ok(ppt.x == dx1 && ppt.y == dy1,
1599                     "Expected drag hotspot [%d,%d] got [%d,%d]\n",
1600                     dx1, dy1, ppt.x, ppt.y);
1601             /* check size of new dragged image */
1602             IImageList_GetIconSize(imglNew, &newx, &newy);
1603             correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
1604             correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
1605             ok(newx == correctx && newy == correcty,
1606                     "Expected drag image size [%d,%d] got [%d,%d]\n",
1607                     correctx, correcty, newx, newy);
1608             sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
1609             IImageList_EndDrag(imgl2);
1610         }
1611     }
1612 #undef SIZEX1
1613 #undef SIZEY1
1614 #undef SIZEX2
1615 #undef SIZEY2
1616 #undef HOTSPOTS_MAX
1617     IImageList_Release(imgl2);
1618     IImageList_Release(imgl1);
1619 }
1620
1621 static void test_IImageList_Add_Remove(void)
1622 {
1623     IImageList *imgl;
1624     HIMAGELIST himl;
1625     HRESULT hr;
1626
1627     HICON hicon1;
1628     HICON hicon2;
1629     HICON hicon3;
1630
1631     int ret;
1632
1633     /* create an imagelist to play with */
1634     himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
1635     ok(himl != 0,"failed to create imagelist\n");
1636
1637     imgl = (IImageList *) himl;
1638
1639     /* load the icons to add to the image list */
1640     hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1641     ok(hicon1 != 0, "no hicon1\n");
1642     hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1643     ok(hicon2 != 0, "no hicon2\n");
1644     hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1645     ok(hicon3 != 0, "no hicon3\n");
1646
1647     /* remove when nothing exists */
1648     hr = IImageList_Remove(imgl, 0);
1649     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1650
1651     /* removing everything from an empty imagelist should succeed */
1652     hr = IImageList_Remove(imgl, -1);
1653     ok(hr == S_OK, "removed nonexistent icon\n");
1654
1655     /* add three */
1656     ret = -1;
1657     ok( IImageList_ReplaceIcon(imgl, -1, hicon1, &ret) == S_OK && (ret == 0),"failed to add icon1\n");
1658     ret = -1;
1659     ok( IImageList_ReplaceIcon(imgl, -1, hicon2, &ret) == S_OK && (ret == 1),"failed to add icon2\n");
1660     ret = -1;
1661     ok( IImageList_ReplaceIcon(imgl, -1, hicon3, &ret) == S_OK && (ret == 2),"failed to add icon3\n");
1662
1663     /* remove an index out of range */
1664     ok( IImageList_Remove(imgl, 4711) == E_INVALIDARG, "got 0x%08x\n", hr);
1665
1666     /* remove three */
1667     ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
1668     ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
1669     ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
1670
1671     /* remove one extra */
1672     ok( IImageList_Remove(imgl, 0) == E_INVALIDARG, "got 0x%08x\n", hr);
1673
1674     IImageList_Release(imgl);
1675     ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
1676     ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
1677     ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
1678 }
1679
1680 static void test_IImageList_Get_SetImageCount(void)
1681 {
1682     IImageList *imgl;
1683     HIMAGELIST himl;
1684     HRESULT hr;
1685     INT ret;
1686
1687     /* create an imagelist to play with */
1688     himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
1689     ok(himl != 0,"failed to create imagelist\n");
1690
1691     imgl = (IImageList *) himl;
1692
1693     /* check SetImageCount/GetImageCount */
1694     hr = IImageList_SetImageCount(imgl, 3);
1695     ok(hr == S_OK, "got 0x%08x\n", hr);
1696     ret = 0;
1697     hr = IImageList_GetImageCount(imgl, &ret);
1698     ok(hr == S_OK && ret == 3, "invalid image count after increase\n");
1699     hr = IImageList_SetImageCount(imgl, 1);
1700     ok(hr == S_OK, "got 0x%08x\n", hr);
1701     ret = 0;
1702     hr = IImageList_GetImageCount(imgl, &ret);
1703     ok(hr == S_OK && ret == 1, "invalid image count after decrease to 1\n");
1704     hr = IImageList_SetImageCount(imgl, 0);
1705     ok(hr == S_OK, "got 0x%08x\n", hr);
1706     ret = -1;
1707     hr = IImageList_GetImageCount(imgl, &ret);
1708     ok(hr == S_OK && ret == 0, "invalid image count after decrease to 0\n");
1709
1710     IImageList_Release(imgl);
1711 }
1712
1713 static void test_IImageList_Draw(void)
1714 {
1715     IImageList *imgl;
1716     HIMAGELIST himl;
1717
1718     HBITMAP hbm1;
1719     HBITMAP hbm2;
1720     HBITMAP hbm3;
1721
1722     IMAGELISTDRAWPARAMS imldp;
1723     HWND hwndfortest;
1724     HRESULT hr;
1725     HDC hdc;
1726     int ret;
1727
1728     hwndfortest = create_a_window();
1729     hdc = GetDC(hwndfortest);
1730     ok(hdc!=NULL, "couldn't get DC\n");
1731
1732     /* create an imagelist to play with */
1733     himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3);
1734     ok(himl!=0,"failed to create imagelist\n");
1735
1736     imgl = (IImageList *) himl;
1737
1738     /* load the icons to add to the image list */
1739     hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
1740     ok(hbm1 != 0, "no bitmap 1\n");
1741     hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
1742     ok(hbm2 != 0, "no bitmap 2\n");
1743     hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
1744     ok(hbm3 != 0, "no bitmap 3\n");
1745
1746     /* add three */
1747     ret = -1;
1748     ok( IImageList_Add(imgl, hbm1, 0, &ret) == S_OK && (ret == 0), "failed to add bitmap 1\n");
1749     ret = -1;
1750     ok( IImageList_Add(imgl, hbm2, 0, &ret) == S_OK && (ret == 1), "failed to add bitmap 2\n");
1751
1752     ok( IImageList_SetImageCount(imgl, 3) == S_OK, "Setimage count failed\n");
1753     ok( IImageList_Replace(imgl, 2, hbm3, 0) == S_OK, "failed to replace bitmap 3\n");
1754
1755 if (0)
1756 {
1757     /* crashes on native */
1758     IImageList_Draw(imgl, NULL);
1759 }
1760
1761     memset(&imldp, 0, sizeof (imldp));
1762     hr = IImageList_Draw(imgl, &imldp);
1763     ok( hr == E_INVALIDARG, "got 0x%08x\n", hr);
1764
1765     imldp.cbSize = IMAGELISTDRAWPARAMS_V3_SIZE;
1766     imldp.hdcDst = hdc;
1767     imldp.himl = himl;
1768
1769     REDRAW(hwndfortest);
1770     WAIT;
1771
1772     imldp.fStyle = SRCCOPY;
1773     imldp.rgbBk = CLR_DEFAULT;
1774     imldp.rgbFg = CLR_DEFAULT;
1775     imldp.y = 100;
1776     imldp.x = 100;
1777     ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1778     imldp.i ++;
1779     ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1780     imldp.i ++;
1781     ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1782     imldp.i ++;
1783     ok( IImageList_Draw(imgl, &imldp) == E_INVALIDARG, "should fail\n");
1784
1785     /* remove three */
1786     ok( IImageList_Remove(imgl, 0) == S_OK, "removing 1st bitmap\n");
1787     ok( IImageList_Remove(imgl, 0) == S_OK, "removing 2nd bitmap\n");
1788     ok( IImageList_Remove(imgl, 0) == S_OK, "removing 3rd bitmap\n");
1789
1790     /* destroy it */
1791     IImageList_Release(imgl);
1792
1793     /* bitmaps should not be deleted by the imagelist */
1794     ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
1795     ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
1796     ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");
1797
1798     ReleaseDC(hwndfortest, hdc);
1799     DestroyWindow(hwndfortest);
1800 }
1801
1802 static void test_IImageList_Merge(void)
1803 {
1804     HIMAGELIST himl1, himl2;
1805     IImageList *imgl1, *imgl2, *merge;
1806     HICON hicon1;
1807     HWND hwnd = create_a_window();
1808     HRESULT hr;
1809     int ret;
1810
1811     himl1 = ImageList_Create(32,32,0,0,3);
1812     ok(himl1 != NULL,"failed to create himl1\n");
1813
1814     himl2 = ImageList_Create(32,32,0,0,3);
1815     ok(himl2 != NULL,"failed to create himl2\n");
1816
1817     hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1818     ok(hicon1 != NULL, "failed to create hicon1\n");
1819
1820     if (!himl1 || !himl2 || !hicon1)
1821         return;
1822
1823     /* cast to IImageList */
1824     imgl1 = (IImageList *) himl1;
1825     imgl2 = (IImageList *) himl2;
1826
1827     ret = -1;
1828     ok( IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret) == S_OK && (ret == 0),"add icon1 to himl2 failed\n");
1829
1830 if (0)
1831 {
1832     /* null cases that crash on native */
1833     IImageList_Merge(imgl1, -1, NULL, 0, 0, 0, &IID_IImageList, (void**)&merge);
1834     IImageList_Merge(imgl1, -1, (IUnknown*) imgl2, 0, 0, 0, &IID_IImageList, NULL);
1835 }
1836
1837     /* If himl1 has no images, merge still succeeds */
1838     hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1839     ok(hr == S_OK, "merge himl1,-1 failed\n");
1840     if (hr == S_OK) IImageList_Release(merge);
1841
1842     hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1843     ok(hr == S_OK, "merge himl1,0 failed\n");
1844     if (hr == S_OK) IImageList_Release(merge);
1845
1846     /* Same happens if himl2 is empty */
1847     IImageList_Release(imgl2);
1848     himl2 = ImageList_Create(32,32,0,0,3);
1849     ok(himl2 != NULL,"failed to recreate himl2\n");
1850
1851     imgl2 = (IImageList *) himl2;
1852
1853     hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, -1, 0, 0, &IID_IImageList, (void **) &merge);
1854     ok(hr == S_OK, "merge himl2,-1 failed\n");
1855     if (hr == S_OK) IImageList_Release(merge);
1856
1857     hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1858     ok(hr == S_OK, "merge himl2,0 failed\n");
1859     if (hr == S_OK) IImageList_Release(merge);
1860
1861     /* Now try merging an image with itself */
1862     ret = -1;
1863     ok( IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret) == S_OK && (ret == 0),"re-add icon1 to himl2 failed\n");
1864
1865     hr = IImageList_Merge(imgl2, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1866     ok(hr == S_OK, "merge himl2 with itself failed\n");
1867     if (hr == S_OK) IImageList_Release(merge);
1868
1869     /* Try merging 2 different image lists */
1870     ret = -1;
1871     ok( IImageList_ReplaceIcon(imgl1, -1, hicon1, &ret) == S_OK && (ret == 0),"add icon1 to himl1 failed\n");
1872
1873     hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1874     ok(hr == S_OK, "merge himl1 with himl2 failed\n");
1875     if (hr == S_OK) IImageList_Release(merge);
1876
1877     hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 8, 16, &IID_IImageList, (void **) &merge);
1878     ok(hr == S_OK, "merge himl1 with himl2 8,16 failed\n");
1879     if (hr == S_OK) IImageList_Release(merge);
1880
1881     IImageList_Release(imgl1);
1882     IImageList_Release(imgl2);
1883
1884     DestroyIcon(hicon1);
1885     DestroyWindow(hwnd);
1886 }
1887
1888 static void test_iconsize(void)
1889 {
1890     HIMAGELIST himl;
1891     INT cx, cy;
1892     BOOL ret;
1893
1894     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1895     /* null pointers, not zero imagelist dimensions */
1896     ret = ImageList_GetIconSize(himl, NULL, NULL);
1897     ok(!ret, "got %d\n", ret);
1898
1899     /* doesn't touch return pointers */
1900     cx = 0x1abe11ed;
1901     ret = ImageList_GetIconSize(himl, &cx, NULL);
1902     ok(!ret, "got %d\n", ret);
1903     ok(cx == 0x1abe11ed, "got %d\n", cx);
1904
1905     cy = 0x1abe11ed;
1906     ret = ImageList_GetIconSize(himl, NULL, &cy);
1907     ok(!ret, "got %d\n", ret);
1908     ok(cy == 0x1abe11ed, "got %d\n", cy);
1909
1910     ImageList_Destroy(himl);
1911
1912     ret = ImageList_GetIconSize((HIMAGELIST)0xdeadbeef, &cx, &cy);
1913     ok(!ret, "got %d\n", ret);
1914 }
1915
1916 static void test_create_destroy(void)
1917 {
1918     HIMAGELIST himl;
1919     BOOL rc;
1920
1921     /* list with zero or negative image dimensions */
1922     himl = ImageList_Create(0, 0, ILC_COLOR16, 0, 3);
1923     ok(himl == NULL, "got %p\n", himl);
1924
1925     himl = ImageList_Create(0, 16, ILC_COLOR16, 0, 3);
1926     ok(himl == NULL, "got %p\n", himl);
1927
1928     himl = ImageList_Create(16, 0, ILC_COLOR16, 0, 3);
1929     ok(himl == NULL, "got %p\n", himl);
1930
1931     himl = ImageList_Create(16, -1, ILC_COLOR16, 0, 3);
1932     ok(himl == NULL, "got %p\n", himl);
1933
1934     himl = ImageList_Create(-1, 16, ILC_COLOR16, 0, 3);
1935     ok(himl == NULL, "got %p\n", himl);
1936
1937     rc = ImageList_Destroy((HIMAGELIST)0xdeadbeef);
1938     ok(rc == FALSE, "ImageList_Destroy(0xdeadbeef) should fail and not crash\n");
1939 }
1940
1941 static void test_IImageList_Clone(void)
1942 {
1943     IImageList *imgl, *imgl2;
1944     HIMAGELIST himl;
1945     HRESULT hr;
1946     ULONG ref;
1947
1948     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1949     imgl = (IImageList*)himl;
1950
1951 if (0)
1952 {
1953     /* crashes on native */
1954     IImageList_Clone(imgl, &IID_IImageList, NULL);
1955 }
1956
1957     hr = IImageList_Clone(imgl, &IID_IImageList, (void**)&imgl2);
1958     ok(hr == S_OK, "got 0x%08x\n", hr);
1959     ref = IImageList_Release(imgl2);
1960     ok(ref == 0, "got %u\n", ref);
1961
1962     IImageList_Release(imgl);
1963 }
1964
1965 static void test_IImageList_GetBkColor(void)
1966 {
1967     IImageList *imgl;
1968     HIMAGELIST himl;
1969     COLORREF color;
1970     HRESULT hr;
1971
1972     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1973     imgl = (IImageList*)himl;
1974
1975 if (0)
1976 {
1977     /* crashes on native */
1978     IImageList_GetBkColor(imgl, NULL);
1979 }
1980
1981     hr = IImageList_GetBkColor(imgl, &color);
1982     ok(hr == S_OK, "got 0x%08x\n", hr);
1983
1984     IImageList_Release(imgl);
1985 }
1986
1987 static void test_IImageList_SetBkColor(void)
1988 {
1989     IImageList *imgl;
1990     HIMAGELIST himl;
1991     COLORREF color;
1992     HRESULT hr;
1993
1994     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1995     imgl = (IImageList*)himl;
1996
1997 if (0)
1998 {
1999     /* crashes on native */
2000     IImageList_SetBkColor(imgl, RGB(0, 0, 0), NULL);
2001 }
2002
2003     hr = IImageList_SetBkColor(imgl, CLR_NONE, &color);
2004     ok(hr == S_OK, "got 0x%08x\n", hr);
2005
2006     hr = IImageList_SetBkColor(imgl, CLR_NONE, &color);
2007     ok(hr == S_OK, "got 0x%08x\n", hr);
2008
2009     color = 0xdeadbeef;
2010     hr = IImageList_GetBkColor(imgl, &color);
2011     ok(hr == S_OK, "got 0x%08x\n", hr);
2012     ok(color == CLR_NONE, "got %x\n", color);
2013
2014     IImageList_Release(imgl);
2015 }
2016
2017 static void test_IImageList_GetImageCount(void)
2018 {
2019     IImageList *imgl;
2020     HIMAGELIST himl;
2021     int count;
2022     HRESULT hr;
2023
2024     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
2025     imgl = (IImageList*)himl;
2026
2027 if (0)
2028 {
2029     /* crashes on native */
2030     IImageList_GetImageCount(imgl, NULL);
2031 }
2032
2033     count = -1;
2034     hr = IImageList_GetImageCount(imgl, &count);
2035     ok(hr == S_OK, "got 0x%08x\n", hr);
2036     ok(count == 0, "got %d\n", count);
2037
2038     IImageList_Release(imgl);
2039 }
2040
2041 static void test_IImageList_GetIconSize(void)
2042 {
2043     IImageList *imgl;
2044     HIMAGELIST himl;
2045     int cx, cy;
2046     HRESULT hr;
2047
2048     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
2049     imgl = (IImageList*)himl;
2050
2051     hr = IImageList_GetIconSize(imgl, NULL, NULL);
2052     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2053
2054     hr = IImageList_GetIconSize(imgl, &cx, NULL);
2055     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2056
2057     hr = IImageList_GetIconSize(imgl, NULL, &cy);
2058     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2059
2060     IImageList_Release(imgl);
2061 }
2062
2063 START_TEST(imagelist)
2064 {
2065     ULONG_PTR ctx_cookie;
2066     HANDLE hCtx;
2067
2068     HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
2069     pImageList_Create = NULL;   /* These are not needed for non-v6.0 tests*/
2070     pImageList_Add = NULL;
2071     pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
2072     pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
2073
2074     hinst = GetModuleHandleA(NULL);
2075
2076     InitCommonControls();
2077
2078     test_create_destroy();
2079     test_hotspot();
2080     test_add_remove();
2081     test_imagecount();
2082     test_DrawIndirect();
2083     test_merge();
2084     test_merge_colors();
2085     test_imagelist_storage();
2086     test_iconsize();
2087
2088     FreeLibrary(hComCtl32);
2089
2090     /* Now perform v6 tests */
2091
2092     if (!load_v6_module(&ctx_cookie, &hCtx))
2093         return;
2094
2095     /* Reload comctl32 */
2096     hComCtl32 = LoadLibraryA("comctl32.dll");
2097     pImageList_Create = (void*)GetProcAddress(hComCtl32, "ImageList_Create");
2098     pImageList_Add = (void*)GetProcAddress(hComCtl32, "ImageList_Add");
2099     pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
2100     pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
2101     pImageList_CoCreateInstance = (void*)GetProcAddress(hComCtl32, "ImageList_CoCreateInstance");
2102     pHIMAGELIST_QueryInterface = (void*)GetProcAddress(hComCtl32, "HIMAGELIST_QueryInterface");
2103
2104     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2105
2106     /* Do v6.0 tests */
2107     test_ImageList_DrawIndirect();
2108     test_shell_imagelist();
2109     test_iimagelist();
2110
2111     test_hotspot_v6();
2112     test_IImageList_Add_Remove();
2113     test_IImageList_Get_SetImageCount();
2114     test_IImageList_Draw();
2115     test_IImageList_Merge();
2116     test_IImageList_Clone();
2117     test_IImageList_GetBkColor();
2118     test_IImageList_SetBkColor();
2119     test_IImageList_GetImageCount();
2120     test_IImageList_GetIconSize();
2121
2122     CoUninitialize();
2123
2124     unload_v6_module(ctx_cookie, hCtx);
2125 }