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