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