imagelist.c 64.5 KB
Newer Older
1 2
/*
 * Unit test suite for imagelist control.
3 4
 *
 * Copyright 2004 Michael Stefaniuc
5
 * Copyright 2002 Mike McCormack for CodeWeavers
6
 * Copyright 2007 Dmitry Timoshkov
7
 * Copyright 2009 Owen Rudge for CodeWeavers
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 23
 */

24 25 26 27
#define COBJMACROS
#define CONST_VTABLE

#include <stdarg.h>
28
#include <stdio.h>
29 30 31 32 33 34 35 36
#include <assert.h>

#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "objbase.h"
#include "commctrl.h" /* must be included after objbase.h to get ImageList_Write */
37 38 39
#include "initguid.h"
#include "commoncontrols.h"
#include "shellapi.h"
40 41

#include "wine/test.h"
42
#include "v6util.h"
43

44 45 46 47 48 49 50 51 52 53
#undef VISIBLE

#ifdef VISIBLE
#define WAIT Sleep (1000)
#define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW)
#else
#define WAIT
#define REDRAW(hwnd)
#endif

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#define IMAGELIST_MAGIC (('L' << 8) | 'I')

#include "pshpack2.h"
/* Header used by ImageList_Read() and ImageList_Write() */
typedef struct _ILHEAD
{
    USHORT	usMagic;
    USHORT	usVersion;
    WORD	cCurImage;
    WORD	cMaxImage;
    WORD	cGrow;
    WORD	cx;
    WORD	cy;
    COLORREF	bkcolor;
    WORD	flags;
    SHORT	ovls[4];
} ILHEAD;
#include "poppack.h"
72

73 74
static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
75 76
static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*);
static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
77 78 79
static HRESULT (WINAPI *pImageList_CoCreateInstance)(REFCLSID,const IUnknown *,
    REFIID,void **);
static HRESULT (WINAPI *pHIMAGELIST_QueryInterface)(HIMAGELIST,REFIID,void **);
80

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
static HINSTANCE hinst;

/* These macros build cursor/bitmap data in 4x4 pixel blocks */
#define B(x,y) ((x?0xf0:0)|(y?0xf:0))
#define ROW1(a,b,c,d,e,f,g,h) B(a,b),B(c,d),B(e,f),B(g,h)
#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), \
  ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h)
#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)
#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), \
  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), \
  ROW2(a,b,c,d,e,f,g,h,i,j,k,l)

static const BYTE empty_bits[48*48/8];

static const BYTE icon_bits[32*32/8] =
{
  ROW32(0,0,0,0,0,0,0,0),
  ROW32(0,0,1,1,1,1,0,0),
  ROW32(0,1,1,1,1,1,1,0),
  ROW32(0,1,1,0,0,1,1,0),
  ROW32(0,1,1,0,0,1,1,0),
  ROW32(0,1,1,1,1,1,1,0),
  ROW32(0,0,1,1,1,1,0,0),
  ROW32(0,0,0,0,0,0,0,0)
};

static const BYTE bitmap_bits[48*48/8] =
{
  ROW48(0,0,0,0,0,0,0,0,0,0,0,0),
  ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
  ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
  ROW48(0,1,0,0,0,0,0,0,1,0,1,0),
  ROW48(0,1,0,0,0,0,0,1,0,0,1,0),
  ROW48(0,1,0,0,0,0,1,0,0,0,1,0),
  ROW48(0,1,0,0,0,1,0,0,0,0,1,0),
  ROW48(0,1,0,0,1,0,0,0,0,0,1,0),
  ROW48(0,1,0,1,0,0,0,0,0,0,1,0),
  ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
  ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
  ROW48(0,0,0,0,0,0,0,0,0,0,0,0)
};
122

123
static HIMAGELIST createImageList(int cx, int cy)
124 125 126
{
    /* Create an ImageList and put an image into it */
    HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1);
127
    HBITMAP hbm = CreateBitmap(48, 48, 1, 1, bitmap_bits);
128
    ImageList_Add(himl, hbm, NULL);
129
    DeleteObject(hbm);
130 131 132
    return himl;
}

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
static HWND create_a_window(void)
{
    char className[] = "bmwnd";
    char winName[]   = "Test Bitmap";
    HWND hWnd;
    static int registered = 0;

    if (!registered)
    {
        WNDCLASSA cls;

        cls.style         = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
        cls.lpfnWndProc   = DefWindowProcA;
        cls.cbClsExtra    = 0;
        cls.cbWndExtra    = 0;
        cls.hInstance     = 0;
149 150
        cls.hIcon         = LoadIconA (0, IDI_APPLICATION);
        cls.hCursor       = LoadCursorA (0, IDC_ARROW);
151
        cls.hbrBackground = GetStockObject (WHITE_BRUSH);
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
        cls.lpszMenuName  = 0;
        cls.lpszClassName = className;

        RegisterClassA (&cls);
        registered = 1;
    }

    /* Setup window */
    hWnd = CreateWindowA (className, winName,
       WS_OVERLAPPEDWINDOW ,
       CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
       0, hinst, 0);

#ifdef VISIBLE
    ShowWindow (hWnd, SW_SHOW);
#endif
    REDRAW(hWnd);
    WAIT;

    return hWnd;
}

static HDC show_image(HWND hwnd, HIMAGELIST himl, int idx, int size,
                      LPCSTR loc, BOOL clear)
{
    HDC hdc = NULL;
#ifdef VISIBLE
    if (!himl) return NULL;

    SetWindowText(hwnd, loc);
    hdc = GetDC(hwnd);
    ImageList_Draw(himl, idx, hdc, 0, 0, ILD_TRANSPARENT);

    REDRAW(hwnd);
    WAIT;

    if (clear)
    {
        BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
        ReleaseDC(hwnd, hdc);
        hdc = NULL;
    }
#endif /* VISIBLE */
    return hdc;
}

/* Useful for checking differences */
199
#if 0
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
static void dump_bits(const BYTE *p, const BYTE *q, int size)
{
  int i, j;

  size /= 8;

  for (i = 0; i < size * 2; i++)
  {
      printf("|");
      for (j = 0; j < size; j++)
          printf("%c%c", p[j] & 0xf0 ? 'X' : ' ', p[j] & 0xf ? 'X' : ' ');
      printf(" -- ");
      for (j = 0; j < size; j++)
          printf("%c%c", q[j] & 0xf0 ? 'X' : ' ', q[j] & 0xf ? 'X' : ' ');
      printf("|\n");
      p += size * 4;
      q += size * 4;
  }
  printf("\n");
}
220
#endif
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256

static void check_bits(HWND hwnd, HIMAGELIST himl, int idx, int size,
                       const BYTE *checkbits, LPCSTR loc)
{
#ifdef VISIBLE
    BYTE bits[100*100/8];
    COLORREF c;
    HDC hdc;
    int x, y, i = -1;

    if (!himl) return;

    memset(bits, 0, sizeof(bits));
    hdc = show_image(hwnd, himl, idx, size, loc, FALSE);

    c = GetPixel(hdc, 0, 0);

    for (y = 0; y < size; y ++)
    {
        for (x = 0; x < size; x++)
        {
            if (!(x & 0x7)) i++;
            if (GetPixel(hdc, x, y) != c) bits[i] |= (0x80 >> (x & 0x7));
        }
    }

    BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
    ReleaseDC(hwnd, hdc);

    ok (memcmp(bits, checkbits, (size * size)/8) == 0,
        "%s: bits different\n", loc);
    if (memcmp(bits, checkbits, (size * size)/8))
        dump_bits(bits, checkbits, size);
#endif /* VISIBLE */
}

257
static void test_hotspot(void)
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
{
    struct hotspot {
        int dx;
        int dy;
    };

#define SIZEX1 47
#define SIZEY1 31
#define SIZEX2 11
#define SIZEY2 17
#define HOTSPOTS_MAX 4       /* Number of entries in hotspots */
    static const struct hotspot hotspots[HOTSPOTS_MAX] = {
        { 10, 7 },
        { SIZEX1, SIZEY1 },
        { -9, -8 },
        { -7, 35 }
    };
    int i, j, ret;
    HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
    HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
278 279
    HWND hwnd = create_a_window();

280 281 282 283 284 285 286 287

    for (i = 0; i < HOTSPOTS_MAX; i++) {
        for (j = 0; j < HOTSPOTS_MAX; j++) {
            int dx1 = hotspots[i].dx;
            int dy1 = hotspots[i].dy;
            int dx2 = hotspots[j].dx;
            int dy2 = hotspots[j].dy;
            int correctx, correcty, newx, newy;
288
            char loc[256];
289 290 291 292 293
            HIMAGELIST himlNew;
            POINT ppt;

            ret = ImageList_BeginDrag(himl1, 0, dx1, dy1);
            ok(ret != 0, "BeginDrag failed for { %d, %d }\n", dx1, dy1);
294 295 296
            sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
            show_image(hwnd, himl1, 0, max(SIZEX1, SIZEY1), loc, TRUE);

297 298 299 300
            /* check merging the dragged image with a second image */
            ret = ImageList_SetDragCursorImage(himl2, 0, dx2, dy2);
            ok(ret != 0, "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
                    dx1, dy1, dx2, dy2);
301 302 303
            sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
            show_image(hwnd, himl2, 0, max(SIZEX2, SIZEY2), loc, TRUE);

304 305 306
            /* check new hotspot, it should be the same like the old one */
            himlNew = ImageList_GetDragImage(NULL, &ppt);
            ok(ppt.x == dx1 && ppt.y == dy1,
307
                    "Expected drag hotspot [%d,%d] got [%d,%d]\n",
308 309 310 311 312 313 314 315
                    dx1, dy1, ppt.x, ppt.y);
            /* check size of new dragged image */
            ImageList_GetIconSize(himlNew, &newx, &newy);
            correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
            correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
            ok(newx == correctx && newy == correcty,
                    "Expected drag image size [%d,%d] got [%d,%d]\n",
                    correctx, correcty, newx, newy);
316 317
            sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
            show_image(hwnd, himlNew, 0, max(correctx, correcty), loc, TRUE);
318 319 320 321 322 323 324 325
            ImageList_EndDrag();
        }
    }
#undef SIZEX1
#undef SIZEY1
#undef SIZEX2
#undef SIZEY2
#undef HOTSPOTS_MAX
326 327
    ImageList_Destroy(himl2);
    ImageList_Destroy(himl1);
328
    DestroyWindow(hwnd);
329 330
}

