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