imagelist.c 102 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 *  ImageList implementation
 *
 *  Copyright 1998 Eric Kohl
5
 *  Copyright 2000 Jason Mawdsley
6
 *  Copyright 2001, 2004 Michael Stefaniuc
7 8
 *  Copyright 2001 Charles Loep for CodeWeavers
 *  Copyright 2002 Dimitrie O. Paun
9
 *  Copyright 2009 Owen Rudge for CodeWeavers
Alexandre Julliard's avatar
Alexandre Julliard committed
10
 *
11 12 13 14 15 16 17 18 19 20 21 22
 * 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
23
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24
 *
25
 * NOTE
26
 *
27 28
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29
 *
Mike Hearn's avatar
Mike Hearn committed
30
 * Unless otherwise noted, we believe this code to be complete, as per
31 32
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
33
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
34
 *  TODO:
35
 *    - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
36
 *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE
37
 *    - Thread-safe locking
Alexandre Julliard's avatar
Alexandre Julliard committed
38 39
 */

40
#include <stdarg.h>
41
#include <stdlib.h>
42
#include <string.h>
43 44 45

#define COBJMACROS

46
#include "winerror.h"
47
#include "windef.h"
48
#include "winbase.h"
49
#include "objbase.h"
50 51
#include "wingdi.h"
#include "winuser.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
52
#include "commctrl.h"
53
#include "comctl32.h"
54
#include "commoncontrols.h"
55
#include "wine/debug.h"
56
#include "wine/exception.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
57

58
WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
59

Alexandre Julliard's avatar
Alexandre Julliard committed
60 61
#define MAX_OVERLAYIMAGE 15

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 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
struct _IMAGELIST
{
    const struct IImageListVtbl *lpVtbl; /* 00: IImageList vtable */

    INT         cCurImage;                 /* 04: ImageCount */
    INT         cMaxImage;                 /* 08: maximages */
    INT         cGrow;                     /* 0C: cGrow */
    INT         cx;                        /* 10: cx */
    INT         cy;                        /* 14: cy */
    DWORD       x4;
    UINT        flags;                     /* 1C: flags */
    COLORREF    clrFg;                     /* 20: foreground color */
    COLORREF    clrBk;                     /* 24: background color */


    HBITMAP     hbmImage;                  /* 28: images Bitmap */
    HBITMAP     hbmMask;                   /* 2C: masks  Bitmap */
    HDC         hdcImage;                  /* 30: images MemDC  */
    HDC         hdcMask;                   /* 34: masks  MemDC  */
    INT         nOvlIdx[MAX_OVERLAYIMAGE]; /* 38: overlay images index */

    /* not yet found out */
    HBRUSH  hbrBlend25;
    HBRUSH  hbrBlend50;
    INT     cInitial;
    UINT    uBitsPixel;
    char   *has_alpha;

    LONG        ref;                       /* reference count */
};

#define IMAGELIST_MAGIC 0x53414D58

/* Header used by ImageList_Read() and ImageList_Write() */
#include "pshpack2.h"
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"

Alexandre Julliard's avatar
Alexandre Julliard committed
112
/* internal image list data used for Drag & Drop operations */
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
typedef struct
{
    HWND	hwnd;
    HIMAGELIST	himl;
    /* position of the drag image relative to the window */
    INT		x;
    INT		y;
    /* offset of the hotspot relative to the origin of the image */
    INT		dxHotspot;
    INT		dyHotspot;
    /* is the drag image visible */
    BOOL	bShow;
    /* saved background */
    HBITMAP	hbmBg;
} INTERNALDRAG;
Alexandre Julliard's avatar
Alexandre Julliard committed
128

129
static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
Alexandre Julliard's avatar
Alexandre Julliard committed
130

131
static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count);
132
static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv);
133
static inline BOOL is_valid(HIMAGELIST himl);
134

135 136 137 138 139 140 141 142 143 144 145 146 147
/*
 * An imagelist with N images is tiled like this:
 *
 *   N/4 ->
 *
 * 4 048C..
 *   159D..
 * | 26AE.N
 * V 37BF.
 */

#define TILE_COUNT 4

148
static inline UINT imagelist_height( UINT count )
149 150 151 152
{
    return ((count + TILE_COUNT - 1)/TILE_COUNT);
}

153 154
static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
{
155 156
    pt->x = (index%TILE_COUNT) * himl->cx;
    pt->y = (index/TILE_COUNT) * himl->cy;
157
}
Alexandre Julliard's avatar
Alexandre Julliard committed
158

159
static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, SIZE *sz )
160
{
161
    sz->cx = himl->cx * TILE_COUNT;
162
    sz->cy = imagelist_height( count ) * himl->cy;
163 164
}

165 166 167 168 169 170 171 172 173 174 175
static inline int get_dib_stride( int width, int bpp )
{
    return ((width * bpp + 31) >> 3) & ~3;
}

static inline int get_dib_image_size( const BITMAPINFO *info )
{
    return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
        * abs( info->bmiHeader.biHeight );
}

176 177 178 179 180 181
/*
 * imagelist_copy_images()
 *
 * Copies a block of count images from offset src in the list to offset dest.
 * Images are copied a row at at time. Assumes hdcSrc and hdcDest are different.
 */