331
static void test_add_remove(void)
332 333 334 335 336 337 338 339
{
    HIMAGELIST himl ;

    HICON hicon1 ;
    HICON hicon2 ;
    HICON hicon3 ;

    /* create an imagelist to play with */
340
    himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
341
    ok(himl!=0,"failed to create imagelist\n");
342 343 344

    /* load the icons to add to the image list */
    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
345
    ok(hicon1 != 0, "no hicon1\n");
346
    hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
347
    ok(hicon2 != 0, "no hicon2\n");
348
    hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
349
    ok(hicon3 != 0, "no hicon3\n");
350 351

    /* remove when nothing exists */
352
    ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
353
    /* removing everything from an empty imagelist should succeed */
354
    ok(ImageList_RemoveAll(himl),"removed nonexistent icon\n");
355 356

    /* add three */
357 358 359
    ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
    ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
    ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
360

361
    /* remove an index out of range */
362
    ok(!ImageList_Remove(himl,4711),"removed nonexistent icon\n");
363

364
    /* remove three */
365 366 367
    ok(ImageList_Remove(himl,0),"can't remove 0\n");
    ok(ImageList_Remove(himl,0),"can't remove 0\n");
    ok(ImageList_Remove(himl,0),"can't remove 0\n");
368 369

    /* remove one extra */
370
    ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
371 372

    /* destroy it */
373
    ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
374

375 376
    ok(-1==ImageList_AddIcon((HIMAGELIST)0xdeadbeef, hicon1),"don't crash on bad handle\n");

377 378 379
    ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
    ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
    ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
380 381
}

382
static void test_imagecount(void)
383
{
384
    HIMAGELIST himl;
385

386 387
    ok(0==ImageList_GetImageCount((HIMAGELIST)0xdeadbeef),"don't crash on bad handle\n");

388 389 390 391 392
    if (!pImageList_SetImageCount)
    {
        win_skip("ImageList_SetImageCount not available\n");
        return;
    }
393

394
    himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
395
    ok(himl!=0,"failed to create imagelist\n");
396

397 398 399 400 401 402
    ok(pImageList_SetImageCount(himl, 3), "couldn't increase image count\n");
    ok(ImageList_GetImageCount(himl) == 3, "invalid image count after increase\n");
    ok(pImageList_SetImageCount(himl, 1), "couldn't decrease image count\n");
    ok(ImageList_GetImageCount(himl) == 1, "invalid image count after decrease to 1\n");
    ok(pImageList_SetImageCount(himl, 0), "couldn't decrease image count\n");
    ok(ImageList_GetImageCount(himl) == 0, "invalid image count after decrease to 0\n");
403

404
    ok(ImageList_Destroy(himl), "destroy imagelist failed\n");
405 406
}

407
static void test_DrawIndirect(void)
408
{
409
    HIMAGELIST himl;
410

411 412 413
    HBITMAP hbm1;
    HBITMAP hbm2;
    HBITMAP hbm3;
414 415 416 417 418

    IMAGELISTDRAWPARAMS imldp;
    HDC hdc;
    HWND hwndfortest;

419 420
    if (!pImageList_DrawIndirect)
    {
421
        win_skip("ImageList_DrawIndirect not available, skipping test\n");
422
        return;
423 424
    }

425 426 427 428 429
    hwndfortest = create_a_window();
    hdc = GetDC(hwndfortest);
    ok(hdc!=NULL, "couldn't get DC\n");

    /* create an imagelist to play with */
430
    himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3);
431
    ok(himl!=0,"failed to create imagelist\n");
432 433 434

    /* load the icons to add to the image list */
    hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
435
    ok(hbm1 != 0, "no bitmap 1\n");
436
    hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
437
    ok(hbm2 != 0, "no bitmap 2\n");
438
    hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
439
    ok(hbm3 != 0, "no bitmap 3\n");
440 441

    /* add three */
442 443
    ok(0==ImageList_Add(himl, hbm1, 0),"failed to add bitmap 1\n");
    ok(1==ImageList_Add(himl, hbm2, 0),"failed to add bitmap 2\n");
444

445 446 447 448 449 450
    if (pImageList_SetImageCount)
    {
        ok(pImageList_SetImageCount(himl,3),"Setimage count failed\n");
        /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
        ok(ImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
    }
451

452
    memset(&imldp, 0, sizeof (imldp));
453
    ok(!pImageList_DrawIndirect(&imldp), "zero data succeeded!\n");
454
    imldp.cbSize = IMAGELISTDRAWPARAMS_V3_SIZE;
455
    ok(!pImageList_DrawIndirect(&imldp), "zero hdc succeeded!\n");
456
    imldp.hdcDst = hdc;
457
    ok(!pImageList_DrawIndirect(&imldp),"zero himl succeeded!\n");
458 459
    imldp.himl = (HIMAGELIST)0xdeadbeef;
    ok(!pImageList_DrawIndirect(&imldp),"bad himl succeeded!\n");
460
    imldp.himl = himl;
461

462 463 464
    REDRAW(hwndfortest);
    WAIT;

465 466 467 468 469
    imldp.fStyle = SRCCOPY;
    imldp.rgbBk = CLR_DEFAULT;
    imldp.rgbFg = CLR_DEFAULT;
    imldp.y = 100;
    imldp.x = 100;
470
    ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
471
    imldp.i ++;
472
    ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
473
    imldp.i ++;
474
    ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
475
    imldp.i ++;
476
    ok(!pImageList_DrawIndirect(&imldp),"should fail\n");
477 478

    /* remove three */
479 480 481
    ok(ImageList_Remove(himl, 0), "removing 1st bitmap\n");
    ok(ImageList_Remove(himl, 0), "removing 2nd bitmap\n");
    ok(ImageList_Remove(himl, 0), "removing 3rd bitmap\n");
482 483

    /* destroy it */
484
    ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
485

486
    /* bitmaps should not be deleted by the imagelist */
487 488 489
    ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
    ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
    ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");
490 491 492 493 494

    ReleaseDC(hwndfortest, hdc);
    DestroyWindow(hwndfortest);
}

495
static void test_merge(void)
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
{
    HIMAGELIST himl1, himl2, hmerge;
    HICON hicon1;
    HWND hwnd = create_a_window();

    himl1 = ImageList_Create(32,32,0,0,3);
    ok(himl1 != NULL,"failed to create himl1\n");

    himl2 = ImageList_Create(32,32,0,0,3);
    ok(himl2 != NULL,"failed to create himl2\n");

    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
    ok(hicon1 != NULL, "failed to create hicon1\n");

    if (!himl1 || !himl2 || !hicon1)
        return;

    ok(0==ImageList_AddIcon(himl2, hicon1),"add icon1 to himl2 failed\n");
    check_bits(hwnd, himl2, 0, 32, icon_bits, "add icon1 to himl2");

    /* If himl1 has no images, merge still succeeds */
    hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
    ok(hmerge != NULL, "merge himl1,-1 failed\n");
    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,-1");
    if (hmerge) ImageList_Destroy(hmerge);

    hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
    ok(hmerge != NULL,"merge himl1,0 failed\n");
    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,0");
    if (hmerge) ImageList_Destroy(hmerge);

527
    /* Same happens if himl2 is empty */
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
    ImageList_Destroy(himl2);
    himl2 = ImageList_Create(32,32,0,0,3);
    ok(himl2 != NULL,"failed to recreate himl2\n");
    if (!himl2)
        return;

    hmerge = ImageList_Merge(himl1, -1, himl2, -1, 0, 0);
    ok(hmerge != NULL, "merge himl2,-1 failed\n");
    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,-1");
    if (hmerge) ImageList_Destroy(hmerge);

    hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
    ok(hmerge != NULL, "merge himl2,0 failed\n");
    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,0");
    if (hmerge) ImageList_Destroy(hmerge);

    /* Now try merging an image with itself */
    ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n");

    hmerge = ImageList_Merge(himl2, 0, himl2, 0, 0, 0);
    ok(hmerge != NULL, "merge himl2 with itself failed\n");
    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2 with itself");
    if (hmerge) ImageList_Destroy(hmerge);

    /* Try merging 2 different image lists */
    ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n");

    hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
    ok(hmerge != NULL, "merge himl1 with himl2 failed\n");
    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2");
    if (hmerge) ImageList_Destroy(hmerge);

    hmerge = ImageList_Merge(himl1, 0, himl2, 0, 8, 16);
    ok(hmerge != NULL, "merge himl1 with himl2 8,16 failed\n");
    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2, 8,16");
    if (hmerge) ImageList_Destroy(hmerge);

    ImageList_Destroy(himl1);
    ImageList_Destroy(himl2);
567
    DestroyIcon(hicon1);
568 569 570
    DestroyWindow(hwnd);
}

