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