comctl32: Test and fix WM_GETTEXTLENGTH for statusbars.
[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 void test_merge(void)
496 {
497     HIMAGELIST himl1, himl2, hmerge;
498     HICON hicon1;
499     HWND hwnd = create_a_window();
500
501     himl1 = ImageList_Create(32,32,0,0,3);
502     ok(himl1 != NULL,"failed to create himl1\n");
503
504     himl2 = ImageList_Create(32,32,0,0,3);
505     ok(himl2 != NULL,"failed to create himl2\n");
506
507     hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
508     ok(hicon1 != NULL, "failed to create hicon1\n");
509
510     if (!himl1 || !himl2 || !hicon1)
511         return;
512
513     ok(0==ImageList_AddIcon(himl2, hicon1),"add icon1 to himl2 failed\n");
514     check_bits(hwnd, himl2, 0, 32, icon_bits, "add icon1 to himl2");
515
516     /* If himl1 has no images, merge still succeeds */
517     hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
518     ok(hmerge != NULL, "merge himl1,-1 failed\n");
519     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,-1");
520     if (hmerge) ImageList_Destroy(hmerge);
521
522     hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
523     ok(hmerge != NULL,"merge himl1,0 failed\n");
524     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,0");
525     if (hmerge) ImageList_Destroy(hmerge);
526
527     /* Same happens if himl2 is empty */
528     ImageList_Destroy(himl2);
529     himl2 = ImageList_Create(32,32,0,0,3);
530     ok(himl2 != NULL,"failed to recreate himl2\n");
531     if (!himl2)
532         return;
533
534     hmerge = ImageList_Merge(himl1, -1, himl2, -1, 0, 0);
535     ok(hmerge != NULL, "merge himl2,-1 failed\n");
536     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,-1");
537     if (hmerge) ImageList_Destroy(hmerge);
538
539     hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
540     ok(hmerge != NULL, "merge himl2,0 failed\n");
541     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,0");
542     if (hmerge) ImageList_Destroy(hmerge);
543
544     /* Now try merging an image with itself */
545     ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n");
546
547     hmerge = ImageList_Merge(himl2, 0, himl2, 0, 0, 0);
548     ok(hmerge != NULL, "merge himl2 with itself failed\n");
549     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2 with itself");
550     if (hmerge) ImageList_Destroy(hmerge);
551
552     /* Try merging 2 different image lists */
553     ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n");
554
555     hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
556     ok(hmerge != NULL, "merge himl1 with himl2 failed\n");
557     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2");
558     if (hmerge) ImageList_Destroy(hmerge);
559
560     hmerge = ImageList_Merge(himl1, 0, himl2, 0, 8, 16);
561     ok(hmerge != NULL, "merge himl1 with himl2 8,16 failed\n");
562     check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2, 8,16");
563     if (hmerge) ImageList_Destroy(hmerge);
564
565     ImageList_Destroy(himl1);
566     ImageList_Destroy(himl2);
567     DestroyIcon(hicon1);
568     DestroyWindow(hwnd);
569 }
570
571 /*********************** imagelist storage test ***************************/
572
573 #define BMP_CX 48
574
575 struct my_IStream
576 {
577     IStream IStream_iface;
578     char *iml_data; /* written imagelist data */
579     ULONG iml_data_size;
580 };
581
582 static struct my_IStream *impl_from_IStream(IStream *iface)
583 {
584     return CONTAINING_RECORD(iface, struct my_IStream, IStream_iface);
585 }
586
587 static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface(IStream *iface, REFIID riid,
588                                                             void **ppvObject)
589 {
590     assert(0);
591     return E_NOTIMPL;
592 }
593
594 static ULONG STDMETHODCALLTYPE Test_Stream_AddRef(IStream *iface)
595 {
596     assert(0);
597     return 2;
598 }
599
600 static ULONG STDMETHODCALLTYPE Test_Stream_Release(IStream *iface)
601 {
602     assert(0);
603     return 1;
604 }
605
606 static HRESULT STDMETHODCALLTYPE Test_Stream_Read(IStream *iface, void *pv, ULONG cb,
607                                                   ULONG *pcbRead)
608 {
609     assert(0);
610     return E_NOTIMPL;
611 }
612
613 static BOOL allocate_storage(struct my_IStream *my_is, ULONG add)
614 {
615     my_is->iml_data_size += add;
616
617     if (!my_is->iml_data)
618         my_is->iml_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data_size);
619     else
620         my_is->iml_data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data, my_is->iml_data_size);
621
622     return my_is->iml_data ? TRUE : FALSE;
623 }
624
625 static HRESULT STDMETHODCALLTYPE Test_Stream_Write(IStream *iface, const void *pv, ULONG cb,
626                                                    ULONG *pcbWritten)
627 {
628     struct my_IStream *my_is = impl_from_IStream(iface);
629     ULONG current_iml_data_size = my_is->iml_data_size;
630
631     if (!allocate_storage(my_is, cb)) return E_FAIL;
632
633     memcpy(my_is->iml_data + current_iml_data_size, pv, cb);
634     if (pcbWritten) *pcbWritten = cb;
635
636     return S_OK;
637 }
638
639 static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
640                                                   DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
641 {
642     assert(0);
643     return E_NOTIMPL;
644 }
645
646 static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
647 {
648     assert(0);
649     return E_NOTIMPL;
650 }
651
652 static HRESULT STDMETHODCALLTYPE Test_Stream_CopyTo(IStream *iface, IStream *pstm,
653                                                     ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead,
654                                                     ULARGE_INTEGER *pcbWritten)
655 {
656     assert(0);
657     return E_NOTIMPL;
658 }
659
660 static HRESULT STDMETHODCALLTYPE Test_Stream_Commit(IStream *iface, DWORD grfCommitFlags)
661 {
662     assert(0);
663     return E_NOTIMPL;
664 }
665
666 static HRESULT STDMETHODCALLTYPE Test_Stream_Revert(IStream *iface)
667 {
668     assert(0);
669     return E_NOTIMPL;
670 }
671
672 static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
673                                                         ULARGE_INTEGER cb, DWORD dwLockType)
674 {
675     assert(0);
676     return E_NOTIMPL;
677 }
678
679 static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
680                                                           ULARGE_INTEGER cb, DWORD dwLockType)
681 {
682     assert(0);
683     return E_NOTIMPL;
684 }
685
686 static HRESULT STDMETHODCALLTYPE Test_Stream_Stat(IStream *iface, STATSTG *pstatstg,
687                                                   DWORD grfStatFlag)
688 {
689     assert(0);
690     return E_NOTIMPL;
691 }
692
693 static HRESULT STDMETHODCALLTYPE Test_Stream_Clone(IStream *iface, IStream **ppstm)
694 {
695     assert(0);
696     return E_NOTIMPL;
697 }
698
699 static const IStreamVtbl Test_Stream_Vtbl =
700 {
701     Test_Stream_QueryInterface,
702     Test_Stream_AddRef,
703     Test_Stream_Release,
704     Test_Stream_Read,
705     Test_Stream_Write,
706     Test_Stream_Seek,
707     Test_Stream_SetSize,
708     Test_Stream_CopyTo,
709     Test_Stream_Commit,
710     Test_Stream_Revert,
711     Test_Stream_LockRegion,
712     Test_Stream_UnlockRegion,
713     Test_Stream_Stat,
714     Test_Stream_Clone
715 };
716
717 static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 };
718
719 static INT DIB_GetWidthBytes( int width, int bpp )
720 {
721     return ((width * bpp + 31) / 8) & ~3;
722 }
723
724 static ULONG check_bitmap_data(const char *bm_data, ULONG bm_data_size,
725                                INT width, INT height, INT bpp,
726                                const char *comment)
727 {
728     const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data;
729     const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh));
730     ULONG hdr_size, image_size;
731
732     hdr_size = sizeof(*bmfh) + sizeof(*bmih);
733     if (bmih->biBitCount <= 8) hdr_size += (1 << bpp) * sizeof(RGBQUAD);
734
735     ok(bmfh->bfType == (('M' << 8) | 'B'), "wrong bfType 0x%02x\n", bmfh->bfType);
736     ok(bmfh->bfSize == hdr_size, "wrong bfSize 0x%02x\n", bmfh->bfSize);
737     ok(bmfh->bfReserved1 == 0, "wrong bfReserved1 0x%02x\n", bmfh->bfReserved1);
738     ok(bmfh->bfReserved2 == 0, "wrong bfReserved2 0x%02x\n", bmfh->bfReserved2);
739     ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits);
740
741     ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize);
742     ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width);
743     ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height);
744     ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes);
745     ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount);
746
747     image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight;
748     ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage);
749 #if 0
750 {
751     char fname[256];
752     FILE *f;
753     sprintf(fname, "bmp_%s.bmp", comment);
754     f = fopen(fname, "wb");
755     fwrite(bm_data, 1, bm_data_size, f);
756     fclose(f);
757 }
758 #endif
759     return hdr_size + image_size;
760 }
761
762 static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max, INT grow, INT flags)
763 {
764     const ILHEAD *ilh = (const ILHEAD *)ilh_data;
765
766     ok(ilh->usMagic == IMAGELIST_MAGIC, "wrong usMagic %4x (expected %02x)\n", ilh->usMagic, IMAGELIST_MAGIC);
767     ok(ilh->usVersion == 0x101, "wrong usVersion %x (expected 0x101)\n", ilh->usVersion);
768     ok(ilh->cCurImage == cur, "wrong cCurImage %d (expected %d)\n", ilh->cCurImage, cur);
769     ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
770     ok(ilh->cGrow == grow, "wrong cGrow %d (expected %d)\n", ilh->cGrow, grow);
771     ok(ilh->cx == cx, "wrong cx %d (expected %d)\n", ilh->cx, cx);
772     ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy);
773     ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor);
774     ok(ilh->flags == flags || broken(!(ilh->flags & 0xfe) && (flags & 0xfe) == ILC_COLOR4),  /* <= w2k */
775        "wrong flags %04x\n", ilh->flags);
776     ok(ilh->ovls[0] == -1, "wrong ovls[0] %04x\n", ilh->ovls[0]);
777     ok(ilh->ovls[1] == -1, "wrong ovls[1] %04x\n", ilh->ovls[1]);
778     ok(ilh->ovls[2] == -1, "wrong ovls[2] %04x\n", ilh->ovls[2]);
779     ok(ilh->ovls[3] == -1, "wrong ovls[3] %04x\n", ilh->ovls[3]);
780 }
781
782 static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment)
783 {
784     HDC hdc;
785     char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
786     BITMAPINFO *bmi = (BITMAPINFO *)bmibuf;
787     HBITMAP hbmp, hbmp_old;
788     HBRUSH hbrush;
789     RECT rc = { 0, 0, cx, cy };
790
791     hdc = CreateCompatibleDC(0);
792
793     memset(bmi, 0, sizeof(*bmi));
794     bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
795     bmi->bmiHeader.biHeight = cx;
796     bmi->bmiHeader.biWidth = cy;
797     bmi->bmiHeader.biBitCount = 24;
798     bmi->bmiHeader.biPlanes = 1;
799     bmi->bmiHeader.biCompression = BI_RGB;
800     hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
801
802     hbmp_old = SelectObject(hdc, hbmp);
803
804     hbrush = CreateSolidBrush(color);
805     FillRect(hdc, &rc, hbrush);
806     DeleteObject(hbrush);
807
808     DrawText(hdc, comment, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
809
810     SelectObject(hdc, hbmp_old);
811     DeleteDC(hdc);
812
813     return hbmp;
814 }
815
816 #define iml_clear_stream_data() \
817     HeapFree(GetProcessHeap(), 0, Test_Stream.iml_data); \
818     Test_Stream.iml_data = NULL; \
819     Test_Stream.iml_data_size = 0;
820
821 static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max, INT grow,
822                            INT width, INT height, INT flags, const char *comment)
823 {
824     INT ret, cxx, cyy, size;
825
826     trace("%s\n", comment);
827
828     ret = ImageList_GetImageCount(himl);
829     ok(ret == cur, "expected image count %d got %d\n", cur, ret);
830
831     ret = ImageList_GetIconSize(himl, &cxx, &cyy);
832     ok(ret, "ImageList_GetIconSize failed\n");
833     ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx);
834     ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy);
835
836     iml_clear_stream_data();
837     ret = ImageList_Write(himl, &Test_Stream.IStream_iface);
838     ok(ret, "ImageList_Write failed\n");
839
840     ok(Test_Stream.iml_data != 0, "ImageList_Write didn't write any data\n");
841     ok(Test_Stream.iml_data_size > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n");
842
843     check_ilhead_data(Test_Stream.iml_data, cx, cy, cur, max, grow, flags);
844     size = check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD),
845                              Test_Stream.iml_data_size - sizeof(ILHEAD),
846                              width, height, flags & 0xfe, comment);
847     if (size < Test_Stream.iml_data_size - sizeof(ILHEAD))  /* mask is present */
848     {
849         ok( flags & ILC_MASK, "extra data %u/%u but mask not expected\n",
850             Test_Stream.iml_data_size, size );
851         check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD) + size,
852                           Test_Stream.iml_data_size - sizeof(ILHEAD) - size,
853                           width, height, 1, comment);
854     }
855 }
856
857 static void image_list_init(HIMAGELIST himl)
858 {
859     HBITMAP hbm;
860     char comment[16];
861     INT n = 1;
862     DWORD i;
863     static const struct test_data
864     {
865         BYTE grey;
866         INT cx, cy, cur, max, grow, width, height, bpp;
867         const char *comment;
868     } td[] =
869     {
870         { 255, BMP_CX, BMP_CX, 1, 2, 4, BMP_CX * 4, BMP_CX * 1, 24, "total 1" },
871         { 170, BMP_CX, BMP_CX, 2, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 2" },
872         { 85, BMP_CX, BMP_CX, 3, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 3" },
873         { 0, BMP_CX, BMP_CX, 4, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 4" },
874         { 0, BMP_CX, BMP_CX, 5, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 5" },
875         { 85, BMP_CX, BMP_CX, 6, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 6" },
876         { 170, BMP_CX, BMP_CX, 7, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 7" },
877         { 255, BMP_CX, BMP_CX, 8, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 8" },
878         { 255, BMP_CX, BMP_CX, 9, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 9" },
879         { 170, BMP_CX, BMP_CX, 10, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 10" },
880         { 85, BMP_CX, BMP_CX, 11, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 11" },
881         { 0, BMP_CX, BMP_CX, 12, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 12" },
882         { 0, BMP_CX, BMP_CX, 13, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 13" },
883         { 85, BMP_CX, BMP_CX, 14, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 14" },
884         { 170, BMP_CX, BMP_CX, 15, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 15" },
885         { 255, BMP_CX, BMP_CX, 16, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 16" },
886         { 255, BMP_CX, BMP_CX, 17, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 17" },
887         { 170, BMP_CX, BMP_CX, 18, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 18" },
888         { 85, BMP_CX, BMP_CX, 19, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 19" },
889         { 0, BMP_CX, BMP_CX, 20, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 20" },
890         { 0, BMP_CX, BMP_CX, 21, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 21" },
891         { 85, BMP_CX, BMP_CX, 22, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 22" },
892         { 170, BMP_CX, BMP_CX, 23, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 23" },
893         { 255, BMP_CX, BMP_CX, 24, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 24" }
894     };
895
896     check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "total 0");
897
898 #define add_bitmap(grey) \
899     sprintf(comment, "%d", n++); \
900     hbm = create_bitmap(BMP_CX, BMP_CX, RGB((grey),(grey),(grey)), comment); \
901     ImageList_Add(himl, hbm, NULL); \
902     DeleteObject(hbm);
903
904     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
905     {
906         add_bitmap(td[i].grey);
907         check_iml_data(himl, td[i].cx, td[i].cy, td[i].cur, td[i].max, td[i].grow,
908                        td[i].width, td[i].height, td[i].bpp, td[i].comment);
909     }
910 #undef add_bitmap
911 }
912
913 static void test_imagelist_storage(void)
914 {
915     HIMAGELIST himl;
916     HBITMAP hbm;
917     HICON icon;
918     INT ret;
919
920     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
921     ok(himl != 0, "ImageList_Create failed\n");
922
923     check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "empty");
924
925     image_list_init(himl);
926     check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "orig");
927
928     ret = ImageList_Remove(himl, 4);
929     ok(ret, "ImageList_Remove failed\n");
930     check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "1");
931
932     ret = ImageList_Remove(himl, 5);
933     ok(ret, "ImageList_Remove failed\n");
934     check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "2");
935
936     ret = ImageList_Remove(himl, 6);
937     ok(ret, "ImageList_Remove failed\n");
938     check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "3");
939
940     ret = ImageList_Remove(himl, 7);
941     ok(ret, "ImageList_Remove failed\n");
942     check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "4");
943
944     ret = ImageList_Remove(himl, -2);
945     ok(!ret, "ImageList_Remove(-2) should fail\n");
946     check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "5");
947
948     ret = ImageList_Remove(himl, 20);
949     ok(!ret, "ImageList_Remove(20) should fail\n");
950     check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "6");
951
952     ret = ImageList_Remove(himl, -1);
953     ok(ret, "ImageList_Remove(-1) failed\n");
954     check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "7");
955
956     ret = ImageList_Destroy(himl);
957     ok(ret, "ImageList_Destroy failed\n");
958
959     iml_clear_stream_data();
960
961     /* test ImageList_Create storage allocation */
962
963     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 0, 32);
964     ok(himl != 0, "ImageList_Create failed\n");
965     check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 32, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "init 0 grow 32");
966     hbm = create_bitmap(BMP_CX * 9, BMP_CX, 0, "9");
967     ret = ImageList_Add(himl, hbm, NULL);
968     ok(ret == 0, "ImageList_Add returned %d, expected 0\n", ret);
969     check_iml_data(himl, BMP_CX, BMP_CX, 1, 34, 32, BMP_CX * 4, BMP_CX * 9, ILC_COLOR24, "add 1 x 9");
970     DeleteObject(hbm);
971     ret = ImageList_Destroy(himl);
972     ok(ret, "ImageList_Destroy failed\n");
973     iml_clear_stream_data();
974
975     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 4);
976     ok(himl != 0, "ImageList_Create failed\n");
977     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 4 grow 4");
978     hbm = create_bitmap(BMP_CX, BMP_CX * 9, 0, "9");
979     ret = ImageList_Add(himl, hbm, NULL);
980     ok(ret == 0, "ImageList_Add returned %d, expected 0\n", ret);
981     check_iml_data(himl, BMP_CX, BMP_CX, 9, 15, 4, BMP_CX * 4, BMP_CX * 4, ILC_COLOR24, "add 9 x 1");
982     ret = ImageList_Add(himl, hbm, NULL);
983     ok(ret == 9, "ImageList_Add returned %d, expected 9\n", ret);
984     check_iml_data(himl, BMP_CX, BMP_CX, 18, 25, 4, BMP_CX * 4, BMP_CX * 7, ILC_COLOR24, "add 9 x 1");
985     DeleteObject(hbm);
986     ret = ImageList_Destroy(himl);
987     ok(ret, "ImageList_Destroy failed\n");
988     iml_clear_stream_data();
989
990     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 207, 209);
991     ok(himl != 0, "ImageList_Create failed\n");
992     check_iml_data(himl, BMP_CX, BMP_CX, 0, 208, 212, BMP_CX * 4, BMP_CX * 52, ILC_COLOR24, "init 207 grow 209");
993     ret = ImageList_Destroy(himl);
994     ok(ret, "ImageList_Destroy failed\n");
995     iml_clear_stream_data();
996
997     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 209, 207);
998     ok(himl != 0, "ImageList_Create failed\n");
999     check_iml_data(himl, BMP_CX, BMP_CX, 0, 210, 208, BMP_CX * 4, BMP_CX * 53, ILC_COLOR24, "init 209 grow 207");
1000     ret = ImageList_Destroy(himl);
1001     ok(ret, "ImageList_Destroy failed\n");
1002     iml_clear_stream_data();
1003
1004     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 14, 4);
1005     ok(himl != 0, "ImageList_Create failed\n");
1006     check_iml_data(himl, BMP_CX, BMP_CX, 0, 15, 4, BMP_CX * 4, BMP_CX * 4, ILC_COLOR24, "init 14 grow 4");
1007     ret = ImageList_Destroy(himl);
1008     ok(ret, "ImageList_Destroy failed\n");
1009     iml_clear_stream_data();
1010
1011     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 5, 9);
1012     ok(himl != 0, "ImageList_Create failed\n");
1013     check_iml_data(himl, BMP_CX, BMP_CX, 0, 6, 12, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 5 grow 9");
1014     ret = ImageList_Destroy(himl);
1015     ok(ret, "ImageList_Destroy failed\n");
1016     iml_clear_stream_data();
1017
1018     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 9, 5);
1019     ok(himl != 0, "ImageList_Create failed\n");
1020     check_iml_data(himl, BMP_CX, BMP_CX, 0, 10, 8, BMP_CX * 4, BMP_CX * 3, ILC_COLOR24, "init 9 grow 5");
1021     ret = ImageList_Destroy(himl);
1022     ok(ret, "ImageList_Destroy failed\n");
1023     iml_clear_stream_data();
1024
1025     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 2, 4);
1026     ok(himl != 0, "ImageList_Create failed\n");
1027     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, BMP_CX * 4, BMP_CX * 1, ILC_COLOR24, "init 2 grow 4");
1028     ret = ImageList_Destroy(himl);
1029     ok(ret, "ImageList_Destroy failed\n");
1030     iml_clear_stream_data();
1031
1032     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 2);
1033     ok(himl != 0, "ImageList_Create failed\n");
1034     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24, "init 4 grow 2");
1035     ret = ImageList_Destroy(himl);
1036     ok(ret, "ImageList_Destroy failed\n");
1037     iml_clear_stream_data();
1038
1039     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR8, 4, 2);
1040     ok(himl != 0, "ImageList_Create failed\n");
1041     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR8, "bpp 8");
1042     ret = ImageList_Destroy(himl);
1043     ok(ret, "ImageList_Destroy failed\n");
1044     iml_clear_stream_data();
1045
1046     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4, 4, 2);
1047     ok(himl != 0, "ImageList_Create failed\n");
1048     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp 4");
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, 0, 4, 2);
1054     ok(himl != 0, "ImageList_Create failed\n");
1055     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp default");
1056     icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1057     ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
1058     ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
1059     DestroyIcon( icon );
1060     check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4, "bpp default");
1061     ret = ImageList_Destroy(himl);
1062     ok(ret, "ImageList_Destroy failed\n");
1063     iml_clear_stream_data();
1064
1065     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24|ILC_MASK, 4, 2);
1066     ok(himl != 0, "ImageList_Create failed\n");
1067     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24|ILC_MASK,
1068                    "bpp 24 + mask");
1069     icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1070     ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
1071     ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
1072     DestroyIcon( icon );
1073     check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR24|ILC_MASK,
1074                    "bpp 24 + mask");
1075     ret = ImageList_Destroy(himl);
1076     ok(ret, "ImageList_Destroy failed\n");
1077     iml_clear_stream_data();
1078
1079     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 4, 2);
1080     ok(himl != 0, "ImageList_Create failed\n");
1081     check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4|ILC_MASK,
1082                    "bpp 4 + mask");
1083     icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1084     ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
1085     ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
1086     DestroyIcon( icon );
1087     check_iml_data(himl, BMP_CX, BMP_CX, 2, 5, 4, BMP_CX * 4, BMP_CX * 2, ILC_COLOR4|ILC_MASK,
1088                    "bpp 4 + mask");
1089     ret = ImageList_Destroy(himl);
1090     ok(ret, "ImageList_Destroy failed\n");
1091     iml_clear_stream_data();
1092
1093     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 99);
1094     ok(himl != 0, "ImageList_Create failed\n");
1095     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1096                    "init 2 grow 99");
1097     icon = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1098     ok( ImageList_AddIcon(himl, icon) == 0,"failed to add icon\n");
1099     ok( ImageList_AddIcon(himl, icon) == 1,"failed to add icon\n");
1100     check_iml_data(himl, BMP_CX, BMP_CX, 2, 3, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1101                    "init 2 grow 99 2 icons");
1102     ok( ImageList_AddIcon(himl, icon) == 2,"failed to add icon\n");
1103     DestroyIcon( icon );
1104     check_iml_data(himl, BMP_CX, BMP_CX, 3, 104, 100, BMP_CX * 4, BMP_CX * 104/4, ILC_COLOR4|ILC_MASK,
1105                    "init 2 grow 99 3 icons");
1106     ok( ImageList_Remove(himl, -1) == TRUE,"failed to remove icon\n");
1107     check_iml_data(himl, BMP_CX, BMP_CX, 0, 100, 100, BMP_CX * 4, BMP_CX * 100/4, ILC_COLOR4|ILC_MASK,
1108                    "init 2 grow 99 empty");
1109     ok( ImageList_SetImageCount(himl, 22) == TRUE,"failed to set image count\n");
1110     check_iml_data(himl, BMP_CX, BMP_CX, 22, 23, 100, BMP_CX * 4, BMP_CX * 24/4, ILC_COLOR4|ILC_MASK,
1111                    "init 2 grow 99 set count 22");
1112     ok( ImageList_SetImageCount(himl, 0) == TRUE,"failed to set image count\n");
1113     check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 100, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1114                    "init 2 grow 99 set count 0");
1115     ok( ImageList_SetImageCount(himl, 42) == TRUE,"failed to set image count\n");
1116     check_iml_data(himl, BMP_CX, BMP_CX, 42, 43, 100, BMP_CX * 4, BMP_CX * 44/4, ILC_COLOR4|ILC_MASK,
1117                    "init 2 grow 99 set count 42");
1118     ret = ImageList_Destroy(himl);
1119     ok(ret, "ImageList_Destroy failed\n");
1120     iml_clear_stream_data();
1121
1122     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 65536+12);
1123     ok(himl != 0, "ImageList_Create failed\n");
1124     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 12, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1125                    "init 2 grow 65536+12");
1126     ret = ImageList_Destroy(himl);
1127     ok(ret, "ImageList_Destroy failed\n");
1128     iml_clear_stream_data();
1129
1130     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, 65535);
1131     ok(himl != 0, "ImageList_Create failed\n");
1132     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 0, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1133                    "init 2 grow 65535");
1134     ret = ImageList_Destroy(himl);
1135     ok(ret, "ImageList_Destroy failed\n");
1136     iml_clear_stream_data();
1137
1138     himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR4|ILC_MASK, 2, -20);
1139     ok(himl != 0, "ImageList_Create failed\n");
1140     check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, BMP_CX * 4, BMP_CX, ILC_COLOR4|ILC_MASK,
1141                    "init 2 grow -20");
1142     ret = ImageList_Destroy(himl);
1143     ok(ret, "ImageList_Destroy failed\n");
1144     iml_clear_stream_data();
1145 }
1146
1147 static void test_shell_imagelist(void)
1148 {
1149     BOOL (WINAPI *pSHGetImageList)(INT, REFIID, void**);
1150     IImageList *iml = NULL;
1151     HMODULE hShell32;
1152     HRESULT hr;
1153     int out = 0;
1154     RECT rect;
1155     int cx, cy;
1156
1157     /* Try to load function from shell32 */
1158     hShell32 = LoadLibrary("shell32.dll");
1159     pSHGetImageList = (void*)GetProcAddress(hShell32, (LPCSTR) 727);
1160
1161     if (!pSHGetImageList)
1162     {
1163         win_skip("SHGetImageList not available, skipping test\n");
1164         return;
1165     }
1166
1167     /* Get system image list */
1168     hr = (pSHGetImageList)(SHIL_SYSSMALL, &IID_IImageList, (void**)&iml);
1169
1170     ok(SUCCEEDED(hr), "SHGetImageList failed, hr=%x\n", hr);
1171
1172     if (hr != S_OK)
1173         return;
1174
1175     IImageList_GetImageCount(iml, &out);
1176     ok(out > 0, "IImageList_GetImageCount returned out <= 0\n");
1177
1178     /* Fetch the small icon size */
1179     cx = GetSystemMetrics(SM_CXSMICON);
1180     cy = GetSystemMetrics(SM_CYSMICON);
1181
1182     /* Check icon size matches */
1183     IImageList_GetImageRect(iml, 0, &rect);
1184     ok(((rect.right == cx) && (rect.bottom == cy)),
1185                  "IImageList_GetImageRect returned r:%d,b:%d\n",
1186                  rect.right, rect.bottom);
1187
1188     IImageList_Release(iml);
1189     FreeLibrary(hShell32);
1190 }
1191
1192 static HBITMAP create_test_bitmap(HDC hdc, int bpp, UINT32 pixel1, UINT32 pixel2)
1193 {
1194     HBITMAP hBitmap;
1195     UINT32 *buffer = NULL;
1196     BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, bpp, BI_RGB,
1197                                 0, 0, 0, 0, 0}};
1198
1199     hBitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, NULL, 0);
1200     ok(hBitmap != NULL && buffer != NULL, "CreateDIBSection failed.\n");
1201
1202     if(!hBitmap || !buffer)
1203     {
1204         DeleteObject(hBitmap);
1205         return NULL;
1206     }
1207
1208     buffer[0] = pixel1;
1209     buffer[1] = pixel2;
1210
1211     return hBitmap;
1212 }
1213
1214 static BOOL colour_match(UINT32 x, UINT32 y)
1215 {
1216     const INT32 tolerance = 8;
1217
1218     const INT32 dr = abs((INT32)(x & 0x000000FF) - (INT32)(y & 0x000000FF));
1219     const INT32 dg = abs((INT32)((x & 0x0000FF00) >> 8) - (INT32)((y & 0x0000FF00) >> 8));
1220     const INT32 db = abs((INT32)((x & 0x00FF0000) >> 16) - (INT32)((y & 0x00FF0000) >> 16));
1221
1222     return (dr <= tolerance && dg <= tolerance && db <= tolerance);
1223 }
1224
1225 static void check_ImageList_DrawIndirect(IMAGELISTDRAWPARAMS *ildp, UINT32 *bits,
1226                                          UINT32 expected, int line)
1227 {
1228     bits[0] = 0x00FFFFFF;
1229     pImageList_DrawIndirect(ildp);
1230     ok(colour_match(bits[0], expected),
1231        "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n",
1232        bits[0] & 0x00FFFFFF, expected, line);
1233 }
1234
1235
1236 static void check_ImageList_DrawIndirect_fStyle(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
1237                                                 UINT fStyle, UINT32 expected, int line)
1238 {
1239     IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
1240         0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, ILS_NORMAL, 0, 0x00000000};
1241     check_ImageList_DrawIndirect(&ildp, bits, expected, line);
1242 }
1243
1244 static void check_ImageList_DrawIndirect_ILD_ROP(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
1245                                                 DWORD dwRop, UINT32 expected, int line)
1246 {
1247     IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
1248         0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, ILD_IMAGE | ILD_ROP, dwRop, ILS_NORMAL, 0, 0x00000000};
1249     check_ImageList_DrawIndirect(&ildp, bits, expected, line);
1250 }
1251
1252 static void check_ImageList_DrawIndirect_fState(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i, UINT fStyle,
1253                                                 UINT fState, DWORD Frame, UINT32 expected, int line)
1254 {
1255     IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
1256         0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000};
1257     check_ImageList_DrawIndirect(&ildp, bits, expected, line);
1258 }
1259
1260 static void check_ImageList_DrawIndirect_broken(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
1261                                                 UINT fStyle, UINT fState, DWORD Frame, UINT32 expected,
1262                                                 UINT32 broken_expected, int line)
1263 {
1264     IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
1265         0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000};
1266     bits[0] = 0x00FFFFFF;
1267     pImageList_DrawIndirect(&ildp);
1268     ok(colour_match(bits[0], expected) ||
1269        broken(colour_match(bits[0], broken_expected)),
1270        "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n",
1271        bits[0] & 0x00FFFFFF, expected, line);
1272 }
1273
1274 static void test_ImageList_DrawIndirect(void)
1275 {
1276     HIMAGELIST himl = NULL;
1277     int ret;
1278     HDC hdcDst = NULL;
1279     HBITMAP hbmOld = NULL, hbmDst = NULL;
1280     HBITMAP hbmMask = NULL, hbmInverseMask = NULL;
1281     HBITMAP hbmImage = NULL, hbmAlphaImage = NULL, hbmTransparentImage = NULL;
1282     int iImage = -1, iAlphaImage = -1, iTransparentImage = -1;
1283     UINT32 *bits = 0;
1284     UINT32 maskBits = 0x00000000, inverseMaskBits = 0xFFFFFFFF;
1285     int bpp, broken_value;
1286
1287     BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, 32, BI_RGB,
1288                                 0, 0, 0, 0, 0}};
1289
1290     hdcDst = CreateCompatibleDC(0);
1291     ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
1292     if (!hdcDst)
1293         return;
1294     bpp = GetDeviceCaps(hdcDst, BITSPIXEL);
1295
1296     hbmMask = CreateBitmap(2, 1, 1, 1, &maskBits);
1297     ok(hbmMask != 0, "CreateBitmap failed\n");
1298     if(!hbmMask) goto cleanup;
1299
1300     hbmInverseMask = CreateBitmap(2, 1, 1, 1, &inverseMaskBits);
1301     ok(hbmInverseMask != 0, "CreateBitmap failed\n");
1302     if(!hbmInverseMask) goto cleanup;
1303
1304     himl = pImageList_Create(2, 1, ILC_COLOR32, 0, 1);
1305     ok(himl != 0, "ImageList_Create failed\n");
1306     if(!himl) goto cleanup;
1307
1308     /* Add a no-alpha image */
1309     hbmImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x00ABCDEF);
1310     if(!hbmImage) goto cleanup;
1311
1312     iImage = pImageList_Add(himl, hbmImage, hbmMask);
1313     ok(iImage != -1, "ImageList_Add failed\n");
1314     if(iImage == -1) goto cleanup;
1315
1316     /* Add an alpha image */
1317     hbmAlphaImage = create_test_bitmap(hdcDst, 32, 0x89ABCDEF, 0x89ABCDEF);
1318     if(!hbmAlphaImage) goto cleanup;
1319
1320     iAlphaImage = pImageList_Add(himl, hbmAlphaImage, hbmMask);
1321     ok(iAlphaImage != -1, "ImageList_Add failed\n");
1322     if(iAlphaImage == -1) goto cleanup;
1323
1324     /* Add a transparent alpha image */
1325     hbmTransparentImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x89ABCDEF);
1326     if(!hbmTransparentImage) goto cleanup;
1327
1328     iTransparentImage = pImageList_Add(himl, hbmTransparentImage, hbmMask);
1329     ok(iTransparentImage != -1, "ImageList_Add failed\n");
1330     if(iTransparentImage == -1) goto cleanup;
1331
1332     /* 32-bit Tests */
1333     bitmapInfo.bmiHeader.biBitCount = 32;
1334     hbmDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
1335     ok (hbmDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
1336     if (!hbmDst || !bits)
1337         goto cleanup;
1338     hbmOld = SelectObject(hdcDst, hbmDst);
1339
1340     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_NORMAL, 0x00ABCDEF, __LINE__);
1341     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_TRANSPARENT, 0x00ABCDEF, __LINE__);
1342     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, 0x00D4D9DD, __LINE__);
1343     if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
1344     else broken_value = 0x00B4BDC4;
1345     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
1346     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_MASK, 0x00ABCDEF, __LINE__);
1347     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_IMAGE, 0x00ABCDEF, __LINE__);
1348     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_PRESERVEALPHA, 0x00ABCDEF, __LINE__);
1349
1350     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, 0x00D3E5F7, __LINE__);
1351     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_TRANSPARENT, 0x00D3E5F7, __LINE__);
1352
1353     if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
1354     else broken_value =  0x009DA8B1;
1355     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
1356     if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
1357     else broken_value =  0x008C99A3;
1358     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
1359     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_MASK, 0x00D3E5F7, __LINE__);
1360     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_IMAGE, 0x00D3E5F7, __LINE__);
1361     todo_wine check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_PRESERVEALPHA, 0x005D6F81, __LINE__);
1362
1363     check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iTransparentImage, ILD_NORMAL, 0x00FFFFFF, __LINE__);
1364
1365     check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCCOPY, 0x00ABCDEF, __LINE__);
1366     check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCINVERT, 0x00543210, __LINE__);
1367
1368     /* ILD_ROP is ignored when the image has an alpha channel */
1369     check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCCOPY, 0x00D3E5F7, __LINE__);
1370     check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCINVERT, 0x00D3E5F7, __LINE__);
1371
1372     todo_wine check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00CCCCCC, __LINE__);
1373     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00AFAFAF, 0x00F0F0F0, __LINE__);
1374
1375     check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_GLOW, 0, 0x00ABCDEF, __LINE__);
1376     check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SHADOW, 0, 0x00ABCDEF, __LINE__);
1377
1378     check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00D5E6F7, __LINE__);
1379     check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00E9F2FB, 0x00AEB7C0, __LINE__);
1380     todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_NORMAL, 127, 0x00E9F2FB, 0x00D3E5F7, __LINE__);
1381
1382 cleanup:
1383
1384     if(hbmOld)
1385         SelectObject(hdcDst, hbmOld);
1386     if(hbmDst)
1387         DeleteObject(hbmDst);
1388
1389     if(hdcDst)
1390         DeleteDC(hdcDst);
1391
1392     if(hbmMask)
1393         DeleteObject(hbmMask);
1394     if(hbmInverseMask)
1395         DeleteObject(hbmInverseMask);
1396
1397     if(hbmImage)
1398         DeleteObject(hbmImage);
1399     if(hbmAlphaImage)
1400         DeleteObject(hbmAlphaImage);
1401     if(hbmTransparentImage)
1402         DeleteObject(hbmTransparentImage);
1403
1404     if(himl)
1405     {
1406         ret = ImageList_Destroy(himl);
1407         ok(ret, "ImageList_Destroy failed\n");
1408     }
1409 }
1410
1411 static void test_iimagelist(void)
1412 {
1413     IImageList *imgl, *imgl2;
1414     HIMAGELIST himl;
1415     HRESULT hr;
1416     ULONG ret;
1417
1418     if (!pHIMAGELIST_QueryInterface)
1419     {
1420         win_skip("XP imagelist functions not available\n");
1421         return;
1422     }
1423
1424     /* test reference counting on destruction */
1425     imgl = (IImageList*)createImageList(32, 32);
1426     ret = IUnknown_AddRef(imgl);
1427     ok(ret == 2, "Expected 2, got %d\n", ret);
1428     ret = ImageList_Destroy((HIMAGELIST)imgl);
1429     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1430     ret = ImageList_Destroy((HIMAGELIST)imgl);
1431     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1432     ret = ImageList_Destroy((HIMAGELIST)imgl);
1433     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
1434
1435     imgl = (IImageList*)createImageList(32, 32);
1436     ret = IUnknown_AddRef(imgl);
1437     ok(ret == 2, "Expected 2, got %d\n", ret);
1438     ret = ImageList_Destroy((HIMAGELIST)imgl);
1439     ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1440     ret = IImageList_Release(imgl);
1441     ok(ret == 0, "Expected 0, got %d\n", ret);
1442     ret = ImageList_Destroy((HIMAGELIST)imgl);
1443     ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
1444
1445     /* ref counting, HIMAGELIST_QueryInterface adds a reference */
1446     imgl = (IImageList*)createImageList(32, 32);
1447     hr = pHIMAGELIST_QueryInterface((HIMAGELIST)imgl, &IID_IImageList, (void**)&imgl2);
1448     ok(hr == S_OK, "got 0x%08x\n", hr);
1449     ok(imgl2 == imgl, "got different pointer\n");
1450     ret = IImageList_Release(imgl);
1451     ok(ret == 1, "got %u\n", ret);
1452     IImageList_Release(imgl);
1453
1454     if (!pImageList_CoCreateInstance)
1455     {
1456         win_skip("Vista imagelist functions not available\n");
1457         return;
1458     }
1459
1460     hr = pImageList_CoCreateInstance(&CLSID_ImageList, NULL, &IID_IImageList, (void **) &imgl);
1461     ok(SUCCEEDED(hr), "ImageList_CoCreateInstance failed, hr=%x\n", hr);
1462
1463     if (hr == S_OK)
1464         IImageList_Release(imgl);
1465
1466     himl = createImageList(32, 32);
1467
1468     if (!himl)
1469         return;
1470
1471     hr = (pHIMAGELIST_QueryInterface)(himl, &IID_IImageList, (void **) &imgl);
1472     ok(SUCCEEDED(hr), "HIMAGELIST_QueryInterface failed, hr=%x\n", hr);
1473
1474     if (hr == S_OK)
1475         IImageList_Release(imgl);
1476
1477     ImageList_Destroy(himl);
1478 }
1479
1480 static void test_hotspot_v6(void)
1481 {
1482     struct hotspot {
1483         int dx;
1484         int dy;
1485     };
1486
1487 #define SIZEX1 47
1488 #define SIZEY1 31
1489 #define SIZEX2 11
1490 #define SIZEY2 17
1491 #define HOTSPOTS_MAX 4       /* Number of entries in hotspots */
1492     static const struct hotspot hotspots[HOTSPOTS_MAX] = {
1493         { 10, 7 },
1494         { SIZEX1, SIZEY1 },
1495         { -9, -8 },
1496         { -7, 35 }
1497     };
1498     int i, j;
1499     HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
1500     HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
1501     IImageList *imgl1, *imgl2;
1502     HRESULT hr;
1503
1504     /* cast to IImageList */
1505     imgl1 = (IImageList *) himl1;
1506     imgl2 = (IImageList *) himl2;
1507
1508     for (i = 0; i < HOTSPOTS_MAX; i++) {
1509         for (j = 0; j < HOTSPOTS_MAX; j++) {
1510             int dx1 = hotspots[i].dx;
1511             int dy1 = hotspots[i].dy;
1512             int dx2 = hotspots[j].dx;
1513             int dy2 = hotspots[j].dy;
1514             int correctx, correcty, newx, newy;
1515             char loc[256];
1516             IImageList *imglNew;
1517             POINT ppt;
1518
1519             hr = IImageList_BeginDrag(imgl1, 0, dx1, dy1);
1520             ok(SUCCEEDED(hr), "BeginDrag failed for { %d, %d }\n", dx1, dy1);
1521             sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
1522
1523             /* check merging the dragged image with a second image */
1524             hr = IImageList_SetDragCursorImage(imgl2, (IUnknown *) imgl2, 0, dx2, dy2);
1525             ok(SUCCEEDED(hr), "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
1526                     dx1, dy1, dx2, dy2);
1527             sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
1528
1529             /* check new hotspot, it should be the same like the old one */
1530             hr = IImageList_GetDragImage(imgl2, NULL, &ppt, &IID_IImageList, (PVOID *) &imglNew);
1531             ok(SUCCEEDED(hr), "GetDragImage failed\n");
1532             ok(ppt.x == dx1 && ppt.y == dy1,
1533                     "Expected drag hotspot [%d,%d] got [%d,%d]\n",
1534                     dx1, dy1, ppt.x, ppt.y);
1535             /* check size of new dragged image */
1536             IImageList_GetIconSize(imglNew, &newx, &newy);
1537             correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
1538             correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
1539             ok(newx == correctx && newy == correcty,
1540                     "Expected drag image size [%d,%d] got [%d,%d]\n",
1541                     correctx, correcty, newx, newy);
1542             sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
1543             IImageList_EndDrag(imgl2);
1544         }
1545     }
1546 #undef SIZEX1
1547 #undef SIZEY1
1548 #undef SIZEX2
1549 #undef SIZEY2
1550 #undef HOTSPOTS_MAX
1551     IImageList_Release(imgl2);
1552     IImageList_Release(imgl1);
1553 }
1554
1555 static void test_IImageList_Add_Remove(void)
1556 {
1557     IImageList *imgl;
1558     HIMAGELIST himl;
1559     HRESULT hr;
1560
1561     HICON hicon1;
1562     HICON hicon2;
1563     HICON hicon3;
1564
1565     int ret;
1566
1567     /* create an imagelist to play with */
1568     himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
1569     ok(himl != 0,"failed to create imagelist\n");
1570
1571     imgl = (IImageList *) himl;
1572
1573     /* load the icons to add to the image list */
1574     hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1575     ok(hicon1 != 0, "no hicon1\n");
1576     hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1577     ok(hicon2 != 0, "no hicon2\n");
1578     hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1579     ok(hicon3 != 0, "no hicon3\n");
1580
1581     /* remove when nothing exists */
1582     hr = IImageList_Remove(imgl, 0);
1583     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1584
1585     /* removing everything from an empty imagelist should succeed */
1586     hr = IImageList_Remove(imgl, -1);
1587     ok(hr == S_OK, "removed nonexistent icon\n");
1588
1589     /* add three */
1590     ret = -1;
1591     ok( IImageList_ReplaceIcon(imgl, -1, hicon1, &ret) == S_OK && (ret == 0),"failed to add icon1\n");
1592     ret = -1;
1593     ok( IImageList_ReplaceIcon(imgl, -1, hicon2, &ret) == S_OK && (ret == 1),"failed to add icon2\n");
1594     ret = -1;
1595     ok( IImageList_ReplaceIcon(imgl, -1, hicon3, &ret) == S_OK && (ret == 2),"failed to add icon3\n");
1596
1597     /* remove an index out of range */
1598     ok( IImageList_Remove(imgl, 4711) == E_INVALIDARG, "got 0x%08x\n", hr);
1599
1600     /* remove three */
1601     ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
1602     ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
1603     ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
1604
1605     /* remove one extra */
1606     ok( IImageList_Remove(imgl, 0) == E_INVALIDARG, "got 0x%08x\n", hr);
1607
1608     IImageList_Release(imgl);
1609     ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
1610     ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
1611     ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
1612 }
1613
1614 static void test_IImageList_Get_SetImageCount(void)
1615 {
1616     IImageList *imgl;
1617     HIMAGELIST himl;
1618     HRESULT hr;
1619     INT ret;
1620
1621     /* create an imagelist to play with */
1622     himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
1623     ok(himl != 0,"failed to create imagelist\n");
1624
1625     imgl = (IImageList *) himl;
1626
1627     /* check SetImageCount/GetImageCount */
1628     hr = IImageList_SetImageCount(imgl, 3);
1629     ok(hr == S_OK, "got 0x%08x\n", hr);
1630     ret = 0;
1631     hr = IImageList_GetImageCount(imgl, &ret);
1632     ok(hr == S_OK && ret == 3, "invalid image count after increase\n");
1633     hr = IImageList_SetImageCount(imgl, 1);
1634     ok(hr == S_OK, "got 0x%08x\n", hr);
1635     ret = 0;
1636     hr = IImageList_GetImageCount(imgl, &ret);
1637     ok(hr == S_OK && ret == 1, "invalid image count after decrease to 1\n");
1638     hr = IImageList_SetImageCount(imgl, 0);
1639     ok(hr == S_OK, "got 0x%08x\n", hr);
1640     ret = -1;
1641     hr = IImageList_GetImageCount(imgl, &ret);
1642     ok(hr == S_OK && ret == 0, "invalid image count after decrease to 0\n");
1643
1644     IImageList_Release(imgl);
1645 }
1646
1647 static void test_IImageList_Draw(void)
1648 {
1649     IImageList *imgl;
1650     HIMAGELIST himl;
1651
1652     HBITMAP hbm1;
1653     HBITMAP hbm2;
1654     HBITMAP hbm3;
1655
1656     IMAGELISTDRAWPARAMS imldp;
1657     HWND hwndfortest;
1658     HRESULT hr;
1659     HDC hdc;
1660     int ret;
1661
1662     hwndfortest = create_a_window();
1663     hdc = GetDC(hwndfortest);
1664     ok(hdc!=NULL, "couldn't get DC\n");
1665
1666     /* create an imagelist to play with */
1667     himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3);
1668     ok(himl!=0,"failed to create imagelist\n");
1669
1670     imgl = (IImageList *) himl;
1671
1672     /* load the icons to add to the image list */
1673     hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
1674     ok(hbm1 != 0, "no bitmap 1\n");
1675     hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
1676     ok(hbm2 != 0, "no bitmap 2\n");
1677     hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
1678     ok(hbm3 != 0, "no bitmap 3\n");
1679
1680     /* add three */
1681     ret = -1;
1682     ok( IImageList_Add(imgl, hbm1, 0, &ret) == S_OK && (ret == 0), "failed to add bitmap 1\n");
1683     ret = -1;
1684     ok( IImageList_Add(imgl, hbm2, 0, &ret) == S_OK && (ret == 1), "failed to add bitmap 2\n");
1685
1686     ok( IImageList_SetImageCount(imgl, 3) == S_OK, "Setimage count failed\n");
1687     ok( IImageList_Replace(imgl, 2, hbm3, 0) == S_OK, "failed to replace bitmap 3\n");
1688
1689 if (0)
1690 {
1691     /* crashes on native */
1692     IImageList_Draw(imgl, NULL);
1693 }
1694
1695     memset(&imldp, 0, sizeof (imldp));
1696     hr = IImageList_Draw(imgl, &imldp);
1697     ok( hr == E_INVALIDARG, "got 0x%08x\n", hr);
1698
1699     imldp.cbSize = IMAGELISTDRAWPARAMS_V3_SIZE;
1700     imldp.hdcDst = hdc;
1701     imldp.himl = himl;
1702
1703     REDRAW(hwndfortest);
1704     WAIT;
1705
1706     imldp.fStyle = SRCCOPY;
1707     imldp.rgbBk = CLR_DEFAULT;
1708     imldp.rgbFg = CLR_DEFAULT;
1709     imldp.y = 100;
1710     imldp.x = 100;
1711     ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1712     imldp.i ++;
1713     ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1714     imldp.i ++;
1715     ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1716     imldp.i ++;
1717     ok( IImageList_Draw(imgl, &imldp) == E_INVALIDARG, "should fail\n");
1718
1719     /* remove three */
1720     ok( IImageList_Remove(imgl, 0) == S_OK, "removing 1st bitmap\n");
1721     ok( IImageList_Remove(imgl, 0) == S_OK, "removing 2nd bitmap\n");
1722     ok( IImageList_Remove(imgl, 0) == S_OK, "removing 3rd bitmap\n");
1723
1724     /* destroy it */
1725     IImageList_Release(imgl);
1726
1727     /* bitmaps should not be deleted by the imagelist */
1728     ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
1729     ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
1730     ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");
1731
1732     ReleaseDC(hwndfortest, hdc);
1733     DestroyWindow(hwndfortest);
1734 }
1735
1736 static void test_IImageList_Merge(void)
1737 {
1738     HIMAGELIST himl1, himl2;
1739     IImageList *imgl1, *imgl2, *merge;
1740     HICON hicon1;
1741     HWND hwnd = create_a_window();
1742     HRESULT hr;
1743     int ret;
1744
1745     himl1 = ImageList_Create(32,32,0,0,3);
1746     ok(himl1 != NULL,"failed to create himl1\n");
1747
1748     himl2 = ImageList_Create(32,32,0,0,3);
1749     ok(himl2 != NULL,"failed to create himl2\n");
1750
1751     hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
1752     ok(hicon1 != NULL, "failed to create hicon1\n");
1753
1754     if (!himl1 || !himl2 || !hicon1)
1755         return;
1756
1757     /* cast to IImageList */
1758     imgl1 = (IImageList *) himl1;
1759     imgl2 = (IImageList *) himl2;
1760
1761     ret = -1;
1762     ok( IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret) == S_OK && (ret == 0),"add icon1 to himl2 failed\n");
1763
1764 if (0)
1765 {
1766     /* null cases that crash on native */
1767     IImageList_Merge(imgl1, -1, NULL, 0, 0, 0, &IID_IImageList, (void**)&merge);
1768     IImageList_Merge(imgl1, -1, (IUnknown*) imgl2, 0, 0, 0, &IID_IImageList, NULL);
1769 }
1770
1771     /* If himl1 has no images, merge still succeeds */
1772     hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1773     ok(hr == S_OK, "merge himl1,-1 failed\n");
1774     if (hr == S_OK) IImageList_Release(merge);
1775
1776     hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1777     ok(hr == S_OK, "merge himl1,0 failed\n");
1778     if (hr == S_OK) IImageList_Release(merge);
1779
1780     /* Same happens if himl2 is empty */
1781     IImageList_Release(imgl2);
1782     himl2 = ImageList_Create(32,32,0,0,3);
1783     ok(himl2 != NULL,"failed to recreate himl2\n");
1784
1785     imgl2 = (IImageList *) himl2;
1786
1787     hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, -1, 0, 0, &IID_IImageList, (void **) &merge);
1788     ok(hr == S_OK, "merge himl2,-1 failed\n");
1789     if (hr == S_OK) IImageList_Release(merge);
1790
1791     hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1792     ok(hr == S_OK, "merge himl2,0 failed\n");
1793     if (hr == S_OK) IImageList_Release(merge);
1794
1795     /* Now try merging an image with itself */
1796     ret = -1;
1797     ok( IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret) == S_OK && (ret == 0),"re-add icon1 to himl2 failed\n");
1798
1799     hr = IImageList_Merge(imgl2, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1800     ok(hr == S_OK, "merge himl2 with itself failed\n");
1801     if (hr == S_OK) IImageList_Release(merge);
1802
1803     /* Try merging 2 different image lists */
1804     ret = -1;
1805     ok( IImageList_ReplaceIcon(imgl1, -1, hicon1, &ret) == S_OK && (ret == 0),"add icon1 to himl1 failed\n");
1806
1807     hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1808     ok(hr == S_OK, "merge himl1 with himl2 failed\n");
1809     if (hr == S_OK) IImageList_Release(merge);
1810
1811     hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 8, 16, &IID_IImageList, (void **) &merge);
1812     ok(hr == S_OK, "merge himl1 with himl2 8,16 failed\n");
1813     if (hr == S_OK) IImageList_Release(merge);
1814
1815     IImageList_Release(imgl1);
1816     IImageList_Release(imgl2);
1817
1818     DestroyIcon(hicon1);
1819     DestroyWindow(hwnd);
1820 }
1821
1822 static void test_iconsize(void)
1823 {
1824     HIMAGELIST himl;
1825     INT cx, cy;
1826     BOOL ret;
1827
1828     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1829     /* null pointers, not zero imagelist dimensions */
1830     ret = ImageList_GetIconSize(himl, NULL, NULL);
1831     ok(!ret, "got %d\n", ret);
1832
1833     /* doesn't touch return pointers */
1834     cx = 0x1abe11ed;
1835     ret = ImageList_GetIconSize(himl, &cx, NULL);
1836     ok(!ret, "got %d\n", ret);
1837     ok(cx == 0x1abe11ed, "got %d\n", cx);
1838
1839     cy = 0x1abe11ed;
1840     ret = ImageList_GetIconSize(himl, NULL, &cy);
1841     ok(!ret, "got %d\n", ret);
1842     ok(cy == 0x1abe11ed, "got %d\n", cy);
1843
1844     ImageList_Destroy(himl);
1845
1846     ret = ImageList_GetIconSize((HIMAGELIST)0xdeadbeef, &cx, &cy);
1847     ok(!ret, "got %d\n", ret);
1848 }
1849
1850 static void test_create_destroy(void)
1851 {
1852     HIMAGELIST himl;
1853     BOOL rc;
1854
1855     /* list with zero or negative image dimensions */
1856     himl = ImageList_Create(0, 0, ILC_COLOR16, 0, 3);
1857     ok(himl == NULL, "got %p\n", himl);
1858
1859     himl = ImageList_Create(0, 16, ILC_COLOR16, 0, 3);
1860     ok(himl == NULL, "got %p\n", himl);
1861
1862     himl = ImageList_Create(16, 0, ILC_COLOR16, 0, 3);
1863     ok(himl == NULL, "got %p\n", himl);
1864
1865     himl = ImageList_Create(16, -1, ILC_COLOR16, 0, 3);
1866     ok(himl == NULL, "got %p\n", himl);
1867
1868     himl = ImageList_Create(-1, 16, ILC_COLOR16, 0, 3);
1869     ok(himl == NULL, "got %p\n", himl);
1870
1871     rc = ImageList_Destroy((HIMAGELIST)0xdeadbeef);
1872     ok(rc == FALSE, "ImageList_Destroy(0xdeadbeef) should fail and not crash\n");
1873 }
1874
1875 static void test_IImageList_Clone(void)
1876 {
1877     IImageList *imgl, *imgl2;
1878     HIMAGELIST himl;
1879     HRESULT hr;
1880     ULONG ref;
1881
1882     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1883     imgl = (IImageList*)himl;
1884
1885 if (0)
1886 {
1887     /* crashes on native */
1888     IImageList_Clone(imgl, &IID_IImageList, NULL);
1889 }
1890
1891     hr = IImageList_Clone(imgl, &IID_IImageList, (void**)&imgl2);
1892     ok(hr == S_OK, "got 0x%08x\n", hr);
1893     ref = IImageList_Release(imgl2);
1894     ok(ref == 0, "got %u\n", ref);
1895
1896     IImageList_Release(imgl);
1897 }
1898
1899 static void test_IImageList_GetBkColor(void)
1900 {
1901     IImageList *imgl;
1902     HIMAGELIST himl;
1903     COLORREF color;
1904     HRESULT hr;
1905
1906     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1907     imgl = (IImageList*)himl;
1908
1909 if (0)
1910 {
1911     /* crashes on native */
1912     IImageList_GetBkColor(imgl, NULL);
1913 }
1914
1915     hr = IImageList_GetBkColor(imgl, &color);
1916     ok(hr == S_OK, "got 0x%08x\n", hr);
1917
1918     IImageList_Release(imgl);
1919 }
1920
1921 static void test_IImageList_SetBkColor(void)
1922 {
1923     IImageList *imgl;
1924     HIMAGELIST himl;
1925     COLORREF color;
1926     HRESULT hr;
1927
1928     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1929     imgl = (IImageList*)himl;
1930
1931 if (0)
1932 {
1933     /* crashes on native */
1934     IImageList_SetBkColor(imgl, RGB(0, 0, 0), NULL);
1935 }
1936
1937     hr = IImageList_SetBkColor(imgl, CLR_NONE, &color);
1938     ok(hr == S_OK, "got 0x%08x\n", hr);
1939
1940     hr = IImageList_SetBkColor(imgl, CLR_NONE, &color);
1941     ok(hr == S_OK, "got 0x%08x\n", hr);
1942
1943     color = 0xdeadbeef;
1944     hr = IImageList_GetBkColor(imgl, &color);
1945     ok(hr == S_OK, "got 0x%08x\n", hr);
1946     ok(color == CLR_NONE, "got %x\n", color);
1947
1948     IImageList_Release(imgl);
1949 }
1950
1951 static void test_IImageList_GetImageCount(void)
1952 {
1953     IImageList *imgl;
1954     HIMAGELIST himl;
1955     int count;
1956     HRESULT hr;
1957
1958     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1959     imgl = (IImageList*)himl;
1960
1961 if (0)
1962 {
1963     /* crashes on native */
1964     IImageList_GetImageCount(imgl, NULL);
1965 }
1966
1967     count = -1;
1968     hr = IImageList_GetImageCount(imgl, &count);
1969     ok(hr == S_OK, "got 0x%08x\n", hr);
1970     ok(count == 0, "got %d\n", count);
1971
1972     IImageList_Release(imgl);
1973 }
1974
1975 static void test_IImageList_GetIconSize(void)
1976 {
1977     IImageList *imgl;
1978     HIMAGELIST himl;
1979     int cx, cy;
1980     HRESULT hr;
1981
1982     himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
1983     imgl = (IImageList*)himl;
1984
1985     hr = IImageList_GetIconSize(imgl, NULL, NULL);
1986     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1987
1988     hr = IImageList_GetIconSize(imgl, &cx, NULL);
1989     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1990
1991     hr = IImageList_GetIconSize(imgl, NULL, &cy);
1992     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1993
1994     IImageList_Release(imgl);
1995 }
1996
1997 START_TEST(imagelist)
1998 {
1999     ULONG_PTR ctx_cookie;
2000     HANDLE hCtx;
2001
2002     HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
2003     pImageList_Create = NULL;   /* These are not needed for non-v6.0 tests*/
2004     pImageList_Add = NULL;
2005     pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
2006     pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
2007
2008     hinst = GetModuleHandleA(NULL);
2009
2010     InitCommonControls();
2011
2012     test_create_destroy();
2013     test_hotspot();
2014     test_add_remove();
2015     test_imagecount();
2016     test_DrawIndirect();
2017     test_merge();
2018     test_imagelist_storage();
2019     test_iconsize();
2020
2021     FreeLibrary(hComCtl32);
2022
2023     /* Now perform v6 tests */
2024
2025     if (!load_v6_module(&ctx_cookie, &hCtx))
2026         return;
2027
2028     /* Reload comctl32 */
2029     hComCtl32 = LoadLibraryA("comctl32.dll");
2030     pImageList_Create = (void*)GetProcAddress(hComCtl32, "ImageList_Create");
2031     pImageList_Add = (void*)GetProcAddress(hComCtl32, "ImageList_Add");
2032     pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
2033     pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
2034     pImageList_CoCreateInstance = (void*)GetProcAddress(hComCtl32, "ImageList_CoCreateInstance");
2035     pHIMAGELIST_QueryInterface = (void*)GetProcAddress(hComCtl32, "HIMAGELIST_QueryInterface");
2036
2037     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2038
2039     /* Do v6.0 tests */
2040     test_ImageList_DrawIndirect();
2041     test_shell_imagelist();
2042     test_iimagelist();
2043
2044     test_hotspot_v6();
2045     test_IImageList_Add_Remove();
2046     test_IImageList_Get_SetImageCount();
2047     test_IImageList_Draw();
2048     test_IImageList_Merge();
2049     test_IImageList_Clone();
2050     test_IImageList_GetBkColor();
2051     test_IImageList_SetBkColor();
2052     test_IImageList_GetImageCount();
2053     test_IImageList_GetIconSize();
2054
2055     CoUninitialize();
2056
2057     unload_v6_module(ctx_cookie, hCtx);
2058 }