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