571 572 573 574 575 576
/*********************** imagelist storage test ***************************/

#define BMP_CX 48

struct my_IStream
{
577
    IStream IStream_iface;
578 579 580 581
    char *iml_data; /* written imagelist data */
    ULONG iml_data_size;
};

582
static struct my_IStream *impl_from_IStream(IStream *iface)
583 584 585 586 587 588
{
    return CONTAINING_RECORD(iface, struct my_IStream, IStream_iface);
}

static HRESULT STDMETHODCALLTYPE Test_Stream_QueryInterface(IStream *iface, REFIID riid,
                                                            void **ppvObject)
589 590 591 592 593
{
    assert(0);
    return E_NOTIMPL;
}

594
static ULONG STDMETHODCALLTYPE Test_Stream_AddRef(IStream *iface)
595 596 597 598 599
{
    assert(0);
    return 2;
}

600
static ULONG STDMETHODCALLTYPE Test_Stream_Release(IStream *iface)
601 602 603 604 605
{
    assert(0);
    return 1;
}

606 607
static HRESULT STDMETHODCALLTYPE Test_Stream_Read(IStream *iface, void *pv, ULONG cb,
                                                  ULONG *pcbRead)
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
{
    assert(0);
    return E_NOTIMPL;
}

static BOOL allocate_storage(struct my_IStream *my_is, ULONG add)
{
    my_is->iml_data_size += add;

    if (!my_is->iml_data)
        my_is->iml_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data_size);
    else
        my_is->iml_data = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, my_is->iml_data, my_is->iml_data_size);

    return my_is->iml_data ? TRUE : FALSE;
}

625 626
static HRESULT STDMETHODCALLTYPE Test_Stream_Write(IStream *iface, const void *pv, ULONG cb,
                                                   ULONG *pcbWritten)
627
{
628
    struct my_IStream *my_is = impl_from_IStream(iface);
629 630 631 632 633 634 635 636 637 638
    ULONG current_iml_data_size = my_is->iml_data_size;

    if (!allocate_storage(my_is, cb)) return E_FAIL;

    memcpy(my_is->iml_data + current_iml_data_size, pv, cb);
    if (pcbWritten) *pcbWritten = cb;

    return S_OK;
}

639 640
static HRESULT STDMETHODCALLTYPE Test_Stream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
                                                  DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
641 642 643 644 645
{
    assert(0);
    return E_NOTIMPL;
}

646
static HRESULT STDMETHODCALLTYPE Test_Stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
647 648 649 650 651
{
    assert(0);
    return E_NOTIMPL;
}

652 653 654
static HRESULT STDMETHODCALLTYPE Test_Stream_CopyTo(IStream *iface, IStream *pstm,
                                                    ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead,
                                                    ULARGE_INTEGER *pcbWritten)
655 656 657 658 659
{
    assert(0);
    return E_NOTIMPL;
}

660
static HRESULT STDMETHODCALLTYPE Test_Stream_Commit(IStream *iface, DWORD grfCommitFlags)
661 662 663 664 665
{
    assert(0);
    return E_NOTIMPL;
}

666
static HRESULT STDMETHODCALLTYPE Test_Stream_Revert(IStream *iface)
667 668 669 670 671
{
    assert(0);
    return E_NOTIMPL;
}

672 673
static HRESULT STDMETHODCALLTYPE Test_Stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
                                                        ULARGE_INTEGER cb, DWORD dwLockType)
674 675 676 677 678
{
    assert(0);
    return E_NOTIMPL;
}

679 680
static HRESULT STDMETHODCALLTYPE Test_Stream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
                                                          ULARGE_INTEGER cb, DWORD dwLockType)
681 682 683 684 685
{
    assert(0);
    return E_NOTIMPL;
}

686 687
static HRESULT STDMETHODCALLTYPE Test_Stream_Stat(IStream *iface, STATSTG *pstatstg,
                                                  DWORD grfStatFlag)
688 689 690 691 692
{
    assert(0);
    return E_NOTIMPL;
}

693
static HRESULT STDMETHODCALLTYPE Test_Stream_Clone(IStream *iface, IStream **ppstm)
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
{
    assert(0);
    return E_NOTIMPL;
}

static const IStreamVtbl Test_Stream_Vtbl =
{
    Test_Stream_QueryInterface,
    Test_Stream_AddRef,
    Test_Stream_Release,
    Test_Stream_Read,
    Test_Stream_Write,
    Test_Stream_Seek,
    Test_Stream_SetSize,
    Test_Stream_CopyTo,
    Test_Stream_Commit,
    Test_Stream_Revert,
    Test_Stream_LockRegion,
    Test_Stream_UnlockRegion,
    Test_Stream_Stat,
    Test_Stream_Clone
};

static struct my_IStream Test_Stream = { { &Test_Stream_Vtbl }, 0, 0 };

static INT DIB_GetWidthBytes( int width, int bpp )
{
721
    return ((width * bpp + 31) / 8) & ~3;
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
}

static void check_bitmap_data(const char *bm_data, ULONG bm_data_size,
                              INT width, INT height, INT bpp,
                              const char *comment)
{
    const BITMAPFILEHEADER *bmfh = (const BITMAPFILEHEADER *)bm_data;
    const BITMAPINFOHEADER *bmih = (const BITMAPINFOHEADER *)(bm_data + sizeof(*bmfh));
    ULONG hdr_size, image_size;

    hdr_size = sizeof(*bmfh) + sizeof(*bmih);
    if (bmih->biBitCount <= 8) hdr_size += (1 << bpp) * sizeof(RGBQUAD);

    ok(bmfh->bfType == (('M' << 8) | 'B'), "wrong bfType 0x%02x\n", bmfh->bfType);
    ok(bmfh->bfSize == hdr_size, "wrong bfSize 0x%02x\n", bmfh->bfSize);
    ok(bmfh->bfReserved1 == 0, "wrong bfReserved1 0x%02x\n", bmfh->bfReserved1);
    ok(bmfh->bfReserved2 == 0, "wrong bfReserved2 0x%02x\n", bmfh->bfReserved2);
    ok(bmfh->bfOffBits == hdr_size, "wrong bfOffBits 0x%02x\n", bmfh->bfOffBits);

    ok(bmih->biSize == sizeof(*bmih), "wrong biSize %d\n", bmih->biSize);
    ok(bmih->biWidth == width, "wrong biWidth %d (expected %d)\n", bmih->biWidth, width);
    ok(bmih->biHeight == height, "wrong biHeight %d (expected %d)\n", bmih->biHeight, height);
    ok(bmih->biPlanes == 1, "wrong biPlanes %d\n", bmih->biPlanes);
    ok(bmih->biBitCount == bpp, "wrong biBitCount %d\n", bmih->biBitCount);

    image_size = DIB_GetWidthBytes(bmih->biWidth, bmih->biBitCount) * bmih->biHeight;
    ok(bmih->biSizeImage == image_size, "wrong biSizeImage %u\n", bmih->biSizeImage);
#if 0
{
    char fname[256];
    FILE *f;
    sprintf(fname, "bmp_%s.bmp", comment);
    f = fopen(fname, "wb");
    fwrite(bm_data, 1, bm_data_size, f);
    fclose(f);
}
#endif
}

761
static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT max, INT grow)
762
{
763
    const ILHEAD *ilh = (const ILHEAD *)ilh_data;
764 765 766 767 768

    ok(ilh->usMagic == IMAGELIST_MAGIC, "wrong usMagic %4x (expected %02x)\n", ilh->usMagic, IMAGELIST_MAGIC);
    ok(ilh->usVersion == 0x101, "wrong usVersion %x (expected 0x101)\n", ilh->usVersion);
    ok(ilh->cCurImage == cur, "wrong cCurImage %d (expected %d)\n", ilh->cCurImage, cur);
    ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
769
    ok(ilh->cGrow == grow, "wrong cGrow %d (expected %d)\n", ilh->cGrow, grow);
770 771 772 773
    ok(ilh->cx == cx, "wrong cx %d (expected %d)\n", ilh->cx, cx);
    ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy);
    ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor);
    ok(ilh->flags == ILC_COLOR24, "wrong flags %04x\n", ilh->flags);
774 775 776 777
    ok(ilh->ovls[0] == -1, "wrong ovls[0] %04x\n", ilh->ovls[0]);
    ok(ilh->ovls[1] == -1, "wrong ovls[1] %04x\n", ilh->ovls[1]);
    ok(ilh->ovls[2] == -1, "wrong ovls[2] %04x\n", ilh->ovls[2]);
    ok(ilh->ovls[3] == -1, "wrong ovls[3] %04x\n", ilh->ovls[3]);
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
}

