push 22b3e00525a9a3743634eb8f21ffe1bf98bf885e
[wine/hacks.git] / dlls / comctl32 / tests / imagelist.c
blob3fe249f3ad5fefb66c89b219981c5ea7f4bb5eab
1 /*
2 * Unit test suite for imagelist control.
4 * Copyright 2004 Michael Stefaniuc
5 * Copyright 2002 Mike McCormack for CodeWeavers
6 * Copyright 2007 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
24 #define CONST_VTABLE
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <assert.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "objbase.h"
35 #include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */
37 #include "wine/test.h"
39 #undef VISIBLE
41 #ifdef VISIBLE
42 #define WAIT Sleep (1000)
43 #define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW)
44 #else
45 #define WAIT
46 #define REDRAW(hwnd)
47 #endif
49 #define IMAGELIST_MAGIC (('L' << 8) | 'I')
51 #include "pshpack2.h"
52 /* Header used by ImageList_Read() and ImageList_Write() */
53 typedef struct _ILHEAD
55 USHORT usMagic;
56 USHORT usVersion;
57 WORD cCurImage;
58 WORD cMaxImage;
59 WORD cGrow;
60 WORD cx;
61 WORD cy;
62 COLORREF bkcolor;
63 WORD flags;
64 SHORT ovls[4];
65 } ILHEAD;
66 #include "poppack.h"
68 static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
69 static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
71 static HDC desktopDC;
72 static HINSTANCE hinst;
74 /* These macros build cursor/bitmap data in 4x4 pixel blocks */
75 #define B(x,y) ((x?0xf0:0)|(y?0xf:0))
76 #define ROW1(a,b,c,d,e,f,g,h) B(a,b),B(c,d),B(e,f),B(g,h)
77 #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), \
78 ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h)
79 #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)
80 #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), \
81 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), \
82 ROW2(a,b,c,d,e,f,g,h,i,j,k,l)
84 static const BYTE empty_bits[48*48/8];
86 static const BYTE icon_bits[32*32/8] =
88 ROW32(0,0,0,0,0,0,0,0),
89 ROW32(0,0,1,1,1,1,0,0),
90 ROW32(0,1,1,1,1,1,1,0),
91 ROW32(0,1,1,0,0,1,1,0),
92 ROW32(0,1,1,0,0,1,1,0),
93 ROW32(0,1,1,1,1,1,1,0),
94 ROW32(0,0,1,1,1,1,0,0),
95 ROW32(0,0,0,0,0,0,0,0)
98 static const BYTE bitmap_bits[48*48/8] =
100 ROW48(0,0,0,0,0,0,0,0,0,0,0,0),
101 ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
102 ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
103 ROW48(0,1,0,0,0,0,0,0,1,0,1,0),
104 ROW48(0,1,0,0,0,0,0,1,0,0,1,0),
105 ROW48(0,1,0,0,0,0,1,0,0,0,1,0),
106 ROW48(0,1,0,0,0,1,0,0,0,0,1,0),
107 ROW48(0,1,0,0,1,0,0,0,0,0,1,0),
108 ROW48(0,1,0,1,0,0,0,0,0,0,1,0),
109 ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
110 ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
111 ROW48(0,0,0,0,0,0,0,0,0,0,0,0)
114 static HIMAGELIST createImageList(int cx, int cy)
116 /* Create an ImageList and put an image into it */
117 HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1);
118 HBITMAP hbm = CreateBitmap(48, 48, 1, 1, bitmap_bits);
119 ImageList_Add(himl, hbm, NULL);
120 return himl;
123 static HWND create_a_window(void)
125 char className[] = "bmwnd";
126 char winName[] = "Test Bitmap";
127 HWND hWnd;
128 static int registered = 0;
130 if (!registered)
132 WNDCLASSA cls;
134 cls.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
135 cls.lpfnWndProc = DefWindowProcA;
136 cls.cbClsExtra = 0;
137 cls.cbWndExtra = 0;
138 cls.hInstance = 0;
139 cls.hIcon = LoadIconA (0, IDI_APPLICATION);
140 cls.hCursor = LoadCursorA (0, IDC_ARROW);
141 cls.hbrBackground = GetStockObject (WHITE_BRUSH);
142 cls.lpszMenuName = 0;
143 cls.lpszClassName = className;
145 RegisterClassA (&cls);
146 registered = 1;
149 /* Setup window */
150 hWnd = CreateWindowA (className, winName,
151 WS_OVERLAPPEDWINDOW ,
152 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
153 0, hinst, 0);
155 #ifdef VISIBLE
156 ShowWindow (hWnd, SW_SHOW);
157 #endif
158 REDRAW(hWnd);
159 WAIT;
161 return hWnd;
164 static HDC show_image(HWND hwnd, HIMAGELIST himl, int idx, int size,
165 LPCSTR loc, BOOL clear)
167 HDC hdc = NULL;
168 #ifdef VISIBLE
169 if (!himl) return NULL;
171 SetWindowText(hwnd, loc);
172 hdc = GetDC(hwnd);
173 ImageList_Draw(himl, idx, hdc, 0, 0, ILD_TRANSPARENT);
175 REDRAW(hwnd);
176 WAIT;
178 if (clear)
180 BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
181 ReleaseDC(hwnd, hdc);
182 hdc = NULL;
184 #endif /* VISIBLE */
185 return hdc;
188 /* Useful for checking differences */
189 #if 0
190 static void dump_bits(const BYTE *p, const BYTE *q, int size)
192 int i, j;
194 size /= 8;
196 for (i = 0; i < size * 2; i++)
198 printf("|");
199 for (j = 0; j < size; j++)
200 printf("%c%c", p[j] & 0xf0 ? 'X' : ' ', p[j] & 0xf ? 'X' : ' ');
201 printf(" -- ");
202 for (j = 0; j < size; j++)
203 printf("%c%c", q[j] & 0xf0 ? 'X' : ' ', q[j] & 0xf ? 'X' : ' ');
204 printf("|\n");
205 p += size * 4;
206 q += size * 4;
208 printf("\n");
210 #endif
212 static void check_bits(HWND hwnd, HIMAGELIST himl, int idx, int size,
213 const BYTE *checkbits, LPCSTR loc)
215 #ifdef VISIBLE
216 BYTE bits[100*100/8];
217 COLORREF c;
218 HDC hdc;
219 int x, y, i = -1;
221 if (!himl) return;
223 memset(bits, 0, sizeof(bits));
224 hdc = show_image(hwnd, himl, idx, size, loc, FALSE);
226 c = GetPixel(hdc, 0, 0);
228 for (y = 0; y < size; y ++)
230 for (x = 0; x < size; x++)
232 if (!(x & 0x7)) i++;
233 if (GetPixel(hdc, x, y) != c) bits[i] |= (0x80 >> (x & 0x7));
237 BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
238 ReleaseDC(hwnd, hdc);
240 ok (memcmp(bits, checkbits, (size * size)/8) == 0,
241 "%s: bits different\n", loc);
242 if (memcmp(bits, checkbits, (size * size)/8))
243 dump_bits(bits, checkbits, size);
244 #endif /* VISIBLE */
247 static void testHotspot (void)
249 struct hotspot {
250 int dx;
251 int dy;
254 #define SIZEX1 47
255 #define SIZEY1 31
256 #define SIZEX2 11
257 #define SIZEY2 17
258 #define HOTSPOTS_MAX 4 /* Number of entries in hotspots */
259 static const struct hotspot hotspots[HOTSPOTS_MAX] = {
260 { 10, 7 },
261 { SIZEX1, SIZEY1 },
262 { -9, -8 },
263 { -7, 35 }
265 int i, j, ret;
266 HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
267 HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
268 HWND hwnd = create_a_window();
271 for (i = 0; i < HOTSPOTS_MAX; i++) {
272 for (j = 0; j < HOTSPOTS_MAX; j++) {
273 int dx1 = hotspots[i].dx;
274 int dy1 = hotspots[i].dy;
275 int dx2 = hotspots[j].dx;
276 int dy2 = hotspots[j].dy;
277 int correctx, correcty, newx, newy;
278 char loc[256];
279 HIMAGELIST himlNew;
280 POINT ppt;
282 ret = ImageList_BeginDrag(himl1, 0, dx1, dy1);
283 ok(ret != 0, "BeginDrag failed for { %d, %d }\n", dx1, dy1);
284 sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
285 show_image(hwnd, himl1, 0, max(SIZEX1, SIZEY1), loc, TRUE);
287 /* check merging the dragged image with a second image */
288 ret = ImageList_SetDragCursorImage(himl2, 0, dx2, dy2);
289 ok(ret != 0, "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
290 dx1, dy1, dx2, dy2);
291 sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
292 show_image(hwnd, himl2, 0, max(SIZEX2, SIZEY2), loc, TRUE);
294 /* check new hotspot, it should be the same like the old one */
295 himlNew = ImageList_GetDragImage(NULL, &ppt);
296 ok(ppt.x == dx1 && ppt.y == dy1,
297 "Expected drag hotspot [%d,%d] got [%d,%d]\n",
298 dx1, dy1, ppt.x, ppt.y);
299 /* check size of new dragged image */
300 ImageList_GetIconSize(himlNew, &newx, &newy);
301 correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
302 correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
303 ok(newx == correctx && newy == correcty,
304 "Expected drag image size [%d,%d] got [%d,%d]\n",
305 correctx, correcty, newx, newy);
306 sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
307 show_image(hwnd, himlNew, 0, max(correctx, correcty), loc, TRUE);
308 ImageList_EndDrag();
311 #undef SIZEX1
312 #undef SIZEY1
313 #undef SIZEX2
314 #undef SIZEY2
315 #undef HOTSPOTS_MAX
316 ImageList_Destroy(himl2);
317 ImageList_Destroy(himl1);
318 DestroyWindow(hwnd);
321 static BOOL DoTest1(void)
323 HIMAGELIST himl ;
325 HICON hicon1 ;
326 HICON hicon2 ;
327 HICON hicon3 ;
329 /* create an imagelist to play with */
330 himl = ImageList_Create(84,84,0x10,0,3);
331 ok(himl!=0,"failed to create imagelist\n");
333 /* load the icons to add to the image list */
334 hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
335 ok(hicon1 != 0, "no hicon1\n");
336 hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
337 ok(hicon2 != 0, "no hicon2\n");
338 hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
339 ok(hicon3 != 0, "no hicon3\n");
341 /* remove when nothing exists */
342 ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
343 /* removing everything from an empty imagelist should succeed */
344 ok(ImageList_RemoveAll(himl),"removed nonexistent icon\n");
346 /* add three */
347 ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
348 ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
349 ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
351 /* remove an index out of range */
352 ok(!ImageList_Remove(himl,4711),"removed nonexistent icon\n");
354 /* remove three */
355 ok(ImageList_Remove(himl,0),"can't remove 0\n");
356 ok(ImageList_Remove(himl,0),"can't remove 0\n");
357 ok(ImageList_Remove(himl,0),"can't remove 0\n");
359 /* remove one extra */
360 ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
362 /* check SetImageCount/GetImageCount */
363 if (pImageList_SetImageCount)
365 ok(pImageList_SetImageCount(himl, 3), "couldn't increase image count\n");
366 ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
367 ok(pImageList_SetImageCount(himl, 1), "couldn't decrease image count\n");
368 ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
369 ok(pImageList_SetImageCount(himl, 0), "couldn't decrease image count\n");
370 ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
372 else
374 skip("skipped ImageList_SetImageCount tests\n");
377 /* destroy it */
378 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
380 ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
381 ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
382 ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
384 return TRUE;
387 static BOOL DoTest2(void)
389 HIMAGELIST himl ;
391 HICON hicon1 ;
392 HICON hicon2 ;
393 HICON hicon3 ;
395 /* create an imagelist to play with */
396 himl = ImageList_Create(84,84,0x10,0,3);
397 ok(himl!=0,"failed to create imagelist\n");
399 /* load the icons to add to the image list */
400 hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
401 ok(hicon1 != 0, "no hicon1\n");
402 hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
403 ok(hicon2 != 0, "no hicon2\n");
404 hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
405 ok(hicon3 != 0, "no hicon3\n");
407 /* add three */
408 ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
409 ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
410 ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
412 /* destroy it */
413 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
415 ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
416 ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
417 ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
419 return TRUE;
422 static BOOL DoTest3(void)
424 HIMAGELIST himl;
426 HBITMAP hbm1;
427 HBITMAP hbm2;
428 HBITMAP hbm3;
430 IMAGELISTDRAWPARAMS imldp;
431 HDC hdc;
432 HWND hwndfortest;
434 if (!pImageList_DrawIndirect)
436 win_skip("ImageList_DrawIndirect not available, skipping test\n");
437 return TRUE;
440 hwndfortest = create_a_window();
441 hdc = GetDC(hwndfortest);
442 ok(hdc!=NULL, "couldn't get DC\n");
444 /* create an imagelist to play with */
445 himl = ImageList_Create(48,48,0x10,0,3);
446 ok(himl!=0,"failed to create imagelist\n");
448 /* load the icons to add to the image list */
449 hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
450 ok(hbm1 != 0, "no bitmap 1\n");
451 hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
452 ok(hbm2 != 0, "no bitmap 2\n");
453 hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
454 ok(hbm3 != 0, "no bitmap 3\n");
456 /* add three */
457 ok(0==ImageList_Add(himl, hbm1, 0),"failed to add bitmap 1\n");
458 ok(1==ImageList_Add(himl, hbm2, 0),"failed to add bitmap 2\n");
460 if (pImageList_SetImageCount)
462 ok(pImageList_SetImageCount(himl,3),"Setimage count failed\n");
463 /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
464 ok(ImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
467 memset(&imldp, 0, sizeof (imldp));
468 ok(!pImageList_DrawIndirect(&imldp), "zero data succeeded!\n");
469 imldp.cbSize = sizeof (imldp);
470 ok(!pImageList_DrawIndirect(&imldp), "zero hdc succeeded!\n");
471 imldp.hdcDst = hdc;
472 ok(!pImageList_DrawIndirect(&imldp),"zero himl succeeded!\n");
473 imldp.himl = himl;
474 if (!pImageList_DrawIndirect(&imldp))
476 /* Earlier versions of native comctl32 use a smaller structure */
477 imldp.cbSize -= 3 * sizeof(DWORD);
478 ok(pImageList_DrawIndirect(&imldp),"DrawIndirect should succeed\n");
480 REDRAW(hwndfortest);
481 WAIT;
483 imldp.fStyle = SRCCOPY;
484 imldp.rgbBk = CLR_DEFAULT;
485 imldp.rgbFg = CLR_DEFAULT;
486 imldp.y = 100;
487 imldp.x = 100;
488 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
489 imldp.i ++;
490 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
491 imldp.i ++;
492 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
493 imldp.i ++;
494 ok(!pImageList_DrawIndirect(&imldp),"should fail\n");
496 /* remove three */
497 ok(ImageList_Remove(himl, 0), "removing 1st bitmap\n");
498 ok(ImageList_Remove(himl, 0), "removing 2nd bitmap\n");
499 ok(ImageList_Remove(himl, 0), "removing 3rd bitmap\n");
501 /* destroy it */
502 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
504 /* bitmaps should not be deleted by the imagelist */
505 ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
506 ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
507 ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");
509 ReleaseDC(hwndfortest, hdc);
510 DestroyWindow(hwndfortest);
512 return TRUE;
515 static void testMerge(void)
517 HIMAGELIST himl1, himl2, hmerge;
518 HICON hicon1;
519 HWND hwnd = create_a_window();
521 himl1 = ImageList_Create(32,32,0,0,3);
522 ok(himl1 != NULL,"failed to create himl1\n");
524 himl2 = ImageList_Create(32,32,0,0,3);
525 ok(himl2 != NULL,"failed to create himl2\n");
527 hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
528 ok(hicon1 != NULL, "failed to create hicon1\n");
530 if (!himl1 || !himl2 || !hicon1)
531 return;
533 ok(0==ImageList_AddIcon(himl2, hicon1),"add icon1 to himl2 failed\n");
534 check_bits(hwnd, himl2, 0, 32, icon_bits, "add icon1 to himl2");
536 /* If himl1 has no images, merge still succeeds */
537 hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
538 ok(hmerge != NULL, "merge himl1,-1 failed\n");
539 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,-1");
540 if (hmerge) ImageList_Destroy(hmerge);
542 hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
543 ok(hmerge != NULL,"merge himl1,0 failed\n");
544 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,0");
545 if (hmerge) ImageList_Destroy(hmerge);
547 /* Same happens if himl2 is empty */
548 ImageList_Destroy(himl2);
549 himl2 = ImageList_Create(32,32,0,0,3);
550 ok(himl2 != NULL,"failed to recreate himl2\n");
551 if (!himl2)
552 return;
554 hmerge = ImageList_Merge(himl1, -1, himl2, -1, 0, 0);
555 ok(hmerge != NULL, "merge himl2,-1 failed\n");
556 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,-1");
557 if (hmerge) ImageList_Destroy(hmerge);
559 hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
560 ok(hmerge != NULL, "merge himl2,0 failed\n");
561 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,0");
562 if (hmerge) ImageList_Destroy(hmerge);
564 /* Now try merging an image with itself */
565 ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n");
567 hmerge = ImageList_Merge(himl2, 0, himl2, 0, 0, 0);
568 ok(hmerge != NULL, "merge himl2 with itself failed\n");
569 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2 with itself");
570 if (hmerge) ImageList_Destroy(hmerge);
572 /* Try merging 2 different image lists */
573 ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n");
575 hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
576 ok(hmerge != NULL, "merge himl1 with himl2 failed\n");
577 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2");
578 if (hmerge) ImageList_Destroy(hmerge);
580 hmerge = ImageList_Merge(himl1, 0, himl2, 0, 8, 16);
581 ok(hmerge != NULL, "merge himl1 with himl2 8,16 failed\n");
582 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2, 8,16");
583 if (hmerge) ImageList_Destroy(hmerge);
585 ImageList_Destroy(himl1);
586 ImageList_Destroy(himl2);
587 DestroyIcon(hicon1);
588 DestroyWindow(hwnd);
591 /*********************** imagelist storage test ***************************/
593 #define BMP_CX 48
595 struct my_IStream
597 IStream is;
598 char *iml_data; /* written imagelist data */
599 ULONG iml_data_size;
602 static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface(
603 IStream* This,
604 REFIID riid,
605 void** ppvObject)
607 assert(0);
608 return E_NOTIMPL;
611 static ULONG STDMETHODCALLTYPE Test_Stream_AddRef(
612 IStream* This)
614 assert(0);
615 return 2;
618 static ULONG STDMETHODCALLTYPE Test_Stream_Release(
619 IStream* This)
621 assert(0);
622 return 1;
625 static HRESULT STDMETHODCALLTYPE Test_Stream_Read(
626 IStream* This,
627 void* pv,
628 ULONG cb,
629 ULONG* pcbRead)
631 assert(0);
632 return E_NOTIMPL;
635 static BOOL allocate_storage(struct my_IStream *my_is, ULONG add)
637 my_is->iml_data_size += add;
639 if (!my_is->iml_data)
640 my_is->iml_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data_size);
641 else
642 my_is->iml_data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data, my_is->iml_data_size);
644 return my_is->iml_data ? TRUE : FALSE;
647 static HRESULT STDMETHODCALLTYPE Test_Stream_Write(
648 IStream* This,
649 const void* pv,
650 ULONG cb,
651 ULONG* pcbWritten)
653 struct my_IStream *my_is = (struct my_IStream *)This;
654 ULONG current_iml_data_size = my_is->iml_data_size;
656 if (!allocate_storage(my_is, cb)) return E_FAIL;
658 memcpy(my_is->iml_data + current_iml_data_size, pv, cb);
659 if (pcbWritten) *pcbWritten = cb;
661 return S_OK;
664 static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(
665 IStream* This,
666 LARGE_INTEGER dlibMove,
667 DWORD dwOrigin,
668 ULARGE_INTEGER* plibNewPosition)
670 assert(0);
671 return E_NOTIMPL;
674 static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(
675 IStream* This,
676 ULARGE_INTEGER libNewSize)
678 assert(0);
679 return E_NOTIMPL;
682 static HRESULT STDMETHODCALLTYPE Test_Stream_CopyTo(
683 IStream* This,
684 IStream* pstm,
685 ULARGE_INTEGER cb,
686 ULARGE_INTEGER* pcbRead,
687 ULARGE_INTEGER* pcbWritten)
689 assert(0);
690 return E_NOTIMPL;
693 static HRESULT STDMETHODCALLTYPE Test_Stream_Commit(
694 IStream* This,
695 DWORD grfCommitFlags)
697 assert(0);
698 return E_NOTIMPL;
701 static HRESULT STDMETHODCALLTYPE Test_Stream_Revert(
702 IStream* This)
704 assert(0);
705 return E_NOTIMPL;
708 static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion(
709 IStream* This,
710 ULARGE_INTEGER libOffset,
711 ULARGE_INTEGER cb,
712 DWORD dwLockType)
714 assert(0);
715 return E_NOTIMPL;
718 static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion(
719 IStream* This,
720 ULARGE_INTEGER libOffset,
721 ULARGE_INTEGER cb,
722 DWORD dwLockType)
724 assert(0);
725 return E_NOTIMPL;
728 static HRESULT STDMETHODCALLTYPE Test_Stream_Stat(
729 IStream* This,
730 STATSTG* pstatstg,
731 DWORD grfStatFlag)
733 assert(0);
734 return E_NOTIMPL;
737 static HRESULT STDMETHODCALLTYPE Test_Stream_Clone(
738 IStream* This,
739 IStream** ppstm)
741 assert(0);
742 return E_NOTIMPL;
745 static const IStreamVtbl Test_Stream_Vtbl =
747 Test_Stream_QueryInterface,
748 Test_Stream_AddRef,
749 Test_Stream_Release,
750 Test_Stream_Read,
751 Test_Stream_Write,
752 Test_Stream_Seek,
753 Test_Stream_SetSize,
754 Test_Stream_CopyTo,
755 Test_Stream_Commit,
756 Test_Stream_Revert,
757 Test_Stream_LockRegion,
758 Test_Stream_UnlockRegion,
759 Test_Stream_Stat,
760 Test_Stream_Clone
763 static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 };
765 static INT DIB_GetWidthBytes( int width, int bpp )
767 int words;
769 switch (bpp)
771 case 1: words = (width + 31) / 32; break;
772 case 4: words = (width + 7) / 8; break;
773 case 8: words = (width + 3) / 4; break;
774 case 15:
775 case 16: words = (width + 1) / 2; break;
776 case 24: words = (width * 3 + 3)/4; break;
777 case 32: words = width; break;
779 default:
780 words=0;
781 trace("Unknown depth %d, please report.\n", bpp );
782 assert(0);
783 break;
785 return 4 * words;
788 static void check_bitmap_data(const char *bm_data, ULONG bm_data_size,
789 INT width, INT height, INT bpp,
790 const char *comment)
792 const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data;
793 const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh));
794 ULONG hdr_size, image_size;
796 hdr_size = sizeof(*bmfh) + sizeof(*bmih);
797 if (bmih->biBitCount <= 8) hdr_size += (1 << bpp) * sizeof(RGBQUAD);
799 ok(bmfh->bfType == (('M' << 8) | 'B'), "wrong bfType 0x%02x\n", bmfh->bfType);
800 ok(bmfh->bfSize == hdr_size, "wrong bfSize 0x%02x\n", bmfh->bfSize);
801 ok(bmfh->bfReserved1 == 0, "wrong bfReserved1 0x%02x\n", bmfh->bfReserved1);
802 ok(bmfh->bfReserved2 == 0, "wrong bfReserved2 0x%02x\n", bmfh->bfReserved2);
803 ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits);
805 ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize);
806 ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width);
807 ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height);
808 ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes);
809 ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount);
811 image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight;
812 ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage);
813 #if 0
815 char fname[256];
816 FILE *f;
817 sprintf(fname, "bmp_%s.bmp", comment);
818 f = fopen(fname, "wb");
819 fwrite(bm_data, 1, bm_data_size, f);
820 fclose(f);
822 #endif
825 static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max)
827 ILHEAD *ilh = (ILHEAD *)ilh_data;
829 ok(ilh->usMagic == IMAGELIST_MAGIC, "wrong usMagic %4x (expected %02x)\n", ilh->usMagic, IMAGELIST_MAGIC);
830 ok(ilh->usVersion == 0x101, "wrong usVersion %x (expected 0x101)\n", ilh->usVersion);
831 ok(ilh->cCurImage == cur, "wrong cCurImage %d (expected %d)\n", ilh->cCurImage, cur);
832 ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
833 ok(ilh->cGrow == 4, "wrong cGrow %d (expected 4)\n", ilh->cGrow);
834 ok(ilh->cx == cx, "wrong cx %d (expected %d)\n", ilh->cx, cx);
835 ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy);
836 ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor);
837 ok(ilh->flags == ILC_COLOR24, "wrong flags %04x\n", ilh->flags);
838 ok(ilh->ovls[0] == -1 ||
839 ilh->ovls[0] == 0, /* win95 */
840 "wrong ovls[0] %04x\n", ilh->ovls[0]);
841 ok(ilh->ovls[1] == -1 ||
842 ilh->ovls[1] == 0, /* win95 */
843 "wrong ovls[1] %04x\n", ilh->ovls[1]);
844 ok(ilh->ovls[2] == -1 ||
845 ilh->ovls[2] == 0, /* win95 */
846 "wrong ovls[2] %04x\n", ilh->ovls[2]);
847 ok(ilh->ovls[3] == -1 ||
848 ilh->ovls[3] == 0, /* win95 */
849 "wrong ovls[3] %04x\n", ilh->ovls[3]);
852 static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment)
854 HDC hdc;
855 char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
856 BITMAPINFO *bmi = (BITMAPINFO *)bmibuf;
857 HBITMAP hbmp, hbmp_old;
858 HBRUSH hbrush;
859 RECT rc = { 0, 0, cx, cy };
861 hdc = CreateCompatibleDC(0);
863 memset(bmi, 0, sizeof(*bmi));
864 bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
865 bmi->bmiHeader.biHeight = cx;
866 bmi->bmiHeader.biWidth = cy;
867 bmi->bmiHeader.biBitCount = 24;
868 bmi->bmiHeader.biPlanes = 1;
869 bmi->bmiHeader.biCompression = BI_RGB;
870 hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
872 hbmp_old = SelectObject(hdc, hbmp);
874 hbrush = CreateSolidBrush(color);
875 FillRect(hdc, &rc, hbrush);
876 DeleteObject(hbrush);
878 DrawText(hdc, comment, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
880 SelectObject(hdc, hbmp_old);
881 DeleteDC(hdc);
883 return hbmp;
886 static void image_list_init(HIMAGELIST himl)
888 HBITMAP hbm;
889 char comment[16];
890 INT n = 1;
892 #define add_bitmap(grey) \
893 sprintf(comment, "%d", n++); \
894 hbm = create_bitmap(BMP_CX, BMP_CX, RGB((grey),(grey),(grey)), comment); \
895 ImageList_Add(himl, hbm, NULL);
897 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
898 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
899 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
900 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
901 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
902 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
903 #undef add_bitmap
906 #define iml_clear_stream_data() \
907 HeapFree(GetProcessHeap(), 0, Test_Stream.iml_data); \
908 Test_Stream.iml_data = NULL; \
909 Test_Stream.iml_data_size = 0;
911 static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max,
912 INT width, INT height, INT bpp, const char *comment)
914 INT ret, cxx, cyy;
916 ret = ImageList_GetImageCount(himl);
917 ok(ret == cur, "expected cur %d got %d\n", cur, ret);
919 ret = ImageList_GetIconSize(himl, &cxx, &cyy);
920 ok(ret, "ImageList_GetIconSize failed\n");
921 ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx);
922 ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy);
924 iml_clear_stream_data();
925 ret = ImageList_Write(himl, &Test_Stream.is);
926 ok(ret, "ImageList_Write failed\n");
928 ok(Test_Stream.iml_data != 0, "ImageList_Write didn't write any data\n");
929 ok(Test_Stream.iml_data_size > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n");
931 check_ilhead_data(Test_Stream.iml_data, cx, cy, cur, max);
932 check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD),
933 Test_Stream.iml_data_size - sizeof(ILHEAD),
934 width, height, bpp, comment);
937 static void test_imagelist_storage(void)
939 HIMAGELIST himl;
940 BOOL ret;
942 himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
943 ok(himl != 0, "ImageList_Create failed\n");
945 check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, BMP_CX * 4, BMP_CX * 1, 24, "empty");
947 image_list_init(himl);
948 check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, BMP_CX * 4, BMP_CX * 7, 24, "orig");
950 ret = ImageList_Remove(himl, 4);
951 ok(ret, "ImageList_Remove failed\n");
952 check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, BMP_CX * 4, BMP_CX * 7, 24, "1");
954 ret = ImageList_Remove(himl, 5);
955 ok(ret, "ImageList_Remove failed\n");
956 check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, BMP_CX * 4, BMP_CX * 7, 24, "2");
958 ret = ImageList_Remove(himl, 6);
959 ok(ret, "ImageList_Remove failed\n");
960 check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, BMP_CX * 4, BMP_CX * 7, 24, "3");
962 ret = ImageList_Remove(himl, 7);
963 ok(ret, "ImageList_Remove failed\n");
964 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "4");
966 ret = ImageList_Remove(himl, -2);
967 ok(!ret, "ImageList_Remove(-2) should fail\n");
968 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "5");
970 ret = ImageList_Remove(himl, 20);
971 ok(!ret, "ImageList_Remove(20) should fail\n");
972 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "6");
974 ret = ImageList_Remove(himl, -1);
975 ok(ret, "ImageList_Remove(-1) failed\n");
976 check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, BMP_CX * 4, BMP_CX * 1, 24, "7");
978 ret = ImageList_Destroy(himl);
979 ok(ret, "ImageList_Destroy failed\n");
981 iml_clear_stream_data();
984 START_TEST(imagelist)
986 HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
987 pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
988 pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
990 desktopDC=GetDC(NULL);
991 hinst = GetModuleHandleA(NULL);
993 InitCommonControls();
995 testHotspot();
996 DoTest1();
997 DoTest2();
998 DoTest3();
999 testMerge();
1000 test_imagelist_storage();