2 * Unit test suite for imagelist control.
4 * Copyright 2004 Michael Stefaniuc
5 * Copyright 2002 Mike McCormack for CodeWeavers
6 * Copyright 2007 Dmitry Timoshkov
7 * Copyright 2009 Owen Rudge for CodeWeavers
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.
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.
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
36 #include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */
38 #include "commoncontrols.h"
41 #include "wine/test.h"
47 #define WAIT Sleep (1000)
48 #define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW)
54 #define IMAGELIST_MAGIC (('L' << 8) | 'I')
57 /* Header used by ImageList_Read() and ImageList_Write() */
58 typedef struct _ILHEAD
73 static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
74 static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
77 static HINSTANCE hinst;
79 /* These macros build cursor/bitmap data in 4x4 pixel blocks */
80 #define B(x,y) ((x?0xf0:0)|(y?0xf:0))
81 #define ROW1(a,b,c,d,e,f,g,h) B(a,b),B(c,d),B(e,f),B(g,h)
82 #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), \
83 ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h)
84 #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)
85 #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), \
86 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), \
87 ROW2(a,b,c,d,e,f,g,h,i,j,k,l)
89 static const BYTE empty_bits[48*48/8];
91 static const BYTE icon_bits[32*32/8] =
93 ROW32(0,0,0,0,0,0,0,0),
94 ROW32(0,0,1,1,1,1,0,0),
95 ROW32(0,1,1,1,1,1,1,0),
96 ROW32(0,1,1,0,0,1,1,0),
97 ROW32(0,1,1,0,0,1,1,0),
98 ROW32(0,1,1,1,1,1,1,0),
99 ROW32(0,0,1,1,1,1,0,0),
100 ROW32(0,0,0,0,0,0,0,0)
103 static const BYTE bitmap_bits[48*48/8] =
105 ROW48(0,0,0,0,0,0,0,0,0,0,0,0),
106 ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
107 ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
108 ROW48(0,1,0,0,0,0,0,0,1,0,1,0),
109 ROW48(0,1,0,0,0,0,0,1,0,0,1,0),
110 ROW48(0,1,0,0,0,0,1,0,0,0,1,0),
111 ROW48(0,1,0,0,0,1,0,0,0,0,1,0),
112 ROW48(0,1,0,0,1,0,0,0,0,0,1,0),
113 ROW48(0,1,0,1,0,0,0,0,0,0,1,0),
114 ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
115 ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
116 ROW48(0,0,0,0,0,0,0,0,0,0,0,0)
119 static HIMAGELIST createImageList(int cx, int cy)
121 /* Create an ImageList and put an image into it */
122 HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1);
123 HBITMAP hbm = CreateBitmap(48, 48, 1, 1, bitmap_bits);
124 ImageList_Add(himl, hbm, NULL);
128 static HWND create_a_window(void)
130 char className[] = "bmwnd";
131 char winName[] = "Test Bitmap";
133 static int registered = 0;
139 cls.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
140 cls.lpfnWndProc = DefWindowProcA;
144 cls.hIcon = LoadIconA (0, IDI_APPLICATION);
145 cls.hCursor = LoadCursorA (0, IDC_ARROW);
146 cls.hbrBackground = GetStockObject (WHITE_BRUSH);
147 cls.lpszMenuName = 0;
148 cls.lpszClassName = className;
150 RegisterClassA (&cls);
155 hWnd = CreateWindowA (className, winName,
156 WS_OVERLAPPEDWINDOW ,
157 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
161 ShowWindow (hWnd, SW_SHOW);
169 static HDC show_image(HWND hwnd, HIMAGELIST himl, int idx, int size,
170 LPCSTR loc, BOOL clear)
174 if (!himl) return NULL;
176 SetWindowText(hwnd, loc);
178 ImageList_Draw(himl, idx, hdc, 0, 0, ILD_TRANSPARENT);
185 BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
186 ReleaseDC(hwnd, hdc);
193 /* Useful for checking differences */
195 static void dump_bits(const BYTE *p, const BYTE *q, int size)
201 for (i = 0; i < size * 2; i++)
204 for (j = 0; j < size; j++)
205 printf("%c%c", p[j] & 0xf0 ? 'X' : ' ', p[j] & 0xf ? 'X' : ' ');
207 for (j = 0; j < size; j++)
208 printf("%c%c", q[j] & 0xf0 ? 'X' : ' ', q[j] & 0xf ? 'X' : ' ');
217 static void check_bits(HWND hwnd, HIMAGELIST himl, int idx, int size,
218 const BYTE *checkbits, LPCSTR loc)
221 BYTE bits[100*100/8];
228 memset(bits, 0, sizeof(bits));
229 hdc = show_image(hwnd, himl, idx, size, loc, FALSE);
231 c = GetPixel(hdc, 0, 0);
233 for (y = 0; y < size; y ++)
235 for (x = 0; x < size; x++)
238 if (GetPixel(hdc, x, y) != c) bits[i] |= (0x80 >> (x & 0x7));
242 BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
243 ReleaseDC(hwnd, hdc);
245 ok (memcmp(bits, checkbits, (size * size)/8) == 0,
246 "%s: bits different\n", loc);
247 if (memcmp(bits, checkbits, (size * size)/8))
248 dump_bits(bits, checkbits, size);
252 static void testHotspot (void)
263 #define HOTSPOTS_MAX 4 /* Number of entries in hotspots */
264 static const struct hotspot hotspots[HOTSPOTS_MAX] = {
271 HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
272 HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
273 HWND hwnd = create_a_window();
276 for (i = 0; i < HOTSPOTS_MAX; i++) {
277 for (j = 0; j < HOTSPOTS_MAX; j++) {
278 int dx1 = hotspots[i].dx;
279 int dy1 = hotspots[i].dy;
280 int dx2 = hotspots[j].dx;
281 int dy2 = hotspots[j].dy;
282 int correctx, correcty, newx, newy;
287 ret = ImageList_BeginDrag(himl1, 0, dx1, dy1);
288 ok(ret != 0, "BeginDrag failed for { %d, %d }\n", dx1, dy1);
289 sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
290 show_image(hwnd, himl1, 0, max(SIZEX1, SIZEY1), loc, TRUE);
292 /* check merging the dragged image with a second image */
293 ret = ImageList_SetDragCursorImage(himl2, 0, dx2, dy2);
294 ok(ret != 0, "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
296 sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
297 show_image(hwnd, himl2, 0, max(SIZEX2, SIZEY2), loc, TRUE);
299 /* check new hotspot, it should be the same like the old one */
300 himlNew = ImageList_GetDragImage(NULL, &ppt);
301 ok(ppt.x == dx1 && ppt.y == dy1,
302 "Expected drag hotspot [%d,%d] got [%d,%d]\n",
303 dx1, dy1, ppt.x, ppt.y);
304 /* check size of new dragged image */
305 ImageList_GetIconSize(himlNew, &newx, &newy);
306 correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
307 correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
308 ok(newx == correctx && newy == correcty,
309 "Expected drag image size [%d,%d] got [%d,%d]\n",
310 correctx, correcty, newx, newy);
311 sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
312 show_image(hwnd, himlNew, 0, max(correctx, correcty), loc, TRUE);
321 ImageList_Destroy(himl2);
322 ImageList_Destroy(himl1);
326 static BOOL DoTest1(void)
334 /* create an imagelist to play with */
335 himl = ImageList_Create(84,84,0x10,0,3);
336 ok(himl!=0,"failed to create imagelist\n");
338 /* load the icons to add to the image list */
339 hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
340 ok(hicon1 != 0, "no hicon1\n");
341 hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
342 ok(hicon2 != 0, "no hicon2\n");
343 hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
344 ok(hicon3 != 0, "no hicon3\n");
346 /* remove when nothing exists */
347 ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
348 /* removing everything from an empty imagelist should succeed */
349 ok(ImageList_RemoveAll(himl),"removed nonexistent icon\n");
352 ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
353 ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
354 ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
356 /* remove an index out of range */
357 ok(!ImageList_Remove(himl,4711),"removed nonexistent icon\n");
360 ok(ImageList_Remove(himl,0),"can't remove 0\n");
361 ok(ImageList_Remove(himl,0),"can't remove 0\n");
362 ok(ImageList_Remove(himl,0),"can't remove 0\n");
364 /* remove one extra */
365 ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
367 /* check SetImageCount/GetImageCount */
368 if (pImageList_SetImageCount)
370 ok(pImageList_SetImageCount(himl, 3), "couldn't increase image count\n");
371 ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
372 ok(pImageList_SetImageCount(himl, 1), "couldn't decrease image count\n");
373 ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
374 ok(pImageList_SetImageCount(himl, 0), "couldn't decrease image count\n");
375 ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
379 skip("skipped ImageList_SetImageCount tests\n");
383 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
385 ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
386 ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
387 ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
392 static BOOL DoTest2(void)
400 /* create an imagelist to play with */
401 himl = ImageList_Create(84,84,0x10,0,3);
402 ok(himl!=0,"failed to create imagelist\n");
404 /* load the icons to add to the image list */
405 hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
406 ok(hicon1 != 0, "no hicon1\n");
407 hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
408 ok(hicon2 != 0, "no hicon2\n");
409 hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
410 ok(hicon3 != 0, "no hicon3\n");
413 ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
414 ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
415 ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
418 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
420 ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
421 ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
422 ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
427 static BOOL DoTest3(void)
435 IMAGELISTDRAWPARAMS imldp;
439 if (!pImageList_DrawIndirect)
441 win_skip("ImageList_DrawIndirect not available, skipping test\n");
445 hwndfortest = create_a_window();
446 hdc = GetDC(hwndfortest);
447 ok(hdc!=NULL, "couldn't get DC\n");
449 /* create an imagelist to play with */
450 himl = ImageList_Create(48,48,0x10,0,3);
451 ok(himl!=0,"failed to create imagelist\n");
453 /* load the icons to add to the image list */
454 hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
455 ok(hbm1 != 0, "no bitmap 1\n");
456 hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
457 ok(hbm2 != 0, "no bitmap 2\n");
458 hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
459 ok(hbm3 != 0, "no bitmap 3\n");
462 ok(0==ImageList_Add(himl, hbm1, 0),"failed to add bitmap 1\n");
463 ok(1==ImageList_Add(himl, hbm2, 0),"failed to add bitmap 2\n");
465 if (pImageList_SetImageCount)
467 ok(pImageList_SetImageCount(himl,3),"Setimage count failed\n");
468 /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
469 ok(ImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
472 memset(&imldp, 0, sizeof (imldp));
473 ok(!pImageList_DrawIndirect(&imldp), "zero data succeeded!\n");
474 imldp.cbSize = sizeof (imldp);
475 ok(!pImageList_DrawIndirect(&imldp), "zero hdc succeeded!\n");
477 ok(!pImageList_DrawIndirect(&imldp),"zero himl succeeded!\n");
479 if (!pImageList_DrawIndirect(&imldp))
481 /* Earlier versions of native comctl32 use a smaller structure */
482 imldp.cbSize -= 3 * sizeof(DWORD);
483 ok(pImageList_DrawIndirect(&imldp),"DrawIndirect should succeed\n");
488 imldp.fStyle = SRCCOPY;
489 imldp.rgbBk = CLR_DEFAULT;
490 imldp.rgbFg = CLR_DEFAULT;
493 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
495 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
497 ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
499 ok(!pImageList_DrawIndirect(&imldp),"should fail\n");
502 ok(ImageList_Remove(himl, 0), "removing 1st bitmap\n");
503 ok(ImageList_Remove(himl, 0), "removing 2nd bitmap\n");
504 ok(ImageList_Remove(himl, 0), "removing 3rd bitmap\n");
507 ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
509 /* bitmaps should not be deleted by the imagelist */
510 ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
511 ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
512 ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");
514 ReleaseDC(hwndfortest, hdc);
515 DestroyWindow(hwndfortest);
520 static void testMerge(void)
522 HIMAGELIST himl1, himl2, hmerge;
524 HWND hwnd = create_a_window();
526 himl1 = ImageList_Create(32,32,0,0,3);
527 ok(himl1 != NULL,"failed to create himl1\n");
529 himl2 = ImageList_Create(32,32,0,0,3);
530 ok(himl2 != NULL,"failed to create himl2\n");
532 hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
533 ok(hicon1 != NULL, "failed to create hicon1\n");
535 if (!himl1 || !himl2 || !hicon1)
538 ok(0==ImageList_AddIcon(himl2, hicon1),"add icon1 to himl2 failed\n");
539 check_bits(hwnd, himl2, 0, 32, icon_bits, "add icon1 to himl2");
541 /* If himl1 has no images, merge still succeeds */
542 hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
543 ok(hmerge != NULL, "merge himl1,-1 failed\n");
544 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,-1");
545 if (hmerge) ImageList_Destroy(hmerge);
547 hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
548 ok(hmerge != NULL,"merge himl1,0 failed\n");
549 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,0");
550 if (hmerge) ImageList_Destroy(hmerge);
552 /* Same happens if himl2 is empty */
553 ImageList_Destroy(himl2);
554 himl2 = ImageList_Create(32,32,0,0,3);
555 ok(himl2 != NULL,"failed to recreate himl2\n");
559 hmerge = ImageList_Merge(himl1, -1, himl2, -1, 0, 0);
560 ok(hmerge != NULL, "merge himl2,-1 failed\n");
561 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,-1");
562 if (hmerge) ImageList_Destroy(hmerge);
564 hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
565 ok(hmerge != NULL, "merge himl2,0 failed\n");
566 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,0");
567 if (hmerge) ImageList_Destroy(hmerge);
569 /* Now try merging an image with itself */
570 ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n");
572 hmerge = ImageList_Merge(himl2, 0, himl2, 0, 0, 0);
573 ok(hmerge != NULL, "merge himl2 with itself failed\n");
574 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2 with itself");
575 if (hmerge) ImageList_Destroy(hmerge);
577 /* Try merging 2 different image lists */
578 ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n");
580 hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
581 ok(hmerge != NULL, "merge himl1 with himl2 failed\n");
582 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2");
583 if (hmerge) ImageList_Destroy(hmerge);
585 hmerge = ImageList_Merge(himl1, 0, himl2, 0, 8, 16);
586 ok(hmerge != NULL, "merge himl1 with himl2 8,16 failed\n");
587 check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2, 8,16");
588 if (hmerge) ImageList_Destroy(hmerge);
590 ImageList_Destroy(himl1);
591 ImageList_Destroy(himl2);
596 /*********************** imagelist storage test ***************************/
603 char *iml_data; /* written imagelist data */
607 static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface(
616 static ULONG STDMETHODCALLTYPE Test_Stream_AddRef(
623 static ULONG STDMETHODCALLTYPE Test_Stream_Release(
630 static HRESULT STDMETHODCALLTYPE Test_Stream_Read(
640 static BOOL allocate_storage(struct my_IStream *my_is, ULONG add)
642 my_is->iml_data_size += add;
644 if (!my_is->iml_data)
645 my_is->iml_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data_size);
647 my_is->iml_data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data, my_is->iml_data_size);
649 return my_is->iml_data ? TRUE : FALSE;
652 static HRESULT STDMETHODCALLTYPE Test_Stream_Write(
658 struct my_IStream *my_is = (struct my_IStream *)This;
659 ULONG current_iml_data_size = my_is->iml_data_size;
661 if (!allocate_storage(my_is, cb)) return E_FAIL;
663 memcpy(my_is->iml_data + current_iml_data_size, pv, cb);
664 if (pcbWritten) *pcbWritten = cb;
669 static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(
671 LARGE_INTEGER dlibMove,
673 ULARGE_INTEGER* plibNewPosition)
679 static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(
681 ULARGE_INTEGER libNewSize)
687 static HRESULT STDMETHODCALLTYPE Test_Stream_CopyTo(
691 ULARGE_INTEGER* pcbRead,
692 ULARGE_INTEGER* pcbWritten)
698 static HRESULT STDMETHODCALLTYPE Test_Stream_Commit(
700 DWORD grfCommitFlags)
706 static HRESULT STDMETHODCALLTYPE Test_Stream_Revert(
713 static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion(
715 ULARGE_INTEGER libOffset,
723 static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion(
725 ULARGE_INTEGER libOffset,
733 static HRESULT STDMETHODCALLTYPE Test_Stream_Stat(
742 static HRESULT STDMETHODCALLTYPE Test_Stream_Clone(
750 static const IStreamVtbl Test_Stream_Vtbl =
752 Test_Stream_QueryInterface,
762 Test_Stream_LockRegion,
763 Test_Stream_UnlockRegion,
768 static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 };
770 static INT DIB_GetWidthBytes( int width, int bpp )
776 case 1: words = (width + 31) / 32; break;
777 case 4: words = (width + 7) / 8; break;
778 case 8: words = (width + 3) / 4; break;
780 case 16: words = (width + 1) / 2; break;
781 case 24: words = (width * 3 + 3)/4; break;
782 case 32: words = width; break;
786 trace("Unknown depth %d, please report.\n", bpp );
793 static void check_bitmap_data(const char *bm_data, ULONG bm_data_size,
794 INT width, INT height, INT bpp,
797 const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data;
798 const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh));
799 ULONG hdr_size, image_size;
801 hdr_size = sizeof(*bmfh) + sizeof(*bmih);
802 if (bmih->biBitCount <= 8) hdr_size += (1 << bpp) * sizeof(RGBQUAD);
804 ok(bmfh->bfType == (('M' << 8) | 'B'), "wrong bfType 0x%02x\n", bmfh->bfType);
805 ok(bmfh->bfSize == hdr_size, "wrong bfSize 0x%02x\n", bmfh->bfSize);
806 ok(bmfh->bfReserved1 == 0, "wrong bfReserved1 0x%02x\n", bmfh->bfReserved1);
807 ok(bmfh->bfReserved2 == 0, "wrong bfReserved2 0x%02x\n", bmfh->bfReserved2);
808 ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits);
810 ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize);
811 ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width);
812 ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height);
813 ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes);
814 ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount);
816 image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight;
817 ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage);
822 sprintf(fname, "bmp_%s.bmp", comment);
823 f = fopen(fname, "wb");
824 fwrite(bm_data, 1, bm_data_size, f);
830 static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max)
832 ILHEAD *ilh = (ILHEAD *)ilh_data;
834 ok(ilh->usMagic == IMAGELIST_MAGIC, "wrong usMagic %4x (expected %02x)\n", ilh->usMagic, IMAGELIST_MAGIC);
835 ok(ilh->usVersion == 0x101, "wrong usVersion %x (expected 0x101)\n", ilh->usVersion);
836 ok(ilh->cCurImage == cur, "wrong cCurImage %d (expected %d)\n", ilh->cCurImage, cur);
837 ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
838 ok(ilh->cGrow == 4, "wrong cGrow %d (expected 4)\n", ilh->cGrow);
839 ok(ilh->cx == cx, "wrong cx %d (expected %d)\n", ilh->cx, cx);
840 ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy);
841 ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor);
842 ok(ilh->flags == ILC_COLOR24, "wrong flags %04x\n", ilh->flags);
843 ok(ilh->ovls[0] == -1 ||
844 ilh->ovls[0] == 0, /* win95 */
845 "wrong ovls[0] %04x\n", ilh->ovls[0]);
846 ok(ilh->ovls[1] == -1 ||
847 ilh->ovls[1] == 0, /* win95 */
848 "wrong ovls[1] %04x\n", ilh->ovls[1]);
849 ok(ilh->ovls[2] == -1 ||
850 ilh->ovls[2] == 0, /* win95 */
851 "wrong ovls[2] %04x\n", ilh->ovls[2]);
852 ok(ilh->ovls[3] == -1 ||
853 ilh->ovls[3] == 0, /* win95 */
854 "wrong ovls[3] %04x\n", ilh->ovls[3]);
857 static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment)
860 char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
861 BITMAPINFO *bmi = (BITMAPINFO *)bmibuf;
862 HBITMAP hbmp, hbmp_old;
864 RECT rc = { 0, 0, cx, cy };
866 hdc = CreateCompatibleDC(0);
868 memset(bmi, 0, sizeof(*bmi));
869 bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
870 bmi->bmiHeader.biHeight = cx;
871 bmi->bmiHeader.biWidth = cy;
872 bmi->bmiHeader.biBitCount = 24;
873 bmi->bmiHeader.biPlanes = 1;
874 bmi->bmiHeader.biCompression = BI_RGB;
875 hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
877 hbmp_old = SelectObject(hdc, hbmp);
879 hbrush = CreateSolidBrush(color);
880 FillRect(hdc, &rc, hbrush);
881 DeleteObject(hbrush);
883 DrawText(hdc, comment, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
885 SelectObject(hdc, hbmp_old);
891 static void image_list_init(HIMAGELIST himl)
897 #define add_bitmap(grey) \
898 sprintf(comment, "%d", n++); \
899 hbm = create_bitmap(BMP_CX, BMP_CX, RGB((grey),(grey),(grey)), comment); \
900 ImageList_Add(himl, hbm, NULL);
902 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
903 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
904 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
905 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
906 add_bitmap(255); add_bitmap(170); add_bitmap(85); add_bitmap(0);
907 add_bitmap(0); add_bitmap(85); add_bitmap(170); add_bitmap(255);
911 #define iml_clear_stream_data() \
912 HeapFree(GetProcessHeap(), 0, Test_Stream.iml_data); \
913 Test_Stream.iml_data = NULL; \
914 Test_Stream.iml_data_size = 0;
916 static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max,
917 INT width, INT height, INT bpp, const char *comment)
921 ret = ImageList_GetImageCount(himl);
922 ok(ret == cur, "expected cur %d got %d\n", cur, ret);
924 ret = ImageList_GetIconSize(himl, &cxx, &cyy);
925 ok(ret, "ImageList_GetIconSize failed\n");
926 ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx);
927 ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy);
929 iml_clear_stream_data();
930 ret = ImageList_Write(himl, &Test_Stream.is);
931 ok(ret, "ImageList_Write failed\n");
933 ok(Test_Stream.iml_data != 0, "ImageList_Write didn't write any data\n");
934 ok(Test_Stream.iml_data_size > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n");
936 check_ilhead_data(Test_Stream.iml_data, cx, cy, cur, max);
937 check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD),
938 Test_Stream.iml_data_size - sizeof(ILHEAD),
939 width, height, bpp, comment);
942 static void test_imagelist_storage(void)
947 himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
948 ok(himl != 0, "ImageList_Create failed\n");
950 check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, BMP_CX * 4, BMP_CX * 1, 24, "empty");
952 image_list_init(himl);
953 check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, BMP_CX * 4, BMP_CX * 7, 24, "orig");
955 ret = ImageList_Remove(himl, 4);
956 ok(ret, "ImageList_Remove failed\n");
957 check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, BMP_CX * 4, BMP_CX * 7, 24, "1");
959 ret = ImageList_Remove(himl, 5);
960 ok(ret, "ImageList_Remove failed\n");
961 check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, BMP_CX * 4, BMP_CX * 7, 24, "2");
963 ret = ImageList_Remove(himl, 6);
964 ok(ret, "ImageList_Remove failed\n");
965 check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, BMP_CX * 4, BMP_CX * 7, 24, "3");
967 ret = ImageList_Remove(himl, 7);
968 ok(ret, "ImageList_Remove failed\n");
969 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "4");
971 ret = ImageList_Remove(himl, -2);
972 ok(!ret, "ImageList_Remove(-2) should fail\n");
973 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "5");
975 ret = ImageList_Remove(himl, 20);
976 ok(!ret, "ImageList_Remove(20) should fail\n");
977 check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, BMP_CX * 4, BMP_CX * 7, 24, "6");
979 ret = ImageList_Remove(himl, -1);
980 ok(ret, "ImageList_Remove(-1) failed\n");
981 check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, BMP_CX * 4, BMP_CX * 1, 24, "7");
983 ret = ImageList_Destroy(himl);
984 ok(ret, "ImageList_Destroy failed\n");
986 iml_clear_stream_data();
989 static void test_shell_imagelist(void)
991 BOOL (WINAPI *pSHGetImageList)(INT, REFIID, void**);
992 IImageList *iml = NULL;
998 /* Try to load function from shell32 */
999 hShell32 = LoadLibrary("shell32.dll");
1000 pSHGetImageList = (void*)GetProcAddress(hShell32, (LPCSTR) 727);
1002 if (!pSHGetImageList)
1004 win_skip("SHGetImageList not available, skipping test\n");
1008 /* Get system image list */
1009 hr = (pSHGetImageList)(SHIL_LARGE, &IID_IImageList, (void**)&iml);
1011 todo_wine ok(SUCCEEDED(hr), "SHGetImageList failed, hr=%x\n", hr);
1016 IImageList_GetImageCount(iml, &out);
1017 todo_wine ok(out > 0, "IImageList_GetImageCount returned out <= 0\n");
1019 /* right and bottom should be 32x32 for large icons, or 48x48 if larger
1020 icons enabled in control panel */
1021 IImageList_GetImageRect(iml, 0, &rect);
1022 todo_wine ok((((rect.right == 32) && (rect.bottom == 32)) ||
1023 ((rect.right == 48) && (rect.bottom == 48))),
1024 "IImageList_GetImageRect returned r:%d,b:%d\n",
1025 rect.right, rect.bottom);
1027 IImageList_Release(iml);
1028 FreeLibrary(hShell32);
1031 START_TEST(imagelist)
1033 ULONG_PTR ctx_cookie;
1035 HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
1036 pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
1037 pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
1039 desktopDC=GetDC(NULL);
1040 hinst = GetModuleHandleA(NULL);
1042 InitCommonControls();
1049 test_imagelist_storage();
1051 /* Now perform v6 tests */
1053 if (!load_v6_module(&ctx_cookie))
1056 test_shell_imagelist();
1058 unload_v6_module(ctx_cookie);