static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment)
{
    HDC hdc;
    char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
    BITMAPINFO *bmi = (BITMAPINFO *)bmibuf;
    HBITMAP hbmp, hbmp_old;
    HBRUSH hbrush;
    RECT rc = { 0, 0, cx, cy };

    hdc = CreateCompatibleDC(0);

    memset(bmi, 0, sizeof(*bmi));
    bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
    bmi->bmiHeader.biHeight = cx;
    bmi->bmiHeader.biWidth = cy;
    bmi->bmiHeader.biBitCount = 24;
    bmi->bmiHeader.biPlanes = 1;
    bmi->bmiHeader.biCompression = BI_RGB;
    hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);

    hbmp_old = SelectObject(hdc, hbmp);

    hbrush = CreateSolidBrush(color);
    FillRect(hdc, &rc, hbrush);
    DeleteObject(hbrush);

    DrawText(hdc, comment, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

    SelectObject(hdc, hbmp_old);
    DeleteDC(hdc);

    return hbmp;
}

#define iml_clear_stream_data() \
    HeapFree(GetProcessHeap(), 0, Test_Stream.iml_data); \
    Test_Stream.iml_data = NULL; \
817
    Test_Stream.iml_data_size = 0;
818

819
static void check_iml_data(HIMAGELIST himl, INT cx, INT cy, INT cur, INT max, INT grow,
820 821
                           INT width, INT height, INT bpp, const char *comment)
{
822 823
    INT ret, cxx, cyy;

824 825
    trace("%s\n", comment);

826
    ret = ImageList_GetImageCount(himl);
827
    ok(ret == cur, "expected image count %d got %d\n", cur, ret);
828 829 830 831 832

    ret = ImageList_GetIconSize(himl, &cxx, &cyy);
    ok(ret, "ImageList_GetIconSize failed\n");
    ok(cxx == cx, "wrong cx %d (expected %d)\n", cxx, cx);
    ok(cyy == cy, "wrong cy %d (expected %d)\n", cyy, cy);
833 834

    iml_clear_stream_data();
835
    ret = ImageList_Write(himl, &Test_Stream.IStream_iface);
836 837 838 839 840
    ok(ret, "ImageList_Write failed\n");

    ok(Test_Stream.iml_data != 0, "ImageList_Write didn't write any data\n");
    ok(Test_Stream.iml_data_size > sizeof(ILHEAD), "ImageList_Write wrote not enough data\n");

841
    check_ilhead_data(Test_Stream.iml_data, cx, cy, cur, max, grow);
842 843 844 845 846
    check_bitmap_data(Test_Stream.iml_data + sizeof(ILHEAD),
                      Test_Stream.iml_data_size - sizeof(ILHEAD),
                      width, height, bpp, comment);
}

847 848 849 850
static void image_list_init(HIMAGELIST himl)
{
    HBITMAP hbm;
    char comment[16];
851 852
    INT n = 1;
    DWORD i;
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
    static const struct test_data
    {
        BYTE grey;
        INT cx, cy, cur, max, grow, width, height, bpp;
        const char *comment;
    } td[] =
    {
        { 255, BMP_CX, BMP_CX, 1, 2, 4, BMP_CX * 4, BMP_CX * 1, 24, "total 1" },
        { 170, BMP_CX, BMP_CX, 2, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 2" },
        { 85, BMP_CX, BMP_CX, 3, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 3" },
        { 0, BMP_CX, BMP_CX, 4, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 4" },
        { 0, BMP_CX, BMP_CX, 5, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 5" },
        { 85, BMP_CX, BMP_CX, 6, 7, 4, BMP_CX * 4, BMP_CX * 2, 24, "total 6" },
        { 170, BMP_CX, BMP_CX, 7, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 7" },
        { 255, BMP_CX, BMP_CX, 8, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 8" },
        { 255, BMP_CX, BMP_CX, 9, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 9" },
        { 170, BMP_CX, BMP_CX, 10, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 10" },
        { 85, BMP_CX, BMP_CX, 11, 12, 4, BMP_CX * 4, BMP_CX * 3, 24, "total 11" },
        { 0, BMP_CX, BMP_CX, 12, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 12" },
        { 0, BMP_CX, BMP_CX, 13, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 13" },
        { 85, BMP_CX, BMP_CX, 14, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 14" },
        { 170, BMP_CX, BMP_CX, 15, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 15" },
        { 255, BMP_CX, BMP_CX, 16, 17, 4, BMP_CX * 4, BMP_CX * 5, 24, "total 16" },
        { 255, BMP_CX, BMP_CX, 17, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 17" },
        { 170, BMP_CX, BMP_CX, 18, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 18" },
        { 85, BMP_CX, BMP_CX, 19, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 19" },
        { 0, BMP_CX, BMP_CX, 20, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 20" },
        { 0, BMP_CX, BMP_CX, 21, 22, 4, BMP_CX * 4, BMP_CX * 6, 24, "total 21" },
        { 85, BMP_CX, BMP_CX, 22, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 22" },
        { 170, BMP_CX, BMP_CX, 23, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 23" },
        { 255, BMP_CX, BMP_CX, 24, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "total 24" }
    };

    check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, BMP_CX * 4, BMP_CX * 1, 24, "total 0");

#define add_bitmap(grey) \
    sprintf(comment, "%d", n++); \
    hbm = create_bitmap(BMP_CX, BMP_CX, RGB((grey),(grey),(grey)), comment); \
    ImageList_Add(himl, hbm, NULL); \
    DeleteObject(hbm);

    for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
    {
        add_bitmap(td[i].grey);
        check_iml_data(himl, td[i].cx, td[i].cy, td[i].cur, td[i].max, td[i].grow,
                       td[i].width, td[i].height, td[i].bpp, td[i].comment);
    }
#undef add_bitmap
}

903 904 905
static void test_imagelist_storage(void)
{
    HIMAGELIST himl;
906 907
    HBITMAP hbm;
    INT ret;
908 909 910 911

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 1, 1);
    ok(himl != 0, "ImageList_Create failed\n");

912
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, 4, BMP_CX * 4, BMP_CX * 1, 24, "empty");
913 914

    image_list_init(himl);
915
    check_iml_data(himl, BMP_CX, BMP_CX, 24, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "orig");
916 917 918

    ret = ImageList_Remove(himl, 4);
    ok(ret, "ImageList_Remove failed\n");
919
    check_iml_data(himl, BMP_CX, BMP_CX, 23, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "1");
920 921 922

    ret = ImageList_Remove(himl, 5);
    ok(ret, "ImageList_Remove failed\n");
923
    check_iml_data(himl, BMP_CX, BMP_CX, 22, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "2");
924 925 926

    ret = ImageList_Remove(himl, 6);
    ok(ret, "ImageList_Remove failed\n");
927
    check_iml_data(himl, BMP_CX, BMP_CX, 21, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "3");
928 929 930

    ret = ImageList_Remove(himl, 7);
    ok(ret, "ImageList_Remove failed\n");
931
    check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "4");
932

933 934
    ret = ImageList_Remove(himl, -2);
    ok(!ret, "ImageList_Remove(-2) should fail\n");
935
    check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "5");
936 937 938

    ret = ImageList_Remove(himl, 20);
    ok(!ret, "ImageList_Remove(20) should fail\n");
939
    check_iml_data(himl, BMP_CX, BMP_CX, 20, 27, 4, BMP_CX * 4, BMP_CX * 7, 24, "6");
940 941 942

    ret = ImageList_Remove(himl, -1);
    ok(ret, "ImageList_Remove(-1) failed\n");
943
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 4, 4, BMP_CX * 4, BMP_CX * 1, 24, "7");
944

945 946 947 948
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");

    iml_clear_stream_data();
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026

    /* test ImageList_Create storage allocation */

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 0, 32);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 1, 32, BMP_CX * 4, BMP_CX * 1, 24, "init 0 grow 32");
    hbm = create_bitmap(BMP_CX * 9, BMP_CX, 0, "9");
    ret = ImageList_Add(himl, hbm, NULL);
    ok(ret == 0, "ImageList_Add returned %d, expected 0\n", ret);
    check_iml_data(himl, BMP_CX, BMP_CX, 1, 34, 32, BMP_CX * 4, BMP_CX * 9, 24, "add 1 x 9");
    DeleteObject(hbm);
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 4);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, 24, "init 4 grow 4");
    hbm = create_bitmap(BMP_CX, BMP_CX * 9, 0, "9");
    ret = ImageList_Add(himl, hbm, NULL);
    ok(ret == 0, "ImageList_Add returned %d, expected 0\n", ret);
    check_iml_data(himl, BMP_CX, BMP_CX, 9, 15, 4, BMP_CX * 4, BMP_CX * 4, 24, "add 9 x 1");
    ret = ImageList_Add(himl, hbm, NULL);
    ok(ret == 9, "ImageList_Add returned %d, expected 9\n", ret);
    check_iml_data(himl, BMP_CX, BMP_CX, 18, 25, 4, BMP_CX * 4, BMP_CX * 7, 24, "add 9 x 1");
    DeleteObject(hbm);
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 207, 209);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 208, 212, BMP_CX * 4, BMP_CX * 52, 24, "init 207 grow 209");
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 209, 207);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 210, 208, BMP_CX * 4, BMP_CX * 53, 24, "init 209 grow 207");
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 14, 4);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 15, 4, BMP_CX * 4, BMP_CX * 4, 24, "init 14 grow 4");
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 5, 9);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 6, 12, BMP_CX * 4, BMP_CX * 2, 24, "init 5 grow 9");
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 9, 5);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 10, 8, BMP_CX * 4, BMP_CX * 3, 24, "init 9 grow 5");
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 2, 4);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 3, 4, BMP_CX * 4, BMP_CX * 1, 24, "init 2 grow 4");
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();

    himl = ImageList_Create(BMP_CX, BMP_CX, ILC_COLOR24, 4, 2);
    ok(himl != 0, "ImageList_Create failed\n");
    check_iml_data(himl, BMP_CX, BMP_CX, 0, 5, 4, BMP_CX * 4, BMP_CX * 2, 24, "init 4 grow 2");
    ret = ImageList_Destroy(himl);
    ok(ret, "ImageList_Destroy failed\n");
    iml_clear_stream_data();
