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