d3dx9: Use a loop in get_vector().
[wine] / dlls / comctl32 / imagelist.c
1 /*
2  *  ImageList implementation
3  *
4  *  Copyright 1998 Eric Kohl
5  *  Copyright 2000 Jason Mawdsley
6  *  Copyright 2001, 2004 Michael Stefaniuc
7  *  Copyright 2001 Charles Loep for CodeWeavers
8  *  Copyright 2002 Dimitrie O. Paun
9  *  Copyright 2009 Owen Rudge for CodeWeavers
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * 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  * This code was audited for completeness against the documented features
28  * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29  *
30  * Unless otherwise noted, we believe this code to be complete, as per
31  * the specification mentioned above.
32  * If you discover missing features, or bugs, please note them below.
33  *
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
38  */
39
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #define COBJMACROS
45
46 #include "winerror.h"
47 #include "windef.h"
48 #include "winbase.h"
49 #include "objbase.h"
50 #include "wingdi.h"
51 #include "winuser.h"
52 #include "commctrl.h"
53 #include "comctl32.h"
54 #include "commoncontrols.h"
55 #include "wine/debug.h"
56 #include "wine/exception.h"
57
58 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
59
60 #define MAX_OVERLAYIMAGE 15
61
62 struct _IMAGELIST
63 {
64     const struct IImageListVtbl *lpVtbl; /* 00: IImageList vtable */
65
66     INT         cCurImage;                 /* 04: ImageCount */
67     INT         cMaxImage;                 /* 08: maximages */
68     INT         cGrow;                     /* 0C: cGrow */
69     INT         cx;                        /* 10: cx */
70     INT         cy;                        /* 14: cy */
71     DWORD       x4;
72     UINT        flags;                     /* 1C: flags */
73     COLORREF    clrFg;                     /* 20: foreground color */
74     COLORREF    clrBk;                     /* 24: background color */
75
76
77     HBITMAP     hbmImage;                  /* 28: images Bitmap */
78     HBITMAP     hbmMask;                   /* 2C: masks  Bitmap */
79     HDC         hdcImage;                  /* 30: images MemDC  */
80     HDC         hdcMask;                   /* 34: masks  MemDC  */
81     INT         nOvlIdx[MAX_OVERLAYIMAGE]; /* 38: overlay images index */
82
83     /* not yet found out */
84     HBRUSH  hbrBlend25;
85     HBRUSH  hbrBlend50;
86     INT     cInitial;
87     UINT    uBitsPixel;
88     char   *has_alpha;
89
90     LONG        ref;                       /* reference count */
91 };
92
93 #define IMAGELIST_MAGIC 0x53414D58
94
95 /* Header used by ImageList_Read() and ImageList_Write() */
96 #include "pshpack2.h"
97 typedef struct _ILHEAD
98 {
99     USHORT      usMagic;
100     USHORT      usVersion;
101     WORD        cCurImage;
102     WORD        cMaxImage;
103     WORD        cGrow;
104     WORD        cx;
105     WORD        cy;
106     COLORREF    bkcolor;
107     WORD        flags;
108     SHORT       ovls[4];
109 } ILHEAD;
110 #include "poppack.h"
111
112 /* internal image list data used for Drag & Drop operations */
113 typedef struct
114 {
115     HWND        hwnd;
116     HIMAGELIST  himl;
117     /* position of the drag image relative to the window */
118     INT         x;
119     INT         y;
120     /* offset of the hotspot relative to the origin of the image */
121     INT         dxHotspot;
122     INT         dyHotspot;
123     /* is the drag image visible */
124     BOOL        bShow;
125     /* saved background */
126     HBITMAP     hbmBg;
127 } INTERNALDRAG;
128
129 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
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  * An imagelist with N images is tiled like this:
137  *
138  *   N/4 ->
139  *
140  * 4 048C..
141  *   159D..
142  * | 26AE.N
143  * V 37BF.
144  */
145
146 #define TILE_COUNT 4
147
148 static inline UINT imagelist_height( UINT count )
149 {
150     return ((count + TILE_COUNT - 1)/TILE_COUNT);
151 }
152
153 static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
154 {
155     pt->x = (index%TILE_COUNT) * himl->cx;
156     pt->y = (index/TILE_COUNT) * himl->cy;
157 }
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 static inline int get_dib_stride( int width, int bpp )
166 {
167     return ((width * bpp + 31) >> 3) & ~3;
168 }
169
170 static inline int get_dib_image_size( const BITMAPINFO *info )
171 {
172     return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
173         * abs( info->bmiHeader.biHeight );
174 }
175
176 /*
177  * imagelist_copy_images()
178  *
179  * Copies a block of count images from offset src in the list to offset dest.
180  * Images are copied a row at at time. Assumes hdcSrc and hdcDest are different.
181  */
182 static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDest,
183                                           UINT src, UINT count, UINT dest )
184 {
185     POINT ptSrc, ptDest;
186     SIZE sz;
187     UINT i;
188
189     for ( i=0; i<TILE_COUNT; i++ )
190     {
191         imagelist_point_from_index( himl, src+i, &ptSrc );
192         imagelist_point_from_index( himl, dest+i, &ptDest );
193         sz.cx = himl->cx;
194         sz.cy = himl->cy * imagelist_height( count - i );
195
196         BitBlt( hdcDest, ptDest.x, ptDest.y, sz.cx, sz.cy,
197                 hdcSrc, ptSrc.x, ptSrc.y, SRCCOPY );
198     }
199 }
200
201 static void add_dib_bits( HIMAGELIST himl, int pos, int count, int width, int height,
202                           BITMAPINFO *info, BITMAPINFO *mask_info, DWORD *bits, BYTE *mask_bits )
203 {
204     int i, j, n;
205     POINT pt;
206     int stride = info->bmiHeader.biWidth;
207     int mask_stride = (info->bmiHeader.biWidth + 31) / 32 * 4;
208
209     for (n = 0; n < count; n++)
210     {
211         int has_alpha = 0;
212
213         imagelist_point_from_index( himl, pos + n, &pt );
214
215         /* check if bitmap has an alpha channel */
216         for (i = 0; i < height && !has_alpha; i++)
217             for (j = n * width; j < (n + 1) * width; j++)
218                 if ((has_alpha = ((bits[i * stride + j] & 0xff000000) != 0))) break;
219
220         if (!has_alpha)  /* generate alpha channel from the mask */
221         {
222             for (i = 0; i < height; i++)
223                 for (j = n * width; j < (n + 1) * width; j++)
224                     if (!mask_info || !((mask_bits[i * mask_stride + j / 8] << (j % 8)) & 0x80))
225                         bits[i * stride + j] |= 0xff000000;
226                     else
227                         bits[i * stride + j] = 0;
228         }
229         else
230         {
231             himl->has_alpha[pos + n] = 1;
232
233             if (mask_info && himl->hbmMask)  /* generate the mask from the alpha channel */
234             {
235                 for (i = 0; i < height; i++)
236                     for (j = n * width; j < (n + 1) * width; j++)
237                         if ((bits[i * stride + j] >> 24) > 25) /* more than 10% alpha */
238                             mask_bits[i * mask_stride + j / 8] &= ~(0x80 >> (j % 8));
239                         else
240                             mask_bits[i * mask_stride + j / 8] |= 0x80 >> (j % 8);
241             }
242         }
243         StretchDIBits( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
244                        n * width, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
245         if (mask_info)
246             StretchDIBits( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
247                            n * width, 0, width, height, mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY );
248     }
249 }
250
251 /* add images with an alpha channel when the image list is 32 bpp */
252 static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
253                             int width, int height, HBITMAP hbmImage, HBITMAP hbmMask )
254 {
255     BOOL ret = FALSE;
256     BITMAP bm;
257     BITMAPINFO *info, *mask_info = NULL;
258     DWORD *bits = NULL;
259     BYTE *mask_bits = NULL;
260     DWORD mask_width;
261
262     if (!GetObjectW( hbmImage, sizeof(bm), &bm )) return FALSE;
263
264     /* if either the imagelist or the source bitmap don't have an alpha channel, bail out now */
265     if (!himl->has_alpha) return FALSE;
266     if (bm.bmBitsPixel != 32) return FALSE;
267
268     SelectObject( hdc, hbmImage );
269     mask_width = (bm.bmWidth + 31) / 32 * 4;
270
271     if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
272     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
273     info->bmiHeader.biWidth = bm.bmWidth;
274     info->bmiHeader.biHeight = -height;
275     info->bmiHeader.biPlanes = 1;
276     info->bmiHeader.biBitCount = 32;
277     info->bmiHeader.biCompression = BI_RGB;
278     info->bmiHeader.biSizeImage = bm.bmWidth * height * 4;
279     info->bmiHeader.biXPelsPerMeter = 0;
280     info->bmiHeader.biYPelsPerMeter = 0;
281     info->bmiHeader.biClrUsed = 0;
282     info->bmiHeader.biClrImportant = 0;
283     if (!(bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
284     if (!GetDIBits( hdc, hbmImage, 0, height, bits, info, DIB_RGB_COLORS )) goto done;
285
286     if (hbmMask)
287     {
288         if (!(mask_info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))
289             goto done;
290         mask_info->bmiHeader = info->bmiHeader;
291         mask_info->bmiHeader.biBitCount = 1;
292         mask_info->bmiHeader.biSizeImage = mask_width * height;
293         if (!(mask_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
294             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     ret = TRUE;
300
301 done:
302     HeapFree( GetProcessHeap(), 0, info );
303     HeapFree( GetProcessHeap(), 0, mask_info );
304     HeapFree( GetProcessHeap(), 0, bits );
305     HeapFree( GetProcessHeap(), 0, mask_bits );
306     return ret;
307 }
308
309 /*************************************************************************
310  * IMAGELIST_InternalExpandBitmaps [Internal]
311  *
312  * Expands the bitmaps of an image list by the given number of images.
313  *
314  * PARAMS
315  *     himl        [I] handle to image list
316  *     nImageCount [I] number of images to add
317  *
318  * RETURNS
319  *     nothing
320  *
321  * NOTES
322  *     This function CANNOT be used to reduce the number of images.
323  */
324 static void
325 IMAGELIST_InternalExpandBitmaps(HIMAGELIST himl, INT nImageCount)
326 {
327     HDC     hdcBitmap;
328     HBITMAP hbmNewBitmap, hbmNull;
329     INT     nNewCount;
330     SIZE    sz;
331
332     TRACE("%p has allocated %d, max %d, grow %d images\n", himl, himl->cCurImage, himl->cMaxImage, himl->cGrow);
333
334     if (himl->cCurImage + nImageCount < himl->cMaxImage)
335         return;
336
337     nNewCount = himl->cMaxImage + max(nImageCount, himl->cGrow) + 1;
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);
343
344     hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
345
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                 himl->hdcImage, 0, 0, SRCCOPY);
354         SelectObject (hdcBitmap, hbmNull);
355     }
356     SelectObject (himl->hdcImage, hbmNewBitmap);
357     DeleteObject (himl->hbmImage);
358     himl->hbmImage = hbmNewBitmap;
359
360     if (himl->flags & ILC_MASK)
361     {
362         hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
363
364         if (hbmNewBitmap == 0)
365             ERR("creating new mask bitmap!\n");
366
367         if(himl->cCurImage)
368         {
369             hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
370             BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
371                     himl->hdcMask, 0, 0, SRCCOPY);
372             SelectObject (hdcBitmap, hbmNull);
373         }
374         SelectObject (himl->hdcMask, hbmNewBitmap);
375         DeleteObject (himl->hbmMask);
376         himl->hbmMask = hbmNewBitmap;
377     }
378
379     if (himl->has_alpha)
380     {
381         char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
382         if (new_alpha) himl->has_alpha = new_alpha;
383         else
384         {
385             HeapFree( GetProcessHeap(), 0, himl->has_alpha );
386             himl->has_alpha = NULL;
387         }
388     }
389
390     himl->cMaxImage = nNewCount;
391
392     DeleteDC (hdcBitmap);
393 }
394
395
396 /*************************************************************************
397  * ImageList_Add [COMCTL32.@]
398  *
399  * Add an image or images to an image list.
400  *
401  * PARAMS
402  *     himl     [I] handle to image list
403  *     hbmImage [I] handle to image bitmap
404  *     hbmMask  [I] handle to mask bitmap
405  *
406  * RETURNS
407  *     Success: Index of the first new image.
408  *     Failure: -1
409  */
410
411 INT WINAPI
412 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
413 {
414     HDC     hdcBitmap, hdcTemp = 0;
415     INT     nFirstIndex, nImageCount, i;
416     BITMAP  bmp;
417     POINT   pt;
418
419     TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
420     if (!is_valid(himl))
421         return -1;
422
423     if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
424         return -1;
425
426     TRACE("himl %p, cCurImage %d, cMaxImage %d, cGrow %d, cx %d, cy %d\n",
427           himl, himl->cCurImage, himl->cMaxImage, himl->cGrow, himl->cx, himl->cy);
428
429     nImageCount = bmp.bmWidth / himl->cx;
430
431     TRACE("%p has %d images (%d x %d)\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight);
432
433     IMAGELIST_InternalExpandBitmaps(himl, nImageCount);
434
435     hdcBitmap = CreateCompatibleDC(0);
436
437     SelectObject(hdcBitmap, hbmImage);
438
439     if (add_with_alpha( himl, hdcBitmap, himl->cCurImage, nImageCount,
440                         himl->cx, min( himl->cy, bmp.bmHeight), hbmImage, hbmMask ))
441         goto done;
442
443     if (himl->hbmMask)
444     {
445         hdcTemp = CreateCompatibleDC(0);
446         SelectObject(hdcTemp, hbmMask);
447     }
448
449     for (i=0; i<nImageCount; i++)
450     {
451         imagelist_point_from_index( himl, himl->cCurImage + i, &pt );
452
453         /* Copy result to the imagelist
454         */
455         BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
456                 hdcBitmap, i*himl->cx, 0, SRCCOPY );
457
458         if (!himl->hbmMask)
459              continue;
460
461         BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
462                 hdcTemp, i*himl->cx, 0, SRCCOPY );
463
464         /* Remove the background from the image
465         */
466         BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
467                 himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
468     }
469     if (hdcTemp) DeleteDC(hdcTemp);
470
471 done:
472     DeleteDC(hdcBitmap);
473
474     nFirstIndex = himl->cCurImage;
475     himl->cCurImage += nImageCount;
476
477     return nFirstIndex;
478 }
479
480
481 /*************************************************************************
482  * ImageList_AddIcon [COMCTL32.@]
483  *
484  * Adds an icon to an image list.
485  *
486  * PARAMS
487  *     himl  [I] handle to image list
488  *     hIcon [I] handle to icon
489  *
490  * RETURNS
491  *     Success: index of the new image
492  *     Failure: -1
493  */
494 #undef ImageList_AddIcon
495 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
496 {
497     return ImageList_ReplaceIcon (himl, -1, hIcon);
498 }
499
500
501 /*************************************************************************
502  * ImageList_AddMasked [COMCTL32.@]
503  *
504  * Adds an image or images to an image list and creates a mask from the
505  * specified bitmap using the mask color.
506  *
507  * PARAMS
508  *     himl    [I] handle to image list.
509  *     hBitmap [I] handle to bitmap
510  *     clrMask [I] mask color.
511  *
512  * RETURNS
513  *     Success: Index of the first new image.
514  *     Failure: -1
515  */
516
517 INT WINAPI
518 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
519 {
520     HDC    hdcMask, hdcBitmap;
521     INT    ret;
522     BITMAP bmp;
523     HBITMAP hMaskBitmap;
524     COLORREF bkColor;
525
526     TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
527     if (!is_valid(himl))
528         return -1;
529
530     if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
531         return -1;
532
533     hdcBitmap = CreateCompatibleDC(0);
534     SelectObject(hdcBitmap, hBitmap);
535
536     /* Create a temp Mask so we can remove the background of the Image */
537     hdcMask = CreateCompatibleDC(0);
538     hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
539     SelectObject(hdcMask, hMaskBitmap);
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      * Remove the background from the image
548      *
549      * WINDOWS BUG ALERT!!!!!!
550      *  The statement below should not be done in common practice
551      *  but this is how ImageList_AddMasked works in Windows.
552      *  It overwrites the original bitmap passed, this was discovered
553      *  by using the same bitmap to iterate the different styles
554      *  on windows where it failed (BUT ImageList_Add is OK)
555      *  This is here in case some apps rely on this bug
556      *
557      *  Blt mode 0x220326 is NOTSRCAND
558      */
559     if (bmp.bmBitsPixel > 8)  /* NOTSRCAND can't work with palettes */
560     {
561         SetBkColor(hdcBitmap, RGB(255,255,255));
562         BitBlt(hdcBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMask, 0, 0, 0x220326);
563     }
564
565     DeleteDC(hdcBitmap);
566     DeleteDC(hdcMask);
567
568     ret = ImageList_Add( himl, hBitmap, hMaskBitmap );
569
570     DeleteObject(hMaskBitmap);
571     return ret;
572 }
573
574
575 /*************************************************************************
576  * ImageList_BeginDrag [COMCTL32.@]
577  *
578  * Creates a temporary image list that contains one image. It will be used
579  * as a drag image.
580  *
581  * PARAMS
582  *     himlTrack [I] handle to the source image list
583  *     iTrack    [I] index of the drag image in the source image list
584  *     dxHotspot [I] X position of the hot spot of the drag image
585  *     dyHotspot [I] Y position of the hot spot of the drag image
586  *
587  * RETURNS
588  *     Success: TRUE
589  *     Failure: FALSE
590  */
591
592 BOOL WINAPI
593 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
594                      INT dxHotspot, INT dyHotspot)
595 {
596     INT cx, cy;
597
598     TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
599           dxHotspot, dyHotspot);
600
601     if (!is_valid(himlTrack))
602         return FALSE;
603
604     if (InternalDrag.himl)
605         ImageList_EndDrag ();
606
607     cx = himlTrack->cx;
608     cy = himlTrack->cy;
609
610     InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
611     if (InternalDrag.himl == NULL) {
612         WARN("Error creating drag image list!\n");
613         return FALSE;
614     }
615
616     InternalDrag.dxHotspot = dxHotspot;
617     InternalDrag.dyHotspot = dyHotspot;
618
619     /* copy image */
620     BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
621
622     /* copy mask */
623     BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
624
625     InternalDrag.himl->cCurImage = 1;
626
627     return TRUE;
628 }
629
630
631 /*************************************************************************
632  * ImageList_Copy [COMCTL32.@]
633  *
634  *  Copies an image of the source image list to an image of the
635  *  destination image list. Images can be copied or swapped.
636  *
637  * PARAMS
638  *     himlDst [I] handle to the destination image list
639  *     iDst    [I] destination image index.
640  *     himlSrc [I] handle to the source image list
641  *     iSrc    [I] source image index
642  *     uFlags  [I] flags for the copy operation
643  *
644  * RETURNS
645  *     Success: TRUE
646  *     Failure: FALSE
647  *
648  * NOTES
649  *     Copying from one image list to another is possible. The original
650  *     implementation just copies or swaps within one image list.
651  *     Could this feature become a bug??? ;-)
652  */
653
654 BOOL WINAPI
655 ImageList_Copy (HIMAGELIST himlDst, INT iDst,   HIMAGELIST himlSrc,
656                 INT iSrc, UINT uFlags)
657 {
658     POINT ptSrc, ptDst;
659
660     TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
661
662     if (!is_valid(himlSrc) || !is_valid(himlDst))
663         return FALSE;
664     if ((iDst < 0) || (iDst >= himlDst->cCurImage))
665         return FALSE;
666     if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
667         return FALSE;
668
669     imagelist_point_from_index( himlDst, iDst, &ptDst );
670     imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
671
672     if (uFlags & ILCF_SWAP) {
673         /* swap */
674         HDC     hdcBmp;
675         HBITMAP hbmTempImage, hbmTempMask;
676
677         hdcBmp = CreateCompatibleDC (0);
678
679         /* create temporary bitmaps */
680         hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
681                                        himlSrc->uBitsPixel, NULL);
682         hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
683                                       1, NULL);
684
685         /* copy (and stretch) destination to temporary bitmaps.(save) */
686         /* image */
687         SelectObject (hdcBmp, hbmTempImage);
688         StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
689                       himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
690                       SRCCOPY);
691         /* mask */
692         SelectObject (hdcBmp, hbmTempMask);
693         StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
694                       himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
695                       SRCCOPY);
696
697         /* copy (and stretch) source to destination */
698         /* image */
699         StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
700                       himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
701                       SRCCOPY);
702         /* mask */
703         StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
704                       himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
705                       SRCCOPY);
706
707         /* copy (without stretching) temporary bitmaps to source (restore) */
708         /* mask */
709         BitBlt       (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
710                       hdcBmp, 0, 0, SRCCOPY);
711
712         /* image */
713         BitBlt       (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
714                       hdcBmp, 0, 0, SRCCOPY);
715         /* delete temporary bitmaps */
716         DeleteObject (hbmTempMask);
717         DeleteObject (hbmTempImage);
718         DeleteDC(hdcBmp);
719     }
720     else {
721         /* copy image */
722         StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
723                       himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
724                       SRCCOPY);
725
726         /* copy mask */
727         StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
728                       himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
729                       SRCCOPY);
730     }
731
732     return TRUE;
733 }
734
735
736 /*************************************************************************
737  * ImageList_Create [COMCTL32.@]
738  *
739  * Creates a new image list.
740  *
741  * PARAMS
742  *     cx       [I] image height
743  *     cy       [I] image width
744  *     flags    [I] creation flags
745  *     cInitial [I] initial number of images in the image list
746  *     cGrow    [I] number of images by which image list grows
747  *
748  * RETURNS
749  *     Success: Handle to the created image list
750  *     Failure: NULL
751  */
752 HIMAGELIST WINAPI
753 ImageList_Create (INT cx, INT cy, UINT flags,
754                   INT cInitial, INT cGrow)
755 {
756     HIMAGELIST himl;
757     INT      nCount;
758     HBITMAP  hbmTemp;
759     UINT     ilc = (flags & 0xFE);
760     static const WORD aBitBlend25[] =
761         {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
762
763     static const WORD aBitBlend50[] =
764         {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
765
766     TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
767
768     if (cx <= 0 || cy <= 0) return NULL;
769
770     /* Create the IImageList interface for the image list */
771     if (FAILED(ImageListImpl_CreateInstance(NULL, &IID_IImageList, (void **)&himl)))
772         return NULL;
773
774     cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
775
776     himl->cx        = cx;
777     himl->cy        = cy;
778     himl->flags     = flags;
779     himl->cMaxImage = cInitial + 1;
780     himl->cInitial  = cInitial;
781     himl->cGrow     = cGrow;
782     himl->clrFg     = CLR_DEFAULT;
783     himl->clrBk     = CLR_NONE;
784
785     /* initialize overlay mask indices */
786     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
787         himl->nOvlIdx[nCount] = -1;
788
789     /* Create Image & Mask DCs */
790     himl->hdcImage = CreateCompatibleDC (0);
791     if (!himl->hdcImage)
792         goto cleanup;
793     if (himl->flags & ILC_MASK){
794         himl->hdcMask = CreateCompatibleDC(0);
795         if (!himl->hdcMask)
796             goto cleanup;
797     }
798
799     /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
800     if (ilc == ILC_COLOR)
801     {
802         ilc = ILC_COLOR4;
803         himl->flags |= ILC_COLOR4;
804     }
805
806     if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
807         himl->uBitsPixel = ilc;
808     else
809         himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
810
811     if (himl->cMaxImage > 0) {
812         himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
813         SelectObject(himl->hdcImage, himl->hbmImage);
814     } else
815         himl->hbmImage = 0;
816
817     if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
818         SIZE sz;
819
820         imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
821         himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
822         if (himl->hbmMask == 0) {
823             ERR("Error creating mask bitmap!\n");
824             goto cleanup;
825         }
826         SelectObject(himl->hdcMask, himl->hbmMask);
827     }
828     else
829         himl->hbmMask = 0;
830
831     if (ilc == ILC_COLOR32)
832         himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
833     else
834         himl->has_alpha = NULL;
835
836     /* create blending brushes */
837     hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend25);
838     himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
839     DeleteObject (hbmTemp);
840
841     hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend50);
842     himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
843     DeleteObject (hbmTemp);
844
845     TRACE("created imagelist %p\n", himl);
846     return himl;
847
848 cleanup:
849     ImageList_Destroy(himl);
850     return NULL;
851 }
852
853
854 /*************************************************************************
855  * ImageList_Destroy [COMCTL32.@]
856  *
857  * Destroys an image list.
858  *
859  * PARAMS
860  *     himl [I] handle to image list
861  *
862  * RETURNS
863  *     Success: TRUE
864  *     Failure: FALSE
865  */
866
867 BOOL WINAPI
868 ImageList_Destroy (HIMAGELIST himl)
869 {
870     if (!is_valid(himl))
871         return FALSE;
872
873     IImageList_Release((IImageList *) himl);
874     return TRUE;
875 }
876
877
878 /*************************************************************************
879  * ImageList_DragEnter [COMCTL32.@]
880  *
881  * Locks window update and displays the drag image at the given position.
882  *
883  * PARAMS
884  *     hwndLock [I] handle of the window that owns the drag image.
885  *     x        [I] X position of the drag image.
886  *     y        [I] Y position of the drag image.
887  *
888  * RETURNS
889  *     Success: TRUE
890  *     Failure: FALSE
891  *
892  * NOTES
893  *     The position of the drag image is relative to the window, not
894  *     the client area.
895  */
896
897 BOOL WINAPI
898 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
899 {
900     TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
901
902     if (!is_valid(InternalDrag.himl))
903         return FALSE;
904
905     if (hwndLock)
906         InternalDrag.hwnd = hwndLock;
907     else
908         InternalDrag.hwnd = GetDesktopWindow ();
909
910     InternalDrag.x = x;
911     InternalDrag.y = y;
912
913     /* draw the drag image and save the background */
914     if (!ImageList_DragShowNolock(TRUE)) {
915         return FALSE;
916     }
917
918     return TRUE;
919 }
920
921
922 /*************************************************************************
923  * ImageList_DragLeave [COMCTL32.@]
924  *
925  * Unlocks window update and hides the drag image.
926  *
927  * PARAMS
928  *     hwndLock [I] handle of the window that owns the drag image.
929  *
930  * RETURNS
931  *     Success: TRUE
932  *     Failure: FALSE
933  */
934
935 BOOL WINAPI
936 ImageList_DragLeave (HWND hwndLock)
937 {
938     /* As we don't save drag info in the window this can lead to problems if
939        an app does not supply the same window as DragEnter */
940     /* if (hwndLock)
941         InternalDrag.hwnd = hwndLock;
942     else
943         InternalDrag.hwnd = GetDesktopWindow (); */
944     if(!hwndLock)
945         hwndLock = GetDesktopWindow();
946     if(InternalDrag.hwnd != hwndLock)
947         FIXME("DragLeave hWnd != DragEnter hWnd\n");
948
949     ImageList_DragShowNolock (FALSE);
950
951     return TRUE;
952 }
953
954
955 /*************************************************************************
956  * ImageList_InternalDragDraw [Internal]
957  *
958  * Draws the drag image.
959  *
960  * PARAMS
961  *     hdc [I] device context to draw into.
962  *     x   [I] X position of the drag image.
963  *     y   [I] Y position of the drag image.
964  *
965  * RETURNS
966  *     Success: TRUE
967  *     Failure: FALSE
968  *
969  * NOTES
970  *     The position of the drag image is relative to the window, not
971  *     the client area.
972  *
973  */
974
975 static inline void
976 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
977 {
978     IMAGELISTDRAWPARAMS imldp;
979
980     ZeroMemory (&imldp, sizeof(imldp));
981     imldp.cbSize  = sizeof(imldp);
982     imldp.himl    = InternalDrag.himl;
983     imldp.i       = 0;
984     imldp.hdcDst  = hdc,
985     imldp.x       = x;
986     imldp.y       = y;
987     imldp.rgbBk   = CLR_DEFAULT;
988     imldp.rgbFg   = CLR_DEFAULT;
989     imldp.fStyle  = ILD_NORMAL;
990     imldp.fState  = ILS_ALPHA;
991     imldp.Frame   = 192;
992     ImageList_DrawIndirect (&imldp);
993 }
994
995 /*************************************************************************
996  * ImageList_DragMove [COMCTL32.@]
997  *
998  * Moves the drag image.
999  *
1000  * PARAMS
1001  *     x [I] X position of the drag image.
1002  *     y [I] Y position of the drag image.
1003  *
1004  * RETURNS
1005  *     Success: TRUE
1006  *     Failure: FALSE
1007  *
1008  * NOTES
1009  *     The position of the drag image is relative to the window, not
1010  *     the client area.
1011  */
1012
1013 BOOL WINAPI
1014 ImageList_DragMove (INT x, INT y)
1015 {
1016     TRACE("(x=%d y=%d)\n", x, y);
1017
1018     if (!is_valid(InternalDrag.himl))
1019         return FALSE;
1020
1021     /* draw/update the drag image */
1022     if (InternalDrag.bShow) {
1023         HDC hdcDrag;
1024         HDC hdcOffScreen;
1025         HDC hdcBg;
1026         HBITMAP hbmOffScreen;
1027         INT origNewX, origNewY;
1028         INT origOldX, origOldY;
1029         INT origRegX, origRegY;
1030         INT sizeRegX, sizeRegY;
1031
1032
1033         /* calculate the update region */
1034         origNewX = x - InternalDrag.dxHotspot;
1035         origNewY = y - InternalDrag.dyHotspot;
1036         origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1037         origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1038         origRegX = min(origNewX, origOldX);
1039         origRegY = min(origNewY, origOldY);
1040         sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1041         sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1042
1043         hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1044                           DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1045         hdcOffScreen = CreateCompatibleDC(hdcDrag);
1046         hdcBg = CreateCompatibleDC(hdcDrag);
1047
1048         hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1049         SelectObject(hdcOffScreen, hbmOffScreen);
1050         SelectObject(hdcBg, InternalDrag.hbmBg);
1051
1052         /* get the actual background of the update region */
1053         BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1054                origRegX, origRegY, SRCCOPY);
1055         /* erase the old image */
1056         BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1057                InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1058                SRCCOPY);
1059         /* save the background */
1060         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1061                hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1062         /* draw the image */
1063         ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX, 
1064                                    origNewY - origRegY);
1065         /* draw the update region to the screen */
1066         BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1067                hdcOffScreen, 0, 0, SRCCOPY);
1068
1069         DeleteDC(hdcBg);
1070         DeleteDC(hdcOffScreen);
1071         DeleteObject(hbmOffScreen);
1072         ReleaseDC(InternalDrag.hwnd, hdcDrag);
1073     }
1074
1075     /* update the image position */
1076     InternalDrag.x = x;
1077     InternalDrag.y = y;
1078
1079     return TRUE;
1080 }
1081
1082
1083 /*************************************************************************
1084  * ImageList_DragShowNolock [COMCTL32.@]
1085  *
1086  * Shows or hides the drag image.
1087  *
1088  * PARAMS
1089  *     bShow [I] TRUE shows the drag image, FALSE hides it.
1090  *
1091  * RETURNS
1092  *     Success: TRUE
1093  *     Failure: FALSE
1094  */
1095
1096 BOOL WINAPI
1097 ImageList_DragShowNolock (BOOL bShow)
1098 {
1099     HDC hdcDrag;
1100     HDC hdcBg;
1101     INT x, y;
1102
1103     if (!is_valid(InternalDrag.himl))
1104         return FALSE;
1105     
1106     TRACE("bShow=0x%X!\n", bShow);
1107
1108     /* DragImage is already visible/hidden */
1109     if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1110         return FALSE;
1111     }
1112
1113     /* position of the origin of the DragImage */
1114     x = InternalDrag.x - InternalDrag.dxHotspot;
1115     y = InternalDrag.y - InternalDrag.dyHotspot;
1116
1117     hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1118                          DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1119     if (!hdcDrag) {
1120         return FALSE;
1121     }
1122
1123     hdcBg = CreateCompatibleDC(hdcDrag);
1124     if (!InternalDrag.hbmBg) {
1125         InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1126                     InternalDrag.himl->cx, InternalDrag.himl->cy);
1127     }
1128     SelectObject(hdcBg, InternalDrag.hbmBg);
1129
1130     if (bShow) {
1131         /* save the background */
1132         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1133                hdcDrag, x, y, SRCCOPY);
1134         /* show the image */
1135         ImageList_InternalDragDraw(hdcDrag, x, y);
1136     } else {
1137         /* hide the image */
1138         BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1139                hdcBg, 0, 0, SRCCOPY);
1140     }
1141
1142     InternalDrag.bShow = !InternalDrag.bShow;
1143
1144     DeleteDC(hdcBg);
1145     ReleaseDC (InternalDrag.hwnd, hdcDrag);
1146     return TRUE;
1147 }
1148
1149
1150 /*************************************************************************
1151  * ImageList_Draw [COMCTL32.@]
1152  *
1153  * Draws an image.
1154  *
1155  * PARAMS
1156  *     himl   [I] handle to image list
1157  *     i      [I] image index
1158  *     hdc    [I] handle to device context
1159  *     x      [I] x position
1160  *     y      [I] y position
1161  *     fStyle [I] drawing flags
1162  *
1163  * RETURNS
1164  *     Success: TRUE
1165  *     Failure: FALSE
1166  *
1167  * SEE
1168  *     ImageList_DrawEx.
1169  */
1170
1171 BOOL WINAPI
1172 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1173 {
1174     return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0, 
1175                              CLR_DEFAULT, CLR_DEFAULT, fStyle);
1176 }
1177
1178
1179 /*************************************************************************
1180  * ImageList_DrawEx [COMCTL32.@]
1181  *
1182  * Draws an image and allows to use extended drawing features.
1183  *
1184  * PARAMS
1185  *     himl   [I] handle to image list
1186  *     i      [I] image index
1187  *     hdc    [I] handle to device context
1188  *     x      [I] X position
1189  *     y      [I] Y position
1190  *     dx     [I] X offset
1191  *     dy     [I] Y offset
1192  *     rgbBk  [I] background color
1193  *     rgbFg  [I] foreground color
1194  *     fStyle [I] drawing flags
1195  *
1196  * RETURNS
1197  *     Success: TRUE
1198  *     Failure: FALSE
1199  *
1200  * NOTES
1201  *     Calls ImageList_DrawIndirect.
1202  *
1203  * SEE
1204  *     ImageList_DrawIndirect.
1205  */
1206
1207 BOOL WINAPI
1208 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1209                   INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1210                   UINT fStyle)
1211 {
1212     IMAGELISTDRAWPARAMS imldp;
1213
1214     ZeroMemory (&imldp, sizeof(imldp));
1215     imldp.cbSize  = sizeof(imldp);
1216     imldp.himl    = himl;
1217     imldp.i       = i;
1218     imldp.hdcDst  = hdc,
1219     imldp.x       = x;
1220     imldp.y       = y;
1221     imldp.cx      = dx;
1222     imldp.cy      = dy;
1223     imldp.rgbBk   = rgbBk;
1224     imldp.rgbFg   = rgbFg;
1225     imldp.fStyle  = fStyle;
1226
1227     return ImageList_DrawIndirect (&imldp);
1228 }
1229
1230
1231 static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
1232                                int src_x, int src_y, int cx, int cy, BLENDFUNCTION func,
1233                                UINT style, COLORREF blend_col )
1234 {
1235     BOOL ret = FALSE;
1236     HDC hdc;
1237     HBITMAP bmp = 0, mask = 0;
1238     BITMAPINFO *info;
1239     void *bits, *mask_bits;
1240     unsigned int *ptr;
1241     int i, j;
1242
1243     if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
1244     if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
1245     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1246     info->bmiHeader.biWidth = cx;
1247     info->bmiHeader.biHeight = cy;
1248     info->bmiHeader.biPlanes = 1;
1249     info->bmiHeader.biBitCount = 32;
1250     info->bmiHeader.biCompression = BI_RGB;
1251     info->bmiHeader.biSizeImage = cx * cy * 4;
1252     info->bmiHeader.biXPelsPerMeter = 0;
1253     info->bmiHeader.biYPelsPerMeter = 0;
1254     info->bmiHeader.biClrUsed = 0;
1255     info->bmiHeader.biClrImportant = 0;
1256     if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1257     SelectObject( hdc, bmp );
1258     BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
1259
1260     if (blend_col != CLR_NONE)
1261     {
1262         BYTE r = GetRValue( blend_col );
1263         BYTE g = GetGValue( blend_col );
1264         BYTE b = GetBValue( blend_col );
1265
1266         if (style & ILD_BLEND25)
1267         {
1268             for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1269                 *ptr = ((*ptr & 0xff000000) |
1270                         ((((*ptr & 0x00ff0000) * 3 + (r << 16)) / 4) & 0x00ff0000) |
1271                         ((((*ptr & 0x0000ff00) * 3 + (g << 8))  / 4) & 0x0000ff00) |
1272                         ((((*ptr & 0x000000ff) * 3 + (b << 0))  / 4) & 0x000000ff));
1273         }
1274         else if (style & ILD_BLEND50)
1275         {
1276             for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1277                 *ptr = ((*ptr & 0xff000000) |
1278                         ((((*ptr & 0x00ff0000) + (r << 16)) / 2) & 0x00ff0000) |
1279                         ((((*ptr & 0x0000ff00) + (g << 8))  / 2) & 0x0000ff00) |
1280                         ((((*ptr & 0x000000ff) + (b << 0))  / 2) & 0x000000ff));
1281         }
1282     }
1283
1284     if (himl->has_alpha)  /* we already have an alpha channel in this case */
1285     {
1286         /* pre-multiply by the alpha channel */
1287         for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1288         {
1289             DWORD alpha = *ptr >> 24;
1290             *ptr = ((*ptr & 0xff000000) |
1291                     (((*ptr & 0x00ff0000) * alpha / 255) & 0x00ff0000) |
1292                     (((*ptr & 0x0000ff00) * alpha / 255) & 0x0000ff00) |
1293                     (((*ptr & 0x000000ff) * alpha / 255)));
1294         }
1295     }
1296     else if (himl->hbmMask)
1297     {
1298         unsigned int width_bytes = (cx + 31) / 32 * 4;
1299         /* generate alpha channel from the mask */
1300         info->bmiHeader.biBitCount = 1;
1301         info->bmiHeader.biSizeImage = width_bytes * cy;
1302         info->bmiColors[0].rgbRed      = 0;
1303         info->bmiColors[0].rgbGreen    = 0;
1304         info->bmiColors[0].rgbBlue     = 0;
1305         info->bmiColors[0].rgbReserved = 0;
1306         info->bmiColors[1].rgbRed      = 0xff;
1307         info->bmiColors[1].rgbGreen    = 0xff;
1308         info->bmiColors[1].rgbBlue     = 0xff;
1309         info->bmiColors[1].rgbReserved = 0;
1310         if (!(mask = CreateDIBSection( himl->hdcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0 )))
1311             goto done;
1312         SelectObject( hdc, mask );
1313         BitBlt( hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY );
1314         SelectObject( hdc, bmp );
1315         for (i = 0, ptr = bits; i < cy; i++)
1316             for (j = 0; j < cx; j++, ptr++)
1317                 if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
1318                 else *ptr |= 0xff000000;
1319     }
1320
1321     ret = GdiAlphaBlend( dest_dc, dest_x, dest_y, cx, cy, hdc, 0, 0, cx, cy, func );
1322
1323 done:
1324     DeleteDC( hdc );
1325     if (bmp) DeleteObject( bmp );
1326     if (mask) DeleteObject( mask );
1327     HeapFree( GetProcessHeap(), 0, info );
1328     return ret;
1329 }
1330
1331 /*************************************************************************
1332  * ImageList_DrawIndirect [COMCTL32.@]
1333  *
1334  * Draws an image using various parameters specified in pimldp.
1335  *
1336  * PARAMS
1337  *     pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1338  *
1339  * RETURNS
1340  *     Success: TRUE
1341  *     Failure: FALSE
1342  */
1343
1344 BOOL WINAPI
1345 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1346 {
1347     INT cx, cy, nOvlIdx;
1348     DWORD fState, dwRop;
1349     UINT fStyle;
1350     COLORREF oldImageBk, oldImageFg;
1351     HDC hImageDC, hImageListDC, hMaskListDC;
1352     HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1353     BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1354     HIMAGELIST himl;
1355     HBRUSH hOldBrush;
1356     POINT pt;
1357     BOOL has_alpha;
1358
1359     if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1360     if (!is_valid(himl)) return FALSE;
1361     if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1362
1363     imagelist_point_from_index( himl, pimldp->i, &pt );
1364     pt.x += pimldp->xBitmap;
1365     pt.y += pimldp->yBitmap;
1366
1367     fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1368     fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1369     cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1370     cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1371
1372     bIsTransparent = (fStyle & ILD_TRANSPARENT);
1373     if( pimldp->rgbBk == CLR_NONE )
1374         bIsTransparent = TRUE;
1375     if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1376         bIsTransparent = TRUE;
1377     bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1378     bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1379
1380     TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1381           himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1382
1383     /* we will use these DCs to access the images and masks in the ImageList */
1384     hImageListDC = himl->hdcImage;
1385     hMaskListDC  = himl->hdcMask;
1386
1387     /* these will accumulate the image and mask for the image we're drawing */
1388     hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1389     hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1390     hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1391
1392     /* Create a compatible DC. */
1393     if (!hImageListDC || !hImageDC || !hImageBmp ||
1394         (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1395         goto cleanup;
1396     
1397     hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1398   
1399     /*
1400      * To obtain a transparent look, background color should be set
1401      * to white and foreground color to black when blitting the
1402      * monochrome mask.
1403      */
1404     oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1405     oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1406
1407     has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
1408     if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
1409     {
1410         COLORREF colour, blend_col = CLR_NONE;
1411         BLENDFUNCTION func;
1412
1413         if (bBlend)
1414         {
1415             blend_col = pimldp->rgbFg;
1416             if (blend_col == CLR_DEFAULT) blend_col = GetSysColor( COLOR_HIGHLIGHT );
1417             else if (blend_col == CLR_NONE) blend_col = GetTextColor( pimldp->hdcDst );
1418         }
1419
1420         func.BlendOp = AC_SRC_OVER;
1421         func.BlendFlags = 0;
1422         func.SourceConstantAlpha = (fState & ILS_ALPHA) ? pimldp->Frame : 255;
1423         func.AlphaFormat = AC_SRC_ALPHA;
1424
1425         if (bIsTransparent)
1426         {
1427             bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1428                                          pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1429             goto end;
1430         }
1431         colour = pimldp->rgbBk;
1432         if (colour == CLR_DEFAULT) colour = himl->clrBk;
1433         if (colour == CLR_NONE) colour = GetBkColor( pimldp->hdcDst );
1434
1435         hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1436         PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1437         alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1438         DeleteObject (SelectObject (hImageDC, hOldBrush));
1439         bResult = BitBlt( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
1440         goto end;
1441     }
1442
1443     /*
1444      * Draw the initial image
1445      */
1446     if( bMask ) {
1447         if (himl->hbmMask) {
1448             hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1449             PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1450             BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1451             DeleteObject (SelectObject (hImageDC, hOldBrush));
1452             if( bIsTransparent )
1453             {
1454                 BitBlt ( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1455                 bResult = TRUE;
1456                 goto end;
1457             }
1458         } else {
1459             hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1460             PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1461             SelectObject(hImageDC, hOldBrush);
1462         }
1463     } else {
1464         /* blend the image with the needed solid background */
1465         COLORREF colour = RGB(0,0,0);
1466
1467         if( !bIsTransparent )
1468         {
1469             colour = pimldp->rgbBk;
1470             if( colour == CLR_DEFAULT )
1471                 colour = himl->clrBk;
1472             if( colour == CLR_NONE )
1473                 colour = GetBkColor(pimldp->hdcDst);
1474         }
1475
1476         hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1477         PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1478         if (himl->hbmMask)
1479         {
1480             BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1481             BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1482         }
1483         else
1484             BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCCOPY);
1485         DeleteObject (SelectObject (hImageDC, hOldBrush));
1486     }
1487
1488     /* Time for blending, if required */
1489     if (bBlend) {
1490         HBRUSH hBlendBrush;
1491         COLORREF clrBlend = pimldp->rgbFg;
1492         HDC hBlendMaskDC = hImageListDC;
1493         HBITMAP hOldBitmap;
1494
1495         /* Create the blend Mask */
1496         hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1497         hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1498         hOldBrush = SelectObject(hBlendMaskDC, hBlendBrush);
1499         PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1500         SelectObject(hBlendMaskDC, hOldBrush);
1501
1502         /* Modify the blend mask if an Image Mask exist */
1503         if(himl->hbmMask) {
1504             BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1505             BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1506         }
1507
1508         /* now apply blend to the current image given the BlendMask */
1509         if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1510         else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1511         hOldBrush = SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1512         BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1513         DeleteObject(SelectObject(hImageDC, hOldBrush));
1514         SelectObject(hBlendMaskDC, hOldBitmap);
1515     }
1516
1517     /* Now do the overlay image, if any */
1518     nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1519     if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1520         nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1521         if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1522             POINT ptOvl;
1523             imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
1524             ptOvl.x += pimldp->xBitmap;
1525             if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1526                 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
1527             BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1528         }
1529     }
1530
1531     if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1532     if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1533     if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1534
1535     if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1536     if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1537     if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1538
1539     /* now copy the image to the screen */
1540     dwRop = SRCCOPY;
1541     if (himl->hbmMask && bIsTransparent ) {
1542         COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1543         COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1544         BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1545         SetBkColor(pimldp->hdcDst, oldDstBk);
1546         SetTextColor(pimldp->hdcDst, oldDstFg);
1547         dwRop = SRCPAINT;
1548     }
1549     if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1550     BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1551
1552     bResult = TRUE;
1553 end:
1554     /* cleanup the mess */
1555     SetBkColor(hImageDC, oldImageBk);
1556     SetTextColor(hImageDC, oldImageFg);
1557     SelectObject(hImageDC, hOldImageBmp);
1558 cleanup:
1559     DeleteObject(hBlendMaskBmp);
1560     DeleteObject(hImageBmp);
1561     DeleteDC(hImageDC);
1562
1563     return bResult;
1564 }
1565
1566
1567 /*************************************************************************
1568  * ImageList_Duplicate [COMCTL32.@]
1569  *
1570  * Duplicates an image list.
1571  *
1572  * PARAMS
1573  *     himlSrc [I] source image list handle
1574  *
1575  * RETURNS
1576  *     Success: Handle of duplicated image list.
1577  *     Failure: NULL
1578  */
1579
1580 HIMAGELIST WINAPI
1581 ImageList_Duplicate (HIMAGELIST himlSrc)
1582 {
1583     HIMAGELIST himlDst;
1584
1585     if (!is_valid(himlSrc)) {
1586         ERR("Invalid image list handle!\n");
1587         return NULL;
1588     }
1589
1590     himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1591                                 himlSrc->cCurImage, himlSrc->cGrow);
1592
1593     if (himlDst)
1594     {
1595         SIZE sz;
1596
1597         imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, &sz);
1598         BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1599                 himlSrc->hdcImage, 0, 0, SRCCOPY);
1600
1601         if (himlDst->hbmMask)
1602             BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1603                     himlSrc->hdcMask, 0, 0, SRCCOPY);
1604
1605         himlDst->cCurImage = himlSrc->cCurImage;
1606         if (himlSrc->has_alpha && himlDst->has_alpha)
1607             memcpy( himlDst->has_alpha, himlSrc->has_alpha, himlDst->cCurImage );
1608     }
1609     return himlDst;
1610 }
1611
1612
1613 /*************************************************************************
1614  * ImageList_EndDrag [COMCTL32.@]
1615  *
1616  * Finishes a drag operation.
1617  *
1618  * PARAMS
1619  *     no Parameters
1620  *
1621  * RETURNS
1622  *     Success: TRUE
1623  *     Failure: FALSE
1624  */
1625
1626 VOID WINAPI
1627 ImageList_EndDrag (void)
1628 {
1629     /* cleanup the InternalDrag struct */
1630     InternalDrag.hwnd = 0;
1631     ImageList_Destroy (InternalDrag.himl);
1632     InternalDrag.himl = 0;
1633     InternalDrag.x= 0;
1634     InternalDrag.y= 0;
1635     InternalDrag.dxHotspot = 0;
1636     InternalDrag.dyHotspot = 0;
1637     InternalDrag.bShow = FALSE;
1638     DeleteObject(InternalDrag.hbmBg);
1639     InternalDrag.hbmBg = 0;
1640 }
1641
1642
1643 /*************************************************************************
1644  * ImageList_GetBkColor [COMCTL32.@]
1645  *
1646  * Returns the background color of an image list.
1647  *
1648  * PARAMS
1649  *     himl [I] Image list handle.
1650  *
1651  * RETURNS
1652  *     Success: background color
1653  *     Failure: CLR_NONE
1654  */
1655
1656 COLORREF WINAPI
1657 ImageList_GetBkColor (HIMAGELIST himl)
1658 {
1659     return himl ? himl->clrBk : CLR_NONE;
1660 }
1661
1662
1663 /*************************************************************************
1664  * ImageList_GetDragImage [COMCTL32.@]
1665  *
1666  * Returns the handle to the internal drag image list.
1667  *
1668  * PARAMS
1669  *     ppt        [O] Pointer to the drag position. Can be NULL.
1670  *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1671  *
1672  * RETURNS
1673  *     Success: Handle of the drag image list.
1674  *     Failure: NULL.
1675  */
1676
1677 HIMAGELIST WINAPI
1678 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1679 {
1680     if (is_valid(InternalDrag.himl)) {
1681         if (ppt) {
1682             ppt->x = InternalDrag.x;
1683             ppt->y = InternalDrag.y;
1684         }
1685         if (pptHotspot) {
1686             pptHotspot->x = InternalDrag.dxHotspot;
1687             pptHotspot->y = InternalDrag.dyHotspot;
1688         }
1689         return (InternalDrag.himl);
1690     }
1691
1692     return NULL;
1693 }
1694
1695
1696 /*************************************************************************
1697  * ImageList_GetFlags [COMCTL32.@]
1698  *
1699  * Gets the flags of the specified image list.
1700  *
1701  * PARAMS
1702  *     himl [I] Handle to image list
1703  *
1704  * RETURNS
1705  *     Image list flags.
1706  *
1707  * BUGS
1708  *    Stub.
1709  */
1710
1711 DWORD WINAPI
1712 ImageList_GetFlags(HIMAGELIST himl)
1713 {
1714     TRACE("%p\n", himl);
1715
1716     return is_valid(himl) ? himl->flags : 0;
1717 }
1718
1719
1720 /*************************************************************************
1721  * ImageList_GetIcon [COMCTL32.@]
1722  *
1723  * Creates an icon from a masked image of an image list.
1724  *
1725  * PARAMS
1726  *     himl  [I] handle to image list
1727  *     i     [I] image index
1728  *     flags [I] drawing style flags
1729  *
1730  * RETURNS
1731  *     Success: icon handle
1732  *     Failure: NULL
1733  */
1734
1735 HICON WINAPI
1736 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1737 {
1738     ICONINFO ii;
1739     HICON hIcon;
1740     HBITMAP hOldDstBitmap;
1741     HDC hdcDst;
1742     POINT pt;
1743
1744     TRACE("%p %d %d\n", himl, i, fStyle);
1745     if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1746
1747     ii.fIcon = TRUE;
1748     ii.xHotspot = 0;
1749     ii.yHotspot = 0;
1750
1751     /* create colour bitmap */
1752     hdcDst = GetDC(0);
1753     ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1754     ReleaseDC(0, hdcDst);
1755
1756     hdcDst = CreateCompatibleDC(0);
1757
1758     imagelist_point_from_index( himl, i, &pt );
1759
1760     /* draw mask*/
1761     ii.hbmMask  = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1762     hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1763     if (himl->hbmMask) {
1764         BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1765                 himl->hdcMask, pt.x, pt.y, SRCCOPY);
1766     }
1767     else
1768         PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1769
1770     /* draw image*/
1771     SelectObject (hdcDst, ii.hbmColor);
1772     BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1773             himl->hdcImage, pt.x, pt.y, SRCCOPY);
1774
1775     /*
1776      * CreateIconIndirect requires us to deselect the bitmaps from
1777      * the DCs before calling
1778      */
1779     SelectObject(hdcDst, hOldDstBitmap);
1780
1781     hIcon = CreateIconIndirect (&ii);
1782
1783     DeleteObject (ii.hbmMask);
1784     DeleteObject (ii.hbmColor);
1785     DeleteDC (hdcDst);
1786
1787     return hIcon;
1788 }
1789
1790
1791 /*************************************************************************
1792  * ImageList_GetIconSize [COMCTL32.@]
1793  *
1794  * Retrieves the size of an image in an image list.
1795  *
1796  * PARAMS
1797  *     himl [I] handle to image list
1798  *     cx   [O] pointer to the image width.
1799  *     cy   [O] pointer to the image height.
1800  *
1801  * RETURNS
1802  *     Success: TRUE
1803  *     Failure: FALSE
1804  *
1805  * NOTES
1806  *     All images in an image list have the same size.
1807  */
1808
1809 BOOL WINAPI
1810 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1811 {
1812     if (!is_valid(himl) || !cx || !cy)
1813         return FALSE;
1814     if ((himl->cx <= 0) || (himl->cy <= 0))
1815         return FALSE;
1816
1817     *cx = himl->cx;
1818     *cy = himl->cy;
1819
1820     return TRUE;
1821 }
1822
1823
1824 /*************************************************************************
1825  * ImageList_GetImageCount [COMCTL32.@]
1826  *
1827  * Returns the number of images in an image list.
1828  *
1829  * PARAMS
1830  *     himl [I] handle to image list
1831  *
1832  * RETURNS
1833  *     Success: Number of images.
1834  *     Failure: 0
1835  */
1836
1837 INT WINAPI
1838 ImageList_GetImageCount (HIMAGELIST himl)
1839 {
1840     if (!is_valid(himl))
1841         return 0;
1842
1843     return himl->cCurImage;
1844 }
1845
1846
1847 /*************************************************************************
1848  * ImageList_GetImageInfo [COMCTL32.@]
1849  *
1850  * Returns information about an image in an image list.
1851  *
1852  * PARAMS
1853  *     himl       [I] handle to image list
1854  *     i          [I] image index
1855  *     pImageInfo [O] pointer to the image information
1856  *
1857  * RETURNS
1858  *     Success: TRUE
1859  *     Failure: FALSE
1860  */
1861
1862 BOOL WINAPI
1863 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1864 {
1865     POINT pt;
1866
1867     if (!is_valid(himl) || (pImageInfo == NULL))
1868         return FALSE;
1869     if ((i < 0) || (i >= himl->cCurImage))
1870         return FALSE;
1871
1872     pImageInfo->hbmImage = himl->hbmImage;
1873     pImageInfo->hbmMask  = himl->hbmMask;
1874
1875     imagelist_point_from_index( himl, i, &pt );
1876     pImageInfo->rcImage.top    = pt.y;
1877     pImageInfo->rcImage.bottom = pt.y + himl->cy;
1878     pImageInfo->rcImage.left   = pt.x;
1879     pImageInfo->rcImage.right  = pt.x + himl->cx;
1880
1881     return TRUE;
1882 }
1883
1884
1885 /*************************************************************************
1886  * ImageList_GetImageRect [COMCTL32.@]
1887  *
1888  * Retrieves the rectangle of the specified image in an image list.
1889  *
1890  * PARAMS
1891  *     himl   [I] handle to image list
1892  *     i      [I] image index
1893  *     lpRect [O] pointer to the image rectangle
1894  *
1895  * RETURNS
1896  *    Success: TRUE
1897  *    Failure: FALSE
1898  *
1899  * NOTES
1900  *    This is an UNDOCUMENTED function!!!
1901  */
1902
1903 BOOL WINAPI
1904 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1905 {
1906     POINT pt;
1907
1908     if (!is_valid(himl) || (lpRect == NULL))
1909         return FALSE;
1910     if ((i < 0) || (i >= himl->cCurImage))
1911         return FALSE;
1912
1913     imagelist_point_from_index( himl, i, &pt );
1914     lpRect->left   = pt.x;
1915     lpRect->top    = pt.y;
1916     lpRect->right  = pt.x + himl->cx;
1917     lpRect->bottom = pt.y + himl->cy;
1918
1919     return TRUE;
1920 }
1921
1922
1923 /*************************************************************************
1924  * ImageList_LoadImage  [COMCTL32.@]
1925  * ImageList_LoadImageA [COMCTL32.@]
1926  *
1927  * Creates an image list from a bitmap, icon or cursor.
1928  *
1929  * See ImageList_LoadImageW.
1930  */
1931
1932 HIMAGELIST WINAPI
1933 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1934                         COLORREF clrMask, UINT uType, UINT uFlags)
1935 {
1936     HIMAGELIST himl;
1937     LPWSTR lpbmpW;
1938     DWORD len;
1939
1940     if (IS_INTRESOURCE(lpbmp))
1941         return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
1942                                     uType, uFlags);
1943
1944     len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1945     lpbmpW = Alloc(len * sizeof(WCHAR));
1946     MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1947
1948     himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1949     Free (lpbmpW);
1950     return himl;
1951 }
1952
1953
1954 /*************************************************************************
1955  * ImageList_LoadImageW [COMCTL32.@]
1956  *
1957  * Creates an image list from a bitmap, icon or cursor.
1958  *
1959  * PARAMS
1960  *     hi      [I] instance handle
1961  *     lpbmp   [I] name or id of the image
1962  *     cx      [I] width of each image
1963  *     cGrow   [I] number of images to expand
1964  *     clrMask [I] mask color
1965  *     uType   [I] type of image to load
1966  *     uFlags  [I] loading flags
1967  *
1968  * RETURNS
1969  *     Success: handle to the loaded image list
1970  *     Failure: NULL
1971  *
1972  * SEE
1973  *     LoadImage ()
1974  */
1975
1976 HIMAGELIST WINAPI
1977 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1978                       COLORREF clrMask, UINT uType, UINT uFlags)
1979 {
1980     HIMAGELIST himl = NULL;
1981     HANDLE   handle;
1982     INT      nImageCount;
1983
1984     handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1985     if (!handle) {
1986         WARN("Couldn't load image\n");
1987         return NULL;
1988     }
1989
1990     if (uType == IMAGE_BITMAP) {
1991         DIBSECTION dib;
1992         UINT color;
1993
1994         if (GetObjectW (handle, sizeof(dib), &dib) == sizeof(BITMAP)) color = ILC_COLOR;
1995         else color = dib.dsBm.bmBitsPixel;
1996
1997         /* To match windows behavior, if cx is set to zero and
1998          the flag DI_DEFAULTSIZE is specified, cx becomes the
1999          system metric value for icons. If the flag is not specified
2000          the function sets the size to the height of the bitmap */
2001         if (cx == 0)
2002         {
2003             if (uFlags & DI_DEFAULTSIZE)
2004                 cx = GetSystemMetrics (SM_CXICON);
2005             else
2006                 cx = dib.dsBm.bmHeight;
2007         }
2008
2009         nImageCount = dib.dsBm.bmWidth / cx;
2010
2011         himl = ImageList_Create (cx, dib.dsBm.bmHeight, ILC_MASK | color, nImageCount, cGrow);
2012         if (!himl) {
2013             DeleteObject (handle);
2014             return NULL;
2015         }
2016         ImageList_AddMasked (himl, handle, clrMask);
2017     }
2018     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
2019         ICONINFO ii;
2020         BITMAP bmp;
2021
2022         GetIconInfo (handle, &ii);
2023         GetObjectW (ii.hbmColor, sizeof(BITMAP), &bmp);
2024         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
2025                                  ILC_MASK | ILC_COLOR, 1, cGrow);
2026         if (!himl) {
2027             DeleteObject (ii.hbmColor);
2028             DeleteObject (ii.hbmMask);
2029             DeleteObject (handle);
2030             return NULL;
2031         }
2032         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
2033         DeleteObject (ii.hbmColor);
2034         DeleteObject (ii.hbmMask);
2035     }
2036
2037     DeleteObject (handle);
2038
2039     return himl;
2040 }
2041
2042
2043 /*************************************************************************
2044  * ImageList_Merge [COMCTL32.@]
2045  *
2046  * Create an image list containing a merged image from two image lists.
2047  *
2048  * PARAMS
2049  *     himl1 [I] handle to first image list
2050  *     i1    [I] first image index
2051  *     himl2 [I] handle to second image list
2052  *     i2    [I] second image index
2053  *     dx    [I] X offset of the second image relative to the first.
2054  *     dy    [I] Y offset of the second image relative to the first.
2055  *
2056  * RETURNS
2057  *     Success: The newly created image list. It contains a single image
2058  *              consisting of the second image merged with the first.
2059  *     Failure: NULL, if either himl1 or himl2 are invalid.
2060  *
2061  * NOTES
2062  *   - The returned image list should be deleted by the caller using
2063  *     ImageList_Destroy() when it is no longer required.
2064  *   - If either i1 or i2 are not valid image indices they will be treated
2065  *     as a blank image.
2066  */
2067 HIMAGELIST WINAPI
2068 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
2069                  INT dx, INT dy)
2070 {
2071     HIMAGELIST himlDst = NULL;
2072     INT      cxDst, cyDst;
2073     INT      xOff1, yOff1, xOff2, yOff2;
2074     POINT    pt1, pt2;
2075
2076     TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
2077            i2, dx, dy);
2078
2079     if (!is_valid(himl1) || !is_valid(himl2))
2080         return NULL;
2081
2082     if (dx > 0) {
2083         cxDst = max (himl1->cx, dx + himl2->cx);
2084         xOff1 = 0;
2085         xOff2 = dx;
2086     }
2087     else if (dx < 0) {
2088         cxDst = max (himl2->cx, himl1->cx - dx);
2089         xOff1 = -dx;
2090         xOff2 = 0;
2091     }
2092     else {
2093         cxDst = max (himl1->cx, himl2->cx);
2094         xOff1 = 0;
2095         xOff2 = 0;
2096     }
2097
2098     if (dy > 0) {
2099         cyDst = max (himl1->cy, dy + himl2->cy);
2100         yOff1 = 0;
2101         yOff2 = dy;
2102     }
2103     else if (dy < 0) {
2104         cyDst = max (himl2->cy, himl1->cy - dy);
2105         yOff1 = -dy;
2106         yOff2 = 0;
2107     }
2108     else {
2109         cyDst = max (himl1->cy, himl2->cy);
2110         yOff1 = 0;
2111         yOff2 = 0;
2112     }
2113
2114     himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
2115
2116     if (himlDst)
2117     {
2118         imagelist_point_from_index( himl1, i1, &pt1 );
2119         imagelist_point_from_index( himl2, i2, &pt2 );
2120
2121         /* copy image */
2122         BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
2123         if (i1 >= 0 && i1 < himl1->cCurImage)
2124             BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
2125         if (i2 >= 0 && i2 < himl2->cCurImage)
2126         {
2127             BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
2128             BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
2129         }
2130
2131         /* copy mask */
2132         BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
2133         if (i1 >= 0 && i1 < himl1->cCurImage)
2134             BitBlt (himlDst->hdcMask,  xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask,  pt1.x, pt1.y, SRCCOPY);
2135         if (i2 >= 0 && i2 < himl2->cCurImage)
2136             BitBlt (himlDst->hdcMask,  xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask,  pt2.x, pt2.y, SRCAND);
2137
2138         himlDst->cCurImage = 1;
2139     }
2140
2141     return himlDst;
2142 }
2143
2144
2145 /* helper for ImageList_Read, see comments below */
2146 static void *read_bitmap(LPSTREAM pstm, BITMAPINFO *bmi)
2147 {
2148     BITMAPFILEHEADER    bmfh;
2149     int bitsperpixel, palspace;
2150     void *bits;
2151
2152     if (FAILED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)))
2153         return NULL;
2154
2155     if (bmfh.bfType != (('M'<<8)|'B'))
2156         return NULL;
2157
2158     if (FAILED(IStream_Read ( pstm, &bmi->bmiHeader, sizeof(bmi->bmiHeader), NULL)))
2159         return NULL;
2160
2161     if ((bmi->bmiHeader.biSize != sizeof(bmi->bmiHeader)))
2162         return NULL;
2163
2164     TRACE("width %u, height %u, planes %u, bpp %u\n",
2165           bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
2166           bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount);
2167
2168     bitsperpixel = bmi->bmiHeader.biPlanes * bmi->bmiHeader.biBitCount;
2169     if (bitsperpixel<=8)
2170         palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2171     else
2172         palspace = 0;
2173
2174     bmi->bmiHeader.biSizeImage = get_dib_image_size( bmi );
2175
2176     /* read the palette right after the end of the bitmapinfoheader */
2177     if (palspace && FAILED(IStream_Read(pstm, bmi->bmiColors, palspace, NULL)))
2178         return NULL;
2179
2180     bits = Alloc(bmi->bmiHeader.biSizeImage);
2181     if (!bits) return NULL;
2182
2183     if (FAILED(IStream_Read(pstm, bits, bmi->bmiHeader.biSizeImage, NULL)))
2184     {
2185         Free(bits);
2186         return NULL;
2187     }
2188     return bits;
2189 }
2190
2191 /*************************************************************************
2192  * ImageList_Read [COMCTL32.@]
2193  *
2194  * Reads an image list from a stream.
2195  *
2196  * PARAMS
2197  *     pstm [I] pointer to a stream
2198  *
2199  * RETURNS
2200  *     Success: handle to image list
2201  *     Failure: NULL
2202  *
2203  * The format is like this:
2204  *      ILHEAD                  ilheadstruct;
2205  *
2206  * for the color image part:
2207  *      BITMAPFILEHEADER        bmfh;
2208  *      BITMAPINFOHEADER        bmih;
2209  * only if it has a palette:
2210  *      RGBQUAD         rgbs[nr_of_paletted_colors];
2211  *
2212  *      BYTE                    colorbits[imagesize];
2213  *
2214  * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2215  *      BITMAPFILEHEADER        bmfh_mask;
2216  *      BITMAPINFOHEADER        bmih_mask;
2217  * only if it has a palette (it usually does not):
2218  *      RGBQUAD         rgbs[nr_of_paletted_colors];
2219  *
2220  *      BYTE                    maskbits[imagesize];
2221  */
2222 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2223 {
2224     char image_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2225     char mask_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2226     BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
2227     BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
2228     void *image_bits, *mask_bits = NULL;
2229     ILHEAD      ilHead;
2230     HIMAGELIST  himl;
2231     int         i;
2232
2233     TRACE("%p\n", pstm);
2234
2235     if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2236         return NULL;
2237     if (ilHead.usMagic != (('L' << 8) | 'I'))
2238         return NULL;
2239     if (ilHead.usVersion != 0x101) /* probably version? */
2240         return NULL;
2241
2242     TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
2243           ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2244
2245     himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2246     if (!himl)
2247         return NULL;
2248
2249     if (!(image_bits = read_bitmap(pstm, image_info)))
2250     {
2251         WARN("failed to read bitmap from stream\n");
2252         return NULL;
2253     }
2254     if (ilHead.flags & ILC_MASK)
2255     {
2256         if (!(mask_bits = read_bitmap(pstm, mask_info)))
2257         {
2258             WARN("failed to read mask bitmap from stream\n");
2259             return NULL;
2260         }
2261     }
2262     else mask_info = NULL;
2263
2264     if (himl->has_alpha && image_info->bmiHeader.biBitCount == 32)
2265     {
2266         DWORD *ptr = image_bits;
2267         BYTE *mask_ptr = mask_bits;
2268         int stride = himl->cy * image_info->bmiHeader.biWidth;
2269
2270         if (image_info->bmiHeader.biHeight > 0)  /* bottom-up */
2271         {
2272             ptr += image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride;
2273             mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 8;
2274             stride = -stride;
2275             image_info->bmiHeader.biHeight = himl->cy;
2276         }
2277         else image_info->bmiHeader.biHeight = -himl->cy;
2278
2279         for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
2280         {
2281             add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
2282                           himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr );
2283             ptr += stride;
2284             mask_ptr += stride / 8;
2285         }
2286     }
2287     else
2288     {
2289         StretchDIBits( himl->hdcImage, 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2290                        0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2291                        image_bits, image_info, DIB_RGB_COLORS, SRCCOPY);
2292         if (mask_info)
2293             StretchDIBits( himl->hdcMask, 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2294                            0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2295                            mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY);
2296     }
2297     Free( image_bits );
2298     Free( mask_bits );
2299
2300     himl->cCurImage = ilHead.cCurImage;
2301     himl->cMaxImage = ilHead.cMaxImage;
2302
2303     ImageList_SetBkColor(himl,ilHead.bkcolor);
2304     for (i=0;i<4;i++)
2305         ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2306     return himl;
2307 }
2308
2309
2310 /*************************************************************************
2311  * ImageList_Remove [COMCTL32.@]
2312  *
2313  * Removes an image from an image list
2314  *
2315  * PARAMS
2316  *     himl [I] image list handle
2317  *     i    [I] image index
2318  *
2319  * RETURNS
2320  *     Success: TRUE
2321  *     Failure: FALSE
2322  *
2323  * FIXME: as the image list storage test shows, native comctl32 simply shifts
2324  * images without creating a new bitmap.
2325  */
2326 BOOL WINAPI
2327 ImageList_Remove (HIMAGELIST himl, INT i)
2328 {
2329     HBITMAP hbmNewImage, hbmNewMask;
2330     HDC     hdcBmp;
2331     SIZE    sz;
2332
2333     TRACE("(himl=%p i=%d)\n", himl, i);
2334
2335     if (!is_valid(himl)) {
2336         ERR("Invalid image list handle!\n");
2337         return FALSE;
2338     }
2339
2340     if ((i < -1) || (i >= himl->cCurImage)) {
2341         TRACE("index out of range! %d\n", i);
2342         return FALSE;
2343     }
2344
2345     if (i == -1) {
2346         INT nCount;
2347
2348         /* remove all */
2349         if (himl->cCurImage == 0) {
2350             /* remove all on empty ImageList is allowed */
2351             TRACE("remove all on empty ImageList!\n");
2352             return TRUE;
2353         }
2354
2355         himl->cMaxImage = himl->cInitial + himl->cGrow - 1;
2356         himl->cCurImage = 0;
2357         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2358              himl->nOvlIdx[nCount] = -1;
2359
2360         hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2361         SelectObject (himl->hdcImage, hbmNewImage);
2362         DeleteObject (himl->hbmImage);
2363         himl->hbmImage = hbmNewImage;
2364
2365         if (himl->hbmMask) {
2366
2367             imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2368             hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2369             SelectObject (himl->hdcMask, hbmNewMask);
2370             DeleteObject (himl->hbmMask);
2371             himl->hbmMask = hbmNewMask;
2372         }
2373     }
2374     else {
2375         /* delete one image */
2376         TRACE("Remove single image! %d\n", i);
2377
2378         /* create new bitmap(s) */
2379         TRACE(" - Number of images: %d / %d (Old/New)\n",
2380                  himl->cCurImage, himl->cCurImage - 1);
2381
2382         hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2383
2384         imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz );
2385         if (himl->hbmMask)
2386             hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2387         else
2388             hbmNewMask = 0;  /* Just to keep compiler happy! */
2389
2390         hdcBmp = CreateCompatibleDC (0);
2391
2392         /* copy all images and masks prior to the "removed" image */
2393         if (i > 0) {
2394             TRACE("Pre image copy: Copy %d images\n", i);
2395
2396             SelectObject (hdcBmp, hbmNewImage);
2397             imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
2398
2399             if (himl->hbmMask) {
2400                 SelectObject (hdcBmp, hbmNewMask);
2401                 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
2402             }
2403         }
2404
2405         /* copy all images and masks behind the removed image */
2406         if (i < himl->cCurImage - 1) {
2407             TRACE("Post image copy!\n");
2408
2409             SelectObject (hdcBmp, hbmNewImage);
2410             imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i + 1,
2411                                    (himl->cCurImage - i), i );
2412
2413             if (himl->hbmMask) {
2414                 SelectObject (hdcBmp, hbmNewMask);
2415                 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i + 1,
2416                                        (himl->cCurImage - i), i );
2417             }
2418         }
2419
2420         DeleteDC (hdcBmp);
2421
2422         /* delete old images and insert new ones */
2423         SelectObject (himl->hdcImage, hbmNewImage);
2424         DeleteObject (himl->hbmImage);
2425         himl->hbmImage = hbmNewImage;
2426         if (himl->hbmMask) {
2427             SelectObject (himl->hdcMask, hbmNewMask);
2428             DeleteObject (himl->hbmMask);
2429             himl->hbmMask = hbmNewMask;
2430         }
2431
2432         himl->cCurImage--;
2433     }
2434
2435     return TRUE;
2436 }
2437
2438
2439 /*************************************************************************
2440  * ImageList_Replace [COMCTL32.@]
2441  *
2442  * Replaces an image in an image list with a new image.
2443  *
2444  * PARAMS
2445  *     himl     [I] handle to image list
2446  *     i        [I] image index
2447  *     hbmImage [I] handle to image bitmap
2448  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2449  *
2450  * RETURNS
2451  *     Success: TRUE
2452  *     Failure: FALSE
2453  */
2454
2455 BOOL WINAPI
2456 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2457                    HBITMAP hbmMask)
2458 {
2459     HDC hdcImage;
2460     BITMAP bmp;
2461     POINT pt;
2462
2463     TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2464
2465     if (!is_valid(himl)) {
2466         ERR("Invalid image list handle!\n");
2467         return FALSE;
2468     }
2469
2470     if ((i >= himl->cMaxImage) || (i < 0)) {
2471         ERR("Invalid image index!\n");
2472         return FALSE;
2473     }
2474
2475     if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
2476         return FALSE;
2477
2478     hdcImage = CreateCompatibleDC (0);
2479
2480     /* Replace Image */
2481     SelectObject (hdcImage, hbmImage);
2482
2483     if (add_with_alpha( himl, hdcImage, i, 1, bmp.bmWidth, bmp.bmHeight, hbmImage, hbmMask ))
2484         goto done;
2485
2486     imagelist_point_from_index(himl, i, &pt);
2487     StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2488                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2489
2490     if (himl->hbmMask)
2491     {
2492         HDC hdcTemp;
2493         HBITMAP hOldBitmapTemp;
2494
2495         hdcTemp   = CreateCompatibleDC(0);
2496         hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2497
2498         StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2499                       hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2500         SelectObject(hdcTemp, hOldBitmapTemp);
2501         DeleteDC(hdcTemp);
2502
2503         /* Remove the background from the image
2504         */
2505         BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2506                 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2507     }
2508
2509 done:
2510     DeleteDC (hdcImage);
2511
2512     return TRUE;
2513 }
2514
2515
2516 /*************************************************************************
2517  * ImageList_ReplaceIcon [COMCTL32.@]
2518  *
2519  * Replaces an image in an image list using an icon.
2520  *
2521  * PARAMS
2522  *     himl  [I] handle to image list
2523  *     i     [I] image index
2524  *     hIcon [I] handle to icon
2525  *
2526  * RETURNS
2527  *     Success: index of the replaced image
2528  *     Failure: -1
2529  */
2530
2531 INT WINAPI
2532 ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
2533 {
2534     HICON   hBestFitIcon;
2535     ICONINFO  ii;
2536     BITMAP  bmp;
2537     BOOL    ret;
2538     POINT   pt;
2539
2540     TRACE("(%p %d %p)\n", himl, nIndex, hIcon);
2541
2542     if (!is_valid(himl)) {
2543         ERR("invalid image list\n");
2544         return -1;
2545     }
2546     if ((nIndex >= himl->cMaxImage) || (nIndex < -1)) {
2547         ERR("invalid image index %d / %d\n", nIndex, himl->cMaxImage);
2548         return -1;
2549     }
2550
2551     hBestFitIcon = CopyImage(
2552         hIcon, IMAGE_ICON,
2553         himl->cx, himl->cy,
2554         LR_COPYFROMRESOURCE);
2555     /* the above will fail if the icon wasn't loaded from a resource, so try
2556      * again without LR_COPYFROMRESOURCE flag */
2557     if (!hBestFitIcon)
2558         hBestFitIcon = CopyImage(
2559             hIcon, IMAGE_ICON,
2560             himl->cx, himl->cy,
2561             0);
2562     if (!hBestFitIcon)
2563         return -1;
2564
2565     if (nIndex == -1) {
2566         if (himl->cCurImage + 1 > himl->cMaxImage)
2567             IMAGELIST_InternalExpandBitmaps(himl, 1);
2568
2569         nIndex = himl->cCurImage;
2570         himl->cCurImage++;
2571     }
2572
2573     if (himl->has_alpha && GetIconInfo (hBestFitIcon, &ii))
2574     {
2575         HDC hdcImage = CreateCompatibleDC( 0 );
2576         GetObjectW (ii.hbmMask, sizeof(BITMAP), &bmp);
2577
2578         if (!ii.hbmColor)
2579         {
2580             UINT height = bmp.bmHeight / 2;
2581             HDC hdcMask = CreateCompatibleDC( 0 );
2582             HBITMAP color = CreateBitmap( bmp.bmWidth, height, 1, 1, NULL );
2583             SelectObject( hdcImage, color );
2584             SelectObject( hdcMask, ii.hbmMask );
2585             BitBlt( hdcImage, 0, 0, bmp.bmWidth, height, hdcMask, 0, height, SRCCOPY );
2586             ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, height, color, ii.hbmMask );
2587             DeleteDC( hdcMask );
2588             DeleteObject( color );
2589         }
2590         else ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, bmp.bmHeight,
2591                                    ii.hbmColor, ii.hbmMask );
2592
2593         DeleteDC( hdcImage );
2594         DeleteObject (ii.hbmMask);
2595         if (ii.hbmColor) DeleteObject (ii.hbmColor);
2596         if (ret) goto done;
2597     }
2598
2599     imagelist_point_from_index(himl, nIndex, &pt);
2600
2601     if (himl->hbmMask)
2602     {
2603         DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_IMAGE );
2604         PatBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy, WHITENESS );
2605         DrawIconEx( himl->hdcMask, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_MASK );
2606     }
2607     else
2608     {
2609         COLORREF color = himl->clrBk != CLR_NONE ? himl->clrBk : comctl32_color.clrWindow;
2610         HBRUSH brush = CreateSolidBrush( GetNearestColor( himl->hdcImage, color ));
2611
2612         SelectObject( himl->hdcImage, brush );
2613         PatBlt( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy, PATCOPY );
2614         SelectObject( himl->hdcImage, GetStockObject(BLACK_BRUSH) );
2615         DeleteObject( brush );
2616         DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_NORMAL );
2617     }
2618
2619 done:
2620     DestroyIcon(hBestFitIcon);
2621
2622     TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2623     return nIndex;
2624 }
2625
2626
2627 /*************************************************************************
2628  * ImageList_SetBkColor [COMCTL32.@]
2629  *
2630  * Sets the background color of an image list.
2631  *
2632  * PARAMS
2633  *     himl  [I] handle to image list
2634  *     clrBk [I] background color
2635  *
2636  * RETURNS
2637  *     Success: previous background color
2638  *     Failure: CLR_NONE
2639  */
2640
2641 COLORREF WINAPI
2642 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2643 {
2644     COLORREF clrOldBk;
2645
2646     if (!is_valid(himl))
2647         return CLR_NONE;
2648
2649     clrOldBk = himl->clrBk;
2650     himl->clrBk = clrBk;
2651     return clrOldBk;
2652 }
2653
2654
2655 /*************************************************************************
2656  * ImageList_SetDragCursorImage [COMCTL32.@]
2657  *
2658  * Combines the specified image with the current drag image
2659  *
2660  * PARAMS
2661  *     himlDrag  [I] handle to drag image list
2662  *     iDrag     [I] drag image index
2663  *     dxHotspot [I] X position of the hot spot
2664  *     dyHotspot [I] Y position of the hot spot
2665  *
2666  * RETURNS
2667  *     Success: TRUE
2668  *     Failure: FALSE
2669  *
2670  * NOTES
2671  *   - The names dxHotspot, dyHotspot are misleading because they have nothing
2672  *     to do with a hotspot but are only the offset of the origin of the new
2673  *     image relative to the origin of the old image.
2674  *
2675  *   - When this function is called and the drag image is visible, a
2676  *     short flickering occurs but this matches the Win9x behavior. It is
2677  *     possible to fix the flickering using code like in ImageList_DragMove.
2678  */
2679
2680 BOOL WINAPI
2681 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2682                               INT dxHotspot, INT dyHotspot)
2683 {
2684     HIMAGELIST himlTemp;
2685     BOOL visible;
2686
2687     if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2688         return FALSE;
2689
2690     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2691            dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2692
2693     visible = InternalDrag.bShow;
2694
2695     himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2696                                 dxHotspot, dyHotspot);
2697
2698     if (visible) {
2699         /* hide the drag image */
2700         ImageList_DragShowNolock(FALSE);
2701     }
2702     if ((InternalDrag.himl->cx != himlTemp->cx) ||
2703            (InternalDrag.himl->cy != himlTemp->cy)) {
2704         /* the size of the drag image changed, invalidate the buffer */
2705         DeleteObject(InternalDrag.hbmBg);
2706         InternalDrag.hbmBg = 0;
2707     }
2708
2709     ImageList_Destroy (InternalDrag.himl);
2710     InternalDrag.himl = himlTemp;
2711
2712     if (visible) {
2713         /* show the drag image */
2714         ImageList_DragShowNolock(TRUE);
2715     }
2716
2717     return TRUE;
2718 }
2719
2720
2721 /*************************************************************************
2722  * ImageList_SetFilter [COMCTL32.@]
2723  *
2724  * Sets a filter (or does something completely different)!!???
2725  * It removes 12 Bytes from the stack (3 Parameters).
2726  *
2727  * PARAMS
2728  *     himl     [I] SHOULD be a handle to image list
2729  *     i        [I] COULD be an index?
2730  *     dwFilter [I] ???
2731  *
2732  * RETURNS
2733  *     Success: TRUE ???
2734  *     Failure: FALSE ???
2735  *
2736  * BUGS
2737  *     This is an UNDOCUMENTED function!!!!
2738  *     empty stub.
2739  */
2740
2741 BOOL WINAPI
2742 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2743 {
2744     FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2745
2746     return FALSE;
2747 }
2748
2749
2750 /*************************************************************************
2751  * ImageList_SetFlags [COMCTL32.@]
2752  *
2753  * Sets the image list flags.
2754  *
2755  * PARAMS
2756  *     himl  [I] Handle to image list
2757  *     flags [I] Flags to set
2758  *
2759  * RETURNS
2760  *     Old flags?
2761  *
2762  * BUGS
2763  *    Stub.
2764  */
2765
2766 DWORD WINAPI
2767 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2768 {
2769     FIXME("(%p %08x):empty stub\n", himl, flags);
2770     return 0;
2771 }
2772
2773
2774 /*************************************************************************
2775  * ImageList_SetIconSize [COMCTL32.@]
2776  *
2777  * Sets the image size of the bitmap and deletes all images.
2778  *
2779  * PARAMS
2780  *     himl [I] handle to image list
2781  *     cx   [I] image width
2782  *     cy   [I] image height
2783  *
2784  * RETURNS
2785  *     Success: TRUE
2786  *     Failure: FALSE
2787  */
2788
2789 BOOL WINAPI
2790 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2791 {
2792     INT nCount;
2793     HBITMAP hbmNew;
2794
2795     if (!is_valid(himl))
2796         return FALSE;
2797
2798     /* remove all images */
2799     himl->cMaxImage = himl->cInitial + 1;
2800     himl->cCurImage = 0;
2801     himl->cx        = cx;
2802     himl->cy        = cy;
2803
2804     /* initialize overlay mask indices */
2805     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2806         himl->nOvlIdx[nCount] = -1;
2807
2808     hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2809     SelectObject (himl->hdcImage, hbmNew);
2810     DeleteObject (himl->hbmImage);
2811     himl->hbmImage = hbmNew;
2812
2813     if (himl->hbmMask) {
2814         SIZE sz;
2815         imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2816         hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2817         SelectObject (himl->hdcMask, hbmNew);
2818         DeleteObject (himl->hbmMask);
2819         himl->hbmMask = hbmNew;
2820     }
2821
2822     return TRUE;
2823 }
2824
2825
2826 /*************************************************************************
2827  * ImageList_SetImageCount [COMCTL32.@]
2828  *
2829  * Resizes an image list to the specified number of images.
2830  *
2831  * PARAMS
2832  *     himl        [I] handle to image list
2833  *     iImageCount [I] number of images in the image list
2834  *
2835  * RETURNS
2836  *     Success: TRUE
2837  *     Failure: FALSE
2838  */
2839
2840 BOOL WINAPI
2841 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2842 {
2843     HDC     hdcBitmap;
2844     HBITMAP hbmNewBitmap, hbmOld;
2845     INT     nNewCount, nCopyCount;
2846
2847     TRACE("%p %d\n",himl,iImageCount);
2848
2849     if (!is_valid(himl))
2850         return FALSE;
2851     if (himl->cMaxImage > iImageCount)
2852     {
2853         himl->cCurImage = iImageCount;
2854         /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
2855         return TRUE;
2856     }
2857
2858     nNewCount = iImageCount + himl->cGrow;
2859     nCopyCount = min(himl->cCurImage, iImageCount);
2860
2861     hdcBitmap = CreateCompatibleDC (0);
2862
2863     hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
2864
2865     if (hbmNewBitmap != 0)
2866     {
2867         hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2868         imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
2869         SelectObject (hdcBitmap, hbmOld);
2870
2871         /* FIXME: delete 'empty' image space? */
2872
2873         SelectObject (himl->hdcImage, hbmNewBitmap);
2874         DeleteObject (himl->hbmImage);
2875         himl->hbmImage = hbmNewBitmap;
2876     }
2877     else
2878         ERR("Could not create new image bitmap !\n");
2879
2880     if (himl->hbmMask)
2881     {
2882         SIZE sz;
2883         imagelist_get_bitmap_size( himl, nNewCount, &sz );
2884         hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2885         if (hbmNewBitmap != 0)
2886         {
2887             hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2888             imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
2889             SelectObject (hdcBitmap, hbmOld);
2890
2891             /* FIXME: delete 'empty' image space? */
2892
2893             SelectObject (himl->hdcMask, hbmNewBitmap);
2894             DeleteObject (himl->hbmMask);
2895             himl->hbmMask = hbmNewBitmap;
2896         }
2897         else
2898             ERR("Could not create new mask bitmap!\n");
2899     }
2900
2901     DeleteDC (hdcBitmap);
2902
2903     if (himl->has_alpha)
2904     {
2905         char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
2906         if (new_alpha) himl->has_alpha = new_alpha;
2907         else
2908         {
2909             HeapFree( GetProcessHeap(), 0, himl->has_alpha );
2910             himl->has_alpha = NULL;
2911         }
2912     }
2913
2914     /* Update max image count and current image count */
2915     himl->cMaxImage = nNewCount;
2916     himl->cCurImage = iImageCount;
2917
2918     return TRUE;
2919 }
2920
2921
2922 /*************************************************************************
2923  * ImageList_SetOverlayImage [COMCTL32.@]
2924  *
2925  * Assigns an overlay mask index to an existing image in an image list.
2926  *
2927  * PARAMS
2928  *     himl     [I] handle to image list
2929  *     iImage   [I] image index
2930  *     iOverlay [I] overlay mask index
2931  *
2932  * RETURNS
2933  *     Success: TRUE
2934  *     Failure: FALSE
2935  */
2936
2937 BOOL WINAPI
2938 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2939 {
2940     if (!is_valid(himl))
2941         return FALSE;
2942     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2943         return FALSE;
2944     if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2945         return FALSE;
2946     himl->nOvlIdx[iOverlay - 1] = iImage;
2947     return TRUE;
2948 }
2949
2950
2951
2952 /* helper for ImageList_Write - write bitmap to pstm
2953  * currently everything is written as 24 bit RGB, except masks
2954  */
2955 static BOOL
2956 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm)
2957 {
2958     LPBITMAPFILEHEADER bmfh;
2959     LPBITMAPINFOHEADER bmih;
2960     LPBYTE data = NULL, lpBits;
2961     BITMAP bm;
2962     INT bitCount, sizeImage, offBits, totalSize;
2963     HDC xdc;
2964     BOOL result = FALSE;
2965
2966     if (!GetObjectW(hBitmap, sizeof(BITMAP), &bm))
2967         return FALSE;
2968
2969     bitCount = bm.bmBitsPixel;
2970     sizeImage = get_dib_stride(bm.bmWidth, bitCount) * bm.bmHeight;
2971
2972     totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2973     if(bitCount <= 8)
2974         totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2975     offBits = totalSize;
2976     totalSize += sizeImage;
2977
2978     data = Alloc(totalSize);
2979     bmfh = (LPBITMAPFILEHEADER)data;
2980     bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2981     lpBits = data + offBits;
2982
2983     /* setup BITMAPFILEHEADER */
2984     bmfh->bfType      = (('M' << 8) | 'B');
2985     bmfh->bfSize      = offBits;
2986     bmfh->bfReserved1 = 0;
2987     bmfh->bfReserved2 = 0;
2988     bmfh->bfOffBits   = offBits;
2989
2990     /* setup BITMAPINFOHEADER */
2991     bmih->biSize          = sizeof(BITMAPINFOHEADER);
2992     bmih->biWidth         = bm.bmWidth;
2993     bmih->biHeight        = bm.bmHeight;
2994     bmih->biPlanes        = 1;
2995     bmih->biBitCount      = bitCount;
2996     bmih->biCompression   = BI_RGB;
2997     bmih->biSizeImage     = sizeImage;
2998     bmih->biXPelsPerMeter = 0;
2999     bmih->biYPelsPerMeter = 0;
3000     bmih->biClrUsed       = 0;
3001     bmih->biClrImportant  = 0;
3002
3003     xdc = GetDC(0);
3004     result = GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBits, (BITMAPINFO *)bmih, DIB_RGB_COLORS) == bm.bmHeight;
3005     ReleaseDC(0, xdc);
3006     if (!result)
3007         goto failed;
3008
3009     TRACE("width %u, height %u, planes %u, bpp %u\n",
3010           bmih->biWidth, bmih->biHeight,
3011           bmih->biPlanes, bmih->biBitCount);
3012
3013     if(FAILED(IStream_Write(pstm, data, totalSize, NULL)))
3014         goto failed;
3015
3016     result = TRUE;
3017
3018 failed:
3019     Free(data);
3020
3021     return result;
3022 }
3023
3024
3025 /*************************************************************************
3026  * ImageList_Write [COMCTL32.@]
3027  *
3028  * Writes an image list to a stream.
3029  *
3030  * PARAMS
3031  *     himl [I] handle to image list
3032  *     pstm [O] Pointer to a stream.
3033  *
3034  * RETURNS
3035  *     Success: TRUE
3036  *     Failure: FALSE
3037  *
3038  * BUGS
3039  *     probably.
3040  */
3041
3042 BOOL WINAPI
3043 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
3044 {
3045     ILHEAD ilHead;
3046     int i;
3047
3048     TRACE("%p %p\n", himl, pstm);
3049
3050     if (!is_valid(himl))
3051         return FALSE;
3052
3053     ilHead.usMagic   = (('L' << 8) | 'I');
3054     ilHead.usVersion = 0x101;
3055     ilHead.cCurImage = himl->cCurImage;
3056     ilHead.cMaxImage = himl->cMaxImage;
3057     ilHead.cGrow     = himl->cGrow;
3058     ilHead.cx        = himl->cx;
3059     ilHead.cy        = himl->cy;
3060     ilHead.bkcolor   = himl->clrBk;
3061     ilHead.flags     = himl->flags;
3062     for(i = 0; i < 4; i++) {
3063         ilHead.ovls[i] = himl->nOvlIdx[i];
3064     }
3065
3066     TRACE("cx %u, cy %u, flags 0x04%x, cCurImage %u, cMaxImage %u\n",
3067           ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
3068
3069     if(FAILED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3070         return FALSE;
3071
3072     /* write the bitmap */
3073     if(!_write_bitmap(himl->hbmImage, pstm))
3074         return FALSE;
3075
3076     /* write the mask if we have one */
3077     if(himl->flags & ILC_MASK) {
3078         if(!_write_bitmap(himl->hbmMask, pstm))
3079             return FALSE;
3080     }
3081
3082     return TRUE;
3083 }
3084
3085
3086 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
3087 {
3088     HBITMAP hbmNewBitmap;
3089     UINT ilc = (himl->flags & 0xFE);
3090     SIZE sz;
3091
3092     imagelist_get_bitmap_size( himl, count, &sz );
3093
3094     if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
3095     {
3096         char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
3097         BITMAPINFO *bmi = (BITMAPINFO *)buffer;
3098
3099         TRACE("Creating DIBSection %d x %d, %d Bits per Pixel\n",
3100               sz.cx, sz.cy, himl->uBitsPixel);
3101
3102         memset( buffer, 0, sizeof(buffer) );
3103         bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3104         bmi->bmiHeader.biWidth = sz.cx;
3105         bmi->bmiHeader.biHeight = sz.cy;
3106         bmi->bmiHeader.biPlanes = 1;
3107         bmi->bmiHeader.biBitCount = himl->uBitsPixel;
3108         bmi->bmiHeader.biCompression = BI_RGB;
3109
3110         if (himl->uBitsPixel <= ILC_COLOR8)
3111         {
3112             /* retrieve the default color map */
3113             HBITMAP tmp = CreateBitmap( 1, 1, 1, 1, NULL );
3114             GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
3115             DeleteObject( tmp );
3116         }
3117         hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, 0, 0);
3118     }
3119     else /*if (ilc == ILC_COLORDDB)*/
3120     {
3121         TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
3122
3123         hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
3124     }
3125     TRACE("returning %p\n", hbmNewBitmap);
3126     return hbmNewBitmap;
3127 }
3128
3129 /*************************************************************************
3130  * ImageList_SetColorTable [COMCTL32.@]
3131  *
3132  * Sets the color table of an image list.
3133  *
3134  * PARAMS
3135  *     himl        [I] Handle to the image list.
3136  *     uStartIndex [I] The first index to set.
3137  *     cEntries    [I] Number of entries to set.
3138  *     prgb        [I] New color information for color table for the image list.
3139  *
3140  * RETURNS
3141  *     Success: Number of entries in the table that were set.
3142  *     Failure: Zero.
3143  *
3144  * SEE
3145  *     ImageList_Create(), SetDIBColorTable()
3146  */
3147
3148 UINT WINAPI
3149 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
3150 {
3151     return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);
3152 }
3153
3154 /*************************************************************************
3155  * ImageList_CoCreateInstance [COMCTL32.@]
3156  *
3157  * Creates a new imagelist instance and returns an interface pointer to it.
3158  *
3159  * PARAMS
3160  *     rclsid      [I] A reference to the CLSID (CLSID_ImageList).
3161  *     punkOuter   [I] Pointer to IUnknown interface for aggregation, if desired
3162  *     riid        [I] Identifier of the requested interface.
3163  *     ppv         [O] Returns the address of the pointer requested, or NULL.
3164  *
3165  * RETURNS
3166  *     Success: S_OK.
3167  *     Failure: Error value.
3168  */
3169 HRESULT WINAPI
3170 ImageList_CoCreateInstance (REFCLSID rclsid, const IUnknown *punkOuter, REFIID riid, void **ppv)
3171 {
3172     TRACE("(%s,%p,%s,%p)\n", debugstr_guid(rclsid), punkOuter, debugstr_guid(riid), ppv);
3173
3174     if (!IsEqualCLSID(&CLSID_ImageList, rclsid))
3175         return E_NOINTERFACE;
3176
3177     return ImageListImpl_CreateInstance(punkOuter, riid, ppv);
3178 }
3179
3180
3181 /*************************************************************************
3182  * IImageList implementation
3183  */
3184
3185 static HRESULT WINAPI ImageListImpl_QueryInterface(IImageList *iface,
3186     REFIID iid, void **ppv)
3187 {
3188     HIMAGELIST This = (HIMAGELIST) iface;
3189     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
3190
3191     if (!ppv) return E_INVALIDARG;
3192
3193     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IImageList, iid))
3194         *ppv = This;
3195     else
3196     {
3197         *ppv = NULL;
3198         return E_NOINTERFACE;
3199     }
3200
3201     IUnknown_AddRef((IUnknown*)*ppv);
3202     return S_OK;
3203 }
3204
3205 static ULONG WINAPI ImageListImpl_AddRef(IImageList *iface)
3206 {
3207     HIMAGELIST This = (HIMAGELIST) iface;
3208     ULONG ref = InterlockedIncrement(&This->ref);
3209
3210     TRACE("(%p) refcount=%u\n", iface, ref);
3211     return ref;
3212 }
3213
3214 static ULONG WINAPI ImageListImpl_Release(IImageList *iface)
3215 {
3216     HIMAGELIST This = (HIMAGELIST) iface;
3217     ULONG ref = InterlockedDecrement(&This->ref);
3218
3219     TRACE("(%p) refcount=%u\n", iface, ref);
3220
3221     if (ref == 0)
3222     {
3223         /* delete image bitmaps */
3224         if (This->hbmImage) DeleteObject (This->hbmImage);
3225         if (This->hbmMask)  DeleteObject (This->hbmMask);
3226
3227         /* delete image & mask DCs */
3228         if (This->hdcImage) DeleteDC (This->hdcImage);
3229         if (This->hdcMask)  DeleteDC (This->hdcMask);
3230
3231         /* delete blending brushes */
3232         if (This->hbrBlend25) DeleteObject (This->hbrBlend25);
3233         if (This->hbrBlend50) DeleteObject (This->hbrBlend50);
3234
3235         This->lpVtbl = NULL;
3236         HeapFree(GetProcessHeap(), 0, This->has_alpha);
3237         HeapFree(GetProcessHeap(), 0, This);
3238     }
3239
3240     return ref;
3241 }
3242
3243 static HRESULT WINAPI ImageListImpl_Add(IImageList *iface, HBITMAP hbmImage,
3244     HBITMAP hbmMask, int *pi)
3245 {
3246     HIMAGELIST This = (HIMAGELIST) iface;
3247     int ret;
3248
3249     if (!pi)
3250         return E_FAIL;
3251
3252     ret = ImageList_Add(This, hbmImage, hbmMask);
3253
3254     if (ret == -1)
3255         return E_FAIL;
3256
3257     *pi = ret;
3258     return S_OK;
3259 }
3260
3261 static HRESULT WINAPI ImageListImpl_ReplaceIcon(IImageList *iface, int i,
3262     HICON hicon, int *pi)
3263 {
3264     HIMAGELIST This = (HIMAGELIST) iface;
3265     int ret;
3266
3267     if (!pi)
3268         return E_FAIL;
3269
3270     ret = ImageList_ReplaceIcon(This, i, hicon);
3271
3272     if (ret == -1)
3273         return E_FAIL;
3274
3275     *pi = ret;
3276     return S_OK;
3277 }
3278
3279 static HRESULT WINAPI ImageListImpl_SetOverlayImage(IImageList *iface,
3280     int iImage, int iOverlay)
3281 {
3282     return ImageList_SetOverlayImage((HIMAGELIST) iface, iImage, iOverlay)
3283         ? S_OK : E_FAIL;
3284 }
3285
3286 static HRESULT WINAPI ImageListImpl_Replace(IImageList *iface, int i,
3287     HBITMAP hbmImage, HBITMAP hbmMask)
3288 {
3289     return ImageList_Replace((HIMAGELIST) iface, i, hbmImage, hbmMask) ? S_OK :
3290         E_FAIL;
3291 }
3292
3293 static HRESULT WINAPI ImageListImpl_AddMasked(IImageList *iface, HBITMAP hbmImage,
3294     COLORREF crMask, int *pi)
3295 {
3296     HIMAGELIST This = (HIMAGELIST) iface;
3297     int ret;
3298
3299     if (!pi)
3300         return E_FAIL;
3301
3302     ret = ImageList_AddMasked(This, hbmImage, crMask);
3303
3304     if (ret == -1)
3305         return E_FAIL;
3306
3307     *pi = ret;
3308     return S_OK;
3309 }
3310
3311 static HRESULT WINAPI ImageListImpl_Draw(IImageList *iface,
3312     IMAGELISTDRAWPARAMS *pimldp)
3313 {
3314     HIMAGELIST This = (HIMAGELIST) iface;
3315     HIMAGELIST old_himl;
3316     int ret;
3317
3318     /* As far as I can tell, Windows simply ignores the contents of pimldp->himl
3319        so we shall simulate the same */
3320     old_himl = pimldp->himl;
3321     pimldp->himl = This;
3322
3323     ret = ImageList_DrawIndirect(pimldp);
3324
3325     pimldp->himl = old_himl;
3326     return ret ? S_OK : E_INVALIDARG;
3327 }
3328
3329 static HRESULT WINAPI ImageListImpl_Remove(IImageList *iface, int i)
3330 {
3331     return (ImageList_Remove((HIMAGELIST) iface, i) == 0) ? E_INVALIDARG : S_OK;
3332 }
3333
3334 static HRESULT WINAPI ImageListImpl_GetIcon(IImageList *iface, int i, UINT flags,
3335     HICON *picon)
3336 {
3337     HICON hIcon;
3338
3339     if (!picon)
3340         return E_FAIL;
3341
3342     hIcon = ImageList_GetIcon((HIMAGELIST) iface, i, flags);
3343
3344     if (hIcon == NULL)
3345         return E_FAIL;
3346
3347     *picon = hIcon;
3348     return S_OK;
3349 }
3350
3351 static HRESULT WINAPI ImageListImpl_GetImageInfo(IImageList *iface, int i,
3352     IMAGEINFO *pImageInfo)
3353 {
3354     return ImageList_GetImageInfo((HIMAGELIST) iface, i, pImageInfo) ? S_OK : E_FAIL;
3355 }
3356
3357 static HRESULT WINAPI ImageListImpl_Copy(IImageList *iface, int iDst,
3358     IUnknown *punkSrc, int iSrc, UINT uFlags)
3359 {
3360     HIMAGELIST This = (HIMAGELIST) iface;
3361     IImageList *src = NULL;
3362     HRESULT ret;
3363
3364     if (!punkSrc)
3365         return E_FAIL;
3366
3367     /* TODO: Add test for IID_ImageList2 too */
3368     if (FAILED(IImageList_QueryInterface(punkSrc, &IID_IImageList,
3369             (void **) &src)))
3370         return E_FAIL;
3371
3372     if (ImageList_Copy(This, iDst, (HIMAGELIST) src, iSrc, uFlags))
3373         ret = S_OK;
3374     else
3375         ret = E_FAIL;
3376
3377     IImageList_Release(src);
3378     return ret;
3379 }
3380
3381 static HRESULT WINAPI ImageListImpl_Merge(IImageList *iface, int i1,
3382     IUnknown *punk2, int i2, int dx, int dy, REFIID riid, void **ppv)
3383 {
3384     HIMAGELIST This = (HIMAGELIST) iface;
3385     IImageList *iml2 = NULL;
3386     HIMAGELIST hNew;
3387     HRESULT ret = E_FAIL;
3388
3389     TRACE("(%p)->(%d %p %d %d %d %s %p)\n", iface, i1, punk2, i2, dx, dy, debugstr_guid(riid), ppv);
3390
3391     /* TODO: Add test for IID_ImageList2 too */
3392     if (FAILED(IImageList_QueryInterface(punk2, &IID_IImageList,
3393             (void **) &iml2)))
3394         return E_FAIL;
3395
3396     hNew = ImageList_Merge(This, i1, (HIMAGELIST) iml2, i2, dx, dy);
3397
3398     /* Get the interface for the new image list */
3399     if (hNew)
3400     {
3401         IImageList *imerge = (IImageList*)hNew;
3402
3403         ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
3404         IImageList_Release(imerge);
3405     }
3406
3407     IImageList_Release(iml2);
3408     return ret;
3409 }
3410
3411 static HRESULT WINAPI ImageListImpl_Clone(IImageList *iface, REFIID riid, void **ppv)
3412 {
3413     HIMAGELIST This = (HIMAGELIST) iface;
3414     HIMAGELIST clone;
3415     HRESULT ret = E_FAIL;
3416
3417     TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
3418
3419     clone = ImageList_Duplicate(This);
3420
3421     /* Get the interface for the new image list */
3422     if (clone)
3423     {
3424         IImageList *iclone = (IImageList*)clone;
3425
3426         ret = HIMAGELIST_QueryInterface(clone, riid, ppv);
3427         IImageList_Release(iclone);
3428     }
3429
3430     return ret;
3431 }
3432
3433 static HRESULT WINAPI ImageListImpl_GetImageRect(IImageList *iface, int i,
3434     RECT *prc)
3435 {
3436     HIMAGELIST This = (HIMAGELIST) iface;
3437     IMAGEINFO info;
3438
3439     if (!prc)
3440         return E_FAIL;
3441
3442     if (!ImageList_GetImageInfo(This, i, &info))
3443         return E_FAIL;
3444
3445     return CopyRect(prc, &info.rcImage) ? S_OK : E_FAIL;
3446 }
3447
3448 static HRESULT WINAPI ImageListImpl_GetIconSize(IImageList *iface, int *cx,
3449     int *cy)
3450 {
3451     HIMAGELIST This = (HIMAGELIST) iface;
3452
3453     return ImageList_GetIconSize(This, cx, cy) ? S_OK : E_INVALIDARG;
3454 }
3455
3456 static HRESULT WINAPI ImageListImpl_SetIconSize(IImageList *iface, int cx,
3457     int cy)
3458 {
3459     return ImageList_SetIconSize((HIMAGELIST) iface, cx, cy) ? S_OK : E_FAIL;
3460 }
3461
3462 static HRESULT WINAPI ImageListImpl_GetImageCount(IImageList *iface, int *pi)
3463 {
3464     *pi = ImageList_GetImageCount((HIMAGELIST) iface);
3465     return S_OK;
3466 }
3467
3468 static HRESULT WINAPI ImageListImpl_SetImageCount(IImageList *iface,
3469     UINT uNewCount)
3470 {
3471     return ImageList_SetImageCount((HIMAGELIST) iface, uNewCount) ? S_OK : E_FAIL;
3472 }
3473
3474 static HRESULT WINAPI ImageListImpl_SetBkColor(IImageList *iface, COLORREF clrBk,
3475     COLORREF *pclr)
3476 {
3477     *pclr = ImageList_SetBkColor((HIMAGELIST) iface, clrBk);
3478     return S_OK;
3479 }
3480
3481 static HRESULT WINAPI ImageListImpl_GetBkColor(IImageList *iface, COLORREF *pclr)
3482 {
3483     *pclr = ImageList_GetBkColor((HIMAGELIST) iface);
3484     return S_OK;
3485 }
3486
3487 static HRESULT WINAPI ImageListImpl_BeginDrag(IImageList *iface, int iTrack,
3488     int dxHotspot, int dyHotspot)
3489 {
3490     return ImageList_BeginDrag((HIMAGELIST) iface, iTrack, dxHotspot, dyHotspot) ? S_OK : E_FAIL;
3491 }
3492
3493 static HRESULT WINAPI ImageListImpl_EndDrag(IImageList *iface)
3494 {
3495     ImageList_EndDrag();
3496     return S_OK;
3497 }
3498
3499 static HRESULT WINAPI ImageListImpl_DragEnter(IImageList *iface, HWND hwndLock,
3500     int x, int y)
3501 {
3502     return ImageList_DragEnter(hwndLock, x, y) ? S_OK : E_FAIL;
3503 }
3504
3505 static HRESULT WINAPI ImageListImpl_DragLeave(IImageList *iface, HWND hwndLock)
3506 {
3507     return ImageList_DragLeave(hwndLock) ? S_OK : E_FAIL;
3508 }
3509
3510 static HRESULT WINAPI ImageListImpl_DragMove(IImageList *iface, int x, int y)
3511 {
3512     return ImageList_DragMove(x, y) ? S_OK : E_FAIL;
3513 }
3514
3515 static HRESULT WINAPI ImageListImpl_SetDragCursorImage(IImageList *iface,
3516     IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot)
3517 {
3518     IImageList *iml2 = NULL;
3519     HRESULT ret;
3520
3521     if (!punk)
3522         return E_FAIL;
3523
3524     /* TODO: Add test for IID_ImageList2 too */
3525     if (FAILED(IImageList_QueryInterface(punk, &IID_IImageList,
3526             (void **) &iml2)))
3527         return E_FAIL;
3528
3529     ret = ImageList_SetDragCursorImage((HIMAGELIST) iml2, iDrag, dxHotspot,
3530         dyHotspot);
3531
3532     IImageList_Release(iml2);
3533
3534     return ret ? S_OK : E_FAIL;
3535 }
3536
3537 static HRESULT WINAPI ImageListImpl_DragShowNolock(IImageList *iface, BOOL fShow)
3538 {
3539     return ImageList_DragShowNolock(fShow) ? S_OK : E_FAIL;
3540 }
3541
3542 static HRESULT WINAPI ImageListImpl_GetDragImage(IImageList *iface, POINT *ppt,
3543     POINT *pptHotspot, REFIID riid, PVOID *ppv)
3544 {
3545     HRESULT ret = E_FAIL;
3546     HIMAGELIST hNew;
3547
3548     if (!ppv)
3549         return E_FAIL;
3550
3551     hNew = ImageList_GetDragImage(ppt, pptHotspot);
3552
3553     /* Get the interface for the new image list */
3554     if (hNew)
3555     {
3556         IImageList *idrag = (IImageList*)hNew;
3557
3558         ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
3559         IImageList_Release(idrag);
3560     }
3561
3562     return ret;
3563 }
3564
3565 static HRESULT WINAPI ImageListImpl_GetItemFlags(IImageList *iface, int i,
3566     DWORD *dwFlags)
3567 {
3568     FIXME("STUB: %p %d %p\n", iface, i, dwFlags);
3569     return E_NOTIMPL;
3570 }
3571
3572 static HRESULT WINAPI ImageListImpl_GetOverlayImage(IImageList *iface, int iOverlay,
3573     int *piIndex)
3574 {
3575     HIMAGELIST This = (HIMAGELIST) iface;
3576     int i;
3577
3578     if ((iOverlay < 0) || (iOverlay > This->cCurImage))
3579         return E_FAIL;
3580
3581     for (i = 0; i < MAX_OVERLAYIMAGE; i++)
3582     {
3583         if (This->nOvlIdx[i] == iOverlay)
3584         {
3585             *piIndex = i + 1;
3586             return S_OK;
3587         }
3588     }
3589
3590     return E_FAIL;
3591 }
3592
3593
3594 static const IImageListVtbl ImageListImpl_Vtbl = {
3595     ImageListImpl_QueryInterface,
3596     ImageListImpl_AddRef,
3597     ImageListImpl_Release,
3598     ImageListImpl_Add,
3599     ImageListImpl_ReplaceIcon,
3600     ImageListImpl_SetOverlayImage,
3601     ImageListImpl_Replace,
3602     ImageListImpl_AddMasked,
3603     ImageListImpl_Draw,
3604     ImageListImpl_Remove,
3605     ImageListImpl_GetIcon,
3606     ImageListImpl_GetImageInfo,
3607     ImageListImpl_Copy,
3608     ImageListImpl_Merge,
3609     ImageListImpl_Clone,
3610     ImageListImpl_GetImageRect,
3611     ImageListImpl_GetIconSize,
3612     ImageListImpl_SetIconSize,
3613     ImageListImpl_GetImageCount,
3614     ImageListImpl_SetImageCount,
3615     ImageListImpl_SetBkColor,
3616     ImageListImpl_GetBkColor,
3617     ImageListImpl_BeginDrag,
3618     ImageListImpl_EndDrag,
3619     ImageListImpl_DragEnter,
3620     ImageListImpl_DragLeave,
3621     ImageListImpl_DragMove,
3622     ImageListImpl_SetDragCursorImage,
3623     ImageListImpl_DragShowNolock,
3624     ImageListImpl_GetDragImage,
3625     ImageListImpl_GetItemFlags,
3626     ImageListImpl_GetOverlayImage
3627 };
3628
3629 static BOOL is_valid(HIMAGELIST himl)
3630 {
3631     BOOL valid;
3632     __TRY
3633     {
3634         valid = himl && himl->lpVtbl == &ImageListImpl_Vtbl;
3635     }
3636     __EXCEPT_PAGE_FAULT
3637     {
3638         valid = FALSE;
3639     }
3640     __ENDTRY
3641     return valid;
3642 }
3643
3644 /*************************************************************************
3645  * HIMAGELIST_QueryInterface [COMCTL32.@]
3646  *
3647  * Returns a pointer to an IImageList or IImageList2 object for the given
3648  * HIMAGELIST.
3649  *
3650  * PARAMS
3651  *     himl        [I] Image list handle.
3652  *     riid        [I] Identifier of the requested interface.
3653  *     ppv         [O] Returns the address of the pointer requested, or NULL.
3654  *
3655  * RETURNS
3656  *     Success: S_OK.
3657  *     Failure: Error value.
3658  */
3659 HRESULT WINAPI
3660 HIMAGELIST_QueryInterface (HIMAGELIST himl, REFIID riid, void **ppv)
3661 {
3662     TRACE("(%p,%s,%p)\n", himl, debugstr_guid(riid), ppv);
3663     return IImageList_QueryInterface((IImageList *) himl, riid, ppv);
3664 }
3665
3666 static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv)
3667 {
3668     HIMAGELIST This;
3669     HRESULT ret;
3670
3671     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
3672
3673     *ppv = NULL;
3674
3675     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
3676
3677     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct _IMAGELIST));
3678     if (!This) return E_OUTOFMEMORY;
3679
3680     This->lpVtbl = &ImageListImpl_Vtbl;
3681     This->ref = 1;
3682
3683     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
3684     IUnknown_Release((IUnknown*)This);
3685
3686     return ret;
3687 }