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