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