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