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
35 #include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */
37 #include "wine/test.h"
42 #define WAIT Sleep (1000)
43 #define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW)
49 #define IMAGELIST_MAGIC (('L' << 8) | 'I')
52 /* Header used by ImageList_Read() and ImageList_Write() */
53 typedef struct _ILHEAD
68 static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
69 static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
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);
123 static HWND create_a_window(void)
125 char className[] = "bmwnd";
126 char winName[] = "Test Bitmap";
128 static int registered = 0;
134 cls.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
135 cls.lpfnWndProc = DefWindowProcA;
139 cls.hIcon = LoadIconA (0, (LPSTR)IDI_APPLICATION);
140 cls.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
141 cls.hbrBackground = GetStockObject (WHITE_BRUSH);
142 cls.lpszMenuName = 0;
143 cls.lpszClassName = className;
145 RegisterClassA (&cls);
150 hWnd = CreateWindowA (className, winName,
151 WS_OVERLAPPEDWINDOW ,
152 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
156 ShowWindow (hWnd, SW_SHOW);
164 static HDC show_image(HWND hwnd, HIMAGELIST himl, int idx, int size,
165 LPCSTR loc, BOOL clear)
169 if (!himl) return NULL;
171 SetWindowText(hwnd, loc);
173 ImageList_Draw(himl, idx, hdc, 0, 0, ILD_TRANSPARENT);
180 BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
181 ReleaseDC(hwnd, hdc);
188 /* Useful for checking differences */
190 static void dump_bits(const BYTE *p, const BYTE *q, int size)
196 for (i = 0; i < size * 2; i++)
199 for (j = 0; j < size; j++)
200 printf("%c%c", p[j] & 0xf0 ? 'X' : ' ', p[j] & 0xf ? 'X' : ' ');
202 for (j = 0; j < size; j++)
203 printf("%c%c", q[j] & 0xf0 ? 'X' : ' ', q[j] & 0xf ? 'X' : ' ');
212 static void check_bits(HWND hwnd, HIMAGELIST himl, int idx, int size,
213 const BYTE *checkbits, LPCSTR loc)
216 BYTE bits[100*100/8];
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++)
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);
247 static void testHotspot (void)
258 #define HOTSPOTS_MAX 4 /* Number of entries in hotspots */
259 static const struct hotspot hotspots[HOTSPOTS_MAX] = {
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;
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",
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);
316 ImageList_Destroy(himl2);
317 ImageList_Destroy(himl1);
321 static BOOL DoTest1(void)
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");
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");
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");
374 skip("skipped ImageList_SetImageCount tests\n");
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");
387 static BOOL DoTest2(void)
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");
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");
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");
422 static BOOL DoTest3(void)
430 IMAGELISTDRAWPARAMS imldp;
434 if (!pImageList_DrawIndirect)
436 win_skip("ImageList_DrawIndirect not available, skipping test\n");
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");
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");
472 ok(!pImageList_DrawIndirect(&imldp),"zero himl succeeded!\n");
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");
483 imldp.fStyle = SRCCOPY;
484 imldp.rgbBk = CLR_DEFAULT;
485 imldp.rgbFg = CLR_DEFAULT;
488 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
490 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
492 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
494 ok(!pImageList_DrawIndirect(&imldp),"should fail\n");
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");
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);
515 static void testMerge(void)
517 HIMAGELIST himl1, himl2, hmerge;
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)
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");
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);
591 /*********************** imagelist storage test ***************************/
598 char *iml_data; /* written imagelist data */
602 static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface(
611 static ULONG STDMETHODCALLTYPE Test_Stream_AddRef(
618 static ULONG STDMETHODCALLTYPE Test_Stream_Release(
625 static HRESULT STDMETHODCALLTYPE Test_Stream_Read(
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);
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(
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;
664 static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(
666 LARGE_INTEGER dlibMove,
668 ULARGE_INTEGER* plibNewPosition)
674 static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(
676 ULARGE_INTEGER libNewSize)
682 static HRESULT STDMETHODCALLTYPE Test_Stream_CopyTo(
686 ULARGE_INTEGER* pcbRead,
687 ULARGE_INTEGER* pcbWritten)
693 static HRESULT STDMETHODCALLTYPE Test_Stream_Commit(
695 DWORD grfCommitFlags)
701 static HRESULT STDMETHODCALLTYPE Test_Stream_Revert(
708 static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion(
710 ULARGE_INTEGER libOffset,
718 static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion(
720 ULARGE_INTEGER libOffset,
728 static HRESULT STDMETHODCALLTYPE Test_Stream_Stat(
737 static HRESULT STDMETHODCALLTYPE Test_Stream_Clone(
745 static const IStreamVtbl Test_Stream_Vtbl =
747 Test_Stream_QueryInterface,
757 Test_Stream_LockRegion,
758 Test_Stream_UnlockRegion,
763 static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 };
765 static INT DIB_GetWidthBytes( int width, int 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;
775 case 16: words = (width + 1) / 2; break;
776 case 24: words = (width * 3 + 3)/4; break;
777 case 32: words = width; break;
781 trace("Unknown depth %d, please report.\n", bpp );
788 static void check_bitmap_data(const char *bm_data, ULONG bm_data_size,
789 INT width, INT height, INT bpp,
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);
817 sprintf(fname, "bmp_%s.bmp", comment);
818 f = fopen(fname, "wb");
819 fwrite(bm_data, 1, bm_data_size, f);
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)
855 char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
856 BITMAPINFO *bmi = (BITMAPINFO *)bmibuf;
857 HBITMAP hbmp, hbmp_old;
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);
886 static void image_list_init(HIMAGELIST himl)
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);
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)
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)
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();
1000 test_imagelist_storage();