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