Autosyncing with Wine HEAD
[reactos.git] / rostests / winetests / comctl32 / 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 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #define COBJMACROS
24 #define CONST_VTABLE
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <assert.h>
29
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 */
36
37 #include "wine/test.h"
38
39 #undef VISIBLE
40
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
48
49 #define IMAGELIST_MAGIC (('L' << 8) | 'I')
50
51 #include "pshpack2.h"
52 /* Header used by ImageList_Read() and ImageList_Write() */
53 typedef struct _ILHEAD
54 {
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"
67
68 static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
69 static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
70
71 static HDC desktopDC;
72 static HINSTANCE hinst;
73
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)
83
84 static const BYTE empty_bits[48*48/8];
85
86 static const BYTE icon_bits[32*32/8] =
87 {
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)
96 };
97
98 static const BYTE bitmap_bits[48*48/8] =
99 {
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)
112 };
113
114 static HIMAGELIST createImageList(int cx, int cy)
115 {
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;
121 }
122
123 static HWND create_a_window(void)
124 {
125 char className[] = "bmwnd";
126 char winName[] = "Test Bitmap";
127 HWND hWnd;
128 static int registered = 0;
129
130 if (!registered)
131 {
132 WNDCLASSA cls;
133
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, (LPSTR)IDI_APPLICATION);
140 cls.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
141 cls.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
142 cls.lpszMenuName = 0;
143 cls.lpszClassName = className;
144
145 RegisterClassA (&cls);
146 registered = 1;
147 }
148
149 /* Setup window */
150 hWnd = CreateWindowA (className, winName,
151 WS_OVERLAPPEDWINDOW ,
152 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
153 0, hinst, 0);
154
155 #ifdef VISIBLE
156 ShowWindow (hWnd, SW_SHOW);
157 #endif
158 REDRAW(hWnd);
159 WAIT;
160
161 return hWnd;
162 }
163
164 static HDC show_image(HWND hwnd, HIMAGELIST himl, int idx, int size,
165 LPCSTR loc, BOOL clear)
166 {
167 HDC hdc = NULL;
168 #ifdef VISIBLE
169 if (!himl) return NULL;
170
171 SetWindowText(hwnd, loc);
172 hdc = GetDC(hwnd);
173 ImageList_Draw(himl, idx, hdc, 0, 0, ILD_TRANSPARENT);
174
175 REDRAW(hwnd);
176 WAIT;
177
178 if (clear)
179 {
180 BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
181 ReleaseDC(hwnd, hdc);
182 hdc = NULL;
183 }
184 #endif /* VISIBLE */
185 return hdc;
186 }
187
188 /* Useful for checking differences */
189 #if 0
190 static void dump_bits(const BYTE *p, const BYTE *q, int size)
191 {
192 int i, j;
193
194 size /= 8;
195
196 for (i = 0; i < size * 2; i++)
197 {
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;
207 }
208 printf("\n");
209 }
210 #endif
211
212 static void check_bits(HWND hwnd, HIMAGELIST himl, int idx, int size,
213 const BYTE *checkbits, LPCSTR loc)
214 {
215 #ifdef VISIBLE
216 BYTE bits[100*100/8];
217 COLORREF c;
218 HDC hdc;
219 int x, y, i = -1;
220
221 if (!himl) return;
222
223 memset(bits, 0, sizeof(bits));
224 hdc = show_image(hwnd, himl, idx, size, loc, FALSE);
225
226 c = GetPixel(hdc, 0, 0);
227
228 for (y = 0; y < size; y ++)
229 {
230 for (x = 0; x < size; x++)
231 {
232 if (!(x & 0x7)) i++;
233 if (GetPixel(hdc, x, y) != c) bits[i] |= (0x80 >> (x & 0x7));
234 }
235 }
236
237 BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
238 ReleaseDC(hwnd, hdc);
239
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 */
245 }
246
247 static void testHotspot (void)
248 {
249 struct hotspot {
250 int dx;
251 int dy;
252 };
253
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 }
264 };
265 int i, j, ret;
266 HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
267 HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
268 HWND hwnd = create_a_window();
269
270
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;
281
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);
286
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);
293
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();
309 }
310 }
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);
319 }
320
321 static BOOL DoTest1(void)
322 {
323 HIMAGELIST himl ;
324
325 HICON hicon1 ;
326 HICON hicon2 ;
327 HICON hicon3 ;
328
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");
332
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");
340
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");
345
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");
350
351 /* remove an index out of range */
352 ok(!ImageList_Remove(himl,4711),"removed nonexistent icon\n");
353
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");
358
359 /* remove one extra */
360 ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
361
362 /* check SetImageCount/GetImageCount */
363 if (pImageList_SetImageCount)
364 {
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");
371 }
372 else
373 {
374 skip("skipped ImageList_SetImageCount tests\n");
375 }
376
377 /* destroy it */
378 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
379
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");
383
384 return TRUE;
385 }
386
387 static BOOL DoTest2(void)
388 {
389 HIMAGELIST himl ;
390
391 HICON hicon1 ;
392 HICON hicon2 ;
393 HICON hicon3 ;
394
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");
398
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");
406
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");
411
412 /* destroy it */
413 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
414
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");
418
419 return TRUE;
420 }
421
422 static BOOL DoTest3(void)
423 {
424 HIMAGELIST himl;
425
426 HBITMAP hbm1;
427 HBITMAP hbm2;
428 HBITMAP hbm3;
429
430 IMAGELISTDRAWPARAMS imldp;
431 HDC hdc;
432 HWND hwndfortest;
433
434 if (!pImageList_DrawIndirect)
435 {
436 trace("ImageList_DrawIndirect not available, skipping test\n");
437 return TRUE;
438 }
439
440 hwndfortest = create_a_window();
441 hdc = GetDC(hwndfortest);
442 ok(hdc!=NULL, "couldn't get DC\n");
443
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");
447
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");
455
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");
459
460 if (pImageList_SetImageCount)
461 {
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");
465 }
466
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))
475 {
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");
479 }
480 REDRAW(hwndfortest);
481 WAIT;
482
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");
495
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");
500
501 /* destroy it */
502 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
503
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");
508
509 ReleaseDC(hwndfortest, hdc);
510 DestroyWindow(hwndfortest);
511
512 return TRUE;
513 }
514
515 static void testMerge(void)
516 {
517 HIMAGELIST himl1, himl2, hmerge;
518 HICON hicon1;
519 HWND hwnd = create_a_window();
520
521 himl1 = ImageList_Create(32,32,0,0,3);
522 ok(himl1 != NULL,"failed to create himl1\n");
523
524 himl2 = ImageList_Create(32,32,0,0,3);
525 ok(himl2 != NULL,"failed to create himl2\n");
526
527 hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
528 ok(hicon1 != NULL, "failed to create hicon1\n");
529
530 if (!himl1 || !himl2 || !hicon1)
531 return;
532
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");
535
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);
541
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);
546
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;
553
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);
558
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);
563
564 /* Now try merging an image with itself */
565 ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n");
566
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);
571
572 /* Try merging 2 different image lists */
573 ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n");
574
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);
579
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);
584
585 ImageList_Destroy(himl1);
586 ImageList_Destroy(himl2);
587 DestroyIcon(hicon1);
588 DestroyWindow(hwnd);
589 }
590
591 /*********************** imagelist storage test ***************************/
592
593 #define BMP_CX 48
594
595 struct my_IStream
596 {
597 IStream is;
598 char *iml_data; /* written imagelist data */
599 ULONG iml_data_size;
600 };
601
602 static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface(
603 IStream* This,
604 REFIID riid,
605 void** ppvObject)
606 {
607 assert(0);
608 return E_NOTIMPL;
609 }
610
611 static ULONG STDMETHODCALLTYPE Test_Stream_AddRef(
612 IStream* This)
613 {
614 assert(0);
615 return 2;
616 }
617
618 static ULONG STDMETHODCALLTYPE Test_Stream_Release(
619 IStream* This)
620 {
621 assert(0);
622 return 1;
623 }
624
625 static HRESULT STDMETHODCALLTYPE Test_Stream_Read(
626 IStream* This,
627 void* pv,
628 ULONG cb,
629 ULONG* pcbRead)
630 {
631 assert(0);
632 return E_NOTIMPL;
633 }
634
635 static BOOL allocate_storage(struct my_IStream *my_is, ULONG add)
636 {
637 my_is->iml_data_size += add;
638
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);
643
644 return my_is->iml_data ? TRUE : FALSE;
645 }
646
647 static HRESULT STDMETHODCALLTYPE Test_Stream_Write(
648 IStream* This,
649 const void* pv,
650 ULONG cb,
651 ULONG* pcbWritten)
652 {
653 struct my_IStream *my_is = (struct my_IStream *)This;
654 ULONG current_iml_data_size = my_is->iml_data_size;
655
656 if (!allocate_storage(my_is, cb)) return E_FAIL;
657
658 memcpy(my_is->iml_data + current_iml_data_size, pv, cb);
659 if (pcbWritten) *pcbWritten = cb;
660
661 return S_OK;
662 }
663
664 static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(
665 IStream* This,
666 LARGE_INTEGER dlibMove,
667 DWORD dwOrigin,
668 ULARGE_INTEGER* plibNewPosition)
669 {
670 assert(0);
671 return E_NOTIMPL;
672 }
673
674 static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(
675 IStream* This,
676 ULARGE_INTEGER libNewSize)
677 {
678 assert(0);
679 return E_NOTIMPL;
680 }
681
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)
688 {
689 assert(0);
690 return E_NOTIMPL;
691 }
692
693 static HRESULT STDMETHODCALLTYPE Test_Stream_Commit(
694 IStream* This,
695 DWORD grfCommitFlags)
696 {
697 assert(0);
698 return E_NOTIMPL;
699 }
700
701 static HRESULT STDMETHODCALLTYPE Test_Stream_Revert(
702 IStream* This)
703 {
704 assert(0);
705 return E_NOTIMPL;
706 }
707
708 static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion(
709 IStream* This,
710 ULARGE_INTEGER libOffset,
711 ULARGE_INTEGER cb,
712 DWORD dwLockType)
713 {
714 assert(0);
715 return E_NOTIMPL;
716 }
717
718 static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion(
719 IStream* This,
720 ULARGE_INTEGER libOffset,
721 ULARGE_INTEGER cb,
722 DWORD dwLockType)
723 {
724 assert(0);
725 return E_NOTIMPL;
726 }
727
728 static HRESULT STDMETHODCALLTYPE Test_Stream_Stat(
729 IStream* This,
730 STATSTG* pstatstg,
731 DWORD grfStatFlag)
732 {
733 assert(0);
734 return E_NOTIMPL;
735 }
736
737 static HRESULT STDMETHODCALLTYPE Test_Stream_Clone(
738 IStream* This,
739 IStream** ppstm)
740 {
741 assert(0);
742 return E_NOTIMPL;
743 }
744
745 static const IStreamVtbl Test_Stream_Vtbl =
746 {
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
761 };
762
763 static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 };
764
765 static INT DIB_GetWidthBytes( int width, int bpp )
766 {
767 int words;
768
769 switch (bpp)
770 {
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;
778
779 default:
780 words=0;
781 trace("Unknown depth %d, please report.\n", bpp );
782 assert(0);
783 break;
784 }
785 return 4 * words;
786 }
787
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)
791 {
792 const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data;
793 const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh));
794 ULONG hdr_size, image_size;
795
796 hdr_size = sizeof(*bmfh) + sizeof(*bmih);
797 if (bmih->biBitCount <= 8) hdr_size += (1 << bpp) * sizeof(RGBQUAD);
798
799 ok(bmfh->bfType == (('M' << 8) | 'B'), "wrong bfType 0x%02x\n", bmfh->bfType);
800 ok(bmfh->bfSize == hdr_size, "wrong bfSize 0x%02x\n", bmfh->bfSize);
801 ok(bmfh->bfReserved1 == 0, "wrong bfReserved1 0x%02x\n", bmfh->bfReserved1);
802 ok(bmfh->bfReserved2 == 0, "wrong bfReserved2 0x%02x\n", bmfh->bfReserved2);
803 ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits);
804
805 ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize);
806 ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width);
807 ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height);
808 ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes);
809 ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount);
810
811 image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight;
812 ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage);
813 #if 0
814 {
815 char fname[256];
816 FILE *f;
817 sprintf(fname, "bmp_%s.bmp", comment);
818 f = fopen(fname, "wb");
819 fwrite(bm_data, 1, bm_data_size, f);
820 fclose(f);
821 }
822 #endif
823 }
824
825 static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max)
826 {
827 ILHEAD *ilh = (ILHEAD *)ilh_data;
828
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, "wrong ovls[0] %04x\n", ilh->ovls[0]);
839 ok(ilh->ovls[1] == -1, "wrong ovls[1] %04x\n", ilh->ovls[1]);
840 ok(ilh->ovls[2] == -1, "wrong ovls[2] %04x\n", ilh->ovls[2]);
841 ok(ilh->ovls[3] == -1, "wrong ovls[3] %04x\n", ilh->ovls[3]);
842 }
843
844 static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment)
845 {
846 HDC hdc;
847 char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
848 BITMAPINFO *bmi = (BITMAPINFO *)bmibuf;
849 HBITMAP hbmp, hbmp_old;
850 HBRUSH hbrush;
851 RECT rc = { 0, 0, cx, cy };
852
853 hdc = CreateCompatibleDC(0);
854
855 memset(bmi, 0, sizeof(*bmi));
856 bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
857 bmi->bmiHeader.biHeight = cx;
858 bmi->bmiHeader.biWidth = cy;
859 bmi->bmiHeader.biBitCount = 24;
860 bmi->bmiHeader.biPlanes = 1;
861 bmi->bmiHeader.biCompression = BI_RGB;
862 hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
863
864 hbmp_old = SelectObject(hdc, hbmp);
865
866 hbrush = CreateSolidBrush(color);
867 FillRect(hdc, &rc, hbrush);
868 DeleteObject(hbrush);
869
870 DrawText(hdc, comment, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
871
872 SelectObject(hdc, hbmp_old);
873 DeleteDC(hdc);
874
875 return hbmp;
876 }
877
878 static void image_list_init(HIMAGELIST himl)
879 {
880 HBITMAP hbm;
881 char comment[16];
882 INT n = 1;
883
884 #define add_bitmap(grey) \
885 sprintf(comment, "%d", n++); \
886 hbm = create_bitmap(BMP_CX, BMP_CX, RGB((grey),(grey),(grey)), comment); \
887 ImageList_Add(himl, hbm, NULL);
888
889 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
890 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
891 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
892 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
893 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
894 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
895 #undef add_bitmap
896 }
897
898 #define iml_clear_stream_data() \
899 HeapFree(GetProcessHeap(), 0, Test_Stream.iml_data); \
900 Test_Stream.iml_data = NULL; \
901 Test_Stream.iml_data_size = 0;
902
903 static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max,
904 INT width, INT height, INT bpp, const char *comment)
905 {
906 INT ret, cxx, cyy;
907
908 ret = ImageList_GetImageCount(himl);
909 ok(ret == cur, "expected cur %d got %d\n", cur, ret);
910
911 ret = ImageList_GetIconSize(himl, &cxx, &cyy);
912 ok(ret, "ImageList_GetIconSize failed\n");
913 ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx);
914 ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy);
915
916 iml_clear_stream_data();
917 ret = ImageList_Write(himl, &Test_Stream.is);
918 ok(ret, "ImageList_Write failed\n");
919
920 ok(Test_Stream.iml_data != 0, "ImageList_Write didn't write any data\n");
921 ok(Test_Stream.iml_data_size > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n");
922
923 check_ilhead_data(Test_Stream.iml_data, cx, cy, cur, max);
924 check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD),
925 Test_Stream.iml_data_size - sizeof(ILHEAD),
926 width, height, bpp, comment);
927 }
928
929 static void test_imagelist_storage(void)
930 {
931 HIMAGELIST himl;
932 BOOL ret;
933
934 himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
935 ok(himl != 0, "ImageList_Create failed\n");
936
937 check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, BMP_CX * 4, BMP_CX * 1, 24, "empty");
938
939 image_list_init(himl);
940 check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, BMP_CX * 4, BMP_CX * 7, 24, "orig");
941
942 ret = ImageList_Remove(himl, 4);
943 ok(ret, "ImageList_Remove failed\n");
944 check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, BMP_CX * 4, BMP_CX * 7, 24, "1");
945
946 ret = ImageList_Remove(himl, 5);
947 ok(ret, "ImageList_Remove failed\n");
948 check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, BMP_CX * 4, BMP_CX * 7, 24, "2");
949
950 ret = ImageList_Remove(himl, 6);
951 ok(ret, "ImageList_Remove failed\n");
952 check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, BMP_CX * 4, BMP_CX * 7, 24, "3");
953
954 ret = ImageList_Remove(himl, 7);
955 ok(ret, "ImageList_Remove failed\n");
956 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "4");
957
958 ret = ImageList_Remove(himl, -2);
959 ok(!ret, "ImageList_Remove(-2) should fail\n");
960 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "5");
961
962 ret = ImageList_Remove(himl, 20);
963 ok(!ret, "ImageList_Remove(20) should fail\n");
964 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "6");
965
966 ret = ImageList_Remove(himl, -1);
967 ok(ret, "ImageList_Remove(-1) failed\n");
968 check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, BMP_CX * 4, BMP_CX * 1, 24, "7");
969
970 ret = ImageList_Destroy(himl);
971 ok(ret, "ImageList_Destroy failed\n");
972
973 iml_clear_stream_data();
974 }
975
976 START_TEST(imagelist)
977 {
978 HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
979 pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
980 pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
981
982 desktopDC=GetDC(NULL);
983 hinst = GetModuleHandleA(NULL);
984
985 InitCommonControls();
986
987 testHotspot();
988 DoTest1();
989 DoTest2();
990 DoTest3();
991 testMerge();
992 test_imagelist_storage();
993 }