1027 1028
}

1029 1030 1031 1032 1033 1034 1035 1036
static void test_shell_imagelist(void)
{
    BOOL (WINAPI *pSHGetImageList)(INT, REFIID, void**);
    IImageList *iml = NULL;
    HMODULE hShell32;
    HRESULT hr;
    int out = 0;
    RECT rect;
1037
    int cx, cy;
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049

    /* Try to load function from shell32 */
    hShell32 = LoadLibrary("shell32.dll");
    pSHGetImageList = (void*)GetProcAddress(hShell32, (LPCSTR) 727);

    if (!pSHGetImageList)
    {
        win_skip("SHGetImageList not available, skipping test\n");
        return;
    }

    /* Get system image list */
1050
    hr = (pSHGetImageList)(SHIL_SYSSMALL, &IID_IImageList, (void**)&iml);
1051

1052
    ok(SUCCEEDED(hr), "SHGetImageList failed, hr=%x\n", hr);
1053 1054 1055 1056 1057

    if (hr != S_OK)
        return;

    IImageList_GetImageCount(iml, &out);
1058
    ok(out > 0, "IImageList_GetImageCount returned out <= 0\n");
1059

1060 1061 1062 1063 1064
    /* Fetch the small icon size */
    cx = GetSystemMetrics(SM_CXSMICON);
    cy = GetSystemMetrics(SM_CYSMICON);

    /* Check icon size matches */
1065
    IImageList_GetImageRect(iml, 0, &rect);
1066
    ok(((rect.right == cx) && (rect.bottom == cy)),
1067
                 "IImageList_GetImageRect returned r:%d,b:%d\n",
1068 1069 1070 1071 1072 1073
                 rect.right, rect.bottom);

    IImageList_Release(iml);
    FreeLibrary(hShell32);
}

1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
static HBITMAP create_test_bitmap(HDC hdc, int bpp, UINT32 pixel1, UINT32 pixel2)
{
    HBITMAP hBitmap;
    UINT32 *buffer = NULL;
    BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, bpp, BI_RGB,
                                0, 0, 0, 0, 0}};

    hBitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, NULL, 0);
    ok(hBitmap != NULL && buffer != NULL, "CreateDIBSection failed.\n");

    if(!hBitmap || !buffer)
    {
        DeleteObject(hBitmap);
        return NULL;
    }

    buffer[0] = pixel1;
    buffer[1] = pixel2;

    return hBitmap;
}

static BOOL colour_match(UINT32 x, UINT32 y)
{
    const INT32 tolerance = 8;

    const INT32 dr = abs((INT32)(x & 0x000000FF) - (INT32)(y & 0x000000FF));
    const INT32 dg = abs((INT32)((x & 0x0000FF00) >> 8) - (INT32)((y & 0x0000FF00) >> 8));
    const INT32 db = abs((INT32)((x & 0x00FF0000) >> 16) - (INT32)((y & 0x00FF0000) >> 16));

    return (dr <= tolerance && dg <= tolerance && db <= tolerance);
}

static void check_ImageList_DrawIndirect(IMAGELISTDRAWPARAMS *ildp, UINT32 *bits,
                                         UINT32 expected, int line)
{
    bits[0] = 0x00FFFFFF;
    pImageList_DrawIndirect(ildp);
    ok(colour_match(bits[0], expected),
       "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n",
       bits[0] & 0x00FFFFFF, expected, line);
}


static void check_ImageList_DrawIndirect_fStyle(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
                                                UINT fStyle, UINT32 expected, int line)
{
    IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
        0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, ILS_NORMAL, 0, 0x00000000};
    check_ImageList_DrawIndirect(&ildp, bits, expected, line);
}

static void check_ImageList_DrawIndirect_ILD_ROP(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
                                                DWORD dwRop, UINT32 expected, int line)
{
    IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
        0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, ILD_IMAGE | ILD_ROP, dwRop, ILS_NORMAL, 0, 0x00000000};
    check_ImageList_DrawIndirect(&ildp, bits, expected, line);
}

static void check_ImageList_DrawIndirect_fState(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i, UINT fStyle,
                                                UINT fState, DWORD Frame, UINT32 expected, int line)
{
    IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
        0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000};
    check_ImageList_DrawIndirect(&ildp, bits, expected, line);
}

static void check_ImageList_DrawIndirect_broken(HDC hdc, HIMAGELIST himl, UINT32 *bits, int i,
                                                UINT fStyle, UINT fState, DWORD Frame, UINT32 expected,
                                                UINT32 broken_expected, int line)
{
    IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), himl, i, hdc,
        0, 0, 0, 0, 0, 0, CLR_NONE, CLR_NONE, fStyle, 0, fState, Frame, 0x00000000};
    bits[0] = 0x00FFFFFF;
    pImageList_DrawIndirect(&ildp);
    ok(colour_match(bits[0], expected) ||
       broken(colour_match(bits[0], broken_expected)),
       "ImageList_DrawIndirect: Pixel %08X, Expected a close match to %08X from line %d\n",
       bits[0] & 0x00FFFFFF, expected, line);
}

static void test_ImageList_DrawIndirect(void)
{
    HIMAGELIST himl = NULL;
    int ret;
    HDC hdcDst = NULL;
    HBITMAP hbmOld = NULL, hbmDst = NULL;
    HBITMAP hbmMask = NULL, hbmInverseMask = NULL;
    HBITMAP hbmImage = NULL, hbmAlphaImage = NULL, hbmTransparentImage = NULL;
    int iImage = -1, iAlphaImage = -1, iTransparentImage = -1;
    UINT32 *bits = 0;
    UINT32 maskBits = 0x00000000, inverseMaskBits = 0xFFFFFFFF;
1167
    int bpp, broken_value;
1168 1169 1170 1171 1172 1173 1174 1175

    BITMAPINFO bitmapInfo = {{sizeof(BITMAPINFOHEADER), 2, 1, 1, 32, BI_RGB,
                                0, 0, 0, 0, 0}};

    hdcDst = CreateCompatibleDC(0);
    ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n");
    if (!hdcDst)
        return;
1176
    bpp = GetDeviceCaps(hdcDst, BITSPIXEL);
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224

    hbmMask = CreateBitmap(2, 1, 1, 1, &maskBits);
    ok(hbmMask != 0, "CreateBitmap failed\n");
    if(!hbmMask) goto cleanup;

    hbmInverseMask = CreateBitmap(2, 1, 1, 1, &inverseMaskBits);
    ok(hbmInverseMask != 0, "CreateBitmap failed\n");
    if(!hbmInverseMask) goto cleanup;

    himl = pImageList_Create(2, 1, ILC_COLOR32, 0, 1);
    ok(himl != 0, "ImageList_Create failed\n");
    if(!himl) goto cleanup;

    /* Add a no-alpha image */
    hbmImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x00ABCDEF);
    if(!hbmImage) goto cleanup;

    iImage = pImageList_Add(himl, hbmImage, hbmMask);
    ok(iImage != -1, "ImageList_Add failed\n");
    if(iImage == -1) goto cleanup;

    /* Add an alpha image */
    hbmAlphaImage = create_test_bitmap(hdcDst, 32, 0x89ABCDEF, 0x89ABCDEF);
    if(!hbmAlphaImage) goto cleanup;

    iAlphaImage = pImageList_Add(himl, hbmAlphaImage, hbmMask);
    ok(iAlphaImage != -1, "ImageList_Add failed\n");
    if(iAlphaImage == -1) goto cleanup;

    /* Add a transparent alpha image */
    hbmTransparentImage = create_test_bitmap(hdcDst, 32, 0x00ABCDEF, 0x89ABCDEF);
    if(!hbmTransparentImage) goto cleanup;

    iTransparentImage = pImageList_Add(himl, hbmTransparentImage, hbmMask);
    ok(iTransparentImage != -1, "ImageList_Add failed\n");
    if(iTransparentImage == -1) goto cleanup;

    /* 32-bit Tests */
    bitmapInfo.bmiHeader.biBitCount = 32;
    hbmDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
    ok (hbmDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n");
    if (!hbmDst || !bits)
        goto cleanup;
    hbmOld = SelectObject(hdcDst, hbmDst);

    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_NORMAL, 0x00ABCDEF, __LINE__);
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_TRANSPARENT, 0x00ABCDEF, __LINE__);
    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, 0x00D4D9DD, __LINE__);
1225 1226 1227
    if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
    else broken_value = 0x00B4BDC4;
    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