182 183 184 185 186
static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDest,
                                          UINT src, UINT count, UINT dest )
{
    POINT ptSrc, ptDest;
    SIZE sz;
187 188 189 190 191 192
    UINT i;

    for ( i=0; i<TILE_COUNT; i++ )
    {
        imagelist_point_from_index( himl, src+i, &ptSrc );
        imagelist_point_from_index( himl, dest+i, &ptDest );
193 194
        sz.cx = himl->cx;
        sz.cy = himl->cy * imagelist_height( count - i );
195 196 197 198

        BitBlt( hdcDest, ptDest.x, ptDest.y, sz.cx, sz.cy,
                hdcSrc, ptSrc.x, ptSrc.y, SRCCOPY );
    }
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 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
static void add_dib_bits( HIMAGELIST himl, int pos, int count, int width, int height,
                          BITMAPINFO *info, BITMAPINFO *mask_info, DWORD *bits, BYTE *mask_bits )
{
    int i, j, n;
    POINT pt;
    int stride = info->bmiHeader.biWidth;
    int mask_stride = (info->bmiHeader.biWidth + 31) / 32 * 4;

    for (n = 0; n < count; n++)
    {
        int has_alpha = 0;

        imagelist_point_from_index( himl, pos + n, &pt );

        /* check if bitmap has an alpha channel */
        for (i = 0; i < height && !has_alpha; i++)
            for (j = n * width; j < (n + 1) * width; j++)
                if ((has_alpha = ((bits[i * stride + j] & 0xff000000) != 0))) break;

        if (!has_alpha)  /* generate alpha channel from the mask */
        {
            for (i = 0; i < height; i++)
                for (j = n * width; j < (n + 1) * width; j++)
                    if (!mask_info || !((mask_bits[i * mask_stride + j / 8] << (j % 8)) & 0x80))
                        bits[i * stride + j] |= 0xff000000;
                    else
                        bits[i * stride + j] = 0;
        }
        else
        {
            himl->has_alpha[pos + n] = 1;

            if (mask_info && himl->hbmMask)  /* generate the mask from the alpha channel */
            {
                for (i = 0; i < height; i++)
                    for (j = n * width; j < (n + 1) * width; j++)
                        if ((bits[i * stride + j] >> 24) > 25) /* more than 10% alpha */
                            mask_bits[i * mask_stride + j / 8] &= ~(0x80 >> (j % 8));
                        else
                            mask_bits[i * mask_stride + j / 8] |= 0x80 >> (j % 8);
            }
        }
        StretchDIBits( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
                       n * width, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
        if (mask_info)
            StretchDIBits( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
                           n * width, 0, width, height, mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY );
    }
}

251 252 253 254 255 256
/* add images with an alpha channel when the image list is 32 bpp */
static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
                            int width, int height, HBITMAP hbmImage, HBITMAP hbmMask )
{
    BOOL ret = FALSE;
    BITMAP bm;
257
    BITMAPINFO *info, *mask_info = NULL;
258 259 260 261 262
    DWORD *bits = NULL;
    BYTE *mask_bits = NULL;
    DWORD mask_width;

    if (!GetObjectW( hbmImage, sizeof(bm), &bm )) return FALSE;
263

264 265 266
    /* if either the imagelist or the source bitmap don't have an alpha channel, bail out now */
    if (!himl->has_alpha) return FALSE;
    if (bm.bmBitsPixel != 32) return FALSE;
267

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
    SelectObject( hdc, hbmImage );
    mask_width = (bm.bmWidth + 31) / 32 * 4;

    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    info->bmiHeader.biWidth = bm.bmWidth;
    info->bmiHeader.biHeight = -height;
    info->bmiHeader.biPlanes = 1;
    info->bmiHeader.biBitCount = 32;
    info->bmiHeader.biCompression = BI_RGB;
    info->bmiHeader.biSizeImage = bm.bmWidth * height * 4;
    info->bmiHeader.biXPelsPerMeter = 0;
    info->bmiHeader.biYPelsPerMeter = 0;
    info->bmiHeader.biClrUsed = 0;
    info->bmiHeader.biClrImportant = 0;
    if (!(bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
    if (!GetDIBits( hdc, hbmImage, 0, height, bits, info, DIB_RGB_COLORS )) goto done;

    if (hbmMask)
    {
288 289 290 291 292
        if (!(mask_info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))
            goto done;
        mask_info->bmiHeader = info->bmiHeader;
        mask_info->bmiHeader.biBitCount = 1;
        mask_info->bmiHeader.biSizeImage = mask_width * height;
293 294
        if (!(mask_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
            goto done;
295
        if (!GetDIBits( hdc, hbmMask, 0, height, mask_bits, mask_info, DIB_RGB_COLORS )) goto done;
296 297
    }

298
    add_dib_bits( himl, pos, count, width, height, info, mask_info, bits, mask_bits );
299 300 301 302
    ret = TRUE;

done:
    HeapFree( GetProcessHeap(), 0, info );
303
    HeapFree( GetProcessHeap(), 0, mask_info );
304 305 306 307 308
    HeapFree( GetProcessHeap(), 0, bits );
    HeapFree( GetProcessHeap(), 0, mask_bits );
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
309
/*************************************************************************
310
 * IMAGELIST_InternalExpandBitmaps [Internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
311 312
 *
 * Expands the bitmaps of an image list by the given number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
313
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
314
 * PARAMS
315 316
 *     himl        [I] handle to image list
 *     nImageCount [I] number of images to add
Alexandre Julliard's avatar
Alexandre Julliard committed
317 318 319 320 321
 *
 * RETURNS
 *     nothing
 *
 * NOTES
322
 *     This function CANNOT be used to reduce the number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
323
 */
324
static void
325
IMAGELIST_InternalExpandBitmaps(HIMAGELIST himl, INT nImageCount)
Alexandre Julliard's avatar
Alexandre Julliard committed
326
{
327 328
    HDC     hdcBitmap;
    HBITMAP hbmNewBitmap, hbmNull;
329
    INT     nNewCount;
330
    SIZE    sz;
Alexandre Julliard's avatar
Alexandre Julliard committed
331

332
    TRACE("%p has allocated %d, max %d, grow %d images\n", himl, himl->cCurImage, himl->cMaxImage, himl->cGrow);
333

334 335
    if (himl->cCurImage + nImageCount < himl->cMaxImage)
        return;
Alexandre Julliard's avatar
Alexandre Julliard committed
336

337
    nNewCount = himl->cMaxImage + max(nImageCount, himl->cGrow) + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
338

339
    imagelist_get_bitmap_size(himl, nNewCount, &sz);
340

341
    TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, sz.cy, nNewCount);
342
    hdcBitmap = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
343

344
    hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
345

Alexandre Julliard's avatar
Alexandre Julliard committed
346
    if (hbmNewBitmap == 0)
347
        ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, sz.cy);
348 349

    if (himl->cCurImage)
350 351
    {
        hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
352
        BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
353 354 355
                himl->hdcImage, 0, 0, SRCCOPY);
        SelectObject (hdcBitmap, hbmNull);
    }
356
    SelectObject (himl->hdcImage, hbmNewBitmap);
357
    DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
358 359
    himl->hbmImage = hbmNewBitmap;

360 361
    if (himl->flags & ILC_MASK)
    {
362
        hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
363 364

        if (hbmNewBitmap == 0)
365
            ERR("creating new mask bitmap!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
366

367 368 369
	if(himl->cCurImage)
	{
	    hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
370
	    BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
371 372 373
		    himl->hdcMask, 0, 0, SRCCOPY);
	    SelectObject (hdcBitmap, hbmNull);
	}
374
        SelectObject (himl->hdcMask, hbmNewBitmap);
375
        DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
376 377 378
        himl->hbmMask = hbmNewBitmap;
    }

379 380
    if (himl->has_alpha)
    {
381
        char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
382 383 384 385 386 387 388 389
        if (new_alpha) himl->has_alpha = new_alpha;
        else
        {
            HeapFree( GetProcessHeap(), 0, himl->has_alpha );
            himl->has_alpha = NULL;
        }
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
390 391
    himl->cMaxImage = nNewCount;

392
    DeleteDC (hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
393 394 395
}


Alexandre Julliard's avatar
Alexandre Julliard committed
396
/*************************************************************************
397
 * ImageList_Add [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
398 399
 *
 * Add an image or images to an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
400
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
401
 * PARAMS
402 403 404
 *     himl     [I] handle to image list
 *     hbmImage [I] handle to image bitmap
 *     hbmMask  [I] handle to mask bitmap
Alexandre Julliard's avatar
Alexandre Julliard committed
405
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
406 407 408
 * RETURNS
 *     Success: Index of the first new image.
 *     Failure: -1
Alexandre Julliard's avatar
Alexandre Julliard committed
409 410
 */

411 412
INT WINAPI
ImageList_Add (HIMAGELIST himl,	HBITMAP hbmImage, HBITMAP hbmMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
413
{
414
    HDC     hdcBitmap, hdcTemp = 0;
415
    INT     nFirstIndex, nImageCount, i;
416
    BITMAP  bmp;
417
    POINT   pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
418

419
    TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
420
    if (!is_valid(himl))
421
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
422

423
    if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
424 425
        return -1;

426 427 428
    TRACE("himl %p, cCurImage %d, cMaxImage %d, cGrow %d, cx %d, cy %d\n",
          himl, himl->cCurImage, himl->cMaxImage, himl->cGrow, himl->cx, himl->cy);

Alexandre Julliard's avatar
Alexandre Julliard committed
429 430
    nImageCount = bmp.bmWidth / himl->cx;

431 432 433
    TRACE("%p has %d images (%d x %d)\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight);

    IMAGELIST_InternalExpandBitmaps(himl, nImageCount);
Alexandre Julliard's avatar
Alexandre Julliard committed
434

435
    hdcBitmap = CreateCompatibleDC(0);
Alexandre Julliard's avatar
Alexandre Julliard committed
436

437 438 439 440 441 442 443 444 445 446 447
    SelectObject(hdcBitmap, hbmImage);

    if (add_with_alpha( himl, hdcBitmap, himl->cCurImage, nImageCount,
                        himl->cx, min( himl->cy, bmp.bmHeight), hbmImage, hbmMask ))
        goto done;

    if (himl->hbmMask)
    {
        hdcTemp = CreateCompatibleDC(0);
        SelectObject(hdcTemp, hbmMask);
    }
448

449
    for (i=0; i<nImageCount; i++)
450
    {
451 452 453 454 455 456 457 458 459
        imagelist_point_from_index( himl, himl->cCurImage + i, &pt );

        /* Copy result to the imagelist
        */
        BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
                hdcBitmap, i*himl->cx, 0, SRCCOPY );

        if (!himl->hbmMask)
             continue;
460

461 462
        BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
                hdcTemp, i*himl->cx, 0, SRCCOPY );
463 464 465

        /* Remove the background from the image
        */
466 467
        BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
                himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
Alexandre Julliard's avatar
Alexandre Julliard committed
468
    }
469
    if (hdcTemp) DeleteDC(hdcTemp);
Alexandre Julliard's avatar
Alexandre Julliard committed
470

471
done:
472
    DeleteDC(hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
473 474 475 476

    nFirstIndex = himl->cCurImage;
    himl->cCurImage += nImageCount;

Alexandre Julliard's avatar
Alexandre Julliard committed
477
    return nFirstIndex;
Alexandre Julliard's avatar
Alexandre Julliard committed
478 479 480
}


Alexandre Julliard's avatar
Alexandre Julliard committed
481
/*************************************************************************
482
 * ImageList_AddIcon [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
483 484 485 486
 *
 * Adds an icon to an image list.
 *
 * PARAMS
487 488
 *     himl  [I] handle to image list
 *     hIcon [I] handle to icon
Alexandre Julliard's avatar
Alexandre Julliard committed
489 490 491 492 493
 *
 * RETURNS
 *     Success: index of the new image
 *     Failure: -1
 */
494 495
#undef ImageList_AddIcon
INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
496
{
497
    return ImageList_ReplaceIcon (himl, -1, hIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
498 499 500
}


Alexandre Julliard's avatar
Alexandre Julliard committed
501
/*************************************************************************
502
 * ImageList_AddMasked [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
503
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
504 505
 * Adds an image or images to an image list and creates a mask from the
 * specified bitmap using the mask color.
Alexandre Julliard's avatar
Alexandre Julliard committed
506
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
507
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
508 509 510
 *     himl    [I] handle to image list.
 *     hBitmap [I] handle to bitmap
 *     clrMask [I] mask color.
Alexandre Julliard's avatar
Alexandre Julliard committed
511 512 513 514
 *
 * RETURNS
 *     Success: Index of the first new image.
 *     Failure: -1
Alexandre Julliard's avatar
Alexandre Julliard committed
515 516
 */

517 518
INT WINAPI
ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
519
{
520
    HDC    hdcMask, hdcBitmap;
521
    INT    ret;
522
    BITMAP bmp;
523
    HBITMAP hMaskBitmap;
524
    COLORREF bkColor;
Alexandre Julliard's avatar
Alexandre Julliard committed
525

526
    TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
527
    if (!is_valid(himl))
528
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
529

530
    if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
531
        return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
532

533
    hdcBitmap = CreateCompatibleDC(0);
534
    SelectObject(hdcBitmap, hBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
535

536 537 538 539
    /* Create a temp Mask so we can remove the background of the Image */
    hdcMask = CreateCompatibleDC(0);
    hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
    SelectObject(hdcMask, hMaskBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
540

541
    /* create monochrome image to the mask bitmap */
542
    bkColor = (clrMask != CLR_DEFAULT) ? clrMask : GetPixel (hdcBitmap, 0, 0);
543
    SetBkColor (hdcBitmap, bkColor);
544
    BitBlt (hdcMask, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
545 546

    /*
547 548 549 550 551 552 553 554 555 556 557 558
     * Remove the background from the image
     *
     * WINDOWS BUG ALERT!!!!!!
     *  The statement below should not be done in common practice
     *  but this is how ImageList_AddMasked works in Windows.
     *  It overwrites the original bitmap passed, this was discovered
     *  by using the same bitmap to iterate the different styles
     *  on windows where it failed (BUT ImageList_Add is OK)
     *  This is here in case some apps rely on this bug
     *
     *  Blt mode 0x220326 is NOTSRCAND
     */
559 560 561 562 563
    if (bmp.bmBitsPixel > 8)  /* NOTSRCAND can't work with palettes */
    {
        SetBkColor(hdcBitmap, RGB(255,255,255));
        BitBlt(hdcBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMask, 0, 0, 0x220326);
    }
564 565 566 567

    DeleteDC(hdcBitmap);
    DeleteDC(hdcMask);

568 569 570 571
    ret = ImageList_Add( himl, hBitmap, hMaskBitmap );

    DeleteObject(hMaskBitmap);
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
572 573 574
}


Alexandre Julliard's avatar
Alexandre Julliard committed
575
/*************************************************************************
576
 * ImageList_BeginDrag [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
577
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
578 579
 * Creates a temporary image list that contains one image. It will be used
 * as a drag image.
Alexandre Julliard's avatar
Alexandre Julliard committed
580
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
581
 * PARAMS
582 583
 *     himlTrack [I] handle to the source image list
 *     iTrack    [I] index of the drag image in the source image list
Alexandre Julliard's avatar
Alexandre Julliard committed
584 585 586 587 588 589
 *     dxHotspot [I] X position of the hot spot of the drag image
 *     dyHotspot [I] Y position of the hot spot of the drag image
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
590 591
 */

592 593 594
BOOL WINAPI
ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
	             INT dxHotspot, INT dyHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
595
{
596
    INT cx, cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
597

598 599
    TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
	  dxHotspot, dyHotspot);
Alexandre Julliard's avatar
Alexandre Julliard committed
600

601
    if (!is_valid(himlTrack))
602
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
603

604 605 606
    if (InternalDrag.himl)
        ImageList_EndDrag ();

607 608 609
    cx = himlTrack->cx;
    cy = himlTrack->cy;

610 611
    InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
    if (InternalDrag.himl == NULL) {
612
        WARN("Error creating drag image list!\n");
613
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
614 615
    }

616 617
    InternalDrag.dxHotspot = dxHotspot;
    InternalDrag.dyHotspot = dyHotspot;
Alexandre Julliard's avatar
Alexandre Julliard committed
618 619

    /* copy image */
620
    BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
621 622

    /* copy mask */
623
    BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
624

625
    InternalDrag.himl->cCurImage = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
626

627
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
628 629 630 631
}


/*************************************************************************
632
 * ImageList_Copy [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
633
 *
634
 *  Copies an image of the source image list to an image of the
Alexandre Julliard's avatar
Alexandre Julliard committed
635
 *  destination image list. Images can be copied or swapped.
Alexandre Julliard's avatar
Alexandre Julliard committed
636
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
637
 * PARAMS
638
 *     himlDst [I] handle to the destination image list
Alexandre Julliard's avatar
Alexandre Julliard committed
639
 *     iDst    [I] destination image index.
640
 *     himlSrc [I] handle to the source image list
Alexandre Julliard's avatar
Alexandre Julliard committed
641 642
 *     iSrc    [I] source image index
 *     uFlags  [I] flags for the copy operation
Alexandre Julliard's avatar
Alexandre Julliard committed
643
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
644 645 646 647 648 649
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Copying from one image list to another is possible. The original
650
 *     implementation just copies or swaps within one image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
651
 *     Could this feature become a bug??? ;-)
Alexandre Julliard's avatar
Alexandre Julliard committed
652 653
 */

654 655
BOOL WINAPI
ImageList_Copy (HIMAGELIST himlDst, INT iDst,	HIMAGELIST himlSrc,
656
		INT iSrc, UINT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
657
{
658 659
    POINT ptSrc, ptDst;

660
    TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
661

662
    if (!is_valid(himlSrc) || !is_valid(himlDst))
Eric Kohl's avatar
Eric Kohl committed
663 664 665 666 667
	return FALSE;
    if ((iDst < 0) || (iDst >= himlDst->cCurImage))
	return FALSE;
    if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
668

669 670 671
    imagelist_point_from_index( himlDst, iDst, &ptDst );
    imagelist_point_from_index( himlSrc, iSrc, &ptSrc );

Alexandre Julliard's avatar
Alexandre Julliard committed
672
    if (uFlags & ILCF_SWAP) {
Alexandre Julliard's avatar
Alexandre Julliard committed
673
        /* swap */
674
        HDC     hdcBmp;
675
        HBITMAP hbmTempImage, hbmTempMask;
Alexandre Julliard's avatar
Alexandre Julliard committed
676

677
        hdcBmp = CreateCompatibleDC (0);
678

Alexandre Julliard's avatar
Alexandre Julliard committed
679
        /* create temporary bitmaps */
680
        hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
681
                                       himlSrc->uBitsPixel, NULL);
682
        hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
683
				      1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
684 685 686

        /* copy (and stretch) destination to temporary bitmaps.(save) */
        /* image */
687 688
        SelectObject (hdcBmp, hbmTempImage);
        StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
689
                      himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
690 691
                      SRCCOPY);
        /* mask */
692 693
        SelectObject (hdcBmp, hbmTempMask);
        StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
694
                      himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
695 696 697 698
                      SRCCOPY);

        /* copy (and stretch) source to destination */
        /* image */
699 700
        StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
                      himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
701 702
                      SRCCOPY);
        /* mask */
703 704
        StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
                      himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
705 706 707 708
                      SRCCOPY);

        /* copy (without stretching) temporary bitmaps to source (restore) */
        /* mask */
709
        BitBlt       (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
710
                      hdcBmp, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
711

712
        /* image */
713
        BitBlt       (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
714
                      hdcBmp, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
715
        /* delete temporary bitmaps */
716 717
        DeleteObject (hbmTempMask);
        DeleteObject (hbmTempImage);
718
        DeleteDC(hdcBmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
719
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
720
    else {
Alexandre Julliard's avatar
Alexandre Julliard committed
721
        /* copy image */
722 723
        StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
                      himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
724 725 726
                      SRCCOPY);

        /* copy mask */
727 728
        StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
                      himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
729 730 731
                      SRCCOPY);
    }

Eric Kohl's avatar
Eric Kohl committed
732
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
733 734 735 736
}


/*************************************************************************
737 738 739
 * ImageList_Create [COMCTL32.@]
 *
 * Creates a new image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
740
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
741 742 743 744 745 746
 * PARAMS
 *     cx       [I] image height
 *     cy       [I] image width
 *     flags    [I] creation flags
 *     cInitial [I] initial number of images in the image list
 *     cGrow    [I] number of images by which image list grows
Alexandre Julliard's avatar
Alexandre Julliard committed
747
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
748
 * RETURNS
Eric Kohl's avatar
Eric Kohl committed
749 750
 *     Success: Handle to the created image list
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
751
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
752
HIMAGELIST WINAPI
753 754
ImageList_Create (INT cx, INT cy, UINT flags,
		  INT cInitial, INT cGrow)
Alexandre Julliard's avatar
Alexandre Julliard committed
755 756
{
    HIMAGELIST himl;
757 758
    INT      nCount;
    HBITMAP  hbmTemp;
759
    UINT     ilc = (flags & 0xFE);
760
    static const WORD aBitBlend25[] =
Eric Kohl's avatar
Eric Kohl committed
761 762
        {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};

763
    static const WORD aBitBlend50[] =
Eric Kohl's avatar
Eric Kohl committed
764
        {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
Alexandre Julliard's avatar
Alexandre Julliard committed
765

766
    TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
Alexandre Julliard's avatar
Alexandre Julliard committed
767

768 769
    if (cx <= 0 || cy <= 0) return NULL;

770
    /* Create the IImageList interface for the image list */
771
    if (FAILED(ImageListImpl_CreateInstance(NULL, &IID_IImageList, (void **)&himl)))
Eric Kohl's avatar
Eric Kohl committed
772 773
        return NULL;

774 775 776 777
    cGrow = (WORD)((max( cGrow, 1 ) + 3) & ~3);

    if (cGrow > 256)
    {
778
        /* Windows doesn't limit the size here, but X11 doesn't let us allocate such huge bitmaps */
779 780 781
        WARN( "grow %d too large, limiting to 256\n", cGrow );
        cGrow = 256;
    }
782

Eric Kohl's avatar
Eric Kohl committed
783 784 785
    himl->cx        = cx;
    himl->cy        = cy;
    himl->flags     = flags;
786
    himl->cMaxImage = cInitial + 1;
Eric Kohl's avatar
Eric Kohl committed
787 788 789 790
    himl->cInitial  = cInitial;
    himl->cGrow     = cGrow;
    himl->clrFg     = CLR_DEFAULT;
    himl->clrBk     = CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
791 792

    /* initialize overlay mask indices */
Alexandre Julliard's avatar
Alexandre Julliard committed
793
    for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
Alexandre Julliard's avatar
Alexandre Julliard committed
794 795
        himl->nOvlIdx[nCount] = -1;

796 797 798 799 800 801 802 803 804 805
    /* Create Image & Mask DCs */
    himl->hdcImage = CreateCompatibleDC (0);
    if (!himl->hdcImage)
        goto cleanup;
    if (himl->flags & ILC_MASK){
        himl->hdcMask = CreateCompatibleDC(0);
        if (!himl->hdcMask)
            goto cleanup;
    }

806
    /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
807
    if (ilc == ILC_COLOR)
808
    {
809
        ilc = ILC_COLOR4;
810 811
        himl->flags |= ILC_COLOR4;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
812

813 814 815 816
    if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
        himl->uBitsPixel = ilc;
    else
        himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
Alexandre Julliard's avatar
Alexandre Julliard committed
817

818
    if (himl->cMaxImage > 0) {
819
        himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
820 821
	SelectObject(himl->hdcImage, himl->hbmImage);
    } else
822
        himl->hbmImage = 0;
823

824
    if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
825 826
        SIZE sz;

827
        imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
828
        himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
829
        if (himl->hbmMask == 0) {
830
            ERR("Error creating mask bitmap!\n");
831
            goto cleanup;
Alexandre Julliard's avatar
Alexandre Julliard committed
832
        }
833
        SelectObject(himl->hdcMask, himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
834
    }
835 836
    else
        himl->hbmMask = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
837

838
    if (ilc == ILC_COLOR32)
839 840 841 842
        himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
    else
        himl->has_alpha = NULL;

Alexandre Julliard's avatar
Alexandre Julliard committed
843
    /* create blending brushes */
844
    hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend25);
845 846
    himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
    DeleteObject (hbmTemp);
Alexandre Julliard's avatar
Alexandre Julliard committed
847

848
    hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend50);
849 850
    himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
    DeleteObject (hbmTemp);
Alexandre Julliard's avatar
Alexandre Julliard committed
851

852
    TRACE("created imagelist %p\n", himl);
Eric Kohl's avatar
Eric Kohl committed
853
    return himl;
854 855

cleanup:
856
    ImageList_Destroy(himl);
857
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
858 859 860
}


Alexandre Julliard's avatar
Alexandre Julliard committed
861
/*************************************************************************
862
 * ImageList_Destroy [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
863 864
 *
 * Destroys an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
865
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
866
 * PARAMS
867
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
868
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
869 870 871
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
872 873
 */

874
BOOL WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
875
ImageList_Destroy (HIMAGELIST himl)
876
{
877
    if (!is_valid(himl))
Eric Kohl's avatar
Eric Kohl committed
878
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
879

880
    IImageList_Release((IImageList *) himl);
Eric Kohl's avatar
Eric Kohl committed
881
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
882 883 884
}


Alexandre Julliard's avatar
Alexandre Julliard committed
885
/*************************************************************************
886
 * ImageList_DragEnter [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
887
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
888 889 890 891 892 893 894 895 896 897 898 899 900 901
 * Locks window update and displays the drag image at the given position.
 *
 * PARAMS
 *     hwndLock [I] handle of the window that owns the drag image.
 *     x        [I] X position of the drag image.
 *     y        [I] Y position of the drag image.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     The position of the drag image is relative to the window, not
 *     the client area.
Alexandre Julliard's avatar
Alexandre Julliard committed
902 903
 */

904 905
BOOL WINAPI
ImageList_DragEnter (HWND hwndLock, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
906
{
907
    TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
908

909
    if (!is_valid(InternalDrag.himl))
910
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
911 912

    if (hwndLock)
913
	InternalDrag.hwnd = hwndLock;
Alexandre Julliard's avatar
Alexandre Julliard committed
914
    else
915
	InternalDrag.hwnd = GetDesktopWindow ();
Alexandre Julliard's avatar
Alexandre Julliard committed
916

917 918
    InternalDrag.x = x;
    InternalDrag.y = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
919

920 921 922 923
    /* draw the drag image and save the background */
    if (!ImageList_DragShowNolock(TRUE)) {
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
924

925
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
926 927 928 929
}


/*************************************************************************
930
 * ImageList_DragLeave [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
931 932 933 934 935 936 937 938 939
 *
 * Unlocks window update and hides the drag image.
 *
 * PARAMS
 *     hwndLock [I] handle of the window that owns the drag image.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
940 941
 */

942 943
BOOL WINAPI
ImageList_DragLeave (HWND hwndLock)
Alexandre Julliard's avatar
Alexandre Julliard committed
944
{
945 946 947
    /* As we don't save drag info in the window this can lead to problems if
       an app does not supply the same window as DragEnter */
    /* if (hwndLock)
948
	InternalDrag.hwnd = hwndLock;
Alexandre Julliard's avatar
Alexandre Julliard committed
949
    else
950 951 952 953 954
	InternalDrag.hwnd = GetDesktopWindow (); */
    if(!hwndLock)
	hwndLock = GetDesktopWindow();
    if(InternalDrag.hwnd != hwndLock)
	FIXME("DragLeave hWnd != DragEnter hWnd\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
955

Alexandre Julliard's avatar
Alexandre Julliard committed
956 957
    ImageList_DragShowNolock (FALSE);

958
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
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
/*************************************************************************
 * ImageList_InternalDragDraw [Internal]
 *
 * Draws the drag image.
 *
 * PARAMS
 *     hdc [I] device context to draw into.
 *     x   [I] X position of the drag image.
 *     y   [I] Y position of the drag image.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     The position of the drag image is relative to the window, not
 *     the client area.
 *
 */

static inline void
ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
{
    IMAGELISTDRAWPARAMS imldp;

    ZeroMemory (&imldp, sizeof(imldp));
    imldp.cbSize  = sizeof(imldp);
    imldp.himl    = InternalDrag.himl;
    imldp.i       = 0;
    imldp.hdcDst  = hdc,
    imldp.x       = x;
    imldp.y       = y;
    imldp.rgbBk   = CLR_DEFAULT;
    imldp.rgbFg   = CLR_DEFAULT;
    imldp.fStyle  = ILD_NORMAL;
    imldp.fState  = ILS_ALPHA;
998
    imldp.Frame   = 192;
999 1000 1001
    ImageList_DrawIndirect (&imldp);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1002
/*************************************************************************
1003
 * ImageList_DragMove [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
 *
 * Moves the drag image.
 *
 * PARAMS
 *     x [I] X position of the drag image.
 *     y [I] Y position of the drag image.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     The position of the drag image is relative to the window, not
 *     the client area.
Alexandre Julliard's avatar
Alexandre Julliard committed
1018 1019
 */

1020 1021
BOOL WINAPI
ImageList_DragMove (INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1022
{
1023 1024
    TRACE("(x=%d y=%d)\n", x, y);

1025
    if (!is_valid(InternalDrag.himl))
1026
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1027

1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
    /* draw/update the drag image */
    if (InternalDrag.bShow) {
	HDC hdcDrag;
	HDC hdcOffScreen;
	HDC hdcBg;
	HBITMAP hbmOffScreen;
	INT origNewX, origNewY;
	INT origOldX, origOldY;
	INT origRegX, origRegY;
	INT sizeRegX, sizeRegY;
1038

1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069

	/* calculate the update region */
	origNewX = x - InternalDrag.dxHotspot;
	origNewY = y - InternalDrag.dyHotspot;
	origOldX = InternalDrag.x - InternalDrag.dxHotspot;
	origOldY = InternalDrag.y - InternalDrag.dyHotspot;
	origRegX = min(origNewX, origOldX);
	origRegY = min(origNewY, origOldY);
	sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
	sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);

	hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
   			  DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
    	hdcOffScreen = CreateCompatibleDC(hdcDrag);
    	hdcBg = CreateCompatibleDC(hdcDrag);

	hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
	SelectObject(hdcOffScreen, hbmOffScreen);
	SelectObject(hdcBg, InternalDrag.hbmBg);

	/* get the actual background of the update region */
	BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
	       origRegX, origRegY, SRCCOPY);
	/* erase the old image */
	BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
	       InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
	       SRCCOPY);
	/* save the background */
	BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
	       hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
	/* draw the image */
1070 1071
	ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX, 
				   origNewY - origRegY);
1072 1073 1074 1075 1076 1077
	/* draw the update region to the screen */
	BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
	       hdcOffScreen, 0, 0, SRCCOPY);

	DeleteDC(hdcBg);
	DeleteDC(hdcOffScreen);
Michael Stefaniuc's avatar
Michael Stefaniuc committed
1078
	DeleteObject(hbmOffScreen);
1079 1080
	ReleaseDC(InternalDrag.hwnd, hdcDrag);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1081

1082 1083 1084
    /* update the image position */
    InternalDrag.x = x;
    InternalDrag.y = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1085

1086
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1087 1088 1089 1090
}


/*************************************************************************
1091
 * ImageList_DragShowNolock [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1092 1093 1094 1095 1096 1097 1098 1099 1100
 *
 * Shows or hides the drag image.
 *
 * PARAMS
 *     bShow [I] TRUE shows the drag image, FALSE hides it.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1101
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1102

1103 1104
BOOL WINAPI
ImageList_DragShowNolock (BOOL bShow)
Alexandre Julliard's avatar
Alexandre Julliard committed
1105
{
1106
    HDC hdcDrag;
1107 1108
    HDC hdcBg;
    INT x, y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1109

1110 1111 1112
    if (!is_valid(InternalDrag.himl))
        return FALSE;
    
1113
    TRACE("bShow=0x%X!\n", bShow);
Alexandre Julliard's avatar
Alexandre Julliard committed
1114

1115 1116 1117 1118
    /* DragImage is already visible/hidden */
    if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1119

1120 1121 1122
    /* position of the origin of the DragImage */
    x = InternalDrag.x - InternalDrag.dxHotspot;
    y = InternalDrag.y - InternalDrag.dyHotspot;
Alexandre Julliard's avatar
Alexandre Julliard committed
1123

1124 1125 1126 1127
    hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
			 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
    if (!hdcDrag) {
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1128 1129
    }

1130 1131 1132 1133 1134 1135
    hdcBg = CreateCompatibleDC(hdcDrag);
    if (!InternalDrag.hbmBg) {
	InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
		    InternalDrag.himl->cx, InternalDrag.himl->cy);
    }
    SelectObject(hdcBg, InternalDrag.hbmBg);
1136

1137 1138 1139 1140 1141
    if (bShow) {
	/* save the background */
	BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
	       hdcDrag, x, y, SRCCOPY);
	/* show the image */
1142
	ImageList_InternalDragDraw(hdcDrag, x, y);
1143
    } else {
1144 1145 1146
	/* hide the image */
	BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
	       hdcBg, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148
    }

1149
    InternalDrag.bShow = !InternalDrag.bShow;
Alexandre Julliard's avatar
Alexandre Julliard committed
1150

1151 1152 1153
    DeleteDC(hdcBg);
    ReleaseDC (InternalDrag.hwnd, hdcDrag);
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1154 1155 1156 1157
}


/*************************************************************************
1158 1159 1160
 * ImageList_Draw [COMCTL32.@]
 *
 * Draws an image.
Alexandre Julliard's avatar
Alexandre Julliard committed
1161 1162
 *
 * PARAMS
1163
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1164
 *     i      [I] image index
1165
 *     hdc    [I] handle to device context
Alexandre Julliard's avatar
Alexandre Julliard committed
1166 1167 1168 1169 1170 1171 1172 1173 1174
 *     x      [I] x position
 *     y      [I] y position
 *     fStyle [I] drawing flags
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * SEE
1175
 *     ImageList_DrawEx.
Alexandre Julliard's avatar
Alexandre Julliard committed
1176 1177
 */

1178
BOOL WINAPI
1179
ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1180
{
1181 1182
    return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0, 
		             CLR_DEFAULT, CLR_DEFAULT, fStyle);
Alexandre Julliard's avatar
Alexandre Julliard committed
1183 1184 1185 1186
}


/*************************************************************************
1187
 * ImageList_DrawEx [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1188
 *
1189
 * Draws an image and allows using extended drawing features.
Alexandre Julliard's avatar
Alexandre Julliard committed
1190 1191
 *
 * PARAMS
1192
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1193
 *     i      [I] image index
1194
 *     hdc    [I] handle to device context
Alexandre Julliard's avatar
Alexandre Julliard committed
1195 1196
 *     x      [I] X position
 *     y      [I] Y position
1197 1198
 *     dx     [I] X offset
 *     dy     [I] Y offset
Alexandre Julliard's avatar
Alexandre Julliard committed
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
 *     rgbBk  [I] background color
 *     rgbFg  [I] foreground color
 *     fStyle [I] drawing flags
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     Calls ImageList_DrawIndirect.
 *
 * SEE
 *     ImageList_DrawIndirect.
Alexandre Julliard's avatar
Alexandre Julliard committed
1212 1213
 */

1214 1215 1216 1217
BOOL WINAPI
ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
		  INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
		  UINT fStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1218 1219 1220
{
    IMAGELISTDRAWPARAMS imldp;

1221 1222
    ZeroMemory (&imldp, sizeof(imldp));
    imldp.cbSize  = sizeof(imldp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1223 1224 1225 1226 1227
    imldp.himl    = himl;
    imldp.i       = i;
    imldp.hdcDst  = hdc,
    imldp.x       = x;
    imldp.y       = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1228 1229
    imldp.cx      = dx;
    imldp.cy      = dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1230 1231 1232 1233
    imldp.rgbBk   = rgbBk;
    imldp.rgbFg   = rgbFg;
    imldp.fStyle  = fStyle;

1234
    return ImageList_DrawIndirect (&imldp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1235 1236 1237
}


1238
static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
1239 1240
                               int src_x, int src_y, int cx, int cy, BLENDFUNCTION func,
                               UINT style, COLORREF blend_col )
1241 1242 1243 1244 1245 1246 1247
{
    BOOL ret = FALSE;
    HDC hdc;
    HBITMAP bmp = 0, mask = 0;
    BITMAPINFO *info;
    void *bits, *mask_bits;
    unsigned int *ptr;
1248
    int i, j;
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266

    if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    info->bmiHeader.biWidth = cx;
    info->bmiHeader.biHeight = cy;
    info->bmiHeader.biPlanes = 1;
    info->bmiHeader.biBitCount = 32;
    info->bmiHeader.biCompression = BI_RGB;
    info->bmiHeader.biSizeImage = cx * cy * 4;
    info->bmiHeader.biXPelsPerMeter = 0;
    info->bmiHeader.biYPelsPerMeter = 0;
    info->bmiHeader.biClrUsed = 0;
    info->bmiHeader.biClrImportant = 0;
    if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
    SelectObject( hdc, bmp );
    BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );

1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
    if (blend_col != CLR_NONE)
    {
        BYTE r = GetRValue( blend_col );
        BYTE g = GetGValue( blend_col );
        BYTE b = GetBValue( blend_col );

        if (style & ILD_BLEND25)
        {
            for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
                *ptr = ((*ptr & 0xff000000) |
                        ((((*ptr & 0x00ff0000) * 3 + (r << 16)) / 4) & 0x00ff0000) |
                        ((((*ptr & 0x0000ff00) * 3 + (g << 8))  / 4) & 0x0000ff00) |
                        ((((*ptr & 0x000000ff) * 3 + (b << 0))  / 4) & 0x000000ff));
        }
        else if (style & ILD_BLEND50)
        {
            for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
                *ptr = ((*ptr & 0xff000000) |
                        ((((*ptr & 0x00ff0000) + (r << 16)) / 2) & 0x00ff0000) |
                        ((((*ptr & 0x0000ff00) + (g << 8))  / 2) & 0x0000ff00) |
                        ((((*ptr & 0x000000ff) + (b << 0))  / 2) & 0x000000ff));
        }
    }

1291
    if (himl->has_alpha)  /* we already have an alpha channel in this case */
1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
    {
        /* pre-multiply by the alpha channel */
        for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
        {
            DWORD alpha = *ptr >> 24;
            *ptr = ((*ptr & 0xff000000) |
                    (((*ptr & 0x00ff0000) * alpha / 255) & 0x00ff0000) |
                    (((*ptr & 0x0000ff00) * alpha / 255) & 0x0000ff00) |
                    (((*ptr & 0x000000ff) * alpha / 255)));
        }
    }
    else if (himl->hbmMask)
1304 1305 1306 1307 1308
    {
        unsigned int width_bytes = (cx + 31) / 32 * 4;
        /* generate alpha channel from the mask */
        info->bmiHeader.biBitCount = 1;
        info->bmiHeader.biSizeImage = width_bytes * cy;
1309 1310 1311 1312 1313 1314 1315 1316
        info->bmiColors[0].rgbRed      = 0;
        info->bmiColors[0].rgbGreen    = 0;
        info->bmiColors[0].rgbBlue     = 0;
        info->bmiColors[0].rgbReserved = 0;
        info->bmiColors[1].rgbRed      = 0xff;
        info->bmiColors[1].rgbGreen    = 0xff;
        info->bmiColors[1].rgbBlue     = 0xff;
        info->bmiColors[1].rgbReserved = 0;
1317 1318 1319 1320 1321 1322 1323 1324
        if (!(mask = CreateDIBSection( himl->hdcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0 )))
            goto done;
        SelectObject( hdc, mask );
        BitBlt( hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY );
        SelectObject( hdc, bmp );
        for (i = 0, ptr = bits; i < cy; i++)
            for (j = 0; j < cx; j++, ptr++)
                if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
1325
                else *ptr |= 0xff000000;
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
    }

    ret = GdiAlphaBlend( dest_dc, dest_x, dest_y, cx, cy, hdc, 0, 0, cx, cy, func );

done:
    DeleteDC( hdc );
    if (bmp) DeleteObject( bmp );
    if (mask) DeleteObject( mask );
    HeapFree( GetProcessHeap(), 0, info );
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1338
/*************************************************************************
1339
 * ImageList_DrawIndirect [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1340
 *
1341
 * Draws an image using various parameters specified in pimldp.
Alexandre Julliard's avatar
Alexandre Julliard committed
1342 1343
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1344
 *     pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
Alexandre Julliard's avatar
Alexandre Julliard committed
1345 1346
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1347 1348
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1349 1350
 */

1351
BOOL WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
1352
ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
Alexandre Julliard's avatar
Alexandre Julliard committed
1353
{
1354
    INT cx, cy, nOvlIdx;
1355 1356
    DWORD fState, dwRop;
    UINT fStyle;
1357
    COLORREF oldImageBk, oldImageFg;
1358
    HDC hImageDC, hImageListDC, hMaskListDC;
1359
    HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1360
    BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1361
    HIMAGELIST himl;
1362
    HBRUSH hOldBrush;
1363
    POINT pt;
1364
    BOOL has_alpha;
1365 1366

    if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1367
    if (!is_valid(himl)) return FALSE;
1368
    if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1369

1370 1371 1372
    imagelist_point_from_index( himl, pimldp->i, &pt );
    pt.x += pimldp->xBitmap;
    pt.y += pimldp->yBitmap;
1373

1374 1375 1376 1377
    fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
    fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
    cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
    cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1378 1379 1380 1381 1382 1383 1384 1385

    bIsTransparent = (fStyle & ILD_TRANSPARENT);
    if( pimldp->rgbBk == CLR_NONE )
        bIsTransparent = TRUE;
    if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
        bIsTransparent = TRUE;
    bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
    bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1386

Frank Richter's avatar
Frank Richter committed
1387 1388
    TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
          himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1389

1390
    /* we will use these DCs to access the images and masks in the ImageList */
1391 1392
    hImageListDC = himl->hdcImage;
    hMaskListDC  = himl->hdcMask;
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405

    /* these will accumulate the image and mask for the image we're drawing */
    hImageDC = CreateCompatibleDC( pimldp->hdcDst );
    hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
    hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;

    /* Create a compatible DC. */
    if (!hImageListDC || !hImageDC || !hImageBmp ||
	(bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
	goto cleanup;
    
    hOldImageBmp = SelectObject(hImageDC, hImageBmp);
  
1406
    /*
1407
     * To obtain a transparent look, background color should be set
1408
     * to white and foreground color to black when blitting the
1409 1410 1411 1412 1413
     * monochrome mask.
     */
    oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
    oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );

1414 1415
    has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
    if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
1416
    {
1417
        COLORREF colour, blend_col = CLR_NONE;
1418 1419
        BLENDFUNCTION func;

1420 1421 1422 1423 1424 1425 1426
        if (bBlend)
        {
            blend_col = pimldp->rgbFg;
            if (blend_col == CLR_DEFAULT) blend_col = GetSysColor( COLOR_HIGHLIGHT );
            else if (blend_col == CLR_NONE) blend_col = GetTextColor( pimldp->hdcDst );
        }

1427 1428 1429 1430
        func.BlendOp = AC_SRC_OVER;
        func.BlendFlags = 0;
        func.SourceConstantAlpha = (fState & ILS_ALPHA) ? pimldp->Frame : 255;
        func.AlphaFormat = AC_SRC_ALPHA;
1431 1432 1433

        if (bIsTransparent)
        {
1434
            bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1435
                                         pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1436 1437 1438 1439 1440 1441 1442 1443
            goto end;
        }
        colour = pimldp->rgbBk;
        if (colour == CLR_DEFAULT) colour = himl->clrBk;
        if (colour == CLR_NONE) colour = GetBkColor( pimldp->hdcDst );

        hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
        PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1444
        alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1445 1446 1447 1448 1449
        DeleteObject (SelectObject (hImageDC, hOldBrush));
        bResult = BitBlt( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
        goto end;
    }

1450
    /*
1451
     * Draw the initial image
1452
     */
1453
    if( bMask ) {
1454
	if (himl->hbmMask) {
1455 1456
            hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
            PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1457
            BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1458 1459 1460 1461 1462 1463 1464
            DeleteObject (SelectObject (hImageDC, hOldBrush));
            if( bIsTransparent )
            {
                BitBlt ( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
                bResult = TRUE;
                goto end;
            }
1465
	} else {
1466
	    hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1467 1468 1469
	    PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
	    SelectObject(hImageDC, hOldBrush);
	}
1470
    } else {
1471
	/* blend the image with the needed solid background */
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483
        COLORREF colour = RGB(0,0,0);

        if( !bIsTransparent )
        {
            colour = pimldp->rgbBk;
            if( colour == CLR_DEFAULT )
                colour = himl->clrBk;
            if( colour == CLR_NONE )
                colour = GetBkColor(pimldp->hdcDst);
        }

        hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1484
        PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1485 1486 1487 1488 1489 1490 1491
        if (himl->hbmMask)
        {
            BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
            BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
        }
        else
            BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCCOPY);
1492
        DeleteObject (SelectObject (hImageDC, hOldBrush));
1493
    }
1494

1495 1496
    /* Time for blending, if required */
    if (bBlend) {
1497
	HBRUSH hBlendBrush;
1498 1499 1500 1501 1502 1503 1504
        COLORREF clrBlend = pimldp->rgbFg;
	HDC hBlendMaskDC = hImageListDC;
	HBITMAP hOldBitmap;

	/* Create the blend Mask */
    	hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
	hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1505
        hOldBrush = SelectObject(hBlendMaskDC, hBlendBrush);
1506 1507 1508 1509 1510
    	PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
    	SelectObject(hBlendMaskDC, hOldBrush);

    	/* Modify the blend mask if an Image Mask exist */
    	if(himl->hbmMask) {
1511
	    BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1512 1513
	    BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
	}
1514

1515 1516 1517
	/* now apply blend to the current image given the BlendMask */
        if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
        else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1518
	hOldBrush = SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1519 1520 1521 1522
	BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
	DeleteObject(SelectObject(hImageDC, hOldBrush));
	SelectObject(hBlendMaskDC, hOldBitmap);
    }
1523 1524

    /* Now do the overlay image, if any */
1525 1526
    nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
    if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1527 1528
	nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
	if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1529 1530 1531
            POINT ptOvl;
            imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
            ptOvl.x += pimldp->xBitmap;
1532
	    if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1533 1534
		BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
	    BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1535
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1536 1537
    }

1538 1539 1540 1541 1542 1543 1544
    if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
    if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
    if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");

    if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
    if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
    if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1545

1546 1547
    /* now copy the image to the screen */
    dwRop = SRCCOPY;
1548
    if (himl->hbmMask && bIsTransparent ) {
1549 1550
	COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
	COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1551
        BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1552 1553 1554 1555 1556 1557 1558 1559
	SetBkColor(pimldp->hdcDst, oldDstBk);
	SetTextColor(pimldp->hdcDst, oldDstFg);
	dwRop = SRCPAINT;
    }
    if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
    BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);

    bResult = TRUE;
1560
end:
1561 1562 1563 1564 1565 1566 1567
    /* cleanup the mess */
    SetBkColor(hImageDC, oldImageBk);
    SetTextColor(hImageDC, oldImageFg);
    SelectObject(hImageDC, hOldImageBmp);
cleanup:
    DeleteObject(hBlendMaskBmp);
    DeleteObject(hImageBmp);
1568
    DeleteDC(hImageDC);
1569 1570

    return bResult;
Alexandre Julliard's avatar
Alexandre Julliard committed
1571 1572 1573
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1574
/*************************************************************************
1575 1576 1577
 * ImageList_Duplicate [COMCTL32.@]
 *
 * Duplicates an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1578
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1579 1580
 * PARAMS
 *     himlSrc [I] source image list handle
Alexandre Julliard's avatar
Alexandre Julliard committed
1581
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1582 1583
 * RETURNS
 *     Success: Handle of duplicated image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1584
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1585 1586
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1587 1588
HIMAGELIST WINAPI
ImageList_Duplicate (HIMAGELIST himlSrc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1589 1590 1591
{
    HIMAGELIST himlDst;

1592
    if (!is_valid(himlSrc)) {
1593
        ERR("Invalid image list handle!\n");
1594
        return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1595 1596 1597
    }

    himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1598
                                himlSrc->cCurImage, himlSrc->cGrow);
Alexandre Julliard's avatar
Alexandre Julliard committed
1599 1600 1601

    if (himlDst)
    {
1602 1603
        SIZE sz;

1604
        imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, &sz);
1605
        BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1606
                himlSrc->hdcImage, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1607 1608

        if (himlDst->hbmMask)
1609
            BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1610
                    himlSrc->hdcMask, 0, 0, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1611

1612
	himlDst->cCurImage = himlSrc->cCurImage;
1613 1614
        if (himlSrc->has_alpha && himlDst->has_alpha)
            memcpy( himlDst->has_alpha, himlSrc->has_alpha, himlDst->cCurImage );
1615
    }
1616
    return himlDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1617 1618 1619
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1620
/*************************************************************************
1621
 * ImageList_EndDrag [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1622 1623
 *
 * Finishes a drag operation.
Alexandre Julliard's avatar
Alexandre Julliard committed
1624
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1625
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1626
 *     no Parameters
Alexandre Julliard's avatar
Alexandre Julliard committed
1627
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1628 1629 1630
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1631 1632
 */

1633
VOID WINAPI
1634
ImageList_EndDrag (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1635
{
1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646
    /* cleanup the InternalDrag struct */
    InternalDrag.hwnd = 0;
    ImageList_Destroy (InternalDrag.himl);
    InternalDrag.himl = 0;
    InternalDrag.x= 0;
    InternalDrag.y= 0;
    InternalDrag.dxHotspot = 0;
    InternalDrag.dyHotspot = 0;
    InternalDrag.bShow = FALSE;
    DeleteObject(InternalDrag.hbmBg);
    InternalDrag.hbmBg = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1647 1648
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1649

Alexandre Julliard's avatar
Alexandre Julliard committed
1650
/*************************************************************************
1651
 * ImageList_GetBkColor [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1652
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1653
 * Returns the background color of an image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1654
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1655 1656 1657 1658
 * PARAMS
 *     himl [I] Image list handle.
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1659 1660
 *     Success: background color
 *     Failure: CLR_NONE
Alexandre Julliard's avatar
Alexandre Julliard committed
1661 1662
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1663 1664
COLORREF WINAPI
ImageList_GetBkColor (HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1665
{
1666
    return himl ? himl->clrBk : CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1667 1668 1669
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1670
/*************************************************************************
1671
 * ImageList_GetDragImage [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1672 1673
 *
 * Returns the handle to the internal drag image list.
Alexandre Julliard's avatar
Alexandre Julliard committed
1674
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1675 1676 1677
 * PARAMS
 *     ppt        [O] Pointer to the drag position. Can be NULL.
 *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
1678
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1679 1680 1681
 * RETURNS
 *     Success: Handle of the drag image list.
 *     Failure: NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
1682 1683
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1684
HIMAGELIST WINAPI
1685
ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
1686
{
1687
    if (is_valid(InternalDrag.himl)) {
1688
	if (ppt) {
1689 1690
	    ppt->x = InternalDrag.x;
	    ppt->y = InternalDrag.y;
1691 1692
	}
	if (pptHotspot) {
1693 1694
	    pptHotspot->x = InternalDrag.dxHotspot;
	    pptHotspot->y = InternalDrag.dyHotspot;
1695
	}
1696
        return (InternalDrag.himl);
1697
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1698

1699
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1700 1701 1702
}


1703
/*************************************************************************
1704
 * ImageList_GetFlags [COMCTL32.@]
1705
 *
1706 1707 1708 1709 1710 1711 1712 1713
 * Gets the flags of the specified image list.
 *
 * PARAMS
 *     himl [I] Handle to image list
 *
 * RETURNS
 *     Image list flags.
 *
1714 1715 1716 1717 1718 1719 1720
 * BUGS
 *    Stub.
 */

DWORD WINAPI
ImageList_GetFlags(HIMAGELIST himl)
{
1721 1722 1723
    TRACE("%p\n", himl);

    return is_valid(himl) ? himl->flags : 0;
1724 1725 1726
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1727
/*************************************************************************
1728
 * ImageList_GetIcon [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1729 1730 1731 1732
 *
 * Creates an icon from a masked image of an image list.
 *
 * PARAMS
1733
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1734 1735 1736 1737 1738 1739
 *     i     [I] image index
 *     flags [I] drawing style flags
 *
 * RETURNS
 *     Success: icon handle
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1740 1741
 */

1742 1743
HICON WINAPI
ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1744
{
1745
    ICONINFO ii;
1746 1747 1748
    HICON hIcon;
    HBITMAP hOldDstBitmap;
    HDC hdcDst;
1749
    POINT pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1750

1751
    TRACE("%p %d %d\n", himl, i, fStyle);
1752
    if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1753

Alexandre Julliard's avatar
Alexandre Julliard committed
1754
    ii.fIcon = TRUE;
1755 1756
    ii.xHotspot = 0;
    ii.yHotspot = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1757

1758 1759 1760 1761 1762 1763 1764
    /* create colour bitmap */
    hdcDst = GetDC(0);
    ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
    ReleaseDC(0, hdcDst);

    hdcDst = CreateCompatibleDC(0);

1765 1766
    imagelist_point_from_index( himl, i, &pt );

Alexandre Julliard's avatar
Alexandre Julliard committed
1767
    /* draw mask*/
1768
    ii.hbmMask  = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1769
    hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1770 1771
    if (himl->hbmMask) {
        BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1772
                himl->hdcMask, pt.x, pt.y, SRCCOPY);
1773 1774 1775
    }
    else
        PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
Alexandre Julliard's avatar
Alexandre Julliard committed
1776 1777

    /* draw image*/
Luc Tourangeau's avatar
Luc Tourangeau committed
1778
    SelectObject (hdcDst, ii.hbmColor);
1779
    BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1780
            himl->hdcImage, pt.x, pt.y, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1781

1782 1783
    /*
     * CreateIconIndirect requires us to deselect the bitmaps from
1784
     * the DCs before calling
1785 1786 1787
     */
    SelectObject(hdcDst, hOldDstBitmap);

1788
    hIcon = CreateIconIndirect (&ii);
Alexandre Julliard's avatar
Alexandre Julliard committed
1789

1790 1791
    DeleteObject (ii.hbmMask);
    DeleteObject (ii.hbmColor);
1792
    DeleteDC (hdcDst);
Alexandre Julliard's avatar
Alexandre Julliard committed
1793

Eric Kohl's avatar
Eric Kohl committed
1794
    return hIcon;
Alexandre Julliard's avatar
Alexandre Julliard committed
1795 1796 1797
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1798
/*************************************************************************
1799
 * ImageList_GetIconSize [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1800 1801 1802 1803
 *
 * Retrieves the size of an image in an image list.
 *
 * PARAMS
1804
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1805 1806 1807 1808 1809 1810 1811 1812 1813
 *     cx   [O] pointer to the image width.
 *     cy   [O] pointer to the image height.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * NOTES
 *     All images in an image list have the same size.
Alexandre Julliard's avatar
Alexandre Julliard committed
1814 1815
 */

1816 1817
BOOL WINAPI
ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1818
{
1819
    if (!is_valid(himl) || !cx || !cy)
Eric Kohl's avatar
Eric Kohl committed
1820 1821 1822
	return FALSE;
    if ((himl->cx <= 0) || (himl->cy <= 0))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1823

1824 1825
    *cx = himl->cx;
    *cy = himl->cy;
Eric Kohl's avatar
Eric Kohl committed
1826 1827

    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1828 1829 1830
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1831
/*************************************************************************
1832
 * ImageList_GetImageCount [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1833 1834 1835 1836
 *
 * Returns the number of images in an image list.
 *
 * PARAMS
1837
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1838 1839 1840
 *
 * RETURNS
 *     Success: Number of images.
Alexandre Julliard's avatar
Alexandre Julliard committed
1841
 *     Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
1842 1843
 */

1844
INT WINAPI
Alexandre Julliard's avatar
Alexandre Julliard committed
1845
ImageList_GetImageCount (HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1846
{
1847
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
1848
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1849

Eric Kohl's avatar
Eric Kohl committed
1850
    return himl->cCurImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
1851 1852 1853
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1854
/*************************************************************************
1855
 * ImageList_GetImageInfo [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1856 1857 1858 1859
 *
 * Returns information about an image in an image list.
 *
 * PARAMS
1860
 *     himl       [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1861
 *     i          [I] image index
1862
 *     pImageInfo [O] pointer to the image information
Alexandre Julliard's avatar
Alexandre Julliard committed
1863 1864 1865 1866
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1867 1868
 */

1869 1870
BOOL WINAPI
ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
1871
{
1872 1873
    POINT pt;

1874
    if (!is_valid(himl) || (pImageInfo == NULL))
Eric Kohl's avatar
Eric Kohl committed
1875 1876 1877
	return FALSE;
    if ((i < 0) || (i >= himl->cCurImage))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1878

Alexandre Julliard's avatar
Alexandre Julliard committed
1879 1880
    pImageInfo->hbmImage = himl->hbmImage;
    pImageInfo->hbmMask  = himl->hbmMask;
1881

1882 1883 1884 1885 1886
    imagelist_point_from_index( himl, i, &pt );
    pImageInfo->rcImage.top    = pt.y;
    pImageInfo->rcImage.bottom = pt.y + himl->cy;
    pImageInfo->rcImage.left   = pt.x;
    pImageInfo->rcImage.right  = pt.x + himl->cx;
1887

Eric Kohl's avatar
Eric Kohl committed
1888
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1889 1890 1891
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1892
/*************************************************************************
1893
 * ImageList_GetImageRect [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1894 1895 1896 1897
 *
 * Retrieves the rectangle of the specified image in an image list.
 *
 * PARAMS
1898
 *     himl   [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1899 1900 1901 1902
 *     i      [I] image index
 *     lpRect [O] pointer to the image rectangle
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1903 1904
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1905
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1906 1907
 * NOTES
 *    This is an UNDOCUMENTED function!!!
Alexandre Julliard's avatar
Alexandre Julliard committed
1908
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1909

1910 1911
BOOL WINAPI
ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1912
{
1913 1914
    POINT pt;

1915
    if (!is_valid(himl) || (lpRect == NULL))
Eric Kohl's avatar
Eric Kohl committed
1916 1917 1918
	return FALSE;
    if ((i < 0) || (i >= himl->cCurImage))
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1919

1920 1921 1922 1923 1924
    imagelist_point_from_index( himl, i, &pt );
    lpRect->left   = pt.x;
    lpRect->top    = pt.y;
    lpRect->right  = pt.x + himl->cx;
    lpRect->bottom = pt.y + himl->cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1925

Eric Kohl's avatar
Eric Kohl committed
1926
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1927 1928 1929
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1930
/*************************************************************************
1931 1932
 * ImageList_LoadImage  [COMCTL32.@]
 * ImageList_LoadImageA [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1933 1934 1935
 *
 * Creates an image list from a bitmap, icon or cursor.
 *
1936
 * See ImageList_LoadImageW.
Alexandre Julliard's avatar
Alexandre Julliard committed
1937 1938
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1939
HIMAGELIST WINAPI
1940 1941
ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
			COLORREF clrMask, UINT uType, UINT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1942
{
1943 1944 1945
    HIMAGELIST himl;
    LPWSTR lpbmpW;
    DWORD len;
Alexandre Julliard's avatar
Alexandre Julliard committed
1946

1947
    if (IS_INTRESOURCE(lpbmp))
1948 1949
        return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
                                    uType, uFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
1950

1951
    len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1952
    lpbmpW = Alloc(len * sizeof(WCHAR));
1953
    MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1954

1955
    himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1956
    Free (lpbmpW);
1957
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
1958 1959 1960
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1961
/*************************************************************************
1962
 * ImageList_LoadImageW [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1963 1964 1965 1966
 *
 * Creates an image list from a bitmap, icon or cursor.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
1967 1968 1969 1970 1971 1972 1973
 *     hi      [I] instance handle
 *     lpbmp   [I] name or id of the image
 *     cx      [I] width of each image
 *     cGrow   [I] number of images to expand
 *     clrMask [I] mask color
 *     uType   [I] type of image to load
 *     uFlags  [I] loading flags
Alexandre Julliard's avatar
Alexandre Julliard committed
1974 1975
 *
 * RETURNS
1976
 *     Success: handle to the loaded image list
Alexandre Julliard's avatar
Alexandre Julliard committed
1977 1978 1979 1980
 *     Failure: NULL
 *
 * SEE
 *     LoadImage ()
Alexandre Julliard's avatar
Alexandre Julliard committed
1981 1982
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
1983
HIMAGELIST WINAPI
1984
ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1985
                      COLORREF clrMask, UINT uType, UINT uFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1986 1987
{
    HIMAGELIST himl = NULL;
1988 1989
    HANDLE   handle;
    INT      nImageCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
1990

1991
    handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
1992
    if (!handle) {
1993
        WARN("Couldn't load image\n");
1994
        return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1995
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1996 1997

    if (uType == IMAGE_BITMAP) {
1998 1999 2000 2001 2002
        DIBSECTION dib;
        UINT color;

        if (GetObjectW (handle, sizeof(dib), &dib) == sizeof(BITMAP)) color = ILC_COLOR;
        else color = dib.dsBm.bmBitsPixel;
2003 2004 2005 2006 2007 2008 2009 2010 2011 2012

        /* To match windows behavior, if cx is set to zero and
         the flag DI_DEFAULTSIZE is specified, cx becomes the
         system metric value for icons. If the flag is not specified
         the function sets the size to the height of the bitmap */
        if (cx == 0)
        {
            if (uFlags & DI_DEFAULTSIZE)
                cx = GetSystemMetrics (SM_CXICON);
            else
2013
                cx = dib.dsBm.bmHeight;
2014 2015
        }

2016
        nImageCount = dib.dsBm.bmWidth / cx;
Alexandre Julliard's avatar
Alexandre Julliard committed
2017

2018
        himl = ImageList_Create (cx, dib.dsBm.bmHeight, ILC_MASK | color, nImageCount, cGrow);
2019 2020 2021 2022
        if (!himl) {
            DeleteObject (handle);
            return NULL;
        }
2023
        ImageList_AddMasked (himl, handle, clrMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2024 2025
    }
    else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
2026 2027
        ICONINFO ii;
        BITMAP bmp;
Alexandre Julliard's avatar
Alexandre Julliard committed
2028

2029
        GetIconInfo (handle, &ii);
2030
        GetObjectW (ii.hbmColor, sizeof(BITMAP), &bmp);
2031
        himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
Alexandre Julliard's avatar
Alexandre Julliard committed
2032
                                 ILC_MASK | ILC_COLOR, 1, cGrow);
2033 2034 2035 2036 2037 2038
        if (!himl) {
            DeleteObject (ii.hbmColor);
            DeleteObject (ii.hbmMask);
            DeleteObject (handle);
            return NULL;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
2039
        ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
2040 2041
        DeleteObject (ii.hbmColor);
        DeleteObject (ii.hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2042 2043
    }

2044
    DeleteObject (handle);
2045

2046
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
2047 2048 2049
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2050
/*************************************************************************
2051
 * ImageList_Merge [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2052
 *
2053
 * Create an image list containing a merged image from two image lists.
Alexandre Julliard's avatar
Alexandre Julliard committed
2054 2055
 *
 * PARAMS
2056
 *     himl1 [I] handle to first image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2057
 *     i1    [I] first image index
2058
 *     himl2 [I] handle to second image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2059 2060 2061 2062 2063
 *     i2    [I] second image index
 *     dx    [I] X offset of the second image relative to the first.
 *     dy    [I] Y offset of the second image relative to the first.
 *
 * RETURNS
2064 2065 2066 2067 2068 2069 2070 2071 2072
 *     Success: The newly created image list. It contains a single image
 *              consisting of the second image merged with the first.
 *     Failure: NULL, if either himl1 or himl2 are invalid.
 *
 * NOTES
 *   - The returned image list should be deleted by the caller using
 *     ImageList_Destroy() when it is no longer required.
 *   - If either i1 or i2 are not valid image indices they will be treated
 *     as a blank image.
Alexandre Julliard's avatar
Alexandre Julliard committed
2073
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
2074
HIMAGELIST WINAPI
2075 2076
ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
		 INT dx, INT dy)
Alexandre Julliard's avatar
Alexandre Julliard committed
2077 2078
{
    HIMAGELIST himlDst = NULL;
2079 2080
    INT      cxDst, cyDst;
    INT      xOff1, yOff1, xOff2, yOff2;
2081
    POINT    pt1, pt2;
Alexandre Julliard's avatar
Alexandre Julliard committed
2082

2083 2084 2085
    TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
	   i2, dx, dy);

2086
    if (!is_valid(himl1) || !is_valid(himl2))
Eric Kohl's avatar
Eric Kohl committed
2087
	return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
2088

Alexandre Julliard's avatar
Alexandre Julliard committed
2089
    if (dx > 0) {
2090
        cxDst = max (himl1->cx, dx + himl2->cx);
Alexandre Julliard's avatar
Alexandre Julliard committed
2091
        xOff1 = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2092
        xOff2 = dx;
Alexandre Julliard's avatar
Alexandre Julliard committed
2093
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2094
    else if (dx < 0) {
2095
        cxDst = max (himl2->cx, himl1->cx - dx);
Alexandre Julliard's avatar
Alexandre Julliard committed
2096
        xOff1 = -dx;
Alexandre Julliard's avatar
Alexandre Julliard committed
2097 2098 2099
        xOff2 = 0;
    }
    else {
2100
        cxDst = max (himl1->cx, himl2->cx);
Alexandre Julliard's avatar
Alexandre Julliard committed
2101 2102 2103 2104
        xOff1 = 0;
        xOff2 = 0;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2105
    if (dy > 0) {
2106
        cyDst = max (himl1->cy, dy + himl2->cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
2107
        yOff1 = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2108
        yOff2 = dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
2109
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2110
    else if (dy < 0) {
2111
        cyDst = max (himl2->cy, himl1->cy - dy);
Alexandre Julliard's avatar
Alexandre Julliard committed
2112
        yOff1 = -dy;
Alexandre Julliard's avatar
Alexandre Julliard committed
2113 2114 2115
        yOff2 = 0;
    }
    else {
2116
        cyDst = max (himl1->cy, himl2->cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
2117 2118 2119 2120 2121 2122
        yOff1 = 0;
        yOff2 = 0;
    }

    himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);

2123 2124
    if (himlDst)
    {
2125
        imagelist_point_from_index( himl1, i1, &pt1 );
2126
        imagelist_point_from_index( himl2, i2, &pt2 );
2127

Alexandre Julliard's avatar
Alexandre Julliard committed
2128
        /* copy image */
2129 2130
        BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
        if (i1 >= 0 && i1 < himl1->cCurImage)
2131
            BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
2132 2133
        if (i2 >= 0 && i2 < himl2->cCurImage)
        {
2134 2135
            BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
            BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
2136
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
2137 2138

        /* copy mask */
2139 2140
        BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
        if (i1 >= 0 && i1 < himl1->cCurImage)
2141
            BitBlt (himlDst->hdcMask,  xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask,  pt1.x, pt1.y, SRCCOPY);
2142
        if (i2 >= 0 && i2 < himl2->cCurImage)
2143
            BitBlt (himlDst->hdcMask,  xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask,  pt2.x, pt2.y, SRCAND);
2144

2145
	himlDst->cCurImage = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2146
    }
2147

Eric Kohl's avatar
Eric Kohl committed
2148
    return himlDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
2149 2150 2151
}


2152
/* helper for ImageList_Read, see comments below */
2153
static void *read_bitmap(LPSTREAM pstm, BITMAPINFO *bmi)
2154
{
2155
    BITMAPFILEHEADER	bmfh;
2156
    int bitsperpixel, palspace;
2157
    void *bits;
2158

2159
    if (FAILED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)))
2160
        return NULL;
2161 2162

    if (bmfh.bfType != (('M'<<8)|'B'))
2163
        return NULL;
2164

2165
    if (FAILED(IStream_Read ( pstm, &bmi->bmiHeader, sizeof(bmi->bmiHeader), NULL)))
2166
        return NULL;
2167

2168
    if ((bmi->bmiHeader.biSize != sizeof(bmi->bmiHeader)))
2169
        return NULL;
2170 2171 2172 2173

    TRACE("width %u, height %u, planes %u, bpp %u\n",
          bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
          bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount);
2174

2175
    bitsperpixel = bmi->bmiHeader.biPlanes * bmi->bmiHeader.biBitCount;
2176
    if (bitsperpixel<=8)
2177
        palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2178
    else
2179 2180
        palspace = 0;

2181
    bmi->bmiHeader.biSizeImage = get_dib_image_size( bmi );
2182 2183

    /* read the palette right after the end of the bitmapinfoheader */
2184
    if (palspace && FAILED(IStream_Read(pstm, bmi->bmiColors, palspace, NULL)))
2185
        return NULL;
2186

2187
    bits = Alloc(bmi->bmiHeader.biSizeImage);
2188
    if (!bits) return NULL;
2189

2190 2191 2192 2193 2194 2195
    if (FAILED(IStream_Read(pstm, bits, bmi->bmiHeader.biSizeImage, NULL)))
    {
        Free(bits);
        return NULL;
    }
    return bits;
2196 2197
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2198
/*************************************************************************
2199
 * ImageList_Read [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2200 2201 2202 2203 2204 2205 2206
 *
 * Reads an image list from a stream.
 *
 * PARAMS
 *     pstm [I] pointer to a stream
 *
 * RETURNS
2207
 *     Success: handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2208
 *     Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
2209
 *
2210
 * The format is like this:
2211
 *	ILHEAD			ilheadstruct;
2212 2213
 *
 * for the color image part:
2214 2215
 *	BITMAPFILEHEADER	bmfh;
 *	BITMAPINFOHEADER	bmih;
2216
 * only if it has a palette:
2217
 *	RGBQUAD		rgbs[nr_of_paletted_colors];
2218 2219 2220 2221 2222 2223 2224
 *
 *	BYTE			colorbits[imagesize];
 *
 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
 *	BITMAPFILEHEADER	bmfh_mask;
 *	BITMAPINFOHEADER	bmih_mask;
 * only if it has a palette (it usually does not):
2225
 *	RGBQUAD		rgbs[nr_of_paletted_colors];
2226 2227
 *
 *	BYTE			maskbits[imagesize];
Alexandre Julliard's avatar
Alexandre Julliard committed
2228
 */
2229
HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
Alexandre Julliard's avatar
Alexandre Julliard committed
2230
{
2231 2232 2233 2234 2235
    char image_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
    char mask_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
    BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
    BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
    void *image_bits, *mask_bits = NULL;
2236 2237 2238 2239
    ILHEAD	ilHead;
    HIMAGELIST	himl;
    int		i;

2240 2241
    TRACE("%p\n", pstm);

2242
    if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2243
	return NULL;
2244 2245 2246 2247
    if (ilHead.usMagic != (('L' << 8) | 'I'))
	return NULL;
    if (ilHead.usVersion != 0x101) /* probably version? */
	return NULL;
2248

2249 2250 2251
    TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
          ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);

2252
    himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2253
    if (!himl)
2254
	return NULL;
2255

2256
    if (!(image_bits = read_bitmap(pstm, image_info)))
2257
    {
2258
	WARN("failed to read bitmap from stream\n");
2259
	return NULL;
2260
    }
2261 2262
    if (ilHead.flags & ILC_MASK)
    {
2263
        if (!(mask_bits = read_bitmap(pstm, mask_info)))
2264 2265
        {
            WARN("failed to read mask bitmap from stream\n");
2266 2267 2268
	    return NULL;
	}
    }
2269 2270 2271 2272 2273 2274 2275 2276 2277 2278
    else mask_info = NULL;

    if (himl->has_alpha && image_info->bmiHeader.biBitCount == 32)
    {
        DWORD *ptr = image_bits;
        BYTE *mask_ptr = mask_bits;
        int stride = himl->cy * image_info->bmiHeader.biWidth;

        if (image_info->bmiHeader.biHeight > 0)  /* bottom-up */
        {
2279 2280
            ptr += image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride;
            mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 8;
2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305
            stride = -stride;
            image_info->bmiHeader.biHeight = himl->cy;
        }
        else image_info->bmiHeader.biHeight = -himl->cy;

        for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
        {
            add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
                          himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr );
            ptr += stride;
            mask_ptr += stride / 8;
        }
    }
    else
    {
        StretchDIBits( himl->hdcImage, 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
                       0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
                       image_bits, image_info, DIB_RGB_COLORS, SRCCOPY);
        if (mask_info)
            StretchDIBits( himl->hdcMask, 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
                           0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
                           mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY);
    }
    Free( image_bits );
    Free( mask_bits );
Alexandre Julliard's avatar
Alexandre Julliard committed
2306

2307 2308
    himl->cCurImage = ilHead.cCurImage;
    himl->cMaxImage = ilHead.cMaxImage;
2309

2310 2311
    ImageList_SetBkColor(himl,ilHead.bkcolor);
    for (i=0;i<4;i++)
2312
	ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2313
    return himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
2314 2315 2316
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2317
/*************************************************************************
2318 2319 2320
 * ImageList_Remove [COMCTL32.@]
 *
 * Removes an image from an image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2321 2322 2323 2324 2325 2326 2327 2328
 *
 * PARAMS
 *     himl [I] image list handle
 *     i    [I] image index
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
2329 2330 2331
 *
 * FIXME: as the image list storage test shows, native comctl32 simply shifts
 * images without creating a new bitmap.
Alexandre Julliard's avatar
Alexandre Julliard committed
2332
 */
2333 2334
BOOL WINAPI
ImageList_Remove (HIMAGELIST himl, INT i)
Alexandre Julliard's avatar
Alexandre Julliard committed
2335
{
2336
    HBITMAP hbmNewImage, hbmNewMask;
2337
    HDC     hdcBmp;
2338
    SIZE    sz;
Alexandre Julliard's avatar
Alexandre Julliard committed
2339

2340 2341
    TRACE("(himl=%p i=%d)\n", himl, i);

2342
    if (!is_valid(himl)) {
2343 2344 2345
        ERR("Invalid image list handle!\n");
        return FALSE;
    }
2346

Alexandre Julliard's avatar
Alexandre Julliard committed
2347
    if ((i < -1) || (i >= himl->cCurImage)) {
2348
        TRACE("index out of range! %d\n", i);
Eric Kohl's avatar
Eric Kohl committed
2349
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2350 2351 2352
    }

    if (i == -1) {
2353 2354
        INT nCount;

Alexandre Julliard's avatar
Alexandre Julliard committed
2355
        /* remove all */
2356 2357 2358 2359 2360
	if (himl->cCurImage == 0) {
	    /* remove all on empty ImageList is allowed */
	    TRACE("remove all on empty ImageList!\n");
	    return TRUE;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2361

2362
        himl->cMaxImage = himl->cGrow;
Alexandre Julliard's avatar
Alexandre Julliard committed
2363
        himl->cCurImage = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2364
        for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
Alexandre Julliard's avatar
Alexandre Julliard committed
2365 2366
             himl->nOvlIdx[nCount] = -1;

2367
        hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2368 2369 2370
        SelectObject (himl->hdcImage, hbmNewImage);
        DeleteObject (himl->hbmImage);
        himl->hbmImage = hbmNewImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
2371 2372

        if (himl->hbmMask) {
2373

2374
            imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2375
            hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2376 2377 2378
            SelectObject (himl->hdcMask, hbmNewMask);
            DeleteObject (himl->hbmMask);
            himl->hbmMask = hbmNewMask;
Alexandre Julliard's avatar
Alexandre Julliard committed
2379 2380 2381 2382
        }
    }
    else {
        /* delete one image */
2383
        TRACE("Remove single image! %d\n", i);
Alexandre Julliard's avatar
Alexandre Julliard committed
2384 2385

        /* create new bitmap(s) */
2386
        TRACE(" - Number of images: %d / %d (Old/New)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2387
                 himl->cCurImage, himl->cCurImage - 1);
2388

2389
        hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2390

2391
        imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz );
Alexandre Julliard's avatar
Alexandre Julliard committed
2392
        if (himl->hbmMask)
2393
            hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2394 2395 2396
        else
            hbmNewMask = 0;  /* Just to keep compiler happy! */

2397
        hdcBmp = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2398 2399 2400

        /* copy all images and masks prior to the "removed" image */
        if (i > 0) {
2401
            TRACE("Pre image copy: Copy %d images\n", i);
2402

2403
            SelectObject (hdcBmp, hbmNewImage);
2404
            imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2405 2406

            if (himl->hbmMask) {
2407
                SelectObject (hdcBmp, hbmNewMask);
2408
                imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2409 2410 2411 2412 2413
            }
        }

        /* copy all images and masks behind the removed image */
        if (i < himl->cCurImage - 1) {
2414
            TRACE("Post image copy!\n");
2415

2416
            SelectObject (hdcBmp, hbmNewImage);
2417 2418
            imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i + 1,
                                   (himl->cCurImage - i), i );
Alexandre Julliard's avatar
Alexandre Julliard committed
2419 2420

            if (himl->hbmMask) {
2421
                SelectObject (hdcBmp, hbmNewMask);
2422 2423
                imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i + 1,
                                       (himl->cCurImage - i), i );
Alexandre Julliard's avatar
Alexandre Julliard committed
2424 2425 2426
            }
        }

2427
        DeleteDC (hdcBmp);
Alexandre Julliard's avatar
Alexandre Julliard committed
2428 2429

        /* delete old images and insert new ones */
2430
        SelectObject (himl->hdcImage, hbmNewImage);
2431
        DeleteObject (himl->hbmImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2432 2433
        himl->hbmImage = hbmNewImage;
        if (himl->hbmMask) {
2434
            SelectObject (himl->hdcMask, hbmNewMask);
2435
            DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2436 2437 2438 2439 2440 2441
            himl->hbmMask = hbmNewMask;
        }

        himl->cCurImage--;
    }

Eric Kohl's avatar
Eric Kohl committed
2442
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2443 2444 2445
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2446
/*************************************************************************
2447
 * ImageList_Replace [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2448 2449 2450 2451
 *
 * Replaces an image in an image list with a new image.
 *
 * PARAMS
2452
 *     himl     [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2453
 *     i        [I] image index
2454 2455
 *     hbmImage [I] handle to image bitmap
 *     hbmMask  [I] handle to mask bitmap. Can be NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
2456 2457 2458 2459 2460 2461
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2462 2463 2464
BOOL WINAPI
ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
		   HBITMAP hbmMask)
Alexandre Julliard's avatar
Alexandre Julliard committed
2465
{
2466
    HDC hdcImage;
2467
    BITMAP bmp;
2468
    POINT pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
2469

2470
    TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2471

2472
    if (!is_valid(himl)) {
2473
        ERR("Invalid image list handle!\n");
Eric Kohl's avatar
Eric Kohl committed
2474
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2475
    }
2476

2477
    if ((i >= himl->cMaxImage) || (i < 0)) {
2478
        ERR("Invalid image index!\n");
Eric Kohl's avatar
Eric Kohl committed
2479
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2480
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2481

2482
    if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
2483 2484
        return FALSE;

2485
    hdcImage = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2486 2487

    /* Replace Image */
2488 2489 2490 2491
    SelectObject (hdcImage, hbmImage);

    if (add_with_alpha( himl, hdcImage, i, 1, bmp.bmWidth, bmp.bmHeight, hbmImage, hbmMask ))
        goto done;
Alexandre Julliard's avatar
Alexandre Julliard committed
2492

2493 2494
    imagelist_point_from_index(himl, i, &pt);
    StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
Alexandre Julliard's avatar
Alexandre Julliard committed
2495
                  hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
Alexandre Julliard's avatar
Alexandre Julliard committed
2496

Alexandre Julliard's avatar
Alexandre Julliard committed
2497 2498
    if (himl->hbmMask)
    {
2499 2500
        HDC hdcTemp;
        HBITMAP hOldBitmapTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
2501

2502 2503
        hdcTemp   = CreateCompatibleDC(0);
        hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2504

2505
        StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2506 2507 2508
                      hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
        SelectObject(hdcTemp, hOldBitmapTemp);
        DeleteDC(hdcTemp);
2509 2510 2511

        /* Remove the background from the image
        */
2512 2513
        BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
                himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
Alexandre Julliard's avatar
Alexandre Julliard committed
2514 2515
    }

2516
done:
2517
    DeleteDC (hdcImage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2518

Eric Kohl's avatar
Eric Kohl committed
2519
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2520 2521 2522
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2523
/*************************************************************************
2524
 * ImageList_ReplaceIcon [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2525 2526 2527 2528
 *
 * Replaces an image in an image list using an icon.
 *
 * PARAMS
2529
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2530
 *     i     [I] image index
2531
 *     hIcon [I] handle to icon
Alexandre Julliard's avatar
Alexandre Julliard committed
2532 2533 2534 2535 2536 2537
 *
 * RETURNS
 *     Success: index of the replaced image
 *     Failure: -1
 */

2538
INT WINAPI
2539
ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
2540
{
2541
    HICON   hBestFitIcon;
2542 2543
    ICONINFO  ii;
    BITMAP  bmp;
2544
    BOOL    ret;
2545
    POINT   pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
2546

2547
    TRACE("(%p %d %p)\n", himl, nIndex, hIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
2548

2549 2550 2551 2552
    if (!is_valid(himl)) {
        ERR("invalid image list\n");
        return -1;
    }
2553 2554
    if ((nIndex >= himl->cMaxImage) || (nIndex < -1)) {
        ERR("invalid image index %d / %d\n", nIndex, himl->cMaxImage);
2555 2556
        return -1;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2557

2558
    hBestFitIcon = CopyImage(
2559 2560
        hIcon, IMAGE_ICON,
        himl->cx, himl->cy,
2561
        LR_COPYFROMRESOURCE);
2562 2563 2564 2565 2566 2567 2568 2569 2570 2571
    /* the above will fail if the icon wasn't loaded from a resource, so try
     * again without LR_COPYFROMRESOURCE flag */
    if (!hBestFitIcon)
        hBestFitIcon = CopyImage(
            hIcon, IMAGE_ICON,
            himl->cx, himl->cy,
            0);
    if (!hBestFitIcon)
        return -1;

2572
    if (nIndex == -1) {
2573
        if (himl->cCurImage + 1 >= himl->cMaxImage)
2574
            IMAGELIST_InternalExpandBitmaps(himl, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
2575

Alexandre Julliard's avatar
Alexandre Julliard committed
2576
        nIndex = himl->cCurImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
2577
        himl->cCurImage++;
Alexandre Julliard's avatar
Alexandre Julliard committed
2578 2579
    }

2580
    if (himl->has_alpha && GetIconInfo (hBestFitIcon, &ii))
2581
    {
2582 2583 2584
        HDC hdcImage = CreateCompatibleDC( 0 );
        GetObjectW (ii.hbmMask, sizeof(BITMAP), &bmp);

2585 2586 2587 2588 2589 2590 2591 2592
        if (!ii.hbmColor)
        {
            UINT height = bmp.bmHeight / 2;
            HDC hdcMask = CreateCompatibleDC( 0 );
            HBITMAP color = CreateBitmap( bmp.bmWidth, height, 1, 1, NULL );
            SelectObject( hdcImage, color );
            SelectObject( hdcMask, ii.hbmMask );
            BitBlt( hdcImage, 0, 0, bmp.bmWidth, height, hdcMask, 0, height, SRCCOPY );
2593
            ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, height, color, ii.hbmMask );
2594 2595 2596
            DeleteDC( hdcMask );
            DeleteObject( color );
        }
2597 2598 2599 2600 2601 2602 2603
        else ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, bmp.bmHeight,
                                   ii.hbmColor, ii.hbmMask );

        DeleteDC( hdcImage );
        DeleteObject (ii.hbmMask);
        if (ii.hbmColor) DeleteObject (ii.hbmColor);
        if (ret) goto done;
2604 2605
    }

2606 2607
    imagelist_point_from_index(himl, nIndex, &pt);

2608
    if (himl->hbmMask)
2609
    {
2610 2611 2612
        DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_IMAGE );
        PatBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy, WHITENESS );
        DrawIconEx( himl->hdcMask, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_MASK );
2613 2614 2615
    }
    else
    {
2616 2617 2618 2619 2620 2621 2622 2623
        COLORREF color = himl->clrBk != CLR_NONE ? himl->clrBk : comctl32_color.clrWindow;
        HBRUSH brush = CreateSolidBrush( GetNearestColor( himl->hdcImage, color ));

        SelectObject( himl->hdcImage, brush );
        PatBlt( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy, PATCOPY );
        SelectObject( himl->hdcImage, GetStockObject(BLACK_BRUSH) );
        DeleteObject( brush );
        DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_NORMAL );
Alexandre Julliard's avatar
Alexandre Julliard committed
2624 2625
    }

2626
done:
2627
    DestroyIcon(hBestFitIcon);
Alexandre Julliard's avatar
Alexandre Julliard committed
2628

2629
    TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
Eric Kohl's avatar
Eric Kohl committed
2630
    return nIndex;
Alexandre Julliard's avatar
Alexandre Julliard committed
2631 2632 2633
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2634
/*************************************************************************
2635
 * ImageList_SetBkColor [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2636 2637 2638 2639
 *
 * Sets the background color of an image list.
 *
 * PARAMS
2640
 *     himl  [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2641 2642 2643 2644 2645 2646 2647 2648 2649
 *     clrBk [I] background color
 *
 * RETURNS
 *     Success: previous background color
 *     Failure: CLR_NONE
 */

COLORREF WINAPI
ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
Alexandre Julliard's avatar
Alexandre Julliard committed
2650 2651 2652
{
    COLORREF clrOldBk;

2653
    if (!is_valid(himl))
Eric Kohl's avatar
Eric Kohl committed
2654
	return CLR_NONE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2655

Alexandre Julliard's avatar
Alexandre Julliard committed
2656 2657
    clrOldBk = himl->clrBk;
    himl->clrBk = clrBk;
Eric Kohl's avatar
Eric Kohl committed
2658
    return clrOldBk;
Alexandre Julliard's avatar
Alexandre Julliard committed
2659 2660 2661
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2662
/*************************************************************************
2663
 * ImageList_SetDragCursorImage [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2664 2665 2666 2667
 *
 * Combines the specified image with the current drag image
 *
 * PARAMS
2668
 *     himlDrag  [I] handle to drag image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2669 2670 2671 2672 2673 2674 2675 2676
 *     iDrag     [I] drag image index
 *     dxHotspot [I] X position of the hot spot
 *     dyHotspot [I] Y position of the hot spot
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
2677
 * NOTES
2678 2679 2680 2681 2682
 *   - The names dxHotspot, dyHotspot are misleading because they have nothing
 *     to do with a hotspot but are only the offset of the origin of the new
 *     image relative to the origin of the old image.
 *
 *   - When this function is called and the drag image is visible, a
2683 2684
 *     short flickering occurs but this matches the Win9x behavior. It is
 *     possible to fix the flickering using code like in ImageList_DragMove.
Alexandre Julliard's avatar
Alexandre Julliard committed
2685 2686
 */

2687 2688 2689
BOOL WINAPI
ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
			      INT dxHotspot, INT dyHotspot)
Alexandre Julliard's avatar
Alexandre Julliard committed
2690
{
Alexandre Julliard's avatar
Alexandre Julliard committed
2691
    HIMAGELIST himlTemp;
2692
    BOOL visible;
Alexandre Julliard's avatar
Alexandre Julliard committed
2693

2694
    if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
Eric Kohl's avatar
Eric Kohl committed
2695
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2696

2697
    TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2698 2699 2700
	   dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);

    visible = InternalDrag.bShow;
Alexandre Julliard's avatar
Alexandre Julliard committed
2701

2702 2703
    himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
                                dxHotspot, dyHotspot);
Alexandre Julliard's avatar
Alexandre Julliard committed
2704

2705 2706 2707 2708 2709 2710 2711 2712 2713 2714
    if (visible) {
	/* hide the drag image */
	ImageList_DragShowNolock(FALSE);
    }
    if ((InternalDrag.himl->cx != himlTemp->cx) ||
	   (InternalDrag.himl->cy != himlTemp->cy)) {
	/* the size of the drag image changed, invalidate the buffer */
	DeleteObject(InternalDrag.hbmBg);
	InternalDrag.hbmBg = 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2715

2716 2717 2718 2719 2720 2721
    ImageList_Destroy (InternalDrag.himl);
    InternalDrag.himl = himlTemp;

    if (visible) {
	/* show the drag image */
	ImageList_DragShowNolock(TRUE);
2722
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2723

2724
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2725 2726 2727
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2728
/*************************************************************************
2729
 * ImageList_SetFilter [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2730 2731
 *
 * Sets a filter (or does something completely different)!!???
2732
 * It removes 12 Bytes from the stack (3 Parameters).
Alexandre Julliard's avatar
Alexandre Julliard committed
2733 2734
 *
 * PARAMS
2735 2736
 *     himl     [I] SHOULD be a handle to image list
 *     i        [I] COULD be an index?
Alexandre Julliard's avatar
Alexandre Julliard committed
2737 2738 2739
 *     dwFilter [I] ???
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
2740 2741
 *     Success: TRUE ???
 *     Failure: FALSE ???
Alexandre Julliard's avatar
Alexandre Julliard committed
2742 2743
 *
 * BUGS
Alexandre Julliard's avatar
Alexandre Julliard committed
2744
 *     This is an UNDOCUMENTED function!!!!
Alexandre Julliard's avatar
Alexandre Julliard committed
2745 2746 2747
 *     empty stub.
 */

2748 2749
BOOL WINAPI
ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
Alexandre Julliard's avatar
Alexandre Julliard committed
2750
{
2751
    FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
Alexandre Julliard's avatar
Alexandre Julliard committed
2752

Alexandre Julliard's avatar
Alexandre Julliard committed
2753
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2754 2755 2756
}


2757
/*************************************************************************
2758
 * ImageList_SetFlags [COMCTL32.@]
2759
 *
2760 2761 2762 2763 2764 2765 2766 2767 2768
 * Sets the image list flags.
 *
 * PARAMS
 *     himl  [I] Handle to image list
 *     flags [I] Flags to set
 *
 * RETURNS
 *     Old flags?
 *
2769 2770 2771 2772 2773 2774 2775
 * BUGS
 *    Stub.
 */

DWORD WINAPI
ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
{
2776
    FIXME("(%p %08x):empty stub\n", himl, flags);
2777 2778 2779 2780
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2781
/*************************************************************************
2782
 * ImageList_SetIconSize [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2783 2784 2785 2786
 *
 * Sets the image size of the bitmap and deletes all images.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
2787
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2788 2789 2790 2791 2792 2793 2794 2795
 *     cx   [I] image width
 *     cy   [I] image height
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2796 2797
BOOL WINAPI
ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
Alexandre Julliard's avatar
Alexandre Julliard committed
2798
{
2799
    INT nCount;
2800
    HBITMAP hbmNew;
Alexandre Julliard's avatar
Alexandre Julliard committed
2801

2802
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
2803
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2804

2805
    /* remove all images */
2806
    himl->cMaxImage = himl->cInitial + 1;
Eric Kohl's avatar
Eric Kohl committed
2807 2808 2809
    himl->cCurImage = 0;
    himl->cx        = cx;
    himl->cy        = cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
2810 2811 2812 2813 2814

    /* initialize overlay mask indices */
    for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
        himl->nOvlIdx[nCount] = -1;

2815
    hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2816 2817 2818
    SelectObject (himl->hdcImage, hbmNew);
    DeleteObject (himl->hbmImage);
    himl->hbmImage = hbmNew;
Alexandre Julliard's avatar
Alexandre Julliard committed
2819 2820

    if (himl->hbmMask) {
2821
        SIZE sz;
2822
        imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2823
        hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2824 2825 2826
        SelectObject (himl->hdcMask, hbmNew);
        DeleteObject (himl->hbmMask);
        himl->hbmMask = hbmNew;
Alexandre Julliard's avatar
Alexandre Julliard committed
2827 2828
    }

Eric Kohl's avatar
Eric Kohl committed
2829
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2830 2831 2832
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2833
/*************************************************************************
2834
 * ImageList_SetImageCount [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2835 2836 2837 2838
 *
 * Resizes an image list to the specified number of images.
 *
 * PARAMS
Alexandre Julliard's avatar
Alexandre Julliard committed
2839
 *     himl        [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2840 2841 2842 2843 2844 2845 2846
 *     iImageCount [I] number of images in the image list
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2847
BOOL WINAPI
2848
ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
Alexandre Julliard's avatar
Alexandre Julliard committed
2849
{
2850
    HDC     hdcBitmap;
2851
    HBITMAP hbmNewBitmap, hbmOld;
2852
    INT     nNewCount, nCopyCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
2853

2854 2855
    TRACE("%p %d\n",himl,iImageCount);

2856
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
2857
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2858

2859
    nNewCount = iImageCount + 1;
2860
    nCopyCount = min(himl->cCurImage, iImageCount);
Alexandre Julliard's avatar
Alexandre Julliard committed
2861

2862
    hdcBitmap = CreateCompatibleDC (0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2863

2864
    hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
2865

2866
    if (hbmNewBitmap != 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
2867
    {
2868
        hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2869
        imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
2870
        SelectObject (hdcBitmap, hbmOld);
2871 2872

	/* FIXME: delete 'empty' image space? */
Eric Kohl's avatar
Eric Kohl committed
2873

2874
        SelectObject (himl->hdcImage, hbmNewBitmap);
2875
	DeleteObject (himl->hbmImage);
2876
	himl->hbmImage = hbmNewBitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
2877 2878
    }
    else
2879
	ERR("Could not create new image bitmap !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2880 2881 2882

    if (himl->hbmMask)
    {
2883
        SIZE sz;
2884
        imagelist_get_bitmap_size( himl, nNewCount, &sz );
2885
        hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
2886 2887
        if (hbmNewBitmap != 0)
        {
2888
            hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2889
            imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
2890
            SelectObject (hdcBitmap, hbmOld);
2891 2892

	    /* FIXME: delete 'empty' image space? */
Eric Kohl's avatar
Eric Kohl committed
2893

2894
            SelectObject (himl->hdcMask, hbmNewBitmap);
2895
            DeleteObject (himl->hbmMask);
Alexandre Julliard's avatar
Alexandre Julliard committed
2896 2897 2898
            himl->hbmMask = hbmNewBitmap;
        }
        else
2899
            ERR("Could not create new mask bitmap!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2900 2901
    }

2902
    DeleteDC (hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
2903

2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914
    if (himl->has_alpha)
    {
        char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
        if (new_alpha) himl->has_alpha = new_alpha;
        else
        {
            HeapFree( GetProcessHeap(), 0, himl->has_alpha );
            himl->has_alpha = NULL;
        }
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2915 2916
    /* Update max image count and current image count */
    himl->cMaxImage = nNewCount;
2917
    himl->cCurImage = iImageCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
2918

Alexandre Julliard's avatar
Alexandre Julliard committed
2919
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2920 2921 2922
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2923
/*************************************************************************
2924
 * ImageList_SetOverlayImage [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
2925 2926 2927 2928
 *
 * Assigns an overlay mask index to an existing image in an image list.
 *
 * PARAMS
2929
 *     himl     [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
2930 2931 2932 2933 2934 2935 2936 2937
 *     iImage   [I] image index
 *     iOverlay [I] overlay mask index
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 */

2938 2939
BOOL WINAPI
ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
Alexandre Julliard's avatar
Alexandre Julliard committed
2940
{
2941
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
2942 2943 2944
	return FALSE;
    if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
	return FALSE;
2945
    if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
Alexandre Julliard's avatar
Alexandre Julliard committed
2946
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2947
    himl->nOvlIdx[iOverlay - 1] = iImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
2948
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2949 2950
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2951

2952

2953
/* helper for ImageList_Write - write bitmap to pstm
2954 2955
 * currently everything is written as 24 bit RGB, except masks
 */
2956
static BOOL
2957
_write_bitmap(HBITMAP hBitmap, LPSTREAM pstm)
2958 2959 2960
{
    LPBITMAPFILEHEADER bmfh;
    LPBITMAPINFOHEADER bmih;
2961
    LPBYTE data = NULL, lpBits;
2962 2963 2964 2965 2966
    BITMAP bm;
    INT bitCount, sizeImage, offBits, totalSize;
    HDC xdc;
    BOOL result = FALSE;

2967
    if (!GetObjectW(hBitmap, sizeof(BITMAP), &bm))
2968
        return FALSE;
2969

2970
    bitCount = bm.bmBitsPixel;
2971
    sizeImage = get_dib_stride(bm.bmWidth, bitCount) * bm.bmHeight;
2972 2973

    totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2974
    if(bitCount <= 8)
2975 2976
	totalSize += (1 << bitCount) * sizeof(RGBQUAD);
    offBits = totalSize;
2977
    totalSize += sizeImage;
2978

2979
    data = Alloc(totalSize);
2980 2981 2982 2983 2984 2985
    bmfh = (LPBITMAPFILEHEADER)data;
    bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
    lpBits = data + offBits;

    /* setup BITMAPFILEHEADER */
    bmfh->bfType      = (('M' << 8) | 'B');
2986
    bmfh->bfSize      = offBits;
2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997
    bmfh->bfReserved1 = 0;
    bmfh->bfReserved2 = 0;
    bmfh->bfOffBits   = offBits;

    /* setup BITMAPINFOHEADER */
    bmih->biSize          = sizeof(BITMAPINFOHEADER);
    bmih->biWidth         = bm.bmWidth;
    bmih->biHeight        = bm.bmHeight;
    bmih->biPlanes        = 1;
    bmih->biBitCount      = bitCount;
    bmih->biCompression   = BI_RGB;
2998
    bmih->biSizeImage     = sizeImage;
2999 3000 3001 3002 3003
    bmih->biXPelsPerMeter = 0;
    bmih->biYPelsPerMeter = 0;
    bmih->biClrUsed       = 0;
    bmih->biClrImportant  = 0;

3004 3005 3006 3007
    xdc = GetDC(0);
    result = GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBits, (BITMAPINFO *)bmih, DIB_RGB_COLORS) == bm.bmHeight;
    ReleaseDC(0, xdc);
    if (!result)
3008
	goto failed;
3009

3010 3011 3012
    TRACE("width %u, height %u, planes %u, bpp %u\n",
          bmih->biWidth, bmih->biHeight,
          bmih->biPlanes, bmih->biBitCount);
3013

3014
    if(FAILED(IStream_Write(pstm, data, totalSize, NULL)))
3015 3016 3017 3018
	goto failed;

    result = TRUE;

3019 3020
failed:
    Free(data);
3021 3022 3023 3024 3025

    return result;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3026
/*************************************************************************
3027
 * ImageList_Write [COMCTL32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
3028 3029 3030 3031
 *
 * Writes an image list to a stream.
 *
 * PARAMS
3032
 *     himl [I] handle to image list
Alexandre Julliard's avatar
Alexandre Julliard committed
3033 3034 3035 3036 3037 3038 3039
 *     pstm [O] Pointer to a stream.
 *
 * RETURNS
 *     Success: TRUE
 *     Failure: FALSE
 *
 * BUGS
3040
 *     probably.
Alexandre Julliard's avatar
Alexandre Julliard committed
3041 3042
 */

3043 3044
BOOL WINAPI
ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
Alexandre Julliard's avatar
Alexandre Julliard committed
3045
{
3046 3047 3048
    ILHEAD ilHead;
    int i;

3049 3050
    TRACE("%p %p\n", himl, pstm);

3051
    if (!is_valid(himl))
Alexandre Julliard's avatar
Alexandre Julliard committed
3052
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3053

3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066
    ilHead.usMagic   = (('L' << 8) | 'I');
    ilHead.usVersion = 0x101;
    ilHead.cCurImage = himl->cCurImage;
    ilHead.cMaxImage = himl->cMaxImage;
    ilHead.cGrow     = himl->cGrow;
    ilHead.cx        = himl->cx;
    ilHead.cy        = himl->cy;
    ilHead.bkcolor   = himl->clrBk;
    ilHead.flags     = himl->flags;
    for(i = 0; i < 4; i++) {
	ilHead.ovls[i] = himl->nOvlIdx[i];
    }

3067 3068 3069
    TRACE("cx %u, cy %u, flags 0x04%x, cCurImage %u, cMaxImage %u\n",
          ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);

3070
    if(FAILED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3071 3072 3073
	return FALSE;

    /* write the bitmap */
3074
    if(!_write_bitmap(himl->hbmImage, pstm))
3075 3076 3077 3078
	return FALSE;

    /* write the mask if we have one */
    if(himl->flags & ILC_MASK) {
3079
	if(!_write_bitmap(himl->hbmMask, pstm))
3080 3081
	    return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
3082

3083
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3084
}
3085 3086


3087
static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
3088 3089 3090
{
    HBITMAP hbmNewBitmap;
    UINT ilc = (himl->flags & 0xFE);
3091 3092
    SIZE sz;

3093
    imagelist_get_bitmap_size( himl, count, &sz );
3094 3095 3096

    if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
    {
3097
        char buffer[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
3098
        BITMAPINFO *bmi = (BITMAPINFO *)buffer;
3099

3100 3101
        TRACE("Creating DIBSection %d x %d, %d Bits per Pixel\n",
              sz.cx, sz.cy, himl->uBitsPixel);
3102

3103
        memset( buffer, 0, sizeof(buffer) );
3104
	bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3105 3106
	bmi->bmiHeader.biWidth = sz.cx;
	bmi->bmiHeader.biHeight = sz.cy;
3107 3108 3109 3110
	bmi->bmiHeader.biPlanes = 1;
	bmi->bmiHeader.biBitCount = himl->uBitsPixel;
	bmi->bmiHeader.biCompression = BI_RGB;

3111 3112 3113 3114 3115 3116 3117 3118
	if (himl->uBitsPixel <= ILC_COLOR8)
	{
            /* retrieve the default color map */
            HBITMAP tmp = CreateBitmap( 1, 1, 1, 1, NULL );
            GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
            DeleteObject( tmp );
	}
	hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, 0, 0);
3119 3120 3121 3122 3123
    }
    else /*if (ilc == ILC_COLORDDB)*/
    {
        TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);

3124
        hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
3125
    }
3126
    TRACE("returning %p\n", hbmNewBitmap);
3127 3128
    return hbmNewBitmap;
}
3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153

/*************************************************************************
 * ImageList_SetColorTable [COMCTL32.@]
 *
 * Sets the color table of an image list.
 *
 * PARAMS
 *     himl        [I] Handle to the image list.
 *     uStartIndex [I] The first index to set.
 *     cEntries    [I] Number of entries to set.
 *     prgb        [I] New color information for color table for the image list.
 *
 * RETURNS
 *     Success: Number of entries in the table that were set.
 *     Failure: Zero.
 *
 * SEE
 *     ImageList_Create(), SetDIBColorTable()
 */

UINT WINAPI
ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
{
    return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);
}
3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172

/*************************************************************************
 * ImageList_CoCreateInstance [COMCTL32.@]
 *
 * Creates a new imagelist instance and returns an interface pointer to it.
 *
 * PARAMS
 *     rclsid      [I] A reference to the CLSID (CLSID_ImageList).
 *     punkOuter   [I] Pointer to IUnknown interface for aggregation, if desired
 *     riid        [I] Identifier of the requested interface.
 *     ppv         [O] Returns the address of the pointer requested, or NULL.
 *
 * RETURNS
 *     Success: S_OK.
 *     Failure: Error value.
 */
HRESULT WINAPI
ImageList_CoCreateInstance (REFCLSID rclsid, const IUnknown *punkOuter, REFIID riid, void **ppv)
{
3173 3174 3175 3176 3177 3178
    TRACE("(%s,%p,%s,%p)\n", debugstr_guid(rclsid), punkOuter, debugstr_guid(riid), ppv);

    if (!IsEqualCLSID(&CLSID_ImageList, rclsid))
        return E_NOINTERFACE;

    return ImageListImpl_CreateInstance(punkOuter, riid, ppv);
3179 3180
}

3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222

/*************************************************************************
 * IImageList implementation
 */

static HRESULT WINAPI ImageListImpl_QueryInterface(IImageList *iface,
    REFIID iid, void **ppv)
{
    HIMAGELIST This = (HIMAGELIST) iface;
    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);

    if (!ppv) return E_INVALIDARG;

    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IImageList, iid))
        *ppv = This;
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }

    IUnknown_AddRef((IUnknown*)*ppv);
    return S_OK;
}

static ULONG WINAPI ImageListImpl_AddRef(IImageList *iface)
{
    HIMAGELIST This = (HIMAGELIST) iface;
    ULONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p) refcount=%u\n", iface, ref);
    return ref;
}

static ULONG WINAPI ImageListImpl_Release(IImageList *iface)
{
    HIMAGELIST This = (HIMAGELIST) iface;
    ULONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) refcount=%u\n", iface, ref);

    if (ref == 0)
3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236
    {
        /* delete image bitmaps */
        if (This->hbmImage) DeleteObject (This->hbmImage);
        if (This->hbmMask)  DeleteObject (This->hbmMask);

        /* delete image & mask DCs */
        if (This->hdcImage) DeleteDC (This->hdcImage);
        if (This->hdcMask)  DeleteDC (This->hdcMask);

        /* delete blending brushes */
        if (This->hbrBlend25) DeleteObject (This->hbrBlend25);
        if (This->hbrBlend50) DeleteObject (This->hbrBlend50);

        This->lpVtbl = NULL;
3237
        HeapFree(GetProcessHeap(), 0, This->has_alpha);
3238
        HeapFree(GetProcessHeap(), 0, This);
3239
    }
3240 3241 3242 3243 3244 3245 3246

    return ref;
}

static HRESULT WINAPI ImageListImpl_Add(IImageList *iface, HBITMAP hbmImage,
    HBITMAP hbmMask, int *pi)
{
3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259
    HIMAGELIST This = (HIMAGELIST) iface;
    int ret;

    if (!pi)
        return E_FAIL;

    ret = ImageList_Add(This, hbmImage, hbmMask);

    if (ret == -1)
        return E_FAIL;

    *pi = ret;
    return S_OK;
3260 3261 3262 3263 3264
}

static HRESULT WINAPI ImageListImpl_ReplaceIcon(IImageList *iface, int i,
    HICON hicon, int *pi)
{
3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277
    HIMAGELIST This = (HIMAGELIST) iface;
    int ret;

    if (!pi)
        return E_FAIL;

    ret = ImageList_ReplaceIcon(This, i, hicon);

    if (ret == -1)
        return E_FAIL;

    *pi = ret;
    return S_OK;
3278 3279 3280 3281 3282
}

static HRESULT WINAPI ImageListImpl_SetOverlayImage(IImageList *iface,
    int iImage, int iOverlay)
{
3283 3284
    return ImageList_SetOverlayImage((HIMAGELIST) iface, iImage, iOverlay)
        ? S_OK : E_FAIL;
3285 3286 3287 3288 3289
}

static HRESULT WINAPI ImageListImpl_Replace(IImageList *iface, int i,
    HBITMAP hbmImage, HBITMAP hbmMask)
{
3290 3291
    return ImageList_Replace((HIMAGELIST) iface, i, hbmImage, hbmMask) ? S_OK :
        E_FAIL;
3292 3293 3294 3295 3296
}

static HRESULT WINAPI ImageListImpl_AddMasked(IImageList *iface, HBITMAP hbmImage,
    COLORREF crMask, int *pi)
{
3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309
    HIMAGELIST This = (HIMAGELIST) iface;
    int ret;

    if (!pi)
        return E_FAIL;

    ret = ImageList_AddMasked(This, hbmImage, crMask);

    if (ret == -1)
        return E_FAIL;

    *pi = ret;
    return S_OK;
3310 3311 3312 3313 3314
}

static HRESULT WINAPI ImageListImpl_Draw(IImageList *iface,
    IMAGELISTDRAWPARAMS *pimldp)
{
3315
    HIMAGELIST This = (HIMAGELIST) iface;
3316 3317
    HIMAGELIST old_himl;
    int ret;
3318 3319 3320 3321 3322 3323 3324 3325 3326

    /* As far as I can tell, Windows simply ignores the contents of pimldp->himl
       so we shall simulate the same */
    old_himl = pimldp->himl;
    pimldp->himl = This;

    ret = ImageList_DrawIndirect(pimldp);

    pimldp->himl = old_himl;
3327
    return ret ? S_OK : E_INVALIDARG;
3328 3329 3330 3331
}

static HRESULT WINAPI ImageListImpl_Remove(IImageList *iface, int i)
{
3332
    return (ImageList_Remove((HIMAGELIST) iface, i) == 0) ? E_INVALIDARG : S_OK;
3333 3334 3335 3336 3337
}

static HRESULT WINAPI ImageListImpl_GetIcon(IImageList *iface, int i, UINT flags,
    HICON *picon)
{
3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349
    HICON hIcon;

    if (!picon)
        return E_FAIL;

    hIcon = ImageList_GetIcon((HIMAGELIST) iface, i, flags);

    if (hIcon == NULL)
        return E_FAIL;

    *picon = hIcon;
    return S_OK;
3350 3351 3352 3353 3354
}

static HRESULT WINAPI ImageListImpl_GetImageInfo(IImageList *iface, int i,
    IMAGEINFO *pImageInfo)
{
3355
    return ImageList_GetImageInfo((HIMAGELIST) iface, i, pImageInfo) ? S_OK : E_FAIL;
3356 3357 3358 3359 3360
}

static HRESULT WINAPI ImageListImpl_Copy(IImageList *iface, int iDst,
    IUnknown *punkSrc, int iSrc, UINT uFlags)
{
3361 3362 3363 3364 3365 3366 3367 3368
    HIMAGELIST This = (HIMAGELIST) iface;
    IImageList *src = NULL;
    HRESULT ret;

    if (!punkSrc)
        return E_FAIL;

    /* TODO: Add test for IID_ImageList2 too */
3369
    if (FAILED(IUnknown_QueryInterface(punkSrc, &IID_IImageList,
3370 3371 3372 3373 3374 3375 3376 3377 3378 3379
            (void **) &src)))
        return E_FAIL;

    if (ImageList_Copy(This, iDst, (HIMAGELIST) src, iSrc, uFlags))
        ret = S_OK;
    else
        ret = E_FAIL;

    IImageList_Release(src);
    return ret;
3380 3381 3382
}

static HRESULT WINAPI ImageListImpl_Merge(IImageList *iface, int i1,
3383
    IUnknown *punk2, int i2, int dx, int dy, REFIID riid, void **ppv)
3384
{
3385 3386 3387 3388 3389
    HIMAGELIST This = (HIMAGELIST) iface;
    IImageList *iml2 = NULL;
    HIMAGELIST hNew;
    HRESULT ret = E_FAIL;

3390
    TRACE("(%p)->(%d %p %d %d %d %s %p)\n", iface, i1, punk2, i2, dx, dy, debugstr_guid(riid), ppv);
3391 3392

    /* TODO: Add test for IID_ImageList2 too */
3393
    if (FAILED(IUnknown_QueryInterface(punk2, &IID_IImageList,
3394 3395 3396 3397 3398 3399 3400
            (void **) &iml2)))
        return E_FAIL;

    hNew = ImageList_Merge(This, i1, (HIMAGELIST) iml2, i2, dx, dy);

    /* Get the interface for the new image list */
    if (hNew)
3401 3402 3403
    {
        IImageList *imerge = (IImageList*)hNew;

3404
        ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
3405 3406
        IImageList_Release(imerge);
    }
3407 3408 3409

    IImageList_Release(iml2);
    return ret;
3410 3411
}

3412
static HRESULT WINAPI ImageListImpl_Clone(IImageList *iface, REFIID riid, void **ppv)
3413
{
3414
    HIMAGELIST This = (HIMAGELIST) iface;
3415
    HIMAGELIST clone;
3416 3417
    HRESULT ret = E_FAIL;

3418
    TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
3419

3420
    clone = ImageList_Duplicate(This);
3421 3422

    /* Get the interface for the new image list */
3423 3424 3425 3426 3427 3428 3429
    if (clone)
    {
        IImageList *iclone = (IImageList*)clone;

        ret = HIMAGELIST_QueryInterface(clone, riid, ppv);
        IImageList_Release(iclone);
    }
3430 3431

    return ret;
3432 3433 3434 3435 3436
}

static HRESULT WINAPI ImageListImpl_GetImageRect(IImageList *iface, int i,
    RECT *prc)
{
3437 3438 3439 3440 3441 3442 3443 3444 3445 3446
    HIMAGELIST This = (HIMAGELIST) iface;
    IMAGEINFO info;

    if (!prc)
        return E_FAIL;

    if (!ImageList_GetImageInfo(This, i, &info))
        return E_FAIL;

    return CopyRect(prc, &info.rcImage) ? S_OK : E_FAIL;
3447 3448 3449 3450 3451
}

static HRESULT WINAPI ImageListImpl_GetIconSize(IImageList *iface, int *cx,
    int *cy)
{
3452 3453
    HIMAGELIST This = (HIMAGELIST) iface;

3454
    return ImageList_GetIconSize(This, cx, cy) ? S_OK : E_INVALIDARG;
3455 3456 3457 3458 3459
}

static HRESULT WINAPI ImageListImpl_SetIconSize(IImageList *iface, int cx,
    int cy)
{
3460
    return ImageList_SetIconSize((HIMAGELIST) iface, cx, cy) ? S_OK : E_FAIL;
3461 3462 3463 3464
}

static HRESULT WINAPI ImageListImpl_GetImageCount(IImageList *iface, int *pi)
{
3465 3466
    *pi = ImageList_GetImageCount((HIMAGELIST) iface);
    return S_OK;
3467 3468 3469 3470 3471
}

static HRESULT WINAPI ImageListImpl_SetImageCount(IImageList *iface,
    UINT uNewCount)
{
3472
    return ImageList_SetImageCount((HIMAGELIST) iface, uNewCount) ? S_OK : E_FAIL;
3473 3474 3475 3476 3477
}

static HRESULT WINAPI ImageListImpl_SetBkColor(IImageList *iface, COLORREF clrBk,
    COLORREF *pclr)
{
3478
    *pclr = ImageList_SetBkColor((HIMAGELIST) iface, clrBk);
3479
    return S_OK;
3480 3481 3482 3483
}

static HRESULT WINAPI ImageListImpl_GetBkColor(IImageList *iface, COLORREF *pclr)
{
3484 3485
    *pclr = ImageList_GetBkColor((HIMAGELIST) iface);
    return S_OK;
3486 3487 3488 3489 3490
}

static HRESULT WINAPI ImageListImpl_BeginDrag(IImageList *iface, int iTrack,
    int dxHotspot, int dyHotspot)
{
3491
    return ImageList_BeginDrag((HIMAGELIST) iface, iTrack, dxHotspot, dyHotspot) ? S_OK : E_FAIL;
3492 3493 3494 3495
}

static HRESULT WINAPI ImageListImpl_EndDrag(IImageList *iface)
{
3496 3497
    ImageList_EndDrag();
    return S_OK;
3498 3499 3500 3501 3502
}

static HRESULT WINAPI ImageListImpl_DragEnter(IImageList *iface, HWND hwndLock,
    int x, int y)
{
3503
    return ImageList_DragEnter(hwndLock, x, y) ? S_OK : E_FAIL;
3504 3505 3506 3507
}

static HRESULT WINAPI ImageListImpl_DragLeave(IImageList *iface, HWND hwndLock)
{
3508
    return ImageList_DragLeave(hwndLock) ? S_OK : E_FAIL;
3509 3510 3511 3512
}

static HRESULT WINAPI ImageListImpl_DragMove(IImageList *iface, int x, int y)
{
3513
    return ImageList_DragMove(x, y) ? S_OK : E_FAIL;
3514 3515 3516 3517 3518
}

static HRESULT WINAPI ImageListImpl_SetDragCursorImage(IImageList *iface,
    IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot)
{
3519 3520 3521 3522 3523 3524 3525
    IImageList *iml2 = NULL;
    HRESULT ret;

    if (!punk)
        return E_FAIL;

    /* TODO: Add test for IID_ImageList2 too */
3526
    if (FAILED(IUnknown_QueryInterface(punk, &IID_IImageList,
3527 3528 3529 3530 3531 3532 3533 3534 3535
            (void **) &iml2)))
        return E_FAIL;

    ret = ImageList_SetDragCursorImage((HIMAGELIST) iml2, iDrag, dxHotspot,
        dyHotspot);

    IImageList_Release(iml2);

    return ret ? S_OK : E_FAIL;
3536 3537 3538 3539
}

static HRESULT WINAPI ImageListImpl_DragShowNolock(IImageList *iface, BOOL fShow)
{
3540
    return ImageList_DragShowNolock(fShow) ? S_OK : E_FAIL;
3541 3542 3543 3544 3545
}

static HRESULT WINAPI ImageListImpl_GetDragImage(IImageList *iface, POINT *ppt,
    POINT *pptHotspot, REFIID riid, PVOID *ppv)
{
3546 3547 3548 3549 3550 3551 3552 3553 3554 3555
    HRESULT ret = E_FAIL;
    HIMAGELIST hNew;

    if (!ppv)
        return E_FAIL;

    hNew = ImageList_GetDragImage(ppt, pptHotspot);

    /* Get the interface for the new image list */
    if (hNew)
3556 3557 3558
    {
        IImageList *idrag = (IImageList*)hNew;

3559
        ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
3560 3561
        IImageList_Release(idrag);
    }
3562 3563

    return ret;
3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575
}

static HRESULT WINAPI ImageListImpl_GetItemFlags(IImageList *iface, int i,
    DWORD *dwFlags)
{
    FIXME("STUB: %p %d %p\n", iface, i, dwFlags);
    return E_NOTIMPL;
}

static HRESULT WINAPI ImageListImpl_GetOverlayImage(IImageList *iface, int iOverlay,
    int *piIndex)
{
3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591
    HIMAGELIST This = (HIMAGELIST) iface;
    int i;

    if ((iOverlay < 0) || (iOverlay > This->cCurImage))
        return E_FAIL;

    for (i = 0; i < MAX_OVERLAYIMAGE; i++)
    {
        if (This->nOvlIdx[i] == iOverlay)
        {
            *piIndex = i + 1;
            return S_OK;
        }
    }

    return E_FAIL;
3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629
}


static const IImageListVtbl ImageListImpl_Vtbl = {
    ImageListImpl_QueryInterface,
    ImageListImpl_AddRef,
    ImageListImpl_Release,
    ImageListImpl_Add,
    ImageListImpl_ReplaceIcon,
    ImageListImpl_SetOverlayImage,
    ImageListImpl_Replace,
    ImageListImpl_AddMasked,
    ImageListImpl_Draw,
    ImageListImpl_Remove,
    ImageListImpl_GetIcon,
    ImageListImpl_GetImageInfo,
    ImageListImpl_Copy,
    ImageListImpl_Merge,
    ImageListImpl_Clone,
    ImageListImpl_GetImageRect,
    ImageListImpl_GetIconSize,
    ImageListImpl_SetIconSize,
    ImageListImpl_GetImageCount,
    ImageListImpl_SetImageCount,
    ImageListImpl_SetBkColor,
    ImageListImpl_GetBkColor,
    ImageListImpl_BeginDrag,
    ImageListImpl_EndDrag,
    ImageListImpl_DragEnter,
    ImageListImpl_DragLeave,
    ImageListImpl_DragMove,
    ImageListImpl_SetDragCursorImage,
    ImageListImpl_DragShowNolock,
    ImageListImpl_GetDragImage,
    ImageListImpl_GetItemFlags,
    ImageListImpl_GetOverlayImage
};

3630
static BOOL is_valid(HIMAGELIST himl)
3631
{
3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642
    BOOL valid;
    __TRY
    {
        valid = himl && himl->lpVtbl == &ImageListImpl_Vtbl;
    }
    __EXCEPT_PAGE_FAULT
    {
        valid = FALSE;
    }
    __ENDTRY
    return valid;
3643 3644
}

3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662
/*************************************************************************
 * HIMAGELIST_QueryInterface [COMCTL32.@]
 *
 * Returns a pointer to an IImageList or IImageList2 object for the given
 * HIMAGELIST.
 *
 * PARAMS
 *     himl        [I] Image list handle.
 *     riid        [I] Identifier of the requested interface.
 *     ppv         [O] Returns the address of the pointer requested, or NULL.
 *
 * RETURNS
 *     Success: S_OK.
 *     Failure: Error value.
 */
HRESULT WINAPI
HIMAGELIST_QueryInterface (HIMAGELIST himl, REFIID riid, void **ppv)
{
3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677
    TRACE("(%p,%s,%p)\n", himl, debugstr_guid(riid), ppv);
    return IImageList_QueryInterface((IImageList *) himl, riid, ppv);
}

static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv)
{
    HIMAGELIST This;
    HRESULT ret;

    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);

    *ppv = NULL;

    if (pUnkOuter) return CLASS_E_NOAGGREGATION;

3678
    This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct _IMAGELIST));
3679 3680 3681 3682 3683 3684 3685 3686 3687
    if (!This) return E_OUTOFMEMORY;

    This->lpVtbl = &ImageListImpl_Vtbl;
    This->ref = 1;

    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
    IUnknown_Release((IUnknown*)This);

    return ret;
3688
}