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