1228 1229 1230 1231
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_MASK, 0x00ABCDEF, __LINE__);
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_IMAGE, 0x00ABCDEF, __LINE__);
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iImage, ILD_PRESERVEALPHA, 0x00ABCDEF, __LINE__);

1232 1233
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, 0x00D3E5F7, __LINE__);
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_TRANSPARENT, 0x00D3E5F7, __LINE__);
1234

1235 1236 1237 1238 1239 1240
    if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
    else broken_value =  0x009DA8B1;
    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND25, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
    if (bpp == 16 || bpp == 24) broken_value = 0x00D4D9DD;
    else broken_value =  0x008C99A3;
    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_BLEND50, ILS_NORMAL, 0, 0x00E8F1FA, broken_value, __LINE__);
1241 1242 1243
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_MASK, 0x00D3E5F7, __LINE__);
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_IMAGE, 0x00D3E5F7, __LINE__);
    todo_wine check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iAlphaImage, ILD_PRESERVEALPHA, 0x005D6F81, __LINE__);
1244

1245
    check_ImageList_DrawIndirect_fStyle(hdcDst, himl, bits, iTransparentImage, ILD_NORMAL, 0x00FFFFFF, __LINE__);
1246 1247 1248 1249 1250

    check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCCOPY, 0x00ABCDEF, __LINE__);
    check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iImage, SRCINVERT, 0x00543210, __LINE__);

    /* ILD_ROP is ignored when the image has an alpha channel */
1251 1252
    check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCCOPY, 0x00D3E5F7, __LINE__);
    check_ImageList_DrawIndirect_ILD_ROP(hdcDst, himl, bits, iAlphaImage, SRCINVERT, 0x00D3E5F7, __LINE__);
1253 1254 1255 1256 1257 1258 1259

    todo_wine check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00CCCCCC, __LINE__);
    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_SATURATE, 0, 0x00AFAFAF, 0x00F0F0F0, __LINE__);

    check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_GLOW, 0, 0x00ABCDEF, __LINE__);
    check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_SHADOW, 0, 0x00ABCDEF, __LINE__);

1260
    check_ImageList_DrawIndirect_fState(hdcDst, himl, bits, iImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00D5E6F7, __LINE__);
1261
    check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_ALPHA, 127, 0x00E9F2FB, 0x00AEB7C0, __LINE__);
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
    todo_wine check_ImageList_DrawIndirect_broken(hdcDst, himl, bits, iAlphaImage, ILD_NORMAL, ILS_NORMAL, 127, 0x00E9F2FB, 0x00D3E5F7, __LINE__);

cleanup:

    if(hbmOld)
        SelectObject(hdcDst, hbmOld);
    if(hbmDst)
        DeleteObject(hbmDst);

    if(hdcDst)
        DeleteDC(hdcDst);

    if(hbmMask)
        DeleteObject(hbmMask);
    if(hbmInverseMask)
        DeleteObject(hbmInverseMask);

    if(hbmImage)
        DeleteObject(hbmImage);
    if(hbmAlphaImage)
        DeleteObject(hbmAlphaImage);
    if(hbmTransparentImage)
        DeleteObject(hbmTransparentImage);

    if(himl)
    {
        ret = ImageList_Destroy(himl);
        ok(ret, "ImageList_Destroy failed\n");
    }
}

1293 1294
static void test_iimagelist(void)
{
1295
    IImageList *imgl, *imgl2;
1296 1297
    HIMAGELIST himl;
    HRESULT hr;
1298
    ULONG ret;
1299

1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
    if (!pHIMAGELIST_QueryInterface)
    {
        win_skip("XP imagelist functions not available\n");
        return;
    }

    /* test reference counting on destruction */
    imgl = (IImageList*)createImageList(32, 32);
    ret = IUnknown_AddRef(imgl);
    ok(ret == 2, "Expected 2, got %d\n", ret);
    ret = ImageList_Destroy((HIMAGELIST)imgl);
    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
    ret = ImageList_Destroy((HIMAGELIST)imgl);
    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
    ret = ImageList_Destroy((HIMAGELIST)imgl);
    ok(ret == FALSE, "Expected FALSE, got %d\n", ret);

    imgl = (IImageList*)createImageList(32, 32);
    ret = IUnknown_AddRef(imgl);
    ok(ret == 2, "Expected 2, got %d\n", ret);
    ret = ImageList_Destroy((HIMAGELIST)imgl);
    ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
    ret = IImageList_Release(imgl);
    ok(ret == 0, "Expected 0, got %d\n", ret);
    ret = ImageList_Destroy((HIMAGELIST)imgl);
    ok(ret == FALSE, "Expected FALSE, got %d\n", ret);

1327 1328 1329 1330 1331 1332 1333 1334 1335
    /* ref counting, HIMAGELIST_QueryInterface adds a reference */
    imgl = (IImageList*)createImageList(32, 32);
    hr = pHIMAGELIST_QueryInterface((HIMAGELIST)imgl, &IID_IImageList, (void**)&imgl2);
    ok(hr == S_OK, "got 0x%08x\n", hr);
    ok(imgl2 == imgl, "got different pointer\n");
    ret = IImageList_Release(imgl);
    ok(ret == 1, "got %u\n", ret);
    IImageList_Release(imgl);

1336
    if (!pImageList_CoCreateInstance)
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
    {
        win_skip("Vista imagelist functions not available\n");
        return;
    }

    hr = pImageList_CoCreateInstance(&CLSID_ImageList, NULL, &IID_IImageList, (void **) &imgl);
    ok(SUCCEEDED(hr), "ImageList_CoCreateInstance failed, hr=%x\n", hr);

    if (hr == S_OK)
        IImageList_Release(imgl);

    himl = createImageList(32, 32);

    if (!himl)
        return;

    hr = (pHIMAGELIST_QueryInterface)(himl, &IID_IImageList, (void **) &imgl);
    ok(SUCCEEDED(hr), "HIMAGELIST_QueryInterface failed, hr=%x\n", hr);

    if (hr == S_OK)
        IImageList_Release(imgl);

    ImageList_Destroy(himl);
}

1362
static void test_hotspot_v6(void)
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
{
    struct hotspot {
        int dx;
        int dy;
    };

#define SIZEX1 47
#define SIZEY1 31
#define SIZEX2 11
#define SIZEY2 17
#define HOTSPOTS_MAX 4       /* Number of entries in hotspots */
    static const struct hotspot hotspots[HOTSPOTS_MAX] = {
        { 10, 7 },
        { SIZEX1, SIZEY1 },
        { -9, -8 },
        { -7, 35 }
    };
    int i, j;
    HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
    HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
    IImageList *imgl1, *imgl2;
    HRESULT hr;

    /* cast to IImageList */
    imgl1 = (IImageList *) himl1;
    imgl2 = (IImageList *) himl2;

    for (i = 0; i < HOTSPOTS_MAX; i++) {
        for (j = 0; j < HOTSPOTS_MAX; j++) {
            int dx1 = hotspots[i].dx;
            int dy1 = hotspots[i].dy;
            int dx2 = hotspots[j].dx;
            int dy2 = hotspots[j].dy;
            int correctx, correcty, newx, newy;
            char loc[256];
            IImageList *imglNew;
            POINT ppt;

            hr = IImageList_BeginDrag(imgl1, 0, dx1, dy1);
            ok(SUCCEEDED(hr), "BeginDrag failed for { %d, %d }\n", dx1, dy1);
            sprintf(loc, "BeginDrag (%d,%d)\n", i, j);

            /* check merging the dragged image with a second image */
            hr = IImageList_SetDragCursorImage(imgl2, (IUnknown *) imgl2, 0, dx2, dy2);
            ok(SUCCEEDED(hr), "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
                    dx1, dy1, dx2, dy2);
            sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);

            /* check new hotspot, it should be the same like the old one */
            hr = IImageList_GetDragImage(imgl2, NULL, &ppt, &IID_IImageList, (PVOID *) &imglNew);
            ok(SUCCEEDED(hr), "GetDragImage failed\n");
            ok(ppt.x == dx1 && ppt.y == dy1,
                    "Expected drag hotspot [%d,%d] got [%d,%d]\n",
                    dx1, dy1, ppt.x, ppt.y);
            /* check size of new dragged image */
            IImageList_GetIconSize(imglNew, &newx, &newy);
            correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
            correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
            ok(newx == correctx && newy == correcty,
                    "Expected drag image size [%d,%d] got [%d,%d]\n",
                    correctx, correcty, newx, newy);
            sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
            IImageList_EndDrag(imgl2);
        }
    }
#undef SIZEX1
#undef SIZEY1
#undef SIZEX2
#undef SIZEY2
#undef HOTSPOTS_MAX
    IImageList_Release(imgl2);
    IImageList_Release(imgl1);
}

1437
static void test_IImageList_Add_Remove(void)
1438 1439 1440 1441 1442 1443 1444 1445 1446
{
    IImageList *imgl;
    HIMAGELIST himl;
    HRESULT hr;

    HICON hicon1;
    HICON hicon2;
    HICON hicon3;

1447
    int ret;
1448 1449

    /* create an imagelist to play with */
1450
    himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
    ok(himl != 0,"failed to create imagelist\n");

    imgl = (IImageList *) himl;

    /* load the icons to add to the image list */
    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
    ok(hicon1 != 0, "no hicon1\n");
    hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
    ok(hicon2 != 0, "no hicon2\n");
    hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
    ok(hicon3 != 0, "no hicon3\n");

    /* remove when nothing exists */
    hr = IImageList_Remove(imgl, 0);
1465
    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1466 1467 1468

    /* removing everything from an empty imagelist should succeed */
    hr = IImageList_Remove(imgl, -1);
1469
    ok(hr == S_OK, "removed nonexistent icon\n");
1470 1471

    /* add three */
1472
    ret = -1;
1473
    ok( IImageList_ReplaceIcon(imgl, -1, hicon1, &ret) == S_OK && (ret == 0),"failed to add icon1\n");
1474
    ret = -1;
1475
    ok( IImageList_ReplaceIcon(imgl, -1, hicon2, &ret) == S_OK && (ret == 1),"failed to add icon2\n");
1476
    ret = -1;
1477
    ok( IImageList_ReplaceIcon(imgl, -1, hicon3, &ret) == S_OK && (ret == 2),"failed to add icon3\n");
1478 1479

    /* remove an index out of range */
1480
    ok( IImageList_Remove(imgl, 4711) == E_INVALIDARG, "got 0x%08x\n", hr);
1481 1482

    /* remove three */
1483 1484 1485
    ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
    ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
    ok( IImageList_Remove(imgl,0) == S_OK, "can't remove 0\n");
1486 1487

    /* remove one extra */
1488
    ok( IImageList_Remove(imgl, 0) == E_INVALIDARG, "got 0x%08x\n", hr);
1489

1490
    IImageList_Release(imgl);
1491 1492 1493 1494 1495
    ok(DestroyIcon(hicon1),"icon 1 wasn't deleted\n");
    ok(DestroyIcon(hicon2),"icon 2 wasn't deleted\n");
    ok(DestroyIcon(hicon3),"icon 3 wasn't deleted\n");
}

1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
static void test_IImageList_Get_SetImageCount(void)
{
    IImageList *imgl;
    HIMAGELIST himl;
    HRESULT hr;
    INT ret;

    /* create an imagelist to play with */
    himl = ImageList_Create(84, 84, ILC_COLOR16, 0, 3);
    ok(himl != 0,"failed to create imagelist\n");

    imgl = (IImageList *) himl;

    /* check SetImageCount/GetImageCount */
    hr = IImageList_SetImageCount(imgl, 3);
    ok(hr == S_OK, "got 0x%08x\n", hr);
    ret = 0;
    hr = IImageList_GetImageCount(imgl, &ret);
    ok(hr == S_OK && ret == 3, "invalid image count after increase\n");
    hr = IImageList_SetImageCount(imgl, 1);
    ok(hr == S_OK, "got 0x%08x\n", hr);
    ret = 0;
    hr = IImageList_GetImageCount(imgl, &ret);
    ok(hr == S_OK && ret == 1, "invalid image count after decrease to 1\n");
    hr = IImageList_SetImageCount(imgl, 0);
    ok(hr == S_OK, "got 0x%08x\n", hr);
    ret = -1;
    hr = IImageList_GetImageCount(imgl, &ret);
    ok(hr == S_OK && ret == 0, "invalid image count after decrease to 0\n");

    IImageList_Release(imgl);
}

static void test_IImageList_Draw(void)
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
{
    IImageList *imgl;
    HIMAGELIST himl;

    HBITMAP hbm1;
    HBITMAP hbm2;
    HBITMAP hbm3;

    IMAGELISTDRAWPARAMS imldp;
    HWND hwndfortest;
1540
    HRESULT hr;
1541 1542 1543 1544 1545 1546 1547 1548
    HDC hdc;
    int ret;

    hwndfortest = create_a_window();
    hdc = GetDC(hwndfortest);
    ok(hdc!=NULL, "couldn't get DC\n");

    /* create an imagelist to play with */
1549
    himl = ImageList_Create(48, 48, ILC_COLOR16, 0, 3);
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
    ok(himl!=0,"failed to create imagelist\n");

    imgl = (IImageList *) himl;

    /* load the icons to add to the image list */
    hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
    ok(hbm1 != 0, "no bitmap 1\n");
    hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
    ok(hbm2 != 0, "no bitmap 2\n");
    hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
    ok(hbm3 != 0, "no bitmap 3\n");

    /* add three */
1563 1564 1565 1566
    ret = -1;
    ok( IImageList_Add(imgl, hbm1, 0, &ret) == S_OK && (ret == 0), "failed to add bitmap 1\n");
    ret = -1;
    ok( IImageList_Add(imgl, hbm2, 0, &ret) == S_OK && (ret == 1), "failed to add bitmap 2\n");
1567

1568 1569
    ok( IImageList_SetImageCount(imgl, 3) == S_OK, "Setimage count failed\n");
    ok( IImageList_Replace(imgl, 2, hbm3, 0) == S_OK, "failed to replace bitmap 3\n");
1570

1571 1572 1573
if (0)
{
    /* crashes on native */
1574
    IImageList_Draw(imgl, NULL);
1575 1576
}

1577
    memset(&imldp, 0, sizeof (imldp));
1578
    hr = IImageList_Draw(imgl, &imldp);
1579
    ok( hr == E_INVALIDARG, "got 0x%08x\n", hr);
1580

1581
    imldp.cbSize = IMAGELISTDRAWPARAMS_V3_SIZE;
1582
    imldp.hdcDst = hdc;
1583 1584
    imldp.himl = himl;

1585 1586 1587 1588 1589 1590 1591 1592
    REDRAW(hwndfortest);
    WAIT;

    imldp.fStyle = SRCCOPY;
    imldp.rgbBk = CLR_DEFAULT;
    imldp.rgbFg = CLR_DEFAULT;
    imldp.y = 100;
    imldp.x = 100;
1593
    ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1594
    imldp.i ++;
1595
    ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1596
    imldp.i ++;
1597
    ok( IImageList_Draw(imgl, &imldp) == S_OK, "should succeed\n");
1598
    imldp.i ++;
1599
    ok( IImageList_Draw(imgl, &imldp) == E_INVALIDARG, "should fail\n");
1600 1601

    /* remove three */
1602 1603 1604
    ok( IImageList_Remove(imgl, 0) == S_OK, "removing 1st bitmap\n");
    ok( IImageList_Remove(imgl, 0) == S_OK, "removing 2nd bitmap\n");
    ok( IImageList_Remove(imgl, 0) == S_OK, "removing 3rd bitmap\n");
1605 1606

    /* destroy it */
1607
    IImageList_Release(imgl);
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617

    /* bitmaps should not be deleted by the imagelist */
    ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
    ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
    ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");

    ReleaseDC(hwndfortest, hdc);
    DestroyWindow(hwndfortest);
}

1618
static void test_IImageList_Merge(void)
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
{
    HIMAGELIST himl1, himl2;
    IImageList *imgl1, *imgl2, *merge;
    HICON hicon1;
    HWND hwnd = create_a_window();
    HRESULT hr;
    int ret;

    himl1 = ImageList_Create(32,32,0,0,3);
    ok(himl1 != NULL,"failed to create himl1\n");

    himl2 = ImageList_Create(32,32,0,0,3);
    ok(himl2 != NULL,"failed to create himl2\n");

    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
    ok(hicon1 != NULL, "failed to create hicon1\n");

    if (!himl1 || !himl2 || !hicon1)
        return;

    /* cast to IImageList */
    imgl1 = (IImageList *) himl1;
    imgl2 = (IImageList *) himl2;

1643 1644
    ret = -1;
    ok( IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret) == S_OK && (ret == 0),"add icon1 to himl2 failed\n");
1645

1646 1647 1648
if (0)
{
    /* null cases that crash on native */
1649 1650
    IImageList_Merge(imgl1, -1, NULL, 0, 0, 0, &IID_IImageList, (void**)&merge);
    IImageList_Merge(imgl1, -1, (IUnknown*) imgl2, 0, 0, 0, &IID_IImageList, NULL);
1651 1652
}

1653 1654
    /* If himl1 has no images, merge still succeeds */
    hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1655 1656
    ok(hr == S_OK, "merge himl1,-1 failed\n");
    if (hr == S_OK) IImageList_Release(merge);
1657 1658

    hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1659 1660
    ok(hr == S_OK, "merge himl1,0 failed\n");
    if (hr == S_OK) IImageList_Release(merge);
1661 1662 1663 1664 1665 1666 1667 1668 1669

    /* Same happens if himl2 is empty */
    IImageList_Release(imgl2);
    himl2 = ImageList_Create(32,32,0,0,3);
    ok(himl2 != NULL,"failed to recreate himl2\n");

    imgl2 = (IImageList *) himl2;

    hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, -1, 0, 0, &IID_IImageList, (void **) &merge);
1670 1671
    ok(hr == S_OK, "merge himl2,-1 failed\n");
    if (hr == S_OK) IImageList_Release(merge);
