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