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