1672 1673

    hr = IImageList_Merge(imgl1, -1, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1674 1675
    ok(hr == S_OK, "merge himl2,0 failed\n");
    if (hr == S_OK) IImageList_Release(merge);
1676 1677

    /* Now try merging an image with itself */
1678 1679
    ret = -1;
    ok( IImageList_ReplaceIcon(imgl2, -1, hicon1, &ret) == S_OK && (ret == 0),"re-add icon1 to himl2 failed\n");
1680 1681

    hr = IImageList_Merge(imgl2, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1682 1683
    ok(hr == S_OK, "merge himl2 with itself failed\n");
    if (hr == S_OK) IImageList_Release(merge);
1684 1685

    /* Try merging 2 different image lists */
1686 1687
    ret = -1;
    ok( IImageList_ReplaceIcon(imgl1, -1, hicon1, &ret) == S_OK && (ret == 0),"add icon1 to himl1 failed\n");
1688 1689

    hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 0, 0, &IID_IImageList, (void **) &merge);
1690 1691
    ok(hr == S_OK, "merge himl1 with himl2 failed\n");
    if (hr == S_OK) IImageList_Release(merge);
1692 1693

    hr = IImageList_Merge(imgl1, 0, (IUnknown *) imgl2, 0, 8, 16, &IID_IImageList, (void **) &merge);
1694 1695
    ok(hr == S_OK, "merge himl1 with himl2 8,16 failed\n");
    if (hr == S_OK) IImageList_Release(merge);
1696 1697 1698 1699 1700 1701 1702 1703

    IImageList_Release(imgl1);
    IImageList_Release(imgl2);

    DestroyIcon(hicon1);
    DestroyWindow(hwnd);
}

1704 1705 1706 1707 1708 1709 1710 1711 1712
static void test_iconsize(void)
{
    HIMAGELIST himl;
    INT cx, cy;
    BOOL ret;

    himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
    /* null pointers, not zero imagelist dimensions */
    ret = ImageList_GetIconSize(himl, NULL, NULL);
1713
    ok(!ret, "got %d\n", ret);
1714 1715

    /* doesn't touch return pointers */
1716
    cx = 0x1abe11ed;
1717 1718
    ret = ImageList_GetIconSize(himl, &cx, NULL);
    ok(!ret, "got %d\n", ret);
1719
    ok(cx == 0x1abe11ed, "got %d\n", cx);
1720

1721
    cy = 0x1abe11ed;
1722 1723
    ret = ImageList_GetIconSize(himl, NULL, &cy);
    ok(!ret, "got %d\n", ret);
1724
    ok(cy == 0x1abe11ed, "got %d\n", cy);
1725

1726
    ImageList_Destroy(himl);
1727 1728 1729

    ret = ImageList_GetIconSize((HIMAGELIST)0xdeadbeef, &cx, &cy);
    ok(!ret, "got %d\n", ret);
1730 1731
}

1732
static void test_create_destroy(void)
1733 1734
{
    HIMAGELIST himl;
1735
    BOOL rc;
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751

    /* list with zero or negative image dimensions */
    himl = ImageList_Create(0, 0, ILC_COLOR16, 0, 3);
    ok(himl == NULL, "got %p\n", himl);

    himl = ImageList_Create(0, 16, ILC_COLOR16, 0, 3);
    ok(himl == NULL, "got %p\n", himl);

    himl = ImageList_Create(16, 0, ILC_COLOR16, 0, 3);
    ok(himl == NULL, "got %p\n", himl);

    himl = ImageList_Create(16, -1, ILC_COLOR16, 0, 3);
    ok(himl == NULL, "got %p\n", himl);

    himl = ImageList_Create(-1, 16, ILC_COLOR16, 0, 3);
    ok(himl == NULL, "got %p\n", himl);
1752 1753 1754

    rc = ImageList_Destroy((HIMAGELIST)0xdeadbeef);
    ok(rc == FALSE, "ImageList_Destroy(0xdeadbeef) should fail and not crash\n");
1755 1756
}

1757 1758 1759 1760 1761
static void test_IImageList_Clone(void)
{
    IImageList *imgl, *imgl2;
    HIMAGELIST himl;
    HRESULT hr;
1762
    ULONG ref;
1763 1764 1765 1766 1767 1768 1769

    himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
    imgl = (IImageList*)himl;

if (0)
{
    /* crashes on native */
1770
    IImageList_Clone(imgl, &IID_IImageList, NULL);
1771 1772 1773 1774
}

    hr = IImageList_Clone(imgl, &IID_IImageList, (void**)&imgl2);
    ok(hr == S_OK, "got 0x%08x\n", hr);
1775 1776
    ref = IImageList_Release(imgl2);
    ok(ref == 0, "got %u\n", ref);
1777 1778 1779 1780

    IImageList_Release(imgl);
}

1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793
static void test_IImageList_GetBkColor(void)
{
    IImageList *imgl;
    HIMAGELIST himl;
    COLORREF color;
    HRESULT hr;

    himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
    imgl = (IImageList*)himl;

if (0)
{
    /* crashes on native */
1794
    IImageList_GetBkColor(imgl, NULL);
1795 1796 1797 1798 1799 1800 1801 1802
}

    hr = IImageList_GetBkColor(imgl, &color);
    ok(hr == S_OK, "got 0x%08x\n", hr);

    IImageList_Release(imgl);
}

1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815
static void test_IImageList_SetBkColor(void)
{
    IImageList *imgl;
    HIMAGELIST himl;
    COLORREF color;
    HRESULT hr;

    himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
    imgl = (IImageList*)himl;

if (0)
{
    /* crashes on native */
1816
    IImageList_SetBkColor(imgl, RGB(0, 0, 0), NULL);
1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
}

    hr = IImageList_SetBkColor(imgl, CLR_NONE, &color);
    ok(hr == S_OK, "got 0x%08x\n", hr);

    hr = IImageList_SetBkColor(imgl, CLR_NONE, &color);
    ok(hr == S_OK, "got 0x%08x\n", hr);

    color = 0xdeadbeef;
    hr = IImageList_GetBkColor(imgl, &color);
    ok(hr == S_OK, "got 0x%08x\n", hr);
    ok(color == CLR_NONE, "got %x\n", color);

    IImageList_Release(imgl);
}

1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845
static void test_IImageList_GetImageCount(void)
{
    IImageList *imgl;
    HIMAGELIST himl;
    int count;
    HRESULT hr;

    himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
    imgl = (IImageList*)himl;

if (0)
{
    /* crashes on native */
1846
    IImageList_GetImageCount(imgl, NULL);
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
}

    count = -1;
    hr = IImageList_GetImageCount(imgl, &count);
    ok(hr == S_OK, "got 0x%08x\n", hr);
    ok(count == 0, "got %d\n", count);

    IImageList_Release(imgl);
}

static void test_IImageList_GetIconSize(void)
{
    IImageList *imgl;
    HIMAGELIST himl;
    int cx, cy;
    HRESULT hr;

    himl = ImageList_Create(16, 16, ILC_COLOR16, 0, 3);
    imgl = (IImageList*)himl;

    hr = IImageList_GetIconSize(imgl, NULL, NULL);
    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);

    hr = IImageList_GetIconSize(imgl, &cx, NULL);
    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);

    hr = IImageList_GetIconSize(imgl, NULL, &cy);
    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);

    IImageList_Release(imgl);
}

1879 1880
START_TEST(imagelist)
{
1881
    ULONG_PTR ctx_cookie;
1882
    HANDLE hCtx;
1883

1884
    HMODULE hComCtl32 = GetModuleHandle("comctl32.dll");
1885 1886
    pImageList_Create = NULL;   /* These are not needed for non-v6.0 tests*/
    pImageList_Add = NULL;
1887 1888 1889
    pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
    pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");

1890
    hinst = GetModuleHandleA(NULL);
1891 1892 1893

    InitCommonControls();

1894
    test_create_destroy();
1895 1896 1897 1898 1899
    test_hotspot();
    test_add_remove();
    test_imagecount();
    test_DrawIndirect();
    test_merge();
1900
    test_imagelist_storage();
1901
    test_iconsize();
1902

1903 1904
    FreeLibrary(hComCtl32);

1905 1906
    /* Now perform v6 tests */

1907
    if (!load_v6_module(&ctx_cookie, &hCtx))
1908 1909
        return;

1910 1911 1912 1913 1914 1915
    /* Reload comctl32 */
    hComCtl32 = LoadLibraryA("comctl32.dll");
    pImageList_Create = (void*)GetProcAddress(hComCtl32, "ImageList_Create");
    pImageList_Add = (void*)GetProcAddress(hComCtl32, "ImageList_Add");
    pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
    pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
1916 1917 1918 1919
    pImageList_CoCreateInstance = (void*)GetProcAddress(hComCtl32, "ImageList_CoCreateInstance");
    pHIMAGELIST_QueryInterface = (void*)GetProcAddress(hComCtl32, "HIMAGELIST_QueryInterface");

    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1920 1921 1922

    /* Do v6.0 tests */
    test_ImageList_DrawIndirect();
1923
    test_shell_imagelist();
1924
    test_iimagelist();
1925

1926 1927 1928 1929 1930
    test_hotspot_v6();
    test_IImageList_Add_Remove();
    test_IImageList_Get_SetImageCount();
    test_IImageList_Draw();
    test_IImageList_Merge();
1931
    test_IImageList_Clone();
1932
    test_IImageList_GetBkColor();
1933
    test_IImageList_SetBkColor();
1934 1935
    test_IImageList_GetImageCount();
    test_IImageList_GetIconSize();
1936 1937

    CoUninitialize();
1938

1939
    unload_v6_module(ctx_cookie, hCtx);